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()"); } } }
static void mbox_mailbox_close(struct mailbox *box) { struct mbox_mailbox *mbox = (struct mbox_mailbox *)box; const struct mail_index_header *hdr; enum mbox_sync_flags sync_flags = 0; if (mbox->mbox_stream != NULL && istream_raw_mbox_is_corrupted(mbox->mbox_stream)) { /* clear the corruption by forcing a full resync */ sync_flags |= MBOX_SYNC_UNDIRTY | MBOX_SYNC_FORCE_SYNC; } if (box->view != NULL) { hdr = mail_index_get_header(box->view); if ((hdr->flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0 && !mbox_is_backend_readonly(mbox)) { /* we've done changes to mbox which haven't been written yet. do it now. */ sync_flags |= MBOX_SYNC_REWRITE; } } if (sync_flags != 0 && !mbox->invalid_mbox_file) (void)mbox_sync(mbox, sync_flags); if (mbox->mbox_global_lock_id != 0) mbox_unlock(mbox, mbox->mbox_global_lock_id); if (mbox->keep_lock_to != NULL) timeout_remove(&mbox->keep_lock_to); mbox_file_close(mbox); if (mbox->mbox_file_stream != NULL) i_stream_destroy(&mbox->mbox_file_stream); index_storage_mailbox_close(box); }
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; }
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; }
static bool mbox_storage_is_readonly(struct mailbox *box) { struct mbox_mailbox *mbox = (struct mbox_mailbox *)box; if (index_storage_is_readonly(box)) return TRUE; if (mbox_is_backend_readonly(mbox)) { /* return read-only only if there are no private flags (that are stored in index files) */ if (mailbox_get_private_flags_mask(box) == 0) return TRUE; } return FALSE; }
void mbox_file_close_stream(struct mbox_mailbox *mbox) { /* if we read anything, fix the atime if needed */ mbox_file_fix_atime(mbox); if (mbox->mbox_stream != NULL) 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); } } }
static int mbox_save_init_file(struct mbox_save_context *ctx, struct mbox_transaction_context *t, bool want_mail) { struct mailbox_transaction_context *_t = &t->t; struct mbox_mailbox *mbox = ctx->mbox; struct mail_storage *storage = &mbox->storage->storage; bool empty = FALSE; int ret; if (mbox_is_backend_readonly(ctx->mbox)) { mail_storage_set_error(storage, MAIL_ERROR_PERM, "Read-only mbox"); return -1; } if ((_t->flags & MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS) != 0 || ctx->ctx.data.uid != 0) want_mail = TRUE; if (ctx->append_offset == (uoff_t)-1) { /* first appended mail in this transaction */ if (t->write_lock_id == 0) { if (mbox_lock(mbox, F_WRLCK, &t->write_lock_id) <= 0) return -1; } if (mbox->mbox_fd == -1) { if (mbox_file_open(mbox) < 0) return -1; } /* update mbox_sync_dirty state */ ret = mbox_sync_has_changed_full(mbox, TRUE, &empty); if (ret < 0) return -1; if (!want_mail && ret == 0) { /* we're not required to assign UIDs for the appended mails immediately. do it only if it doesn't require syncing. */ mbox_save_init_sync(_t); } } if (!ctx->synced && (want_mail || empty)) { /* we'll need to assign UID for the mail immediately. */ if (mbox_sync(mbox, 0) < 0) return -1; mbox_save_init_sync(_t); } /* the syncing above could have changed the append offset */ if (ctx->append_offset == (uoff_t)-1) { if (mbox_seek_to_end(ctx, &ctx->append_offset) < 0) return -1; ctx->output = o_stream_create_fd_file(mbox->mbox_fd, ctx->append_offset, FALSE); o_stream_cork(ctx->output); } return 0; }