mbox-file.c revision 573f0491a5733fe21fa062a455acb4790b4e0499
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "istream.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mbox-storage.h"
dfa2201c6ac8ddb2d2798dee15662cfe774e644eMartti Rannanjärvi#include "mbox-sync-private.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "mbox-file.h"
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen#include "istream-raw-mbox.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <sys/stat.h>
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen#include <utime.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MBOX_READ_BLOCK_SIZE (1024*4)
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint mbox_file_open(struct mbox_mailbox *mbox)
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen{
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen struct stat st;
5a6343181a5183b1ae1c39d40fc5a1deb3b840d9Timo Sirainen int fd;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(mbox->mbox_fd == -1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mbox->mbox_file_stream != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* read-only mbox stream */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(mbox->ibox.backend_readonly);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen fd = open(mbox->ibox.box.path,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox->ibox.backend_readonly ? O_RDONLY : O_RDWR);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (fd == -1 && errno == EACCES && !mbox->ibox.backend_readonly) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox->ibox.backend_readonly = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen fd = open(mbox->ibox.box.path, O_RDONLY);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (fd == -1) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mbox_set_syscall_error(mbox, "open()");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (fstat(fd, &st) < 0) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mbox_set_syscall_error(mbox, "fstat()");
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen (void)close(fd);
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen return -1;
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen }
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mbox->mbox_writeonly = S_ISFIFO(st.st_mode);
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen mbox->mbox_fd = fd;
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen mbox->mbox_dev = st.st_dev;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->mbox_ino = st.st_ino;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
104318260228780a5c6b3181b3401e8e504e2776Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid mbox_file_close(struct mbox_mailbox *mbox)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox_file_close_stream(mbox);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mbox->mbox_fd != -1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (close(mbox->mbox_fd) < 0)
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen mbox_set_syscall_error(mbox, "close()");
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen mbox->mbox_fd = -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint mbox_file_open_stream(struct mbox_mailbox *mbox)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen if (mbox->mbox_stream != NULL)
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen return 0;
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen if (mbox->mbox_file_stream != NULL) {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen /* read-only mbox stream */
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen i_assert(mbox->mbox_fd == -1 && mbox->ibox.backend_readonly);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen } else {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen if (mbox->mbox_fd == -1) {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen if (mbox_file_open(mbox) < 0)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen return -1;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen }
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen if (mbox->mbox_writeonly) {
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen mbox->mbox_file_stream =
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen i_stream_create_from_data(NULL, 0);
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen } else {
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen mbox->mbox_file_stream =
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_create_fd(mbox->mbox_fd,
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen MBOX_READ_BLOCK_SIZE,
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen FALSE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_set_init_buffer_size(mbox->mbox_file_stream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MBOX_READ_BLOCK_SIZE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mbox->mbox_stream = i_stream_create_raw_mbox(mbox->mbox_file_stream,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mbox->ibox.box.path);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (mbox->mbox_lock_type != F_UNLCK)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen istream_raw_mbox_set_locked(mbox->mbox_stream);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void mbox_file_fix_atime(struct mbox_mailbox *mbox)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct utimbuf buf;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct stat st;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mbox->ibox.recent_flags_count > 0 &&
7fe37c2b0e4cd2a39896ab16e47eb418a59e3934Timo Sirainen (mbox->ibox.box.flags & MAILBOX_FLAG_KEEP_RECENT) != 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox->mbox_fd != -1 && !mbox->ibox.backend_readonly) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we've seen recent messages which we want to keep recent.
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen keep file's atime lower than mtime so \Marked status
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen gets shown while listing */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (fstat(mbox->mbox_fd, &st) < 0) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen mbox_set_syscall_error(mbox, "fstat()");
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen return;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (st.st_atime >= st.st_mtime) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen buf.modtime = st.st_mtime;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen buf.actime = buf.modtime - 1;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (utime(mbox->ibox.box.path, &buf) < 0) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen mbox_set_syscall_error(mbox, "utimes()");
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen return;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen}
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenvoid mbox_file_close_stream(struct mbox_mailbox *mbox)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen{
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* if we read anything, fix the atime if needed */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen mbox_file_fix_atime(mbox);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (mbox->mbox_stream != NULL)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen i_stream_destroy(&mbox->mbox_stream);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (mbox->mbox_file_stream != NULL) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (mbox->mbox_fd == -1) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* read-only mbox stream */
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen i_assert(mbox->ibox.backend_readonly);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen i_stream_seek(mbox->mbox_file_stream, 0);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen } else {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen i_stream_destroy(&mbox->mbox_file_stream);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenint mbox_file_lookup_offset(struct mbox_mailbox *mbox,
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen struct mail_index_view *view,
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen uint32_t seq, uoff_t *offset_r)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen{
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen const void *data;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen bool deleted;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen mail_index_lookup_ext(view, seq, mbox->mbox_ext_idx, &data, &deleted);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (deleted)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (data == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
28bf8f762fcd21c57bf71822cf818447babce9a0Timo Sirainen "Cached message offset lost for seq %u in mbox file %s",
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen seq, mbox->ibox.box.path);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen mbox->mbox_hdr.dirty_flag = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox->mbox_broken_offsets = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen *offset_r = *((const uint64_t *)data);
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen return 1;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen}
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Boschint mbox_file_seek(struct mbox_mailbox *mbox, struct mail_index_view *view,
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen uint32_t seq, bool *deleted_r)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen uoff_t offset;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen int ret;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen ret = mbox_file_lookup_offset(mbox, view, seq, &offset);
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen if (ret <= 0) {
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen *deleted_r = ret < 0;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen return ret;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen }
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen *deleted_r = FALSE;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (istream_raw_mbox_seek(mbox->mbox_stream, offset) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (offset == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox->invalid_mbox_file = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_error(&mbox->storage->storage,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAIL_ERROR_NOTPOSSIBLE,
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen "Mailbox isn't a valid mbox file");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen }
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen if (mbox->mbox_hdr.dirty_flag)
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen return 0;
28bf8f762fcd21c57bf71822cf818447babce9a0Timo Sirainen
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen "Cached message offset %s is invalid for mbox file %s",
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen dec2str(offset), mbox->ibox.box.path);
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen mbox->mbox_hdr.dirty_flag = TRUE;
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen mbox->mbox_broken_offsets = TRUE;
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mbox->mbox_hdr.dirty_flag) {
1904e2fc786dbc037039d284b371730777277fc5Aki Tuomi /* we're dirty - make sure this is the correct mail */
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen if (!mbox_sync_parse_match_mail(mbox, view, seq))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen ret = istream_raw_mbox_seek(mbox->mbox_stream, offset);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(ret == 0);
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen }
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen return 1;
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen