]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: mailbox_list_delete_mailbox_nonrecursive() - Fix error handling
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 27 Jun 2017 12:39:12 +0000 (15:39 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 3 Jul 2017 12:22:18 +0000 (15:22 +0300)
It should return error on unexpected readdir(), closedir() and unlink()
failures. Also fix handling a race condition with another process deleting
the mailbox at the same time.

src/lib-storage/list/mailbox-list-delete.c

index d94dbfa2ab4fc63f6b0f9ff1587e446bc0c28b56..89d1e373537c6210fbabb384316a81b9b37c4acb 100644 (file)
@@ -146,6 +146,7 @@ int mailbox_list_delete_mailbox_nonrecursive(struct mailbox_list *list,
        string_t *full_path;
        size_t dir_len;
        bool mailbox_dir, unlinked_something = FALSE;
+       int ret = 0;
 
        if (mailbox_list_check_root_delete(list, name, path) < 0)
                return -1;
@@ -203,20 +204,30 @@ int mailbox_list_delete_mailbox_nonrecursive(struct mailbox_list *list,
                else if (errno != ENOENT && !UNLINK_EISDIR(errno)) {
                        mailbox_list_set_critical(list,
                                "unlink(%s) failed: %m", str_c(full_path));
+                       ret = -1;
                }
        }
-       if (errno != 0)
+       if (errno != 0) {
                mailbox_list_set_critical(list, "readdir(%s) failed: %m", path);
+               ret = -1;
+       }
        if (closedir(dir) < 0) {
                mailbox_list_set_critical(list, "closedir(%s) failed: %m",
                                          path);
+               ret = -1;
        }
+       if (ret < 0)
+               return -1;
 
        if (rmdir_path) {
                if (rmdir(path) == 0)
                        unlinked_something = TRUE;
-               else if (errno != ENOENT &&
-                        errno != ENOTEMPTY && errno != EEXIST) {
+               else if (errno == ENOENT) {
+                       /* race condition with another process, which finished
+                          deleting it first. */
+                       mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+                               T_MAILBOX_LIST_ERR_NOT_FOUND(list, name));
+               } else if (errno != ENOTEMPTY && errno != EEXIST) {
                        mailbox_list_set_critical(list, "rmdir(%s) failed: %m",
                                                  path);
                        return -1;