]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dbox: Fixed race condition when opening a message that was just moved to a different...
authorTimo Sirainen <tss@iki.fi>
Wed, 25 Mar 2009 22:13:36 +0000 (18:13 -0400)
committerTimo Sirainen <tss@iki.fi>
Wed, 25 Mar 2009 22:13:36 +0000 (18:13 -0400)
--HG--
branch : HEAD

src/lib-storage/index/dbox/dbox-file.c
src/lib-storage/index/dbox/dbox-file.h
src/lib-storage/index/dbox/dbox-mail.c
src/lib-storage/index/dbox/dbox-map-private.h
src/lib-storage/index/dbox/dbox-map.h

index ce0f3c8ed76bbeefe049c42abbdc56fdf8a8b2fc..dc1b6032e462c79b3dca892c37d2791a2b28d394 100644 (file)
@@ -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 {
index aa49ee0747eb3669472cff64391e07a20f343efc..1b8bc313dd1f4c808936e2d94ddd21afdc009211 100644 (file)
@@ -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);
index fde2368a8574675b7bde33be5c2f253a05779f58..8af53b08042c0d051578220460c01d305c211342 100644 (file)
@@ -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;
        }
index 398f4ba5ee90e490974c19a98b9e3fd744fed373..1e5a71ef5b0b3e3ac191e4a08b2ee5af86cbbaf3 100644 (file)
@@ -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);
 
index e12eef70e205818f0bbad0f71642300f3df53d20..145d4537d0608c19544c1a4d9f83d52f05c8650c 100644 (file)
@@ -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. */