registry: Implement recursive deletes for dir-backed registry.
authorAndrew Kroeger <andrew@sprocks.gotdns.com>
Sat, 16 Feb 2008 21:15:50 +0000 (15:15 -0600)
committerAndrew Kroeger <andrew@sprocks.gotdns.com>
Wed, 27 Feb 2008 01:27:14 +0000 (19:27 -0600)
When deleting a registry key that contains subkeys or values, Windows performs a
recursive deletion that removes any subkeys or values.  This update makes
deletes for an dir-backed registry consistent with Windows.

The dir-backed registry relies on the underlying filesystem, which does not
generally have transactional integrity when performing multiple operations.
Therefore, if an error occurs during the recursive deletion, the dir-backed
registry may be left in an inconsistent state.
(This used to be commit 6b5fbf7e4e38342bcd80e63f46cd295f89ab1ee9)

source4/lib/registry/dir.c

index 27cae8c49062ed9ba1ba670f47f3bc594b422763..dc3717e88614e80e312df946033bf00a2a33d866 100644 (file)
@@ -55,18 +55,66 @@ static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx,
        return WERR_GENERAL_FAILURE;
 }
 
        return WERR_GENERAL_FAILURE;
 }
 
+static WERROR reg_dir_delete_recursive(const char *name)
+{
+       DIR *d;
+       struct dirent *e;
+       WERROR werr;
+
+       d = opendir(name);
+       if (d == NULL) {
+               DEBUG(3,("Unable to open '%s': %s\n", name,
+                     strerror(errno)));
+               return WERR_BADFILE;
+       }
+
+       while((e = readdir(d))) {
+               char *path;
+               struct stat stbuf;
+
+               if (ISDOT(e->d_name) || ISDOTDOT(e->d_name))
+                       continue;
+
+               path = talloc_asprintf(name, "%s/%s", name, e->d_name);
+               if (!path)
+                       return WERR_NOMEM;
+
+               stat(path, &stbuf);
+
+               if (!S_ISDIR(stbuf.st_mode)) {
+                       if (unlink(path) < 0) {
+                               talloc_free(path);
+                               closedir(d);
+                               return WERR_GENERAL_FAILURE;
+                       }
+               } else {
+                       werr = reg_dir_delete_recursive(path);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               talloc_free(path);
+                               closedir(d);
+                               return werr;
+                       }
+               }
+
+               talloc_free(path);
+       }
+       closedir(d);
+
+       if (rmdir(name) == 0)
+               return WERR_OK;
+       else if (errno == ENOENT)
+               return WERR_BADFILE;
+       else
+               return WERR_GENERAL_FAILURE;
+}
+
 static WERROR reg_dir_del_key(const struct hive_key *k, const char *name)
 {
        struct dir_key *dk = talloc_get_type(k, struct dir_key);
        char *child = talloc_asprintf(NULL, "%s/%s", dk->path, name);
        WERROR ret;
 
 static WERROR reg_dir_del_key(const struct hive_key *k, const char *name)
 {
        struct dir_key *dk = talloc_get_type(k, struct dir_key);
        char *child = talloc_asprintf(NULL, "%s/%s", dk->path, name);
        WERROR ret;
 
-       if (rmdir(child) == 0)
-               ret = WERR_OK;
-       else if (errno == ENOENT)
-               ret = WERR_BADFILE;
-       else
-               ret = WERR_GENERAL_FAILURE;
+       ret = reg_dir_delete_recursive(child);
 
        talloc_free(child);
 
 
        talloc_free(child);