mbox-file.c revision 23bdbb7b1831785c6ba6df190f6369da882d2b9d
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#include "lib.h"
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#include "istream.h"
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#include "mbox-storage.h"
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch#include "mbox-sync-private.h"
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#include "mbox-file.h"
833bed942977673526c72e79bccc09314fc57104Phil Carmody#include "istream-raw-mbox.h"
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch#include <sys/stat.h>
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#include <utime.h>
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#define MBOX_READ_BLOCK_SIZE IO_BLOCK_SIZE
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Boschint mbox_file_open(struct mbox_mailbox *mbox)
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch{
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch struct stat st;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch int fd;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch i_assert(mbox->mbox_fd == -1);
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch if (mbox->mbox_file_stream != NULL) {
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch /* read-only mbox stream */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_assert(mbox_is_backend_readonly(mbox));
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return 0;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch fd = open(mailbox_get_path(&mbox->box),
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox_is_backend_readonly(mbox) ? O_RDONLY : O_RDWR);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (fd == -1 && errno == EACCES && !mbox->backend_readonly) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox->backend_readonly = TRUE;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch fd = open(mailbox_get_path(&mbox->box), O_RDONLY);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (fd == -1) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox_set_syscall_error(mbox, "open()");
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return -1;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (fstat(fd, &st) < 0) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox_set_syscall_error(mbox, "fstat()");
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_close_fd(&fd);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return -1;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox->mbox_writeonly = S_ISFIFO(st.st_mode);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox->mbox_fd = fd;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox->mbox_dev = st.st_dev;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox->mbox_ino = st.st_ino;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return 0;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch}
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Boschvoid mbox_file_close(struct mbox_mailbox *mbox)
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch{
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch mbox_file_close_stream(mbox);
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch if (mbox->mbox_fd != -1) {
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch if (close(mbox->mbox_fd) < 0)
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch mbox_set_syscall_error(mbox, "close()");
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch mbox->mbox_fd = -1;
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch }
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch}
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch
38af46387e565053adf6c47f7f6871676d685de8Stephan Boschint mbox_file_open_stream(struct mbox_mailbox *mbox)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch{
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox->mbox_stream != NULL)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return 0;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox->mbox_file_stream != NULL) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* read-only mbox stream */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_assert(mbox->mbox_fd == -1 && mbox_is_backend_readonly(mbox));
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch } else {
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch if (mbox->mbox_fd == -1) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox_file_open(mbox) < 0)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return -1;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox->mbox_writeonly) {
7c7117e542b6a44c1db7fc91c0180bdace6dbce7Stephan Bosch mbox->mbox_file_stream =
7c7117e542b6a44c1db7fc91c0180bdace6dbce7Stephan Bosch i_stream_create_from_data("", 0);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch } else {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox->mbox_file_stream =
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_stream_create_fd(mbox->mbox_fd,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen MBOX_READ_BLOCK_SIZE);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen i_stream_set_init_buffer_size(mbox->mbox_file_stream,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen MBOX_READ_BLOCK_SIZE);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen i_stream_set_name(mbox->mbox_file_stream,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mailbox_get_path(&mbox->box));
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mbox->mbox_stream = i_stream_create_raw_mbox(mbox->mbox_file_stream);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox->mbox_lock_type != F_UNLCK)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch istream_raw_mbox_set_locked(mbox->mbox_stream);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return 0;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch}
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstatic void mbox_file_fix_atime(struct mbox_mailbox *mbox)
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch{
dc05b1fb4b7a2b4d91248078311458cb4cbad9a1Stephan Bosch struct utimbuf buf;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch struct stat st;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox->box.recent_flags_count > 0 &&
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch (mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) == 0 &&
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox->mbox_fd != -1 && !mbox_is_backend_readonly(mbox)) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* we've seen recent messages which we want to keep recent.
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch keep file's atime lower than mtime so \Marked status
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch gets shown while listing */
201c3b9375760bafbc180629b4c6ad71ed554aecStephan Bosch if (fstat(mbox->mbox_fd, &st) < 0) {
201c3b9375760bafbc180629b4c6ad71ed554aecStephan Bosch mbox_set_syscall_error(mbox, "fstat()");
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (st.st_atime >= st.st_mtime) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch buf.modtime = st.st_mtime;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch buf.actime = buf.modtime - 1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen /* EPERM can happen with shared mailboxes */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (utime(mailbox_get_path(&mbox->box), &buf) < 0 &&
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen errno != EPERM)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mbox_set_syscall_error(mbox, "utime()");
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
a5886aec87fbfd767a110e6168ce96411acfe798Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch}
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschvoid mbox_file_close_stream(struct mbox_mailbox *mbox)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch{
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* if we read anything, fix the atime if needed */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox_file_fix_atime(mbox);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox->mbox_stream != NULL)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_stream_destroy(&mbox->mbox_stream);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox->mbox_file_stream != NULL) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox->mbox_fd == -1) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* read-only mbox stream */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_assert(mbox_is_backend_readonly(mbox));
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_stream_seek(mbox->mbox_file_stream, 0);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch } else {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_stream_destroy(&mbox->mbox_file_stream);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch}
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
38af46387e565053adf6c47f7f6871676d685de8Stephan Boschint mbox_file_lookup_offset(struct mbox_mailbox *mbox,
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch struct mail_index_view *view,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch uint32_t seq, uoff_t *offset_r)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch{
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch const void *data;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch bool deleted;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mail_index_lookup_ext(view, seq, mbox->mbox_ext_idx, &data, &deleted);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (deleted)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen return -1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (data == NULL) {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen "Cached message offset lost for seq %u in mbox file %s",
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen seq, mailbox_get_path(&mbox->box));
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox->mbox_hdr.dirty_flag = TRUE;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox->mbox_broken_offsets = TRUE;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return 0;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch *offset_r = *((const uint64_t *)data);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return 1;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch}
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschint mbox_file_seek(struct mbox_mailbox *mbox, struct mail_index_view *view,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch uint32_t seq, bool *deleted_r)
e1a4ea6ad3e799ef8df7395e765c0ae9218e6c5dStephan Bosch{
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen uoff_t offset;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int ret;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch ret = mbox_file_lookup_offset(mbox, view, seq, &offset);
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch if (ret <= 0) {
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch *deleted_r = ret < 0;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch return ret;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch }
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch *deleted_r = FALSE;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch if (istream_raw_mbox_seek(mbox->mbox_stream, offset) < 0) {
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch if (offset == 0) {
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch mbox->invalid_mbox_file = TRUE;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch mail_storage_set_error(&mbox->storage->storage,
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch MAIL_ERROR_NOTPOSSIBLE,
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch "Mailbox isn't a valid mbox file");
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch return -1;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mbox->mbox_hdr.dirty_flag != 0)
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch return 0;
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch mail_storage_set_critical(&mbox->storage->storage,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch "Cached message offset %s is invalid for mbox file %s",
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch dec2str(offset), mailbox_get_path(&mbox->box));
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch mbox->mbox_hdr.dirty_flag = TRUE;
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch mbox->mbox_broken_offsets = TRUE;
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch return 0;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch }
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch if (mbox->mbox_hdr.dirty_flag != 0) {
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch /* we're dirty - make sure this is the correct mail */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (!mbox_sync_parse_match_mail(mbox, view, seq))
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch return 0;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch ret = istream_raw_mbox_seek(mbox->mbox_stream, offset);
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch i_assert(ret == 0);
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch }
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch return 1;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch}
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch