2 Unix SMB/CIFS implementation.
5 Copyright (C) Jelmer Vernooij 2004
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "dynconfig.h"
24 #include "lib/registry/registry.h"
25 #include "lib/cmdline/popt_common.h"
26 #include "system/filesys.h"
28 #define DEFAULT_IDENT_STRING "SAMBA4 REGISTRY"
30 static struct reg_diff_key
*diff_find_add_key(struct reg_diff
*diff
, const char *path
)
34 for (i
= 0; diff
->numkeys
; i
++) {
35 if (!strcasecmp(diff
->keys
[i
].name
, path
))
36 return &diff
->keys
[i
];
39 diff
->keys
= talloc_realloc(diff
, diff
->keys
, struct reg_diff_key
, diff
->numkeys
+2);
40 diff
->keys
[diff
->numkeys
].name
= talloc_strdup(diff
->keys
, path
);
41 diff
->keys
[diff
->numkeys
].changetype
= REG_DIFF_CHANGE_KEY
;
42 diff
->keys
[diff
->numkeys
].numvalues
= 0;
43 diff
->keys
[diff
->numkeys
].values
= NULL
;
50 * Generate difference between two keys
52 static WERROR
reg_generate_diff_key(struct reg_diff
*diff
, struct registry_key
*oldkey
, struct registry_key
*newkey
)
55 struct registry_key
*t1
, *t2
;
56 struct registry_value
*v1
, *v2
;
57 WERROR error1
, error2
;
58 TALLOC_CTX
*mem_ctx
= talloc_init("writediff");
60 /* Subkeys that were deleted */
61 for(i
= 0; W_ERROR_IS_OK(error1
= reg_key_get_subkey_by_index(mem_ctx
, oldkey
, i
, &t1
)); i
++) {
62 error2
= reg_key_get_subkey_by_name(mem_ctx
, newkey
, t1
->name
, &t2
);
64 if (W_ERROR_IS_OK(error2
))
67 if (!W_ERROR_EQUAL(error2
, WERR_DEST_NOT_FOUND
)) {
68 DEBUG(0, ("Error occured while getting subkey by name: %d\n", W_ERROR_V(error2
)));
72 /* newkey didn't have such a subkey, add del diff */
73 diff
->keys
= talloc_realloc(diff
, diff
->keys
, struct reg_diff_key
, diff
->numkeys
+2);
74 diff
->keys
[diff
->numkeys
].name
= talloc_strdup(diff
->keys
, t1
->path
);
75 diff
->keys
[diff
->numkeys
].changetype
= REG_DIFF_DEL_KEY
;
79 if(!W_ERROR_EQUAL(error1
, WERR_NO_MORE_ITEMS
)) {
80 DEBUG(0, ("Error occured while getting subkey by index: %d\n", W_ERROR_V(error1
)));
85 /* Subkeys that were added */
86 for(i
= 0; W_ERROR_IS_OK(error1
= reg_key_get_subkey_by_index(mem_ctx
, newkey
, i
, &t1
)); i
++) {
87 error2
= reg_key_get_subkey_by_name(mem_ctx
, oldkey
, t1
->name
, &t2
);
89 if (W_ERROR_IS_OK(error2
))
92 if (!W_ERROR_EQUAL(error2
, WERR_DEST_NOT_FOUND
)) {
93 DEBUG(0, ("Error occured while getting subkey by name: %d\n", W_ERROR_V(error2
)));
97 /* oldkey didn't have such a subkey, add add diff */
98 diff
->keys
= talloc_realloc(diff
, diff
->keys
, struct reg_diff_key
, diff
->numkeys
+2);
99 diff
->keys
[diff
->numkeys
].name
= talloc_strdup(diff
->keys
, t1
->path
);
100 diff
->keys
[diff
->numkeys
].changetype
= REG_DIFF_CHANGE_KEY
;
101 diff
->keys
[diff
->numkeys
].numvalues
= 0;
102 diff
->keys
[diff
->numkeys
].values
= NULL
;
105 reg_generate_diff_key(diff
, t1
, t2
);
108 if(!W_ERROR_EQUAL(error1
, WERR_NO_MORE_ITEMS
)) {
109 DEBUG(0, ("Error occured while getting subkey by index: %d\n", W_ERROR_V(error1
)));
110 talloc_free(mem_ctx
);
114 /* Values that were changed */
115 for(i
= 0; W_ERROR_IS_OK(error1
= reg_key_get_value_by_index(mem_ctx
, newkey
, i
, &v1
)); i
++) {
116 struct reg_diff_key
*thiskey
= NULL
;
117 error2
= reg_key_get_value_by_name(mem_ctx
, oldkey
, v1
->name
, &v2
);
119 if(!W_ERROR_IS_OK(error2
) &&
120 !W_ERROR_EQUAL(error2
, WERR_DEST_NOT_FOUND
)) {
121 DEBUG(0, ("Error occured while getting value by name: %d\n", W_ERROR_V(error2
)));
125 if (W_ERROR_IS_OK(error2
) && data_blob_equal(&v1
->data
, &v2
->data
))
128 thiskey
= diff_find_add_key(diff
, oldkey
->path
);
129 thiskey
->values
= talloc_realloc(diff
, thiskey
->values
, struct reg_diff_value
, thiskey
->numvalues
+2);
130 thiskey
->values
[thiskey
->numvalues
].name
= talloc_strdup(thiskey
->values
, v1
->name
);
131 thiskey
->values
[thiskey
->numvalues
].type
= v2
->data_type
;
132 thiskey
->values
[thiskey
->numvalues
].changetype
= REG_DIFF_SET_VAL
;
133 thiskey
->values
[thiskey
->numvalues
].data
= data_blob_dup_talloc(thiskey
->values
, &v2
->data
);
134 thiskey
->numvalues
++;
137 if(!W_ERROR_EQUAL(error1
, WERR_NO_MORE_ITEMS
)) {
138 DEBUG(0, ("Error occured while getting value by index: %d\n", W_ERROR_V(error1
)));
139 talloc_free(mem_ctx
);
143 /* Values that were deleted */
144 for(i
= 0; W_ERROR_IS_OK(error1
= reg_key_get_value_by_index(mem_ctx
, oldkey
, i
, &v1
)); i
++) {
145 struct reg_diff_key
*thiskey
= NULL
;
146 error2
= reg_key_get_value_by_name(mem_ctx
, newkey
, v1
->name
, &v2
);
148 if (W_ERROR_IS_OK(error2
))
151 if (!W_ERROR_EQUAL(error2
, WERR_DEST_NOT_FOUND
)) {
152 DEBUG(0, ("Error occured while getting value by name: %d\n", W_ERROR_V(error2
)));
156 thiskey
= diff_find_add_key(diff
, oldkey
->path
);
157 thiskey
->values
= talloc_realloc(diff
, thiskey
->values
, struct reg_diff_value
, thiskey
->numvalues
+2);
158 thiskey
->values
[thiskey
->numvalues
].name
= talloc_strdup(thiskey
->values
, v1
->name
);
159 thiskey
->values
[thiskey
->numvalues
].changetype
= REG_DIFF_DEL_VAL
;
160 thiskey
->numvalues
++;
163 if(!W_ERROR_EQUAL(error1
, WERR_NO_MORE_ITEMS
)) {
164 DEBUG(0, ("Error occured while getting value by index: %d\n", W_ERROR_V(error1
)));
165 talloc_free(mem_ctx
);
169 talloc_free(mem_ctx
);
174 * Generate diff between two registry contexts
176 struct reg_diff
*reg_generate_diff(TALLOC_CTX
*mem_ctx
, struct registry_context
*ctx1
, struct registry_context
*ctx2
)
178 struct reg_diff
*diff
= talloc_zero(mem_ctx
, struct reg_diff
);
182 for(i
= HKEY_CLASSES_ROOT
; i
<= HKEY_PERFORMANCE_NLSTEXT
; i
++) {
183 struct registry_key
*r1
, *r2
;
184 error
= reg_get_predefined_key(ctx1
, i
, &r1
);
185 if (!W_ERROR_IS_OK(error
)) {
186 DEBUG(0, ("Unable to open hive %s for backend 1\n", reg_get_predef_name(i
)));
190 error
= reg_get_predefined_key(ctx2
, i
, &r2
);
191 if (!W_ERROR_IS_OK(error
)) {
192 DEBUG(0, ("Unable to open hive %s for backend 2\n", reg_get_predef_name(i
)));
196 reg_generate_diff_key(diff
, r1
, r2
);
205 WERROR
reg_diff_save(const struct reg_diff
*diff
, const char *filename
)
210 xf
= open(filename
, O_CREAT
, 0755);
212 DEBUG(0, ("Unable to open %s\n", filename
));
218 fdprintf(xf
, "%s\n\n", diff
->format
?diff
->format
:DEFAULT_IDENT_STRING
);
220 for (i
= 0; i
< diff
->numkeys
; i
++) {
221 if (diff
->keys
[i
].changetype
== REG_DIFF_DEL_KEY
) {
222 fdprintf(xf
, "-%s\n\n", diff
->keys
[i
].name
);
226 fdprintf(xf
, "[%s]\n", diff
->keys
[i
].name
);
228 for (j
= 0; j
< diff
->keys
[i
].numvalues
; j
++) {
229 fdprintf(xf
, "\"%s\"=", diff
->keys
[i
].values
[j
].name
);
230 switch (diff
->keys
[i
].values
[j
].changetype
) {
231 case REG_DIFF_DEL_VAL
:
234 case REG_DIFF_SET_VAL
:
235 fdprintf(xf
, "%s:%s\n",
236 str_regtype(diff
->keys
[i
].values
[j
].type
),
237 reg_val_data_string(NULL
,
238 diff
->keys
[i
].values
[j
].type
,
239 &diff
->keys
[i
].values
[j
].data
));
255 struct reg_diff
*reg_diff_load(TALLOC_CTX
*ctx
, const char *fn
)
257 struct reg_diff
*diff
;
260 struct reg_diff_key
*curkey
;
261 struct reg_diff_value
*curval
;
263 fd
= open(fn
, O_RDONLY
, 0);
265 DEBUG(0, ("Error opening registry patch file `%s'\n", fn
));
269 diff
= talloc_zero(ctx
, struct reg_diff
);
275 diff
->format
= afdgets(fd
, diff
, 0);
282 while ((line
= afdgets(fd
, diff
, 0))) {
283 /* Ignore comments and empty lines */
284 if (strlen(line
) == 0 || line
[0] == ';') {
291 if (line
[0] == '[') {
292 p
= strchr_m(line
, ']');
293 if (p
[strlen(p
)-2] != ']') {
294 DEBUG(0, ("Malformed line\n"));
297 diff
->keys
= talloc_realloc(diff
, diff
->keys
, struct reg_diff_key
, diff
->numkeys
+2);
298 diff
->keys
[diff
->numkeys
].name
= talloc_strndup(diff
->keys
, line
+1, strlen(line
)-2);
299 diff
->keys
[diff
->numkeys
].changetype
= REG_DIFF_CHANGE_KEY
;
300 diff
->keys
[diff
->numkeys
].numvalues
= 0;
301 diff
->keys
[diff
->numkeys
].values
= NULL
;
302 curkey
= &diff
->keys
[diff
->numkeys
];
309 if (line
[0] == '-') {
310 diff
->keys
= talloc_realloc(diff
, diff
->keys
, struct reg_diff_key
, diff
->numkeys
+2);
311 diff
->keys
[diff
->numkeys
].name
= talloc_strdup(diff
->keys
, line
+1);
312 diff
->keys
[diff
->numkeys
].changetype
= REG_DIFF_DEL_KEY
;
318 /* Deleting/Changing value */
319 p
= strchr_m(line
, '=');
321 DEBUG(0, ("Malformed line\n"));
328 if (curkey
== NULL
) {
329 DEBUG(0, ("Value change without key\n"));
334 curkey
->values
= talloc_realloc(diff
->keys
, curkey
->values
, struct reg_diff_value
, curkey
->numvalues
+2);
335 curval
= &curkey
->values
[curkey
->numvalues
];
337 curval
->name
= talloc_strdup(curkey
->values
, line
);
340 if (strcmp(p
, "-")) {
341 curval
->changetype
= REG_DIFF_DEL_VAL
;
346 q
= strchr_m(p
, ':');
352 curval
->changetype
= REG_DIFF_SET_VAL
;
353 reg_string_to_val(curkey
->values
, q
?p
:"REG_SZ", q
?q
:p
, &curval
->type
, &curval
->data
);
364 * Apply diff to a registry context
366 BOOL
reg_diff_apply (const struct reg_diff
*diff
, struct registry_context
*ctx
)
368 TALLOC_CTX
*mem_ctx
= talloc_init("apply_cmd_file");
369 struct registry_key
*tmp
= NULL
;
373 for (i
= 0; i
< diff
->numkeys
; i
++) {
374 if (diff
->keys
[i
].changetype
== REG_DIFF_DEL_KEY
) {
375 error
= reg_key_del_abs(ctx
, diff
->keys
[i
].name
);
377 if(!W_ERROR_IS_OK(error
)) {
378 DEBUG(0, ("Unable to delete key '%s'\n", diff
->keys
[i
].name
));
385 /* Add / change key */
386 error
= reg_open_key_abs(mem_ctx
, ctx
, diff
->keys
[i
].name
, &tmp
);
388 /* If we found it, apply the other bits, else create such a key */
389 if (W_ERROR_EQUAL(error
, WERR_DEST_NOT_FOUND
)) {
390 if(!W_ERROR_IS_OK(reg_key_add_abs(mem_ctx
, ctx
, diff
->keys
[i
].name
, 0, NULL
, &tmp
))) {
391 DEBUG(0, ("Error adding new key '%s'\n", diff
->keys
[i
].name
));
396 for (j
= 0; j
< diff
->keys
[i
].numvalues
; j
++) {
397 if (diff
->keys
[i
].values
[j
].changetype
== REG_DIFF_DEL_VAL
) {
398 error
= reg_del_value(tmp
, diff
->keys
[i
].values
[j
].name
);
399 if (!W_ERROR_IS_OK(error
)) {
400 DEBUG(0, ("Error deleting value '%s'\n", diff
->keys
[i
].values
[j
].name
));
404 error
= reg_val_set(tmp
, diff
->keys
[i
].values
[j
].name
,
405 diff
->keys
[i
].values
[j
].type
,
406 diff
->keys
[i
].values
[j
].data
);
407 if (!W_ERROR_IS_OK(error
)) {
408 DEBUG(0, ("Error setting value '%s'\n", diff
->keys
[i
].values
[j
].name
));