From: Timo Sirainen Date: Wed, 25 Mar 2009 22:13:36 +0000 (-0400) Subject: dbox: Fixed race condition when opening a message that was just moved to a different... X-Git-Tag: 2.0.alpha1~1038^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5af57c4025545884f6c5942f46f3dc3a2824154a;p=thirdparty%2Fdovecot%2Fcore.git dbox: Fixed race condition when opening a message that was just moved to a different file. --HG-- branch : HEAD --- diff --git a/src/lib-storage/index/dbox/dbox-file.c b/src/lib-storage/index/dbox/dbox-file.c index ce0f3c8ed7..dc1b6032e4 100644 --- a/src/lib-storage/index/dbox/dbox-file.c +++ b/src/lib-storage/index/dbox/dbox-file.c @@ -387,13 +387,13 @@ static int dbox_file_open_fd(struct dbox_file *file) return 1; } -static int dbox_file_open(struct dbox_file *file, bool *deleted_r) +int dbox_file_open(struct dbox_file *file, bool *deleted_r) { int ret; - i_assert(file->input == NULL); - *deleted_r = FALSE; + if (file->input != NULL) + return 1; if (file->fd == -1) { T_BEGIN { diff --git a/src/lib-storage/index/dbox/dbox-file.h b/src/lib-storage/index/dbox/dbox-file.h index aa49ee0747..1b8bc313dd 100644 --- a/src/lib-storage/index/dbox/dbox-file.h +++ b/src/lib-storage/index/dbox/dbox-file.h @@ -131,9 +131,10 @@ void dbox_files_free(struct dbox_storage *storage); for multi files assign map UID. */ int dbox_file_assign_id(struct dbox_file *file, uint32_t id); -/* Open the file if uid or file_id is not 0, otherwise create it. Returns 1 if - ok, 0 if file header is corrupted, -1 if error. If file is deleted, - deleted_r=TRUE and 1 is returned. */ +/* Open the file. Returns 1 if ok, 0 if file header is corrupted, -1 if error. + If file is deleted, deleted_r=TRUE and 1 is returned. */ +int dbox_file_open(struct dbox_file *file, bool *deleted_r); +/* Open the file if uid or file_id is not 0, otherwise create it. */ int dbox_file_open_or_create(struct dbox_file *file, bool *deleted_r); /* Close the file handle from the file, but don't free it. */ void dbox_file_close(struct dbox_file *file); diff --git a/src/lib-storage/index/dbox/dbox-mail.c b/src/lib-storage/index/dbox/dbox-mail.c index fde2368a85..8af53b0804 100644 --- a/src/lib-storage/index/dbox/dbox-mail.c +++ b/src/lib-storage/index/dbox/dbox-mail.c @@ -113,37 +113,62 @@ static void dbox_mail_set_expunged(struct dbox_mail *mail) mbox->storage->sync_rebuild = TRUE; } -static int dbox_mail_open(struct dbox_mail *mail, - uoff_t *offset_r, struct dbox_file **file_r) +static int dbox_mail_open_init(struct dbox_mail *mail) { struct dbox_mailbox *mbox = (struct dbox_mailbox *)mail->imail.ibox; struct mail *_mail = &mail->imail.mail.mail; uint32_t file_id; int ret; - if (mail->open_file == NULL) { - if (dbox_mail_lookup(mbox, mbox->ibox.view, _mail->seq, - &mail->map_uid) < 0) + if (mail->map_uid == 0) + mail->open_file = dbox_file_init_single(mbox, _mail->uid); + else if ((ret = dbox_map_lookup(mbox->storage->map, mail->map_uid, + &file_id, &mail->offset)) <= 0) { + if (ret < 0) return -1; - if (mail->map_uid == 0) { - mail->open_file = - dbox_file_init_single(mbox, _mail->uid); - } else if ((ret = dbox_map_lookup(mbox->storage->map, - mail->map_uid, &file_id, - &mail->offset)) <= 0) { - if (ret < 0) + + /* map_uid doesn't exist anymore. either it + got just expunged or the map index is + corrupted. */ + dbox_mail_set_expunged(mail); + return -1; + } else { + mail->open_file = dbox_file_init_multi(mbox->storage, file_id); + } + return 0; +} + +static int dbox_mail_open(struct dbox_mail *mail, + uoff_t *offset_r, struct dbox_file **file_r) +{ + struct dbox_mailbox *mbox = (struct dbox_mailbox *)mail->imail.ibox; + struct mail *_mail = &mail->imail.mail.mail; + uint32_t prev_file_id = 0; + bool deleted; + + do { + if (mail->open_file == NULL) { + if (dbox_mail_lookup(mbox, mbox->ibox.view, _mail->seq, + &mail->map_uid) < 0) + return -1; + if (dbox_mail_open_init(mail) < 0) return -1; + } - /* map_uid doesn't exist anymore. either it - got just expunged or the map index is - corrupted. */ - dbox_mail_set_expunged(mail); + if (dbox_file_open(mail->open_file, &deleted) <= 0) return -1; - } else { - mail->open_file = - dbox_file_init_multi(mbox->storage, file_id); + if (deleted) { + /* either it's expunged now or moved to another file. */ + if (mail->open_file->file_id == prev_file_id) { + dbox_mail_set_expunged(mail); + return -1; + } + prev_file_id = mail->open_file->file_id; + if (dbox_map_refresh(mbox->storage->map) < 0) + return -1; + dbox_file_unref(&mail->open_file); } - } + } while (mail->open_file == NULL); *file_r = mail->open_file; *offset_r = mail->offset; @@ -162,10 +187,7 @@ dbox_mail_metadata_read(struct dbox_mail *mail, struct dbox_file **file_r) if (dbox_file_get_mail_stream(*file_r, offset, &size, NULL, &expunged) <= 0) return -1; - if (expunged) { - dbox_mail_set_expunged(mail); - return -1; - } + i_assert(!expunged); if (dbox_file_metadata_read(*file_r) <= 0) return -1; return 0; @@ -339,10 +361,7 @@ dbox_mail_get_stream(struct mail *_mail, struct message_size *hdr_size, "%"PRIuUOFF_T, _mail->uid, offset); return -1; } - if (expunged) { - dbox_mail_set_expunged(mail); - return -1; - } + i_assert(!expunged); data->physical_size = size; data->stream = input; } diff --git a/src/lib-storage/index/dbox/dbox-map-private.h b/src/lib-storage/index/dbox/dbox-map-private.h index 398f4ba5ee..1e5a71ef5b 100644 --- a/src/lib-storage/index/dbox/dbox-map-private.h +++ b/src/lib-storage/index/dbox/dbox-map-private.h @@ -44,7 +44,6 @@ struct dbox_map_append_context { unsigned int committed:1; }; -int dbox_map_refresh(struct dbox_map *map); int dbox_map_view_lookup_rec(struct dbox_map *map, struct mail_index_view *view, uint32_t seq, struct dbox_mail_lookup_rec *rec_r); diff --git a/src/lib-storage/index/dbox/dbox-map.h b/src/lib-storage/index/dbox/dbox-map.h index e12eef70e2..145d4537d0 100644 --- a/src/lib-storage/index/dbox/dbox-map.h +++ b/src/lib-storage/index/dbox/dbox-map.h @@ -32,6 +32,8 @@ void dbox_map_deinit(struct dbox_map **map); /* Open the map. This is done automatically for most operations. Returns 0 if ok, -1 if error. */ int dbox_map_open(struct dbox_map *map, bool create_missing); +/* Refresh the map. Returns 0 if ok, -1 if error. */ +int dbox_map_refresh(struct dbox_map *map); /* Look up file_id and offset for given map UID. Returns 1 if ok, 0 if UID is already expunged, -1 if error. */