LCOV - code coverage report
Current view: top level - source4/lib/registry - patchfile.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 139 264 52.7 %
Date: 2024-04-21 15:09:00 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Reading registry patch files
       4             : 
       5             :    Copyright (C) Jelmer Vernooij 2004-2007
       6             :    Copyright (C) Wilco Baan Hofman 2006
       7             :    Copyright (C) Matthias Dieter Wallnöfer 2008-2010
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "lib/registry/registry.h"
      25             : #include "system/filesys.h"
      26             : 
      27             : 
      28             : _PUBLIC_ WERROR reg_preg_diff_load(int fd,
      29             :                                    const struct reg_diff_callbacks *callbacks,
      30             :                                    void *callback_data);
      31             : 
      32             : _PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
      33             :                                      const struct reg_diff_callbacks *callbacks,
      34             :                                      void *callback_data);
      35             : 
      36             : /*
      37             :  * Generate difference between two keys
      38             :  */
      39          36 : WERROR reg_generate_diff_key(struct registry_key *oldkey,
      40             :                              struct registry_key *newkey,
      41             :                              const char *path,
      42             :                              const struct reg_diff_callbacks *callbacks,
      43             :                              void *callback_data)
      44             : {
      45          36 :         unsigned int i;
      46          36 :         struct registry_key *t1 = NULL, *t2 = NULL;
      47          36 :         char *tmppath;
      48          36 :         const char *keyname1;
      49          36 :         WERROR error, error1, error2;
      50          36 :         TALLOC_CTX *mem_ctx = talloc_init("writediff");
      51          36 :         uint32_t old_num_subkeys, old_num_values,
      52             :                          new_num_subkeys, new_num_values;
      53             : 
      54          36 :         if (oldkey != NULL) {
      55           8 :                 error = reg_key_get_info(mem_ctx, oldkey, NULL,
      56             :                                          &old_num_subkeys, &old_num_values,
      57             :                                          NULL, NULL, NULL, NULL);
      58           8 :                 if (!W_ERROR_IS_OK(error)) {
      59           0 :                         DEBUG(0, ("Error occurred while getting key info: %s\n",
      60             :                                 win_errstr(error)));
      61           0 :                         talloc_free(mem_ctx);
      62           0 :                         return error;
      63             :                 }
      64             :         } else {
      65          28 :                 old_num_subkeys = 0;
      66          28 :                 old_num_values = 0;
      67             :         }
      68             : 
      69             :         /* Subkeys that were changed or deleted */
      70          40 :         for (i = 0; i < old_num_subkeys; i++) {
      71           4 :                 error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i,
      72             :                                                      &keyname1, NULL, NULL);
      73           4 :                 if (!W_ERROR_IS_OK(error1)) {
      74           0 :                         DEBUG(0, ("Error occurred while getting subkey by index: %s\n",
      75             :                                 win_errstr(error1)));
      76           0 :                         continue;
      77             :                 }
      78             : 
      79           4 :                 if (newkey != NULL) {
      80           2 :                         error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
      81             :                 } else {
      82           2 :                         error2 = WERR_FILE_NOT_FOUND;
      83           2 :                         t2 = NULL;
      84             :                 }
      85             : 
      86           4 :                 if (!W_ERROR_IS_OK(error2) && !W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
      87           0 :                         DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
      88             :                                 win_errstr(error2)));
      89           0 :                         talloc_free(mem_ctx);
      90           0 :                         return error2;
      91             :                 }
      92             : 
      93             :                 /* if "error2" is going to be "WERR_FILE_NOT_FOUND", then newkey */
      94             :                 /* didn't have such a subkey and therefore add a del diff */
      95           4 :                 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
      96           4 :                 if (tmppath == NULL) {
      97           0 :                         DEBUG(0, ("Out of memory\n"));
      98           0 :                         talloc_free(mem_ctx);
      99           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     100             :                 }
     101           4 :                 if (!W_ERROR_IS_OK(error2))
     102           4 :                         callbacks->del_key(callback_data, tmppath);
     103             : 
     104             :                 /* perform here also the recursive invocation */
     105           4 :                 error1 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
     106           4 :                 if (!W_ERROR_IS_OK(error1)) {
     107           0 :                         DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
     108             :                         win_errstr(error1)));
     109           0 :                         talloc_free(mem_ctx);
     110           0 :                         return error1;
     111             :                 }
     112           4 :                 reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
     113             : 
     114           4 :                 talloc_free(tmppath);
     115             :         }
     116             : 
     117          36 :         if (newkey != NULL) {
     118          16 :                 error = reg_key_get_info(mem_ctx, newkey, NULL,
     119             :                                          &new_num_subkeys, &new_num_values,
     120             :                                          NULL, NULL, NULL, NULL);
     121          16 :                 if (!W_ERROR_IS_OK(error)) {
     122           0 :                         DEBUG(0, ("Error occurred while getting key info: %s\n",
     123             :                                 win_errstr(error)));
     124           0 :                         talloc_free(mem_ctx);
     125           0 :                         return error;
     126             :                 }
     127             :         } else {
     128          20 :                 new_num_subkeys = 0;
     129          20 :                 new_num_values = 0;
     130             :         }
     131             : 
     132             :         /* Subkeys that were added */
     133          48 :         for(i = 0; i < new_num_subkeys; i++) {
     134          12 :                 error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i,
     135             :                                                      &keyname1, NULL, NULL);
     136          12 :                 if (!W_ERROR_IS_OK(error1)) {
     137           0 :                         DEBUG(0, ("Error occurred while getting subkey by index: %s\n",
     138             :                                 win_errstr(error1)));
     139           0 :                         talloc_free(mem_ctx);
     140           0 :                         return error1;
     141             :                 }
     142             : 
     143          12 :                 if (oldkey != NULL) {
     144           2 :                         error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
     145             : 
     146           2 :                         if (W_ERROR_IS_OK(error2))
     147           0 :                                 continue;
     148             :                 } else {
     149          10 :                         error2 = WERR_FILE_NOT_FOUND;
     150          10 :                         t1 = NULL;
     151             :                 }
     152             : 
     153          12 :                 if (!W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
     154           0 :                         DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
     155             :                                 win_errstr(error2)));
     156           0 :                         talloc_free(mem_ctx);
     157           0 :                         return error2;
     158             :                 }
     159             : 
     160             :                 /* oldkey didn't have such a subkey, add a add diff */
     161          12 :                 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
     162          12 :                 if (tmppath == NULL) {
     163           0 :                         DEBUG(0, ("Out of memory\n"));
     164           0 :                         talloc_free(mem_ctx);
     165           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     166             :                 }
     167          12 :                 callbacks->add_key(callback_data, tmppath);
     168             : 
     169             :                 /* perform here also the recursive invocation */
     170          12 :                 error1 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
     171          12 :                 if (!W_ERROR_IS_OK(error1)) {
     172           0 :                         DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
     173             :                         win_errstr(error1)));
     174           0 :                         talloc_free(mem_ctx);
     175           0 :                         return error1;
     176             :                 }
     177          12 :                 reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
     178             : 
     179          12 :                 talloc_free(tmppath);
     180             :         }
     181             : 
     182             :         /* Values that were added or changed */
     183          38 :         for(i = 0; i < new_num_values; i++) {
     184           2 :                 const char *name;
     185           2 :                 uint32_t type1, type2;
     186           2 :                 DATA_BLOB contents1 = { NULL, 0 }, contents2 = { NULL, 0 };
     187             : 
     188           2 :                 error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
     189             :                                                     &name, &type1, &contents1);
     190           2 :                 if (!W_ERROR_IS_OK(error1)) {
     191           0 :                         DEBUG(0, ("Unable to get value by index: %s\n",
     192             :                                 win_errstr(error1)));
     193           0 :                         talloc_free(mem_ctx);
     194           0 :                         return error1;
     195             :                 }
     196             : 
     197           2 :                 if (oldkey != NULL) {
     198           0 :                         error2 = reg_key_get_value_by_name(mem_ctx, oldkey,
     199             :                                                            name, &type2,
     200             :                                                            &contents2);
     201             :                 } else
     202           0 :                         error2 = WERR_FILE_NOT_FOUND;
     203             : 
     204           2 :                 if (!W_ERROR_IS_OK(error2)
     205           2 :                         && !W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
     206           0 :                         DEBUG(0, ("Error occurred while getting value by name: %s\n",
     207             :                                 win_errstr(error2)));
     208           0 :                         talloc_free(mem_ctx);
     209           0 :                         return error2;
     210             :                 }
     211             : 
     212           2 :                 if (W_ERROR_IS_OK(error2)
     213           0 :                     && (data_blob_cmp(&contents1, &contents2) == 0)
     214           0 :                     && (type1 == type2)) {
     215           0 :                         talloc_free(discard_const_p(char, name));
     216           0 :                         talloc_free(contents1.data);
     217           0 :                         talloc_free(contents2.data);
     218           0 :                         continue;
     219             :                 }
     220             : 
     221           2 :                 callbacks->set_value(callback_data, path, name,
     222             :                                      type1, contents1);
     223             : 
     224           2 :                 talloc_free(discard_const_p(char, name));
     225           2 :                 talloc_free(contents1.data);
     226           2 :                 talloc_free(contents2.data);
     227             :         }
     228             : 
     229             :         /* Values that were deleted */
     230          36 :         for (i = 0; i < old_num_values; i++) {
     231           0 :                 const char *name;
     232           0 :                 uint32_t type;
     233           0 :                 DATA_BLOB contents = { NULL, 0 };
     234             : 
     235           0 :                 error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
     236             :                                                     &type, &contents);
     237           0 :                 if (!W_ERROR_IS_OK(error1)) {
     238           0 :                         DEBUG(0, ("Unable to get value by index: %s\n",
     239             :                                 win_errstr(error1)));
     240           0 :                         talloc_free(mem_ctx);
     241           0 :                         return error1;
     242             :                 }
     243             : 
     244           0 :                 if (newkey != NULL)
     245           0 :                         error2 = reg_key_get_value_by_name(mem_ctx, newkey,
     246             :                                  name, &type, &contents);
     247             :                 else
     248           0 :                         error2 = WERR_FILE_NOT_FOUND;
     249             : 
     250           0 :                 if (W_ERROR_IS_OK(error2)) {
     251           0 :                         talloc_free(discard_const_p(char, name));
     252           0 :                         talloc_free(contents.data);
     253           0 :                         continue;
     254             :                 }
     255             : 
     256           0 :                 if (!W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
     257           0 :                         DEBUG(0, ("Error occurred while getting value by name: %s\n",
     258             :                                 win_errstr(error2)));
     259           0 :                         talloc_free(mem_ctx);
     260           0 :                         return error2;
     261             :                 }
     262             : 
     263           0 :                 callbacks->del_value(callback_data, path, name);
     264             : 
     265           0 :                 talloc_free(discard_const_p(char, name));
     266           0 :                 talloc_free(contents.data);
     267             :         }
     268             : 
     269          36 :         talloc_free(mem_ctx);
     270          36 :         return WERR_OK;
     271             : }
     272             : 
     273             : /**
     274             :  * Generate diff between two registry contexts
     275             :  */
     276           2 : _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
     277             :                                   struct registry_context *ctx2,
     278             :                                   const struct reg_diff_callbacks *callbacks,
     279             :                                   void *callback_data)
     280             : {
     281           2 :         unsigned int i;
     282           2 :         WERROR error;
     283             : 
     284          20 :         for (i = 0; reg_predefined_keys[i].name; i++) {
     285          18 :                 struct registry_key *r1 = NULL, *r2 = NULL;
     286             : 
     287          36 :                 error = reg_get_predefined_key(ctx1,
     288          18 :                         reg_predefined_keys[i].handle, &r1);
     289          18 :                 if (!W_ERROR_IS_OK(error) &&
     290           0 :                     !W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
     291           0 :                         DEBUG(0, ("Unable to open hive %s for backend 1\n",
     292             :                                 reg_predefined_keys[i].name));
     293           0 :                         continue;
     294             :                 }
     295             : 
     296          18 :                 error = reg_get_predefined_key(ctx2,
     297           0 :                         reg_predefined_keys[i].handle, &r2);
     298          18 :                 if (!W_ERROR_IS_OK(error) &&
     299           0 :                     !W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
     300           0 :                         DEBUG(0, ("Unable to open hive %s for backend 2\n",
     301             :                                 reg_predefined_keys[i].name));
     302           0 :                         continue;
     303             :                 }
     304             : 
     305             :                 /* if "r1" is NULL (old hive) and "r2" isn't (new hive) then
     306             :                  * the hive doesn't exist yet and we have to generate an add
     307             :                  * diff */
     308          18 :                 if ((r1 == NULL) && (r2 != NULL)) {
     309           0 :                         callbacks->add_key(callback_data,
     310           0 :                                            reg_predefined_keys[i].name);
     311             :                 }
     312             :                 /* if "r1" isn't NULL (old hive) and "r2" is (new hive) then
     313             :                  * the hive shouldn't exist anymore and we have to generate a
     314             :                  * del diff */
     315          18 :                 if ((r1 != NULL) && (r2 == NULL)) {
     316           0 :                         callbacks->del_key(callback_data,
     317           0 :                                            reg_predefined_keys[i].name);
     318             :                 }
     319             : 
     320          18 :                 error = reg_generate_diff_key(r1, r2,
     321           0 :                         reg_predefined_keys[i].name, callbacks,
     322             :                         callback_data);
     323          18 :                 if (!W_ERROR_IS_OK(error)) {
     324           0 :                         DEBUG(0, ("Unable to determine diff: %s\n",
     325             :                                 win_errstr(error)));
     326           0 :                         return error;
     327             :                 }
     328             :         }
     329           2 :         if (callbacks->done != NULL) {
     330           2 :                 callbacks->done(callback_data);
     331             :         }
     332           2 :         return WERR_OK;
     333             : }
     334             : 
     335             : /**
     336             :  * Load diff file
     337             :  */
     338         207 : _PUBLIC_ WERROR reg_diff_load(const char *filename,
     339             :                               const struct reg_diff_callbacks *callbacks,
     340             :                               void *callback_data)
     341             : {
     342          25 :         int fd;
     343          25 :         char hdr[4];
     344             : 
     345         207 :         fd = open(filename, O_RDONLY, 0);
     346         207 :         if (fd == -1) {
     347           0 :                 DEBUG(0, ("Error opening registry patch file `%s'\n",
     348             :                         filename));
     349           0 :                 return WERR_GEN_FAILURE;
     350             :         }
     351             : 
     352         207 :         if (read(fd, &hdr, 4) != 4) {
     353           0 :                 DEBUG(0, ("Error reading registry patch file `%s'\n",
     354             :                         filename));
     355           0 :                 close(fd);
     356           0 :                 return WERR_GEN_FAILURE;
     357             :         }
     358             : 
     359             :         /* Reset position in file */
     360         207 :         lseek(fd, 0, SEEK_SET);
     361             : #if 0 /* These backends are not supported yet. */
     362             :         if (strncmp(hdr, "CREG", 4) == 0) {
     363             :                 /* Must be a W9x CREG Config.pol file */
     364             :                 return reg_creg_diff_load(diff, fd);
     365             :         } else if (strncmp(hdr, "regf", 4) == 0) {
     366             :                 /* Must be a REGF NTConfig.pol file */
     367             :                 return reg_regf_diff_load(diff, fd);
     368             :         } else
     369             : #endif
     370         207 :         if (strncmp(hdr, "PReg", 4) == 0) {
     371             :                 /* Must be a GPO Registry.pol file */
     372           1 :                 return reg_preg_diff_load(fd, callbacks, callback_data);
     373             :         } else {
     374             :                 /* Must be a normal .REG file */
     375         206 :                 return reg_dotreg_diff_load(fd, callbacks, callback_data);
     376             :         }
     377             : }
     378             : 
     379             : /**
     380             :  * The reg_diff_apply functions
     381             :  */
     382        4107 : static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
     383             : {
     384        4107 :         struct registry_context *ctx = (struct registry_context *)_ctx;
     385         467 :         struct registry_key *tmp;
     386         467 :         char *buf, *buf_ptr;
     387         467 :         WERROR error;
     388             : 
     389             :         /* Recursively create the path */
     390        4107 :         buf = talloc_strdup(ctx, key_name);
     391        4107 :         W_ERROR_HAVE_NO_MEMORY(buf);
     392        3640 :         buf_ptr = buf;
     393             : 
     394      181619 :         while (*buf_ptr++ != '\0' ) {
     395      176872 :                 if (*buf_ptr == '\\') {
     396       10687 :                         *buf_ptr = '\0';
     397       10687 :                         error = reg_key_add_abs(ctx, ctx, buf, 0, NULL, &tmp);
     398             : 
     399       10687 :                         if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
     400        6370 :                                     !W_ERROR_IS_OK(error)) {
     401           0 :                                 DEBUG(0, ("Error adding new key '%s': %s\n",
     402             :                                         key_name, win_errstr(error)));
     403           0 :                                 return error;
     404             :                         }
     405       10687 :                         *buf_ptr++ = '\\';
     406       10687 :                         talloc_free(tmp);
     407             :                 }
     408             :         }
     409             : 
     410        4107 :         talloc_free(buf);
     411             : 
     412             :         /* Add the key */
     413        4107 :         error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
     414             : 
     415        4107 :         if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
     416        3094 :                     !W_ERROR_IS_OK(error)) {
     417           0 :                 DEBUG(0, ("Error adding new key '%s': %s\n",
     418             :                         key_name, win_errstr(error)));
     419           0 :                 return error;
     420             :         }
     421        4107 :         talloc_free(tmp);
     422             : 
     423        4107 :         return WERR_OK;
     424             : }
     425             : 
     426           4 : static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
     427             : {
     428           4 :         struct registry_context *ctx = (struct registry_context *)_ctx;
     429             : 
     430             :         /* We can't proof here for success, because a common superkey could */
     431             :         /* have been deleted before the subkey's (diff order). This removed */
     432             :         /* therefore all children recursively and the "WERR_FILE_NOT_FOUND" result is */
     433             :         /* expected. */
     434             : 
     435           4 :         reg_key_del_abs(ctx, key_name);
     436             : 
     437           4 :         return WERR_OK;
     438             : }
     439             : 
     440         617 : static WERROR reg_diff_apply_set_value(void *_ctx, const char *path,
     441             :                                        const char *value_name,
     442             :                                        uint32_t value_type, DATA_BLOB value)
     443             : {
     444         617 :         struct registry_context *ctx = (struct registry_context *)_ctx;
     445          71 :         struct registry_key *tmp;
     446          71 :         WERROR error;
     447             : 
     448             :         /* Open key */
     449         617 :         error = reg_open_key_abs(ctx, ctx, path, &tmp);
     450             : 
     451         617 :         if (W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
     452           0 :                 DEBUG(0, ("Error opening key '%s'\n", path));
     453           0 :                 return error;
     454             :         }
     455             : 
     456             :         /* Set value */
     457         617 :         error = reg_val_set(tmp, value_name,
     458             :                                  value_type, value);
     459         617 :         if (!W_ERROR_IS_OK(error)) {
     460           0 :                 DEBUG(0, ("Error setting value '%s'\n", value_name));
     461           0 :                 return error;
     462             :         }
     463             : 
     464         617 :         talloc_free(tmp);
     465             : 
     466         617 :         return WERR_OK;
     467             : }
     468             : 
     469           0 : static WERROR reg_diff_apply_del_value(void *_ctx, const char *key_name,
     470             :                                        const char *value_name)
     471             : {
     472           0 :         struct registry_context *ctx = (struct registry_context *)_ctx;
     473           0 :         struct registry_key *tmp;
     474           0 :         WERROR error;
     475             : 
     476             :         /* Open key */
     477           0 :         error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
     478             : 
     479           0 :         if (!W_ERROR_IS_OK(error)) {
     480           0 :                 DEBUG(0, ("Error opening key '%s'\n", key_name));
     481           0 :                 return error;
     482             :         }
     483             : 
     484           0 :         error = reg_del_value(ctx, tmp, value_name);
     485           0 :         if (!W_ERROR_IS_OK(error)) {
     486           0 :                 DEBUG(0, ("Error deleting value '%s'\n", value_name));
     487           0 :                 return error;
     488             :         }
     489             : 
     490           0 :         talloc_free(tmp);
     491             : 
     492           0 :         return WERR_OK;
     493             : }
     494             : 
     495           0 : static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
     496             : {
     497           0 :         struct registry_context *ctx = (struct registry_context *)_ctx;
     498           0 :         struct registry_key *key;
     499           0 :         WERROR error;
     500           0 :         const char *value_name;
     501             : 
     502           0 :         error = reg_open_key_abs(ctx, ctx, key_name, &key);
     503             : 
     504           0 :         if (!W_ERROR_IS_OK(error)) {
     505           0 :                 DEBUG(0, ("Error opening key '%s'\n", key_name));
     506           0 :                 return error;
     507             :         }
     508             : 
     509           0 :         W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key, NULL,
     510             :                                NULL, NULL, NULL, NULL, NULL, NULL));
     511             : 
     512           0 :         while (W_ERROR_IS_OK(reg_key_get_value_by_index(
     513             :                         ctx, key, 0, &value_name, NULL, NULL))) {
     514           0 :                 error = reg_del_value(ctx, key, value_name);
     515           0 :                 if (!W_ERROR_IS_OK(error)) {
     516           0 :                         DEBUG(0, ("Error deleting value '%s'\n", value_name));
     517           0 :                         return error;
     518             :                 }
     519           0 :                 talloc_free(discard_const_p(char, value_name));
     520             :         }
     521             : 
     522           0 :         talloc_free(key);
     523             : 
     524           0 :         return WERR_OK;
     525             : }
     526             : 
     527             : /**
     528             :  * Apply diff to a registry context
     529             :  */
     530         207 : _PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx, 
     531             :                                                            const char *filename)
     532             : {
     533          25 :         struct reg_diff_callbacks callbacks;
     534             : 
     535         207 :         callbacks.add_key = reg_diff_apply_add_key;
     536         207 :         callbacks.del_key = reg_diff_apply_del_key;
     537         207 :         callbacks.set_value = reg_diff_apply_set_value;
     538         207 :         callbacks.del_value = reg_diff_apply_del_value;
     539         207 :         callbacks.del_all_values = reg_diff_apply_del_all_values;
     540         207 :         callbacks.done = NULL;
     541             : 
     542         207 :         return reg_diff_load(filename, &callbacks, ctx);
     543             : }

Generated by: LCOV version 1.14