]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
[m]dbox: If alt-dir exists for a mailbox while trying to create it, rebuild mailbox...
authorTimo Sirainen <tss@iki.fi>
Mon, 28 Jun 2010 21:00:58 +0000 (22:00 +0100)
committerTimo Sirainen <tss@iki.fi>
Mon, 28 Jun 2010 21:00:58 +0000 (22:00 +0100)
This makes sure that if there are any mails in the alt-dir, they become
visible rather than be overwritten.

--HG--
branch : HEAD

src/lib-storage/index/dbox-common/dbox-storage.c
src/lib-storage/index/dbox-common/dbox-storage.h
src/lib-storage/index/dbox-multi/mdbox-storage.c
src/lib-storage/index/dbox-single/sdbox-storage.c
src/lib-storage/list/mailbox-list-fs.c

index 5fb7b0a132eb3086d6846b1634c7b5dc10775c6d..871444a93b122f517a2d8be34918ddedd3eed40c 100644 (file)
@@ -10,6 +10,8 @@
 #include "dbox-storage.h"
 
 #include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
 
 void dbox_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
                                    struct mailbox_list_settings *set)
@@ -90,6 +92,36 @@ int dbox_mailbox_open(struct mailbox *box)
        }
 }
 
+static int dir_is_empty(struct mail_storage *storage, const char *path)
+{
+       DIR *dir;
+       struct dirent *d;
+       int ret = 1;
+
+       dir = opendir(path);
+       if (dir == NULL) {
+               if (errno == ENOENT) {
+                       /* race condition with DELETE/RENAME? */
+                       return 1;
+               }
+               mail_storage_set_critical(storage, "opendir(%s) failed: %m",
+                                         path);
+               return -1;
+       }
+       while ((d = readdir(dir)) != NULL) {
+               if (*d->d_name == '.')
+                       continue;
+
+               ret = 0;
+       }
+       if (closedir(dir) < 0) {
+               mail_storage_set_critical(storage, "closedir(%s) failed: %m",
+                                         path);
+               ret = -1;
+       }
+       return ret;
+}
+
 int dbox_mailbox_create(struct mailbox *box,
                        const struct mailbox_update *update, bool directory)
 {
@@ -97,6 +129,8 @@ int dbox_mailbox_create(struct mailbox *box,
        struct mail_index_sync_ctx *sync_ctx;
        struct mail_index_view *view;
        struct mail_index_transaction *trans;
+       const char *alt_path;
+       struct stat st;
        int ret;
 
        if (directory &&
@@ -106,6 +140,25 @@ int dbox_mailbox_create(struct mailbox *box,
        if (index_storage_mailbox_open(box, FALSE) < 0)
                return -1;
 
+       /* if alt path already exists and contains files, rebuild storage so
+          that we don't start overwriting files. */
+       alt_path = mailbox_list_get_path(box->list, box->name,
+                                        MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX);
+       if (alt_path != NULL && stat(alt_path, &st) == 0) {
+               ret = dir_is_empty(box->storage, alt_path);
+               if (ret < 0)
+                       return -1;
+               if (ret == 0) {
+                       mail_storage_set_critical(&storage->storage,
+                               "Mailbox %s has existing files in alt path, "
+                               "rebuilding storage to avoid losing messages",
+                               box->vname);
+                       storage->v.set_mailbox_corrupted(box);
+                       return -1;
+               }
+               /* dir is empty, ignore it */
+       }
+
        /* use syncing as a lock */
        ret = mail_index_sync_begin(box->index, &sync_ctx, &view, &trans, 0);
        if (ret <= 0) {
index 782932203b19ec466049ff7b40fc8b77b48475d8..84955aaa326b53f0524259c7ea1429aa3f4febeb 100644 (file)
@@ -39,6 +39,8 @@ struct dbox_storage_vfuncs {
        int (*mailbox_create_indexes)(struct mailbox *box,
                                      const struct mailbox_update *update,
                                      struct mail_index_transaction *trans);
+       /* mark the mailbox corrupted */
+       void (*set_mailbox_corrupted)(struct mailbox *box);
        /* mark the file corrupted */
        void (*set_file_corrupted)(struct dbox_file *file);
 };
index a3e499cf2a3378b55ca3f06ffaf616af7ee29222..fc54288d7223aa0e87663cb7f9346639731947e4 100644 (file)
@@ -270,6 +270,13 @@ void mdbox_storage_set_corrupted(struct mdbox_storage *storage)
        }
 }
 
+static void mdbox_set_mailbox_corrupted(struct mailbox *box)
+{
+       struct mdbox_storage *mstorage = (struct mdbox_storage *)box->storage;
+
+       mdbox_storage_set_corrupted(mstorage);
+}
+
 static void mdbox_set_file_corrupted(struct dbox_file *file)
 {
        struct mdbox_storage *mstorage = (struct mdbox_storage *)file->storage;
@@ -426,5 +433,6 @@ struct dbox_storage_vfuncs mdbox_dbox_storage_vfuncs = {
        mdbox_file_create_fd,
        mdbox_mail_open,
        mdbox_mailbox_create_indexes,
+       mdbox_set_mailbox_corrupted,
        mdbox_set_file_corrupted
 };
index 3d5ea02c685623dc809efe3b90dd01e3487c2d12..78990a4beb79347f70fd818eca8a45df3d9eb1bf 100644 (file)
@@ -198,11 +198,18 @@ static int sdbox_mailbox_create_indexes(struct mailbox *box,
        return ret;
 }
 
-static void sdbox_set_file_corrupted(struct dbox_file *file ATTR_UNUSED)
+static void sdbox_set_mailbox_corrupted(struct mailbox *box ATTR_UNUSED)
 {
        /* FIXME */
 }
 
+static void sdbox_set_file_corrupted(struct dbox_file *_file)
+{
+       struct sdbox_file *file = (struct sdbox_file *)_file;
+
+       sdbox_set_mailbox_corrupted(&file->mbox->box);
+}
+
 static int
 sdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
 {
@@ -309,5 +316,6 @@ struct dbox_storage_vfuncs sdbox_dbox_storage_vfuncs = {
        sdbox_file_create_fd,
        sdbox_mail_open,
        sdbox_mailbox_create_indexes,
+       sdbox_set_mailbox_corrupted,
        sdbox_set_file_corrupted
 };
index 5fdd7f3c788b41a56e8ad40e9e5cda0c404372fe..4fe139648fa45e341fa80710238be0a8b22ab474 100644 (file)
@@ -316,27 +316,12 @@ static int
 fs_list_create_mailbox_dir(struct mailbox_list *list, const char *name,
                           bool directory)
 {
-       const char *path, *alt_path, *gid_origin, *p;
-       struct stat st;
+       const char *path, *gid_origin, *p;
        mode_t mode;
        gid_t gid;
        bool create_parent_dir;
        int ret;
 
-       /* make sure the alt path doesn't exist yet. it shouldn't (except with
-          race conditions with RENAME/DELETE), but if something crashed and
-          left it lying around we don't want to start overwriting files in
-          it. */
-       if (!directory) {
-               alt_path = mailbox_list_get_path(list, name,
-                                       MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX);
-               if (alt_path != NULL && stat(alt_path, &st) == 0) {
-                       mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
-                                              "Mailbox already exists");
-                       return -1;
-               }
-       }
-
        path = mailbox_list_get_path(list, name,
                                     directory ? MAILBOX_LIST_PATH_TYPE_DIR :
                                     MAILBOX_LIST_PATH_TYPE_MAILBOX);