summaryrefslogtreecommitdiff
path: root/source4/lib/registry/patchfile.c
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2007-08-26 15:16:40 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 15:02:34 -0500
commitb409d4120f9ae451f93a2322267c0f346531d9f3 (patch)
tree04ac2189f16db99537c36320a9d9e7c3c9d43b6f /source4/lib/registry/patchfile.c
parent8e789517b723955f1530837058d5e9fe98aba19f (diff)
downloadsamba-b409d4120f9ae451f93a2322267c0f346531d9f3.tar.gz
samba-b409d4120f9ae451f93a2322267c0f346531d9f3.tar.bz2
samba-b409d4120f9ae451f93a2322267c0f346531d9f3.zip
r24667: Finally merge the registry improvements that Wilco Baan Hofman and I have
been working on for at least half a year now. Contains the following improvements: * proper layering (finally!) for the registry library. Distinction is now made between 'real' backends (local, remote, wine, etc) and the low-level hive backends (regf, creg, ldb, ...) that are only used by the local registry backend * tests for all important hive and registry operations * re-enable RPC-WINREG tests (still needs more work though, as some return values aren't checked yet) * write support for REGF files * dir backend now supports setting/reading values, creating keys * support for storing security descriptors * remove CREG backend as it was incomplete, didn't match the data model and wasn't used at all anyway * support for parsing ADM files as used by the policy editor (see lib/policy) * support for parsing PREG files (format used by .POL files) * new streaming interface for registry diffs (improves speed and memory usage for regdiff/regpatch significantly) ... and fixes a large number of bugs in the registry code (This used to be commit 7a1eec6358bc863dfc671c542b7185d3e39d7b5a)
Diffstat (limited to 'source4/lib/registry/patchfile.c')
-rw-r--r--source4/lib/registry/patchfile.c561
1 files changed, 281 insertions, 280 deletions
diff --git a/source4/lib/registry/patchfile.c b/source4/lib/registry/patchfile.c
index 12847eedd8..50c8f54397 100644
--- a/source4/lib/registry/patchfile.c
+++ b/source4/lib/registry/patchfile.c
@@ -1,8 +1,9 @@
/*
Unix SMB/CIFS implementation.
- Reading .REG files
+ Reading registry patch files
- Copyright (C) Jelmer Vernooij 2004
+ Copyright (C) Jelmer Vernooij 2004-2007
+ Copyright (C) Wilco Baan Hofman 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,153 +20,191 @@
*/
#include "includes.h"
+#include "lib/registry/patchfile.h"
#include "lib/registry/registry.h"
#include "system/filesys.h"
-/**
- * @file
- * @brief Registry patch files
- */
-
-#define DEFAULT_IDENT_STRING "SAMBA4 REGISTRY"
-
-static struct reg_diff_key *diff_find_add_key(struct reg_diff *diff, const char *path)
-{
- int i;
-
- for (i = 0; diff->numkeys; i++) {
- if (!strcasecmp(diff->keys[i].name, path))
- return &diff->keys[i];
- }
- diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
- diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, path);
- diff->keys[diff->numkeys].changetype = REG_DIFF_CHANGE_KEY;
- diff->keys[diff->numkeys].numvalues = 0;
- diff->keys[diff->numkeys].values = NULL;
+_PUBLIC_ WERROR reg_preg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data);
- diff->numkeys++;
- return NULL;
-}
+_PUBLIC_ WERROR reg_dotreg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data);
/*
* Generate difference between two keys
*/
-static WERROR reg_generate_diff_key(struct reg_diff *diff, struct registry_key *oldkey, struct registry_key *newkey)
+WERROR reg_generate_diff_key(struct registry_key *oldkey,
+ struct registry_key *newkey,
+ const char *path,
+ const struct reg_diff_callbacks *callbacks,
+ void *callback_data)
{
int i;
struct registry_key *t1, *t2;
- struct registry_value *v1, *v2;
- WERROR error1, error2;
+ char *tmppath;
+ const char *keyname1;
+ WERROR error, error1, error2;
TALLOC_CTX *mem_ctx = talloc_init("writediff");
+ uint32_t old_num_subkeys, old_num_values,
+ new_num_subkeys, new_num_values;
- /* Subkeys that were deleted */
- for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i, &t1)); i++) {
- error2 = reg_key_get_subkey_by_name(mem_ctx, newkey, t1->name, &t2);
+ if (oldkey != NULL) {
+ error = reg_key_get_info(mem_ctx, oldkey, NULL, &old_num_subkeys, &old_num_values,
+ NULL);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error occured while getting key info: %s\n",
+ win_errstr(error)));
+ return error;
+ }
+ } else {
+ old_num_subkeys = 0;
+ old_num_values = 0;
+ }
- if (W_ERROR_IS_OK(error2))
+ /* Subkeys that were deleted */
+ for (i = 0; i < old_num_subkeys; i++) {
+ error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i, &keyname1,
+ NULL, NULL);
+ if (!W_ERROR_IS_OK(error1)) {
+ DEBUG(0, ("Error occured while getting subkey by index: %s\n",
+ win_errstr(error2)));
continue;
+ }
+
+ if (newkey != NULL) {
+ error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
+
+ if (W_ERROR_IS_OK(error2))
+ continue;
+ } else {
+ error2 = WERR_DEST_NOT_FOUND;
+ t2 = NULL;
+ }
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
- DEBUG(0, ("Error occured while getting subkey by name: %d\n", W_ERROR_V(error2)));
+ DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+ win_errstr(error2)));
+ talloc_free(mem_ctx);
return error2;
}
/* newkey didn't have such a subkey, add del diff */
- diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
- diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, t1->path);
- diff->keys[diff->numkeys].changetype = REG_DIFF_DEL_KEY;
- diff->numkeys++;
+ tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
+ callbacks->del_key(callback_data, tmppath);
+ talloc_free(tmppath);
}
- if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
- DEBUG(0, ("Error occured while getting subkey by index: %d\n", W_ERROR_V(error1)));
- talloc_free(mem_ctx);
- return error1;
+ if (newkey != NULL) {
+ error = reg_key_get_info(mem_ctx, newkey, NULL, &new_num_subkeys, &new_num_values,
+ NULL);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error occured while getting key info: %s\n",
+ win_errstr(error)));
+ return error;
+ }
+ } else {
+ new_num_subkeys = 0;
+ new_num_values = 0;
}
/* Subkeys that were added */
- for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i, &t1)); i++) {
- error2 = reg_key_get_subkey_by_name(mem_ctx, oldkey, t1->name, &t2);
+ for(i = 0; i < new_num_subkeys; i++) {
+ error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i, &keyname1,
+ NULL, NULL);
+ if (!W_ERROR_IS_OK(error1)) {
+ DEBUG(0, ("Error occured while getting subkey by index: %s\n",
+ win_errstr(error1)));
+ talloc_free(mem_ctx);
+ return error1;
+ }
+
+ if (oldkey != NULL) {
+ error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
+
+ if (W_ERROR_IS_OK(error2))
+ continue;
+ } else {
+ t1 = NULL;
+ error2 = WERR_DEST_NOT_FOUND;
+ }
- if (W_ERROR_IS_OK(error2))
- continue;
-
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
- DEBUG(0, ("Error occured while getting subkey by name: %d\n", W_ERROR_V(error2)));
+ DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+ win_errstr(error2)));
+ talloc_free(mem_ctx);
return error2;
}
/* oldkey didn't have such a subkey, add add diff */
- diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
- diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, t1->path);
- diff->keys[diff->numkeys].changetype = REG_DIFF_CHANGE_KEY;
- diff->keys[diff->numkeys].numvalues = 0;
- diff->keys[diff->numkeys].values = NULL;
- diff->numkeys++;
-
- reg_generate_diff_key(diff, t1, t2);
- }
+ tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
+ callbacks->add_key(callback_data, tmppath);
- if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
- DEBUG(0, ("Error occured while getting subkey by index: %d\n", W_ERROR_V(error1)));
- talloc_free(mem_ctx);
- return error1;
+ W_ERROR_NOT_OK_RETURN(
+ reg_open_key(mem_ctx, newkey, keyname1, &t2));
+
+ reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
+ talloc_free(tmppath);
}
/* Values that were changed */
- for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_value_by_index(mem_ctx, newkey, i, &v1)); i++) {
- struct reg_diff_key *thiskey = NULL;
- error2 = reg_key_get_value_by_name(mem_ctx, oldkey, v1->name, &v2);
+ for(i = 0; i < new_num_values; i++) {
+ const char *name;
+ uint32_t type1, type2;
+ DATA_BLOB contents1, contents2;
+
+ error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
+ &name, &type1, &contents1);
+ if (!W_ERROR_IS_OK(error1)) {
+ DEBUG(0, ("Unable to get key by index: %s\n",
+ win_errstr(error1)));
+ talloc_free(mem_ctx);
+ return error1;
+ }
+
+ if (oldkey != NULL) {
+ error2 = reg_key_get_value_by_name(mem_ctx, oldkey, name,
+ &type2, &contents2);
+ } else
+ error2 = WERR_DEST_NOT_FOUND;
if(!W_ERROR_IS_OK(error2) &&
!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
- DEBUG(0, ("Error occured while getting value by name: %d\n", W_ERROR_V(error2)));
+ DEBUG(0, ("Error occured while getting value by name: %s\n",
+ win_errstr(error2)));
+ talloc_free(mem_ctx);
return error2;
}
- if (W_ERROR_IS_OK(error2) && data_blob_cmp(&v1->data, &v2->data) == 0)
+ if (W_ERROR_IS_OK(error2) && data_blob_cmp(&contents1, &contents2) == 0)
continue;
- thiskey = diff_find_add_key(diff, oldkey->path);
- thiskey->values = talloc_realloc(diff, thiskey->values, struct reg_diff_value, thiskey->numvalues+2);
- thiskey->values[thiskey->numvalues].name = talloc_strdup(thiskey->values, v1->name);
- thiskey->values[thiskey->numvalues].type = v2->data_type;
- thiskey->values[thiskey->numvalues].changetype = REG_DIFF_SET_VAL;
- thiskey->values[thiskey->numvalues].data = data_blob_dup_talloc(thiskey->values, &v2->data);
- thiskey->numvalues++;
- }
-
- if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
- DEBUG(0, ("Error occured while getting value by index: %d\n", W_ERROR_V(error1)));
- talloc_free(mem_ctx);
- return error1;
+ callbacks->set_value(callback_data, path, name, type1, contents1);
}
/* Values that were deleted */
- for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &v1)); i++) {
- struct reg_diff_key *thiskey = NULL;
- error2 = reg_key_get_value_by_name(mem_ctx, newkey, v1->name, &v2);
+ for (i = 0; i < old_num_values; i++) {
+ const char *name;
+ error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
+ NULL, NULL);
+ if (!W_ERROR_IS_OK(error1)) {
+ DEBUG(0, ("Error ocurred getting value by index: %s\n",
+ win_errstr(error1)));
+ talloc_free(mem_ctx);
+ return error1;
+ }
+
+ error2 = reg_key_get_value_by_name(mem_ctx, newkey, name, NULL,
+ NULL);
if (W_ERROR_IS_OK(error2))
continue;
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
- DEBUG(0, ("Error occured while getting value by name: %d\n", W_ERROR_V(error2)));
+ DEBUG(0, ("Error occured while getting value by name: %s\n",
+ win_errstr(error2)));
return error2;
}
- thiskey = diff_find_add_key(diff, oldkey->path);
- thiskey->values = talloc_realloc(diff, thiskey->values, struct reg_diff_value, thiskey->numvalues+2);
- thiskey->values[thiskey->numvalues].name = talloc_strdup(thiskey->values, v1->name);
- thiskey->values[thiskey->numvalues].changetype = REG_DIFF_DEL_VAL;
- thiskey->numvalues++;
- }
-
- if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
- DEBUG(0, ("Error occured while getting value by index: %d\n", W_ERROR_V(error1)));
- talloc_free(mem_ctx);
- return error1;
+ callbacks->del_value(callback_data, path, name);
}
talloc_free(mem_ctx);
@@ -175,244 +214,206 @@ static WERROR reg_generate_diff_key(struct reg_diff *diff, struct registry_key *
/**
* Generate diff between two registry contexts
*/
-_PUBLIC_ struct reg_diff *reg_generate_diff(TALLOC_CTX *mem_ctx, struct registry_context *ctx1, struct registry_context *ctx2)
+_PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
+ struct registry_context *ctx2,
+ const struct reg_diff_callbacks *callbacks,
+ void *callback_data)
{
- struct reg_diff *diff = talloc_zero(mem_ctx, struct reg_diff);
int i;
WERROR error;
- for(i = HKEY_CLASSES_ROOT; i <= HKEY_PERFORMANCE_NLSTEXT; i++) {
- struct registry_key *r1, *r2;
+ for(i = HKEY_FIRST; i <= HKEY_LAST; i++) {
+ struct registry_key *r1 = NULL, *r2 = NULL;
error = reg_get_predefined_key(ctx1, i, &r1);
- if (!W_ERROR_IS_OK(error)) {
+ if (!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
DEBUG(0, ("Unable to open hive %s for backend 1\n", reg_get_predef_name(i)));
- continue;
}
error = reg_get_predefined_key(ctx2, i, &r2);
- if (!W_ERROR_IS_OK(error)) {
+ if (!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
DEBUG(0, ("Unable to open hive %s for backend 2\n", reg_get_predef_name(i)));
- continue;
}
- reg_generate_diff_key(diff, r1, r2);
- }
-
- return diff;
-}
-
-/**
- * Save registry diff
- */
-_PUBLIC_ WERROR reg_diff_save(const struct reg_diff *diff, const char *filename)
-{
- int xf, i, j;
-
- if (filename) {
- xf = open(filename, O_CREAT, 0755);
- if (xf == -1) {
- DEBUG(0, ("Unable to open %s\n", filename));
- return WERR_BADFILE;
- }
- } else
- xf = STDIN_FILENO;
-
- fdprintf(xf, "%s\n\n", diff->format?diff->format:DEFAULT_IDENT_STRING);
-
- for (i = 0; i < diff->numkeys; i++) {
- if (diff->keys[i].changetype == REG_DIFF_DEL_KEY) {
- fdprintf(xf, "-%s\n\n", diff->keys[i].name);
+ if (r1 == NULL && r2 == NULL)
continue;
- }
- fdprintf(xf, "[%s]\n", diff->keys[i].name);
-
- for (j = 0; j < diff->keys[i].numvalues; j++) {
- fdprintf(xf, "\"%s\"=", diff->keys[i].values[j].name);
- switch (diff->keys[i].values[j].changetype) {
- case REG_DIFF_DEL_VAL:
- fdprintf(xf, "-\n");
- break;
- case REG_DIFF_SET_VAL:
- fdprintf(xf, "%s:%s\n",
- str_regtype(diff->keys[i].values[j].type),
- reg_val_data_string(NULL,
- diff->keys[i].values[j].type,
- &diff->keys[i].values[j].data));
- break;
- }
+ error = reg_generate_diff_key(r1, r2, reg_get_predef_name(i), callbacks, callback_data);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Unable to determine diff: %s\n", win_errstr(error)));
+ return error;
}
-
- fdprintf(xf, "\n");
}
-
- close(xf);
-
+ if (callbacks->done != NULL) {
+ callbacks->done(callback_data);
+ }
return WERR_OK;
}
/**
* Load diff file
*/
-_PUBLIC_ struct reg_diff *reg_diff_load(TALLOC_CTX *ctx, const char *fn)
+_PUBLIC_ WERROR reg_diff_load(const char *filename, const struct reg_diff_callbacks *callbacks, void *callback_data)
{
- struct reg_diff *diff;
int fd;
- char *line, *p, *q;
- struct reg_diff_key *curkey = NULL;
- struct reg_diff_value *curval;
-
- fd = open(fn, O_RDONLY, 0);
+ char hdr[4];
+
+ fd = open(filename, O_RDONLY, 0);
if (fd == -1) {
- DEBUG(0, ("Error opening registry patch file `%s'\n", fn));
- return NULL;
+ DEBUG(0, ("Error opening registry patch file `%s'\n", filename));
+ return WERR_GENERAL_FAILURE;
}
- diff = talloc_zero(ctx, struct reg_diff);
- if (diff == NULL) {
- close(fd);
- return NULL;
+ if (read(fd, &hdr, 4) != 4) {
+ DEBUG(0, ("Error reading registry patch file `%s'\n", filename));
+ return WERR_GENERAL_FAILURE;
}
-
- diff->format = afdgets(fd, diff, 0);
- if (!diff->format) {
- talloc_free(diff);
- close(fd);
- return NULL;
+
+ /* Reset position in file */
+ lseek(fd, 0, SEEK_SET);
+#if 0
+ if (strncmp(hdr, "CREG", 4) == 0) {
+ /* Must be a W9x CREG Config.pol file */
+ return reg_creg_diff_load(diff, fd);
+ } else if (strncmp(hdr, "regf", 4) == 0) {
+ /* Must be a REGF NTConfig.pol file */
+ return reg_regf_diff_load(diff, fd);
+ } else
+#endif
+ if (strncmp(hdr, "PReg", 4) == 0) {
+ /* Must be a GPO Registry.pol file */
+ return reg_preg_diff_load(fd, callbacks, callback_data);
+ } else {
+ /* Must be a normal .REG file */
+ return reg_dotreg_diff_load(fd, callbacks, callback_data);
}
+}
- while ((line = afdgets(fd, diff, 0))) {
- /* Ignore comments and empty lines */
- if (strlen(line) == 0 || line[0] == ';') {
- curkey = NULL;
- talloc_free(line);
- continue;
- }
+/**
+ * The reg_diff_apply functions
+ */
+static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
+{
+ struct registry_context *ctx = _ctx;
+ struct registry_key *tmp;
+ WERROR error;
- /* Start of key */
- if (line[0] == '[') {
- p = strchr_m(line, ']');
- if (p[strlen(p)-2] != ']') {
- DEBUG(0, ("Malformed line\n"));
- return NULL;
- }
- diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
- diff->keys[diff->numkeys].name = talloc_strndup(diff->keys, line+1, strlen(line)-2);
- diff->keys[diff->numkeys].changetype = REG_DIFF_CHANGE_KEY;
- diff->keys[diff->numkeys].numvalues = 0;
- diff->keys[diff->numkeys].values = NULL;
- curkey = &diff->keys[diff->numkeys];
- diff->numkeys++;
- talloc_free(line);
- continue;
- }
+ error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
- /* Deleting key */
- if (line[0] == '-') {
- diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
- diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, line+1);
- diff->keys[diff->numkeys].changetype = REG_DIFF_DEL_KEY;
- diff->numkeys++;
- talloc_free(line);
- continue;
- }
+ if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) && !W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error adding new key '%s': %s\n", key_name, win_errstr(error)));
+ return error;
+ }
+ return WERR_OK;
+}
- /* Deleting/Changing value */
- p = strchr_m(line, '=');
- if (p == NULL) {
- DEBUG(0, ("Malformed line\n"));
- talloc_free(line);
- continue;
- }
+static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
+{
+ struct registry_context *ctx = _ctx;
+ WERROR error;
- *p = '\0'; p++;
+ error = reg_key_del_abs(ctx, key_name);
- if (curkey == NULL) {
- DEBUG(0, ("Value change without key\n"));
- talloc_free(line);
- continue;
- }
+ if(!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Unable to delete key '%s'\n", key_name));
+ return error;
+ }
+
+ return WERR_OK;
+}
- curkey->values = talloc_realloc(diff->keys, curkey->values, struct reg_diff_value, curkey->numvalues+2);
- curval = &curkey->values[curkey->numvalues];
- curkey->numvalues++;
- curval->name = talloc_strdup(curkey->values, line);
+static WERROR reg_diff_apply_set_value(void *_ctx, const char *path, const char *value_name, uint32_t value_type, DATA_BLOB value)
+{
+ struct registry_context *ctx = _ctx;
+ struct registry_key *tmp;
+ WERROR error;
+
+ /* Open key */
+ error = reg_open_key_abs(ctx, ctx, path, &tmp);
- /* Delete value */
- if (strcmp(p, "-")) {
- curval->changetype = REG_DIFF_DEL_VAL;
- talloc_free(line);
- continue;
- }
-
- q = strchr_m(p, ':');
- if (q) {
- *q = '\0';
- q++;
- }
+ if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
+ DEBUG(0, ("Error opening key '%s'\n", path));
+ return error;
+ }
- curval->changetype = REG_DIFF_SET_VAL;
- reg_string_to_val(curkey->values, q?p:"REG_SZ", q?q:p, &curval->type, &curval->data);
+ /* Set value */
+ error = reg_val_set(tmp, value_name,
+ value_type, value);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error setting value '%s'\n", value_name));
+ return error;
+ }
+
+ return WERR_OK;
+}
- talloc_free(line);
+static WERROR reg_diff_apply_del_value (void *_ctx, const char *key_name, const char *value_name)
+{
+ struct registry_context *ctx = _ctx;
+ struct registry_key *tmp;
+ WERROR error;
+
+ /* Open key */
+ error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
+
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error opening key '%s'\n", key_name));
+ return error;
}
- close(fd);
+ error = reg_del_value(tmp, value_name);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error deleting value '%s'\n", value_name));
+ return error;
+ }
+
- return diff;
+ return WERR_OK;
}
-/**
- * Apply diff to a registry context
- */
-_PUBLIC_ BOOL reg_diff_apply (const struct reg_diff *diff, struct registry_context *ctx)
+static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
{
- TALLOC_CTX *mem_ctx = talloc_init("apply_cmd_file");
- struct registry_key *tmp = NULL;
+ struct registry_context *ctx = _ctx;
+ struct registry_key *key;
WERROR error;
- int i, j;
+ int i;
+ uint32_t num_values;
- for (i = 0; i < diff->numkeys; i++) {
- if (diff->keys[i].changetype == REG_DIFF_DEL_KEY) {
- error = reg_key_del_abs(ctx, diff->keys[i].name);
+ error = reg_open_key_abs(ctx, ctx, key_name, &key);
- if(!W_ERROR_IS_OK(error)) {
- DEBUG(0, ("Unable to delete key '%s'\n", diff->keys[i].name));
- return False;
- }
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error opening key '%s'\n", key_name));
+ return error;
+ }
- continue;
- }
+ W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key,
+ NULL,
+ NULL,
+ &num_values,
+ NULL));
+
+ for (i = 0; i < num_values; i++) {
+ const char *name;
+ W_ERROR_NOT_OK_RETURN(reg_key_get_value_by_index(ctx, key, i, &name,
+ NULL, NULL));
+ W_ERROR_NOT_OK_RETURN(reg_del_value(key, name));
+ }
- /* Add / change key */
- error = reg_open_key_abs(mem_ctx, ctx, diff->keys[i].name, &tmp);
+ return WERR_OK;
+}
- /* If we found it, apply the other bits, else create such a key */
- if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
- if(!W_ERROR_IS_OK(reg_key_add_abs(mem_ctx, ctx, diff->keys[i].name, 0, NULL, &tmp))) {
- DEBUG(0, ("Error adding new key '%s'\n", diff->keys[i].name));
- return False;
- }
- }
+/**
+ * Apply diff to a registry context
+ */
+_PUBLIC_ WERROR reg_diff_apply (const char *filename, struct registry_context *ctx)
+{
+ struct reg_diff_callbacks callbacks;
- for (j = 0; j < diff->keys[i].numvalues; j++) {
- if (diff->keys[i].values[j].changetype == REG_DIFF_DEL_VAL) {
- error = reg_del_value(tmp, diff->keys[i].values[j].name);
- if (!W_ERROR_IS_OK(error)) {
- DEBUG(0, ("Error deleting value '%s'\n", diff->keys[i].values[j].name));
- return False;
- }
-
- error = reg_val_set(tmp, diff->keys[i].values[j].name,
- diff->keys[i].values[j].type,
- diff->keys[i].values[j].data);
- if (!W_ERROR_IS_OK(error)) {
- DEBUG(0, ("Error setting value '%s'\n", diff->keys[i].values[j].name));
- return False;
- }
- }
- }
- }
+ callbacks.add_key = reg_diff_apply_add_key;
+ callbacks.del_key = reg_diff_apply_del_key;
+ callbacks.set_value = reg_diff_apply_set_value;
+ callbacks.del_value = reg_diff_apply_del_value;
+ callbacks.del_all_values = reg_diff_apply_del_all_values;
+ callbacks.done = NULL;
- return True;
+ return reg_diff_load(filename, &callbacks, ctx);
}