[dovecot-cvs] dovecot/src/lib-storage/index/mbox mbox-sync-private.h, 1.56.2.9, 1.56.2.10 mbox-sync-rewrite.c, 1.62.2.15, 1.62.2.16 mbox-sync.c, 1.181.2.16, 1.181.2.17
tss at dovecot.org
tss at dovecot.org
Wed Mar 21 23:57:15 EET 2007
Update of /var/lib/cvs/dovecot/src/lib-storage/index/mbox
In directory talvi:/tmp/cvs-serv22770
Modified Files:
Tag: branch_1_0
mbox-sync-private.h mbox-sync-rewrite.c mbox-sync.c
Log Message:
Check if mbox has been modified externally before doing any dangerous
writes. Also changed the old "space needed changed unexpectedly" assert to a
more informative panic.
Index: mbox-sync-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync-private.h,v
retrieving revision 1.56.2.9
retrieving revision 1.56.2.10
diff -u -d -r1.56.2.9 -r1.56.2.10
--- mbox-sync-private.h 14 Mar 2007 12:09:36 -0000 1.56.2.9
+++ mbox-sync-private.h 21 Mar 2007 21:57:13 -0000 1.56.2.10
@@ -4,6 +4,8 @@
#include "md5.h"
#include "mail-index.h"
+#include <sys/stat.h>
+
enum mbox_sync_flags {
MBOX_SYNC_LAST_COMMIT = 0x01,
MBOX_SYNC_HEADER = 0x02,
@@ -103,6 +105,7 @@
time_t orig_mtime;
uoff_t orig_size;
+ struct stat last_stat;
struct mail_index_sync_ctx *index_sync_ctx;
struct mail_index_view *sync_view;
@@ -159,6 +162,8 @@
struct mbox_sync_mail *mail,
bool *keywords_changed_r);
int mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset);
+bool mbox_sync_file_is_ext_modified(struct mbox_sync_context *sync_ctx);
+void mbox_sync_file_updated(struct mbox_sync_context *sync_ctx, bool dirty);
int mbox_move(struct mbox_sync_context *sync_ctx,
uoff_t dest, uoff_t source, uoff_t size);
void mbox_sync_move_buffer(struct mbox_sync_mail_context *ctx,
Index: mbox-sync-rewrite.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync-rewrite.c,v
retrieving revision 1.62.2.15
retrieving revision 1.62.2.16
diff -u -d -r1.62.2.15 -r1.62.2.16
--- mbox-sync-rewrite.c 21 Mar 2007 21:12:52 -0000 1.62.2.15
+++ mbox-sync-rewrite.c 21 Mar 2007 21:57:13 -0000 1.62.2.16
@@ -55,7 +55,7 @@
"o_stream_send_istream()");
}
- i_stream_sync(sync_ctx->input);
+ mbox_sync_file_updated(sync_ctx, FALSE);
o_stream_destroy(&output);
return (int)ret;
}
@@ -79,6 +79,7 @@
mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
return -1;
}
+ mbox_sync_file_updated(sync_ctx, TRUE);
return 0;
}
@@ -314,7 +315,7 @@
mbox_sync_first_mail_written(ctx, ctx->hdr_offset + move_diff);
}
- i_stream_sync(sync_ctx->input);
+ mbox_sync_file_updated(sync_ctx, FALSE);
return 1;
}
@@ -408,19 +409,15 @@
i_stream_seek(sync_ctx->input, mail_ctx->body_offset);
}
- if (first_nonexpunged && expunged_space > 0) {
- /* move From-line (after parsing headers so we don't
- overwrite them) */
- if (mbox_move(sync_ctx, mails[idx].from_offset - expunged_space,
- mails[idx].from_offset,
- mails[idx].offset - mails[idx].from_offset) < 0)
- return -1;
- }
-
if (mail_ctx->mail.space <= 0) {
need_space = str_len(mail_ctx->header) - mail_ctx->mail.space -
(mail_ctx->body_offset - mail_ctx->hdr_offset);
if (need_space != (uoff_t)-mails[idx].space) {
+ /* this check works only if we're doing the first
+ write, or if the file size was changed externally */
+ if (mbox_sync_file_is_ext_modified(sync_ctx))
+ return -1;
+
i_panic("mbox %s: seq=%u uid=%u uid_broken=%d "
"originally needed %"PRIuUOFF_T
" bytes, now needs %"PRIuSIZE_T" bytes",
@@ -430,6 +427,15 @@
}
}
+ if (first_nonexpunged && expunged_space > 0) {
+ /* move From-line (after parsing headers so we don't
+ overwrite them) */
+ if (mbox_move(sync_ctx, mails[idx].from_offset - expunged_space,
+ mails[idx].from_offset,
+ mails[idx].offset - mails[idx].from_offset) < 0)
+ return -1;
+ }
+
if (mails[idx].space == 0) {
/* don't touch spacing */
} else if (padding < (uoff_t)mail_ctx->mail.space) {
@@ -458,6 +464,7 @@
mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
return -1;
}
+ mbox_sync_file_updated(sync_ctx, TRUE);
if (sync_ctx->dest_first_mail) {
mbox_sync_first_mail_written(mail_ctx, dest_offset);
@@ -585,7 +592,7 @@
i_assert(mails[idx].from_offset == start_offset);
i_assert(move_diff + (off_t)expunged_space >= 0);
- i_stream_sync(sync_ctx->input);
+ mbox_sync_file_updated(sync_ctx, FALSE);
sync_ctx->prev_msg_uid = orig_prev_msg_uid;
return ret;
}
Index: mbox-sync.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync.c,v
retrieving revision 1.181.2.16
retrieving revision 1.181.2.17
diff -u -d -r1.181.2.16 -r1.181.2.17
--- mbox-sync.c 14 Mar 2007 16:17:48 -0000 1.181.2.16
+++ mbox-sync.c 21 Mar 2007 21:57:13 -0000 1.181.2.17
@@ -74,6 +74,46 @@
return 0;
}
+bool mbox_sync_file_is_ext_modified(struct mbox_sync_context *sync_ctx)
+{
+ struct stat st;
+
+ if (fstat(sync_ctx->write_fd, &st) < 0) {
+ mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
+ return TRUE;
+ }
+
+ if (st.st_size != sync_ctx->last_stat.st_size ||
+ (sync_ctx->last_stat.st_mtime != 0 &&
+ (st.st_mtime != sync_ctx->last_stat.st_mtime
+#ifdef HAVE_STAT_TV_NSEC
+ /* nanoseconds give better precision to this check if they're
+ supported by the OS */
+ || st.st_mtim.tv_nsec != sync_ctx->last_stat.st_mtim.tv_nsec
+#endif
+ ))) {
+ mail_storage_set_critical(STORAGE(sync_ctx->mbox->storage),
+ "mbox file %s was modified while we were syncing, "
+ "check your locking settings", sync_ctx->mbox->path);
+ return TRUE;
+ }
+
+ sync_ctx->last_stat = st;
+ return FALSE;
+}
+
+void mbox_sync_file_updated(struct mbox_sync_context *sync_ctx, bool dirty)
+{
+ if (dirty) {
+ /* just mark the stat as dirty. */
+ sync_ctx->last_stat.st_mtime = 0;
+ return;
+ }
+ if (fstat(sync_ctx->write_fd, &sync_ctx->last_stat) < 0)
+ mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
+ i_stream_sync(sync_ctx->input);
+}
+
static void mbox_sync_array_delete_to(array_t *syncs_arr, uint32_t last_uid)
{
ARRAY_SET_TYPE(syncs_arr, struct mail_index_sync_rec);
@@ -624,6 +664,7 @@
mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
return -1;
}
+ mbox_sync_file_updated(sync_ctx, FALSE);
sync_ctx->base_uid_last = sync_ctx->next_uid - 1;
return 0;
@@ -640,7 +681,7 @@
return -1;
}
- i_stream_sync(ctx->sync_ctx->input);
+ mbox_sync_file_updated(ctx->sync_ctx, FALSE);
return 0;
}
@@ -851,6 +892,9 @@
extra_space = sync_ctx->space_diff;
}
+ if (mbox_sync_file_is_ext_modified(sync_ctx))
+ return -1;
+
if (mbox_sync_rewrite(sync_ctx,
last_seq == sync_ctx->seq ? mail_ctx : NULL,
end_offset, move_diff, extra_space,
@@ -1185,6 +1229,9 @@
} else if (sync_ctx->expunged_space > 0) {
if (!expunged) {
/* move the body */
+ if (mbox_sync_file_is_ext_modified(sync_ctx))
+ return -1;
+
if (mbox_move(sync_ctx,
mail_ctx->body_offset -
sync_ctx->expunged_space,
@@ -1280,9 +1327,6 @@
return 0;
}
- /* make sure i_stream_stat() doesn't try to use cached file size */
- i_stream_sync(sync_ctx->file_input);
-
st = i_stream_stat(sync_ctx->file_input, TRUE);
if (st == NULL) {
mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
@@ -1317,6 +1361,9 @@
i_assert(sync_ctx->space_diff < 0);
+ if (mbox_sync_file_is_ext_modified(sync_ctx))
+ return -1;
+
if (file_set_size(sync_ctx->write_fd,
file_size + -sync_ctx->space_diff) < 0) {
mbox_set_syscall_error(sync_ctx->mbox,
@@ -1327,7 +1374,7 @@
}
return -1;
}
- i_stream_sync(sync_ctx->input);
+ mbox_sync_file_updated(sync_ctx, FALSE);
if (mbox_sync_rewrite(sync_ctx, mail_ctx, file_size,
-sync_ctx->space_diff, padding,
@@ -1345,15 +1392,11 @@
if (sync_ctx->expunged_space > 0) {
i_assert(sync_ctx->write_fd != -1);
- /* copy trailer, then truncate the file */
- st = i_stream_stat(sync_ctx->file_input, TRUE);
- if (st == NULL) {
- mbox_set_syscall_error(sync_ctx->mbox,
- "i_stream_stat()");
+ if (mbox_sync_file_is_ext_modified(sync_ctx))
return -1;
- }
- file_size = st->st_size;
+ /* copy trailer, then truncate the file */
+ file_size = sync_ctx->last_stat.st_size;
if (file_size == (uoff_t)sync_ctx->expunged_space) {
/* everything deleted, the trailer_size still contains
the \n trailer though */
@@ -1380,7 +1423,7 @@
}
sync_ctx->expunged_space = 0;
- i_stream_sync(sync_ctx->input);
+ mbox_sync_file_updated(sync_ctx, FALSE);
}
return 0;
}
@@ -1516,6 +1559,7 @@
mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
return -1;
}
+ sync_ctx->last_stat = *st;
sync_ctx->orig_size = st->st_size;
sync_ctx->orig_mtime = st->st_mtime;
More information about the dovecot-cvs
mailing list