dovecot: If uidlist changes while it's being iterated, don't crash.

dovecot at dovecot.org dovecot at dovecot.org
Mon Jul 9 05:44:41 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/699356ffe549
changeset: 5913:699356ffe549
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Jul 08 22:53:31 2007 +0300
description:
If uidlist changes while it's being iterated, don't crash.

diffstat:

1 file changed, 35 insertions(+)
src/lib-storage/index/maildir/maildir-uidlist.c |   35 +++++++++++++++++++++++

diffs (98 lines):

diff -r 53abd603e04b -r 699356ffe549 src/lib-storage/index/maildir/maildir-uidlist.c
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Sun Jul 08 22:19:56 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Sun Jul 08 22:53:31 2007 +0300
@@ -50,6 +50,8 @@ struct maildir_uidlist {
 	pool_t record_pool;
 	ARRAY_TYPE(maildir_uidlist_rec_p) records;
 	struct hash_table *files;
+	unsigned int change_counter;
+
 	struct dotlock_settings dotlock_settings;
 	struct dotlock *dotlock;
 
@@ -81,7 +83,11 @@ struct maildir_uidlist_sync_ctx {
 };
 
 struct maildir_uidlist_iter_ctx {
+	struct maildir_uidlist *uidlist;
 	struct maildir_uidlist_rec *const *next, *const *end;
+
+	unsigned int change_counter;
+	uint32_t prev_uid;
 };
 
 static int maildir_uidlist_lock_timeout(struct maildir_uidlist *uidlist,
@@ -372,6 +378,7 @@ maildir_uidlist_update_read(struct maild
 		uidlist->uid_validity = uid_validity;
 		uidlist->next_uid = next_uid;
 		uidlist->prev_read_uid = 0;
+		uidlist->change_counter++;
 
 		ret = 1;
 		while ((line = i_stream_read_next_line(input)) != NULL) {
@@ -772,6 +779,7 @@ maildir_uidlist_sync_next_partial(struct
 			    struct maildir_uidlist_rec, 1);
 		rec->uid = (uint32_t)-1;
 		array_append(&uidlist->records, &rec, 1);
+		uidlist->change_counter++;
 	}
 
 	if ((flags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0 &&
@@ -942,6 +950,8 @@ static void maildir_uidlist_swap(struct 
 
 	if (ctx->new_files_count != 0)
 		maildir_uidlist_assign_uids(ctx, count - ctx->new_files_count);
+
+	ctx->uidlist->change_counter++;
 }
 
 void maildir_uidlist_sync_finish(struct maildir_uidlist_sync_ctx *ctx)
@@ -1031,9 +1041,30 @@ maildir_uidlist_iter_init(struct maildir
 	unsigned int count;
 
 	ctx = i_new(struct maildir_uidlist_iter_ctx, 1);
+	ctx->uidlist = uidlist;
 	ctx->next = array_get(&uidlist->records, &count);
 	ctx->end = ctx->next + count;
+	ctx->change_counter = ctx->uidlist->change_counter;
 	return ctx;
+}
+
+static void
+maildir_uidlist_iter_update_idx(struct maildir_uidlist_iter_ctx *ctx)
+{
+	unsigned int old_rev_idx, idx, count;
+
+	old_rev_idx = ctx->end - ctx->next;
+	ctx->next = array_get(&ctx->uidlist->records, &count);
+	ctx->end = ctx->next + count;
+
+	idx = old_rev_idx >= count ? 0 :
+		count - old_rev_idx;
+	while (idx < count && ctx->next[idx]->uid <= ctx->prev_uid)
+		idx++;
+	while (idx > 0 && ctx->next[idx-1]->uid > ctx->prev_uid)
+		idx--;
+
+	ctx->next += idx;
 }
 
 int maildir_uidlist_iter_next(struct maildir_uidlist_iter_ctx *ctx,
@@ -1041,6 +1072,9 @@ int maildir_uidlist_iter_next(struct mai
 			      enum maildir_uidlist_rec_flag *flags_r,
 			      const char **filename_r)
 {
+	if (ctx->change_counter != ctx->uidlist->change_counter)
+		maildir_uidlist_iter_update_idx(ctx);
+
 	if (ctx->next == ctx->end)
 		return 0;
 
@@ -1048,6 +1082,7 @@ int maildir_uidlist_iter_next(struct mai
 	*flags_r = (*ctx->next)->flags;
 	*filename_r = (*ctx->next)->filename;
 	ctx->next++;
+	ctx->prev_uid = *uid_r;
 	return 1;
 }
 


More information about the dovecot-cvs mailing list