docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source4 / lib / registry / patchfile.c
index d49d46250d3d7b5d70da6afe9069be84cdc1dc59..8069ed70f8a3cc9ae1592696b7e4001f401cf929 100644 (file)
@@ -4,7 +4,7 @@
 
    Copyright (C) Jelmer Vernooij 2004-2007
    Copyright (C) Wilco Baan Hofman 2006
-   Copyright (C) Matthias Dieter Wallnöfer 2008
+   Copyright (C) Matthias Dieter Wallnöfer 2008-2010
 
    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
 #include "includes.h"
 #include "lib/registry/registry.h"
 #include "system/filesys.h"
-#include "param/param.h"
 
 
 _PUBLIC_ WERROR reg_preg_diff_load(int fd,
-                                  struct smb_iconv_convenience *iconv_convenience, 
                                   const struct reg_diff_callbacks *callbacks,
                                   void *callback_data);
 
 _PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
-                                    struct smb_iconv_convenience *iconv_convenience,
                                     const struct reg_diff_callbacks *callbacks,
                                     void *callback_data);
 
@@ -45,7 +42,7 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                             const struct reg_diff_callbacks *callbacks,
                             void *callback_data)
 {
-       int i;
+       unsigned int i;
        struct registry_key *t1 = NULL, *t2 = NULL;
        char *tmppath;
        const char *keyname1;
@@ -69,7 +66,7 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                old_num_values = 0;
        }
 
-       /* Subkeys that were deleted */
+       /* Subkeys that were changed or deleted */
        for (i = 0; i < old_num_subkeys; i++) {
                error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i,
                                                     &keyname1, NULL, NULL);
@@ -81,29 +78,33 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
 
                if (newkey != NULL) {
                        error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
-
-                       if (W_ERROR_IS_OK(error2))
-                               continue;
                } else {
-                       error2 = WERR_BADFILE;
+                       error2 = WERR_FILE_NOT_FOUND;
                        t2 = NULL;
                }
 
-               if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
-                       DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+               if (!W_ERROR_IS_OK(error2) && !W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
+                       DEBUG(0, ("Error occurred 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 */
+               /* if "error2" is going to be "WERR_FILE_NOT_FOUND", then newkey */
+               /* didn't have such a subkey and therefore add a del diff */
                tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
-               callbacks->del_key(callback_data, tmppath);
+               if (tmppath == NULL) {
+                       DEBUG(0, ("Out of memory\n"));
+                       talloc_free(mem_ctx);
+                       return WERR_NOT_ENOUGH_MEMORY;
+               }
+               if (!W_ERROR_IS_OK(error2))
+                       callbacks->del_key(callback_data, tmppath);
 
                /* perform here also the recursive invocation */
                error1 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
                if (!W_ERROR_IS_OK(error1)) {
-                       DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+                       DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
                        win_errstr(error1)));
                        talloc_free(mem_ctx);
                        return error1;
@@ -145,25 +146,30 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                        if (W_ERROR_IS_OK(error2))
                                continue;
                } else {
-                       error2 = WERR_BADFILE;  
+                       error2 = WERR_FILE_NOT_FOUND;
                        t1 = NULL;
                }
 
-               if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
+               if (!W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
                        DEBUG(0, ("Error occurred 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 */
+               /* oldkey didn't have such a subkey, add a add diff */
                tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
+               if (tmppath == NULL) {
+                       DEBUG(0, ("Out of memory\n"));
+                       talloc_free(mem_ctx);
+                       return WERR_NOT_ENOUGH_MEMORY;
+               }
                callbacks->add_key(callback_data, tmppath);
 
                /* perform here also the recursive invocation */
                error1 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
                if (!W_ERROR_IS_OK(error1)) {
-                       DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+                       DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
                        win_errstr(error1)));
                        talloc_free(mem_ctx);
                        return error1;
@@ -177,7 +183,7 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
        for(i = 0; i < new_num_values; i++) {
                const char *name;
                uint32_t type1, type2;
-               DATA_BLOB contents1, contents2;
+               DATA_BLOB contents1 = { NULL, 0 }, contents2 = { NULL, 0 };
 
                error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
                                                    &name, &type1, &contents1);
@@ -193,10 +199,10 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                                                           name, &type2,
                                                           &contents2);
                } else
-                       error2 = WERR_BADFILE;
+                       error2 = WERR_FILE_NOT_FOUND;
 
                if (!W_ERROR_IS_OK(error2)
-                       && !W_ERROR_EQUAL(error2, WERR_BADFILE)) {
+                       && !W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
                        DEBUG(0, ("Error occurred while getting value by name: %s\n",
                                win_errstr(error2)));
                        talloc_free(mem_ctx);
@@ -204,19 +210,27 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                }
 
                if (W_ERROR_IS_OK(error2)
-                       && (data_blob_cmp(&contents1, &contents2) == 0)
-                       && (type1 == type2))
+                   && (data_blob_cmp(&contents1, &contents2) == 0)
+                   && (type1 == type2)) {
+                       talloc_free(discard_const_p(char, name));
+                       talloc_free(contents1.data);
+                       talloc_free(contents2.data);
                        continue;
+               }
 
                callbacks->set_value(callback_data, path, name,
                                     type1, contents1);
+
+               talloc_free(discard_const_p(char, name));
+               talloc_free(contents1.data);
+               talloc_free(contents2.data);
        }
 
        /* Values that were deleted */
        for (i = 0; i < old_num_values; i++) {
                const char *name;
                uint32_t type;
-               DATA_BLOB contents;
+               DATA_BLOB contents = { NULL, 0 };
 
                error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
                                                    &type, &contents);
@@ -231,12 +245,15 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                        error2 = reg_key_get_value_by_name(mem_ctx, newkey,
                                 name, &type, &contents);
                else
-                       error2 = WERR_BADFILE;
+                       error2 = WERR_FILE_NOT_FOUND;
 
-               if (W_ERROR_IS_OK(error2))
+               if (W_ERROR_IS_OK(error2)) {
+                       talloc_free(discard_const_p(char, name));
+                       talloc_free(contents.data);
                        continue;
+               }
 
-               if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
+               if (!W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
                        DEBUG(0, ("Error occurred while getting value by name: %s\n",
                                win_errstr(error2)));
                        talloc_free(mem_ctx);
@@ -244,6 +261,9 @@ WERROR reg_generate_diff_key(struct registry_key *oldkey,
                }
 
                callbacks->del_value(callback_data, path, name);
+
+               talloc_free(discard_const_p(char, name));
+               talloc_free(contents.data);
        }
 
        talloc_free(mem_ctx);
@@ -258,7 +278,7 @@ _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
                                  const struct reg_diff_callbacks *callbacks,
                                  void *callback_data)
 {
-       int i;
+       unsigned int i;
        WERROR error;
 
        for (i = 0; reg_predefined_keys[i].name; i++) {
@@ -267,7 +287,7 @@ _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
                error = reg_get_predefined_key(ctx1,
                        reg_predefined_keys[i].handle, &r1);
                if (!W_ERROR_IS_OK(error) &&
-                   !W_ERROR_EQUAL(error, WERR_BADFILE)) {
+                   !W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
                        DEBUG(0, ("Unable to open hive %s for backend 1\n",
                                reg_predefined_keys[i].name));
                        continue;
@@ -276,12 +296,27 @@ _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
                error = reg_get_predefined_key(ctx2,
                        reg_predefined_keys[i].handle, &r2);
                if (!W_ERROR_IS_OK(error) &&
-                   !W_ERROR_EQUAL(error, WERR_BADFILE)) {
+                   !W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
                        DEBUG(0, ("Unable to open hive %s for backend 2\n",
                                reg_predefined_keys[i].name));
                        continue;
                }
 
+               /* if "r1" is NULL (old hive) and "r2" isn't (new hive) then
+                * the hive doesn't exist yet and we have to generate an add
+                * diff */
+               if ((r1 == NULL) && (r2 != NULL)) {
+                       callbacks->add_key(callback_data,
+                                          reg_predefined_keys[i].name);
+               }
+               /* if "r1" isn't NULL (old hive) and "r2" is (new hive) then
+                * the hive shouldn't exist anymore and we have to generate a
+                * del diff */
+               if ((r1 != NULL) && (r2 == NULL)) {
+                       callbacks->del_key(callback_data,
+                                          reg_predefined_keys[i].name);
+               }
+
                error = reg_generate_diff_key(r1, r2,
                        reg_predefined_keys[i].name, callbacks,
                        callback_data);
@@ -301,7 +336,6 @@ _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
  * Load diff file
  */
 _PUBLIC_ WERROR reg_diff_load(const char *filename,
-                             struct smb_iconv_convenience *iconv_convenience,
                              const struct reg_diff_callbacks *callbacks,
                              void *callback_data)
 {
@@ -312,13 +346,14 @@ _PUBLIC_ WERROR reg_diff_load(const char *filename,
        if (fd == -1) {
                DEBUG(0, ("Error opening registry patch file `%s'\n",
                        filename));
-               return WERR_GENERAL_FAILURE;
+               return WERR_GEN_FAILURE;
        }
 
        if (read(fd, &hdr, 4) != 4) {
                DEBUG(0, ("Error reading registry patch file `%s'\n",
                        filename));
-               return WERR_GENERAL_FAILURE;
+               close(fd);
+               return WERR_GEN_FAILURE;
        }
 
        /* Reset position in file */
@@ -334,10 +369,10 @@ _PUBLIC_ WERROR reg_diff_load(const char *filename,
 #endif
        if (strncmp(hdr, "PReg", 4) == 0) {
                /* Must be a GPO Registry.pol file */
-               return reg_preg_diff_load(fd, iconv_convenience, callbacks, callback_data);
+               return reg_preg_diff_load(fd, callbacks, callback_data);
        } else {
                /* Must be a normal .REG file */
-               return reg_dotreg_diff_load(fd, iconv_convenience, callbacks, callback_data);
+               return reg_dotreg_diff_load(fd, callbacks, callback_data);
        }
 }
 
@@ -353,6 +388,7 @@ static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
 
        /* Recursively create the path */
        buf = talloc_strdup(ctx, key_name);
+       W_ERROR_HAVE_NO_MEMORY(buf);
        buf_ptr = buf;
 
        while (*buf_ptr++ != '\0' ) {
@@ -367,9 +403,12 @@ static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
                                return error;
                        }
                        *buf_ptr++ = '\\';
+                       talloc_free(tmp);
                }
        }
 
+       talloc_free(buf);
+
        /* Add the key */
        error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
 
@@ -379,20 +418,21 @@ static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
                        key_name, win_errstr(error)));
                return error;
        }
+       talloc_free(tmp);
+
        return WERR_OK;
 }
 
 static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
 {
        struct registry_context *ctx = (struct registry_context *)_ctx;
-       WERROR error;
 
-       error = reg_key_del_abs(ctx, key_name);
+       /* We can't proof here for success, because a common superkey could */
+       /* have been deleted before the subkey's (diff order). This removed */
+       /* therefore all children recursively and the "WERR_FILE_NOT_FOUND" result is */
+       /* expected. */
 
-       if(!W_ERROR_IS_OK(error)) {
-               DEBUG(0, ("Unable to delete key '%s'\n", key_name));
-               return error;
-       }
+       reg_key_del_abs(ctx, key_name);
 
        return WERR_OK;
 }
@@ -408,7 +448,7 @@ static WERROR reg_diff_apply_set_value(void *_ctx, const char *path,
        /* Open key */
        error = reg_open_key_abs(ctx, ctx, path, &tmp);
 
-       if (W_ERROR_EQUAL(error, WERR_BADFILE)) {
+       if (W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
                DEBUG(0, ("Error opening key '%s'\n", path));
                return error;
        }
@@ -421,6 +461,8 @@ static WERROR reg_diff_apply_set_value(void *_ctx, const char *path,
                return error;
        }
 
+       talloc_free(tmp);
+
        return WERR_OK;
 }
 
@@ -439,12 +481,13 @@ static WERROR reg_diff_apply_del_value(void *_ctx, const char *key_name,
                return error;
        }
 
-       error = reg_del_value(tmp, value_name);
+       error = reg_del_value(ctx, tmp, value_name);
        if (!W_ERROR_IS_OK(error)) {
                DEBUG(0, ("Error deleting value '%s'\n", value_name));
                return error;
        }
 
+       talloc_free(tmp);
 
        return WERR_OK;
 }
@@ -454,8 +497,7 @@ static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
        struct registry_context *ctx = (struct registry_context *)_ctx;
        struct registry_key *key;
        WERROR error;
-       int i;
-       uint32_t num_values;
+       const char *value_name;
 
        error = reg_open_key_abs(ctx, ctx, key_name, &key);
 
@@ -465,23 +507,28 @@ static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
        }
 
        W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key, NULL,
-                              NULL, &num_values, NULL, NULL, NULL, NULL));
+                              NULL, NULL, NULL, NULL, NULL, 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));
+       while (W_ERROR_IS_OK(reg_key_get_value_by_index(
+                       ctx, key, 0, &value_name, NULL, NULL))) {
+               error = reg_del_value(ctx, key, value_name);
+               if (!W_ERROR_IS_OK(error)) {
+                       DEBUG(0, ("Error deleting value '%s'\n", value_name));
+                       return error;
+               }
+               talloc_free(discard_const_p(char, value_name));
        }
 
+       talloc_free(key);
+
        return WERR_OK;
 }
 
 /**
  * Apply diff to a registry context
  */
-_PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx, const char *filename)
+_PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx, 
+                                                          const char *filename)
 {
        struct reg_diff_callbacks callbacks;
 
@@ -492,6 +539,5 @@ _PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx, const char *filenam
        callbacks.del_all_values = reg_diff_apply_del_all_values;
        callbacks.done = NULL;
 
-       return reg_diff_load(filename, lp_iconv_convenience(global_loadparm), 
-                            &callbacks, ctx);
+       return reg_diff_load(filename, &callbacks, ctx);
 }