diff options
author | Andrew Kroeger <andrew@sprocks.gotdns.com> | 2008-02-16 15:15:50 -0600 |
---|---|---|
committer | Andrew Kroeger <andrew@sprocks.gotdns.com> | 2008-02-26 19:27:14 -0600 |
commit | 2bbd319cafe64935682799240b9c0aa9ff4d7e7a (patch) | |
tree | 3bb7f8636e5fc2beae5b088daf2a5748c8f30ab1 /source4/lib/registry | |
parent | 7dac0598ec6edb63f15a7cce7c231f56f9ab7f7d (diff) | |
download | samba-2bbd319cafe64935682799240b9c0aa9ff4d7e7a.tar.gz samba-2bbd319cafe64935682799240b9c0aa9ff4d7e7a.tar.bz2 samba-2bbd319cafe64935682799240b9c0aa9ff4d7e7a.zip |
registry: Implement recursive deletes for dir-backed registry.
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)
Diffstat (limited to 'source4/lib/registry')
-rw-r--r-- | source4/lib/registry/dir.c | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/source4/lib/registry/dir.c b/source4/lib/registry/dir.c index 27cae8c490..dc3717e886 100644 --- a/source4/lib/registry/dir.c +++ b/source4/lib/registry/dir.c @@ -55,18 +55,66 @@ static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx, 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; - 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); |