mbox-sync.c revision 28b30e9bd1a0a8b9019124abd821cb2989a03910
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen/* Copyright (c) 2004-2008 Dovecot authors, see the included COPYING file */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen Modifying mbox can be slow, so we try to do it all at once minimizing the
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen required disk I/O. We may need to:
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - Update message flags in Status, X-Status and X-Keywords headers
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - Write missing X-UID and X-IMAPbase headers
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - Write missing or broken Content-Length header if there's space
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - Expunge specified messages
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen Here's how we do it:
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - Start reading the mails from the beginning
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - X-Keywords, X-UID and X-IMAPbase headers may contain padding at the end
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen of them, remember how much each message has and offset to beginning of the
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - If header needs to be rewritten and there's enough space, do it
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - If we didn't have enough space, remember how much was missing
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - Continue reading and counting the padding in each message. If available
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen padding is enough to rewrite all the previous messages needing it, do it
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - When we encounter expunged message, treat all of it as padding and
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen rewrite previous messages if needed (and there's enough space).
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen Afterwards keep moving messages backwards to fill the expunged space.
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen Moving is done by rewriting each message's headers, with possibly adding
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen missing Content-Length header and padding. Message bodies are moved
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen without modifications.
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - If we encounter end of file, grow the file and rewrite needed messages
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen - Rewriting is done by moving message body forward, rewriting message's
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen header and doing the same for previous message, until all of them are
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen/* The text below was taken exactly as c-client wrote it to my mailbox,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen so it's probably copyrighted by University of Washington. */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen"This text is part of the internal format of your mail folder, and is not\n" \
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen"a real message. It is created automatically by the mail system software.\n" \
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen"If deleted, important folder data will be lost, and it will be re-created\n" \
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen"with the data reset to initial values.\n"
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid mbox_sync_set_critical(struct mbox_sync_context *sync_ctx,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen const char *fmt, ...)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen "mbox file %s was modified while we were syncing, "
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen "check your locking settings", sync_ctx->mbox->path);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen "Unexpectedly lost From-line at offset %"PRIuUOFF_T
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainenvoid mbox_sync_file_update_ext_modified(struct mbox_sync_context *sync_ctx)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* Do this even if ext_modified is already set. Expunging code relies
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen on last_stat being updated. */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (st.st_size != sync_ctx->last_stat.st_size ||
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid mbox_sync_file_updated(struct mbox_sync_context *sync_ctx, bool dirty)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* just mark the stat as dirty. */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (fstat(sync_ctx->write_fd, &sync_ctx->last_stat) < 0)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* get EOF */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
return TRUE;
return ret;
unsigned char hdr_md5_sum[],
const void *data;
bool nocheck)
const void *data;
if (!nocheck) {
const void *ext_data;
&idx_keywords);
MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
bool dirty;
const unsigned char *data;
if (from_line_size == 0)
const char *str;
int ret;
if (ret < 0) {
if (ret == 0) {
unsigned int i, count;
for (i = 0; i < count; i++) {
int ret;
if (ret < 0)
if (ret > 0) {
-move_diff);
move_diff = 0;
int ret;
bool deleted;
if (seq == 0) {
seq++;
if (ret < 0) {
if (deleted) {
if (ret == 0) {
old_offset) < 0) {
uid = 0;
bool *skipped_mails)
int ret;
if (uid != 0) {
if (ret == 0) {
return ret;
return TRUE;
return FALSE;
bool partial)
int ret;
if (ret <= 0)
return ret;
uid = 0;
if (uid != 0) {
ret = 0;
if (ret == 0) {
uid = 0;
} else if (uid == 0 &&
&expunged);
if (!expunged) {
} T_END;
} T_END;
if (!expunged) {
} else if (partial) {
&partial,
if (ret <= 0) {
if (ret < 0)
if (!skipped_mails)
unsigned int uid_validity;
trailer_size = 0;
trailer_size) < 0)
if (offset == 0) {
if (ret > 0)
if (ret < 0)
bool empty;
bool *empty_r)
unsigned int lock_id = 0;
bool delay_writes;
if (!changed)
lock_id = 0;
if (changed) {
int ret;
sync_flags = 0;
if (ret <= 0) {
if (ret < 0)
if (lock_id != 0)
return ret;
if (lock_id != 0)
bool expunged;
if (uid == 0) {
goto nothing_to_do;
if (lock_id == 0) {
goto again;
if (ret < 0)
unsigned int read_lock_id = 0;
return ret;
int ret;
return ret;
struct mailbox_sync_context *
int ret = 0;