mbox-file.c revision e5afebd2df1d4990f7bec2a839260ff2e6d78168
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mbox-storage.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mbox-sync-private.h"
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen#include "mbox-file.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-raw-mbox.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <utime.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mbox_file_open(struct mbox_mailbox *mbox)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct stat st;
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen int fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(mbox->mbox_fd == -1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mbox->mbox_file_stream != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* read-only mbox stream */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(mbox->mbox_readonly);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fd = open(mbox->path, mbox->mbox_readonly ? O_RDONLY : O_RDWR);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fd == -1 && errno == EACCES && !mbox->mbox_readonly) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->mbox_readonly = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen fd = open(mbox->path, O_RDONLY);
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fd == -1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox_set_syscall_error(mbox, "open()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen if (fstat(fd, &st) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox_set_syscall_error(mbox, "fstat()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)close(fd);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen mbox->mbox_writeonly = S_ISFIFO(st.st_mode);
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen mbox->mbox_fd = fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->mbox_dev = st.st_dev;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen mbox->mbox_ino = st.st_ino;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mbox_file_close(struct mbox_mailbox *mbox)
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen{
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen mbox_file_close_stream(mbox);
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen if (mbox->mbox_fd != -1) {
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen if (close(mbox->mbox_fd) < 0)
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen i_error("close(mbox) failed: %m");
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen mbox->mbox_fd = -1;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainenint mbox_file_open_stream(struct mbox_mailbox *mbox)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mbox->mbox_stream != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mbox->mbox_file_stream != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* read-only mbox stream */
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_assert(mbox->mbox_fd == -1 && mbox->mbox_readonly);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen mbox->mbox_stream =
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_stream_create_raw_mbox(mbox->mbox_file_stream,
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen mbox->path);
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (mbox->mbox_fd == -1) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mbox_file_open(mbox) < 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return -1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (mbox->mbox_writeonly)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->mbox_file_stream = i_stream_create_from_data(NULL, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->mbox_file_stream =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_create_fd(mbox->mbox_fd,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen MAIL_READ_BLOCK_SIZE, FALSE);
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen mbox->mbox_stream = i_stream_create_raw_mbox(mbox->mbox_file_stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->path);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return 0;
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen}
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainenstatic void mbox_file_fix_atime(struct mbox_mailbox *mbox)
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen{
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen struct utimbuf buf;
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen struct stat st;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (mbox->ibox.recent_flags_count > 0 && mbox->ibox.keep_recent &&
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mbox->mbox_fd != -1 && !mbox->mbox_readonly) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* we've seen recent messages which we want to keep recent.
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen keep file's atime lower than mtime so \Marked status
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen gets shown while listing */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (fstat(mbox->mbox_fd, &st) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox_set_syscall_error(mbox, "fstat()");
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen }
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (st.st_atime >= st.st_mtime) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen buf.modtime = st.st_mtime;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen buf.actime = buf.modtime - 1;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (utime(mbox->path, &buf) < 0) {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen mbox_set_syscall_error(mbox, "utimes()");
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen}
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenvoid mbox_file_close_stream(struct mbox_mailbox *mbox)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* if we read anything, fix the atime if needed */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen mbox_file_fix_atime(mbox);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mbox->mbox_stream != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_destroy(&mbox->mbox_stream);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (mbox->mbox_file_stream != NULL) {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (mbox->mbox_fd == -1) {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen /* read-only mbox stream */
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_assert(mbox->mbox_readonly);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_stream_seek(mbox->mbox_file_stream, 0);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen } else {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_stream_destroy(&mbox->mbox_file_stream);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen }
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainenint mbox_file_lookup_offset(struct mbox_mailbox *mbox,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen struct mail_index_view *view,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen uint32_t seq, uoff_t *offset_r)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen{
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen const void *data;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen bool deleted;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen mail_index_lookup_ext(view, seq, mbox->mbox_ext_idx, &data, &deleted);
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen if (deleted)
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen return -1;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen if (data == NULL) {
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen "Cached message offset lost for seq %u in mbox file %s",
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen seq, mbox->path);
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen mbox->mbox_sync_dirty = TRUE;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen return 0;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen *offset_r = *((const uint64_t *)data);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return 1;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen}
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainenint mbox_file_seek(struct mbox_mailbox *mbox, struct mail_index_view *view,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen uint32_t seq, bool *deleted_r)
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen{
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen uoff_t offset;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen int ret;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen ret = mbox_file_lookup_offset(mbox, view, seq, &offset);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (ret <= 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen *deleted_r = ret < 0;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return ret;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen *deleted_r = FALSE;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
8b58939517a381db55670089c0984da39fc0f099Timo Sirainen if (istream_raw_mbox_seek(mbox->mbox_stream, offset) < 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (offset == 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen mbox->invalid_mbox_file = TRUE;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen mail_storage_set_error(&mbox->storage->storage,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen MAIL_ERROR_NOTPOSSIBLE,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen "Mailbox isn't a valid mbox file");
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return -1;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (mbox->mbox_sync_dirty)
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return 0;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen "Cached message offset %s is invalid for mbox file %s",
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen dec2str(offset), mbox->path);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen mbox->mbox_sync_dirty = TRUE;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return 0;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (mbox->mbox_sync_dirty) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* we're dirty - make sure this is the correct mail */
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (!mbox_sync_parse_match_mail(mbox, view, seq))
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return 0;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen ret = istream_raw_mbox_seek(mbox->mbox_stream, offset);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen i_assert(ret == 0);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return 1;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen}
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen