registry: free temporary data in regdb_fetch_key_internal().
[ira/wip.git] / source3 / registry / reg_backend_db.c
index 9fa62fb7c47d8e64b2762d34355fb66ca9da01be..d1ec8e4b61a61670960ab365866cb2f788abadc2 100644 (file)
@@ -27,6 +27,8 @@
 static struct db_context *regdb = NULL;
 static int regdb_refcount;
 
+static bool regdb_key_exists(const char *key);
+
 /* List the deepest path into the registry.  All part components will be created.*/
 
 /* If you want to have a part of the path controlled by the tdb and part by
@@ -199,6 +201,10 @@ WERROR init_registry_key(const char *add_path)
 {
        WERROR werr;
 
+       if (regdb_key_exists(add_path)) {
+               return WERR_OK;
+       }
+
        if (regdb->transaction_start(regdb) != 0) {
                DEBUG(0, ("init_registry_key: transaction_start failed\n"));
                return WERR_REG_IO_FAILURE;
@@ -231,11 +237,44 @@ fail:
 WERROR init_registry_data(void)
 {
        WERROR werr;
-       TALLOC_CTX *frame = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
        REGVAL_CTR *values;
        int i;
        UNISTR2 data;
 
+       /*
+        * First, check for the existence of the needed keys and values.
+        * If all do already exist, we can save the writes.
+        */
+       for (i=0; builtin_registry_paths[i] != NULL; i++) {
+               if (!regdb_key_exists(builtin_registry_paths[i])) {
+                       goto do_init;
+               }
+       }
+
+       for (i=0; builtin_registry_values[i].path != NULL; i++) {
+               values = TALLOC_ZERO_P(frame, REGVAL_CTR);
+               if (values == NULL) {
+                       werr = WERR_NOMEM;
+                       goto done;
+               }
+
+               regdb_fetch_values(builtin_registry_values[i].path, values);
+               if (!regval_ctr_key_exists(values,
+                                       builtin_registry_values[i].valuename))
+               {
+                       TALLOC_FREE(values);
+                       goto do_init;
+               }
+
+               TALLOC_FREE(values);
+       }
+
+       werr = WERR_OK;
+       goto done;
+
+do_init:
+
        /*
         * There are potentially quite a few store operations which are all
         * indiviually wrapped in tdb transactions. Wrapping them in a single
@@ -247,12 +286,16 @@ WERROR init_registry_data(void)
        if (regdb->transaction_start(regdb) != 0) {
                DEBUG(0, ("init_registry_data: tdb_transaction_start "
                          "failed\n"));
-               return WERR_REG_IO_FAILURE;
+               werr = WERR_REG_IO_FAILURE;
+               goto done;
        }
 
        /* loop over all of the predefined paths and add each component */
 
        for (i=0; builtin_registry_paths[i] != NULL; i++) {
+               if (regdb_key_exists(builtin_registry_paths[i])) {
+                       continue;
+               }
                werr = init_registry_key_internal(builtin_registry_paths[i]);
                if (!W_ERROR_IS_OK(werr)) {
                        goto fail;
@@ -261,8 +304,6 @@ WERROR init_registry_data(void)
 
        /* loop over all of the predefined values and add each component */
 
-       frame = talloc_stackframe();
-
        for (i=0; builtin_registry_values[i].path != NULL; i++) {
 
                values = TALLOC_ZERO_P(frame, REGVAL_CTR);
@@ -310,25 +351,24 @@ WERROR init_registry_data(void)
                TALLOC_FREE(values);
        }
 
-       TALLOC_FREE(frame);
-
        if (regdb->transaction_commit(regdb) != 0) {
                DEBUG(0, ("init_registry_data: Could not commit "
                          "transaction\n"));
-               return WERR_REG_IO_FAILURE;
+               werr = WERR_REG_IO_FAILURE;
+       } else {
+               werr = WERR_OK;
        }
 
-       return WERR_OK;
-
- fail:
-
-       TALLOC_FREE(frame);
+       goto done;
 
+fail:
        if (regdb->transaction_cancel(regdb) != 0) {
                smb_panic("init_registry_data: tdb_transaction_cancel "
                          "failed\n");
        }
 
+done:
+       TALLOC_FREE(frame);
        return werr;
 }
 
@@ -713,18 +753,37 @@ fail:
 }
 
 
-static TDB_DATA regdb_fetch_key_internal(const char *key, TALLOC_CTX *mem_ctx)
+static TDB_DATA regdb_fetch_key_internal(TALLOC_CTX *mem_ctx, const char *key)
 {
        char *path = NULL;
+       TDB_DATA data;
 
        path = normalize_reg_path(mem_ctx, key);
        if (!path) {
                return make_tdb_data(NULL, 0);
        }
 
-       return dbwrap_fetch_bystring(regdb, mem_ctx, path);
+       data = dbwrap_fetch_bystring(regdb, mem_ctx, path);
+
+       TALLOC_FREE(path);
+       return data;
 }
 
+
+static bool regdb_key_exists(const char *key)
+{
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
+       TDB_DATA value;
+       bool ret;
+
+       value = regdb_fetch_key_internal(mem_ctx, key);
+       ret = (value.dptr != NULL);
+
+       TALLOC_FREE(mem_ctx);
+       return ret;
+}
+
+
 /***********************************************************************
  Retrieve an array of strings containing subkeys.  Memory should be
  released by the caller.
@@ -746,7 +805,7 @@ int regdb_fetch_keys(const char *key, REGSUBKEY_CTR *ctr)
 
        ctr->seqnum = regdb_get_seqnum();
 
-       value = regdb_fetch_key_internal(key, frame);
+       value = regdb_fetch_key_internal(frame, key);
 
        buf = value.dptr;
        buflen = value.dsize;
@@ -873,14 +932,10 @@ int regdb_fetch_values( const char* key, REGVAL_CTR *values )
        if (!keystr) {
                return 0;
        }
-       keystr = normalize_reg_path(ctx, keystr);
-       if (!keystr) {
-               goto done;
-       }
 
        values->seqnum = regdb_get_seqnum();
 
-       value = dbwrap_fetch_bystring(regdb, ctx, keystr);
+       value = regdb_fetch_key_internal(ctx, keystr);
 
        if (!value.dptr) {
                /* all keys have zero values by default */