]> 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)
committerGitLab <gitlab@git.dovecot.net>
Thu, 29 Jun 2017 12:46:49 +0000 (15:46 +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 9dc44bf3f1113bb502ed9e88486b9791a1bed856..5ecd4525285286e139ebdca93025f99c3df41ea3 100644 (file)
@@ -147,6 +147,7 @@ int mailbox_list_delete_mailbox_nonrecursive(struct mailbox_list *list,
        size_t dir_len;
        const char *error;
        bool mailbox_dir, unlinked_something = FALSE;
+       int ret = 0;
 
        if (mailbox_list_check_root_delete(list, name, path) < 0)
                return -1;
@@ -204,20 +205,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;