summaryrefslogtreecommitdiffstats
path: root/src/lib-storage/index/mbox/mbox-file.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
commitf7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch)
treea3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/lib-storage/index/mbox/mbox-file.c
parentInitial commit. (diff)
downloaddovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.tar.xz
dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.zip
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib-storage/index/mbox/mbox-file.c')
-rw-r--r--src/lib-storage/index/mbox/mbox-file.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/lib-storage/index/mbox/mbox-file.c b/src/lib-storage/index/mbox/mbox-file.c
new file mode 100644
index 0000000..b71abb8
--- /dev/null
+++ b/src/lib-storage/index/mbox/mbox-file.c
@@ -0,0 +1,207 @@
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "istream.h"
+#include "mbox-storage.h"
+#include "mbox-sync-private.h"
+#include "mbox-file.h"
+#include "istream-raw-mbox.h"
+
+#include <sys/stat.h>
+#include <utime.h>
+
+#define MBOX_READ_BLOCK_SIZE IO_BLOCK_SIZE
+
+int mbox_file_open(struct mbox_mailbox *mbox)
+{
+ struct stat st;
+ int fd;
+
+ i_assert(mbox->mbox_fd == -1);
+
+ if (mbox->mbox_file_stream != NULL) {
+ /* read-only mbox stream */
+ i_assert(mbox_is_backend_readonly(mbox));
+ return 0;
+ }
+
+ fd = open(mailbox_get_path(&mbox->box),
+ mbox_is_backend_readonly(mbox) ? O_RDONLY : O_RDWR);
+ if (fd == -1 && errno == EACCES && !mbox->backend_readonly) {
+ mbox->backend_readonly = TRUE;
+ fd = open(mailbox_get_path(&mbox->box), O_RDONLY);
+ }
+
+ if (fd == -1) {
+ mbox_set_syscall_error(mbox, "open()");
+ return -1;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ mbox_set_syscall_error(mbox, "fstat()");
+ i_close_fd(&fd);
+ return -1;
+ }
+
+ mbox->mbox_writeonly = S_ISFIFO(st.st_mode);
+ mbox->mbox_fd = fd;
+ mbox->mbox_dev = st.st_dev;
+ mbox->mbox_ino = st.st_ino;
+ return 0;
+}
+
+void mbox_file_close(struct mbox_mailbox *mbox)
+{
+ mbox_file_close_stream(mbox);
+
+ if (mbox->mbox_fd != -1) {
+ if (close(mbox->mbox_fd) < 0)
+ mbox_set_syscall_error(mbox, "close()");
+ mbox->mbox_fd = -1;
+ }
+}
+
+int mbox_file_open_stream(struct mbox_mailbox *mbox)
+{
+ if (mbox->mbox_stream != NULL)
+ return 0;
+
+ if (mbox->mbox_file_stream != NULL) {
+ /* read-only mbox stream */
+ i_assert(mbox->mbox_fd == -1 && mbox_is_backend_readonly(mbox));
+ } else {
+ if (mbox->mbox_fd == -1) {
+ if (mbox_file_open(mbox) < 0)
+ return -1;
+ }
+
+ if (mbox->mbox_writeonly) {
+ mbox->mbox_file_stream =
+ i_stream_create_from_data("", 0);
+ } else {
+ mbox->mbox_file_stream =
+ i_stream_create_fd(mbox->mbox_fd,
+ MBOX_READ_BLOCK_SIZE);
+ i_stream_set_init_buffer_size(mbox->mbox_file_stream,
+ MBOX_READ_BLOCK_SIZE);
+ }
+ i_stream_set_name(mbox->mbox_file_stream,
+ mailbox_get_path(&mbox->box));
+ }
+
+ mbox->mbox_stream = i_stream_create_raw_mbox(mbox->mbox_file_stream);
+ if (mbox->mbox_lock_type != F_UNLCK)
+ istream_raw_mbox_set_locked(mbox->mbox_stream);
+ return 0;
+}
+
+static void mbox_file_fix_atime(struct mbox_mailbox *mbox)
+{
+ struct utimbuf buf;
+ struct stat st;
+
+ if (mbox->box.recent_flags_count > 0 &&
+ (mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) == 0 &&
+ mbox->mbox_fd != -1 && !mbox_is_backend_readonly(mbox)) {
+ /* we've seen recent messages which we want to keep recent.
+ keep file's atime lower than mtime so \Marked status
+ gets shown while listing */
+ if (fstat(mbox->mbox_fd, &st) < 0) {
+ mbox_set_syscall_error(mbox, "fstat()");
+ return;
+ }
+ if (st.st_atime >= st.st_mtime) {
+ buf.modtime = st.st_mtime;
+ buf.actime = buf.modtime - 1;
+ /* EPERM can happen with shared mailboxes */
+ if (utime(mailbox_get_path(&mbox->box), &buf) < 0 &&
+ errno != EPERM)
+ mbox_set_syscall_error(mbox, "utime()");
+ }
+ }
+}
+void mbox_file_close_stream(struct mbox_mailbox *mbox)
+{
+ /* if we read anything, fix the atime if needed */
+ mbox_file_fix_atime(mbox);
+
+ i_stream_destroy(&mbox->mbox_stream);
+
+ if (mbox->mbox_file_stream != NULL) {
+ if (mbox->mbox_fd == -1) {
+ /* read-only mbox stream */
+ i_assert(mbox_is_backend_readonly(mbox));
+ i_stream_seek(mbox->mbox_file_stream, 0);
+ } else {
+ i_stream_destroy(&mbox->mbox_file_stream);
+ }
+ }
+}
+
+int mbox_file_lookup_offset(struct mbox_mailbox *mbox,
+ struct mail_index_view *view,
+ uint32_t seq, uoff_t *offset_r)
+{
+ const void *data;
+ bool deleted;
+
+ mail_index_lookup_ext(view, seq, mbox->mbox_ext_idx, &data, &deleted);
+ if (deleted)
+ return -1;
+
+ if (data == NULL) {
+ mailbox_set_critical(&mbox->box,
+ "Cached message offset lost for seq %u in mbox", seq);
+ mbox->mbox_hdr.dirty_flag = 1;
+ mbox->mbox_broken_offsets = TRUE;
+ return 0;
+ }
+
+ *offset_r = *((const uint64_t *)data);
+ return 1;
+}
+
+int mbox_file_seek(struct mbox_mailbox *mbox, struct mail_index_view *view,
+ uint32_t seq, bool *deleted_r)
+{
+ uoff_t offset;
+ int ret;
+
+ ret = mbox_file_lookup_offset(mbox, view, seq, &offset);
+ if (ret <= 0) {
+ *deleted_r = ret < 0;
+ return ret;
+ }
+ *deleted_r = FALSE;
+
+ if (istream_raw_mbox_seek(mbox->mbox_stream, offset) < 0) {
+ if (offset == 0) {
+ mbox->invalid_mbox_file = TRUE;
+ mail_storage_set_error(&mbox->storage->storage,
+ MAIL_ERROR_NOTPOSSIBLE,
+ "Mailbox isn't a valid mbox file");
+ return -1;
+ }
+
+ if (mbox->mbox_hdr.dirty_flag != 0)
+ return 0;
+
+ mailbox_set_critical(&mbox->box,
+ "Cached message offset %s is invalid for mbox",
+ dec2str(offset));
+ mbox->mbox_hdr.dirty_flag = 1;
+ mbox->mbox_broken_offsets = TRUE;
+ return 0;
+ }
+
+ if (mbox->mbox_hdr.dirty_flag != 0) {
+ /* we're dirty - make sure this is the correct mail */
+ if (!mbox_sync_parse_match_mail(mbox, view, seq))
+ return 0;
+
+ ret = istream_raw_mbox_seek(mbox->mbox_stream, offset);
+ i_assert(ret == 0);
+ }
+
+ return 1;
+}