From b409d4120f9ae451f93a2322267c0f346531d9f3 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 26 Aug 2007 15:16:40 +0000 Subject: 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) --- source4/lib/registry/patchfile.c | 561 ++++++++++++++++++++------------------- 1 file changed, 281 insertions(+), 280 deletions(-) (limited to 'source4/lib/registry/patchfile.c') 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); } -- cgit