]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
maildir: If we see unwanted non-empty directories in new/ or cur/, move them to ...
authorTimo Sirainen <tss@iki.fi>
Tue, 28 Sep 2010 16:15:52 +0000 (17:15 +0100)
committerTimo Sirainen <tss@iki.fi>
Tue, 28 Sep 2010 16:15:52 +0000 (17:15 +0100)
src/lib-storage/index/maildir/maildir-mail.c
src/lib-storage/index/maildir/maildir-storage.h
src/lib-storage/index/maildir/maildir-sync-index.c
src/lib-storage/index/maildir/maildir-util.c

index 8742cc310275353bb15827dc26bf512418cd174b..7bebdaf8a7e8f877540b261b05cc3c402aa36590 100644 (file)
@@ -58,22 +58,6 @@ do_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
        return -1;
 }
 
-static int
-maildir_rmdir_unexpected_dir(struct mail_storage *storage, const char *path)
-{
-       if (rmdir(path) == 0) {
-               mail_storage_set_critical(storage,
-                       "Maildir: rmdir()ed unwanted empty directory: %s",
-                       path);
-               return 0;
-       } else {
-               mail_storage_set_critical(storage,
-                       "Maildir: Found unwanted directory %s, "
-                       "but rmdir() failed: %m", path);
-               return -1;
-       }
-}
-
 static struct istream *
 maildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
                  bool *deleted_r)
@@ -105,14 +89,9 @@ maildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
 
        input = i_stream_create_fd(ctx.fd, 0, TRUE);
        if (input->stream_errno == EISDIR) {
-               /* there's a directory in maildir. many installations seem to
-                  have messed up something and causing "cur", "new" and "tmp"
-                  directories to be created under the "cur" directory.
-                  if the directory is empty, just get rid of it and log an
-                  error */
                i_stream_destroy(&input);
-               if (maildir_rmdir_unexpected_dir(&mbox->storage->storage,
-                                                ctx.path) == 0)
+               if (maildir_lose_unexpected_dir(&mbox->storage->storage,
+                                               ctx.path) >= 0)
                        *deleted_r = TRUE;
        } else {
                i_stream_set_name(input, ctx.path);
index 2f532d5f6fa78da7d2abeffcf7cb2760371ae8ac..c76bbe59c7fb85432928b5cd116fcc3f2b6808da 100644 (file)
@@ -109,6 +109,7 @@ int maildir_file_do(struct maildir_mailbox *mbox, uint32_t uid,
 
 bool maildir_set_deleted(struct mailbox *box);
 uint32_t maildir_get_uidvalidity_next(struct mailbox_list *list);
+int maildir_lose_unexpected_dir(struct mail_storage *storage, const char *path);
 
 struct mail_save_context *
 maildir_save_alloc(struct mailbox_transaction_context *_t);
index bd62d1be5b75a3840e3b33649cd51d6ba4f9abdd..7e710619ec374cca939eebe8a0182087ce7b63fb 100644 (file)
@@ -98,6 +98,8 @@ static int maildir_expunge(struct maildir_mailbox *mbox, const char *path,
        }
        if (errno == ENOENT)
                return 0;
+       if (errno == EISDIR)
+               return maildir_lose_unexpected_dir(box->storage, path);
 
        mail_storage_set_critical(&mbox->storage->storage,
                                  "unlink(%s) failed: %m", path);
index b4be61d4370a9d2d65912073e3624cb34946805c..47bd1191713bdd2c36909f0063e5d8b4e11ed621 100644 (file)
@@ -12,6 +12,7 @@
 #include "maildir-filename.h"
 #include "maildir-sync.h"
 
+#include <stdio.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <fcntl.h>
@@ -224,3 +225,54 @@ bool maildir_set_deleted(struct mailbox *box)
        } T_END;
        return ret < 0 ? FALSE : TRUE;
 }
+
+int maildir_lose_unexpected_dir(struct mail_storage *storage, const char *path)
+{
+       const char *dest, *fname, *p;
+
+       /* There's a directory in maildir, get rid of it.
+
+          In some installations this was caused by a messed up configuration
+          where e.g. mails was initially delivered to new/new/ directory.
+          Also Dovecot v2.0.0 - v2.0.4 sometimes may have renamed tmp/
+          directory under new/ or cur/. */
+       if (rmdir(path) == 0) {
+               mail_storage_set_critical(storage,
+                       "Maildir: rmdir()ed unwanted empty directory: %s",
+                       path);
+               return 1;
+       } else if (errno == ENOENT) {
+               /* someone else rmdired or renamed it */
+               return 0;
+       } else if (errno != ENOTEMPTY) {
+               mail_storage_set_critical(storage,
+                       "Maildir: Found unwanted directory %s, "
+                       "but rmdir() failed: %m", path);
+               return -1;
+       }
+
+       /* It's not safe to delete this directory since it has some files in it,
+          but it's also not helpful to log this message over and over again.
+          Get rid of this error by renaming the directory elsewhere */
+       p = strrchr(path, '/');
+       i_assert(p != NULL);
+       fname = p + 1;
+       while (p != path && p[-1] != '/') p--;
+       i_assert(p != NULL);
+
+       dest = t_strconcat(t_strdup_until(path, p), "extra-", fname, NULL);
+       if (rename(path, dest) == 0) {
+               mail_storage_set_critical(storage,
+                       "Maildir: renamed unwanted directory %s to %s",
+                       path, dest);
+               return 1;
+       } else if (errno == ENOENT) {
+               /* someone else renamed it (could have been flag change) */
+               return 0;
+       } else {
+               mail_storage_set_critical(storage,
+                       "Maildir: Found unwanted directory, "
+                       "but rename(%s, %s) failed: %m", path, dest);
+               return -1;
+       }
+}