s3:registry: update the seqnum in the subkey cache at the end of regval_store_keys
[ddiss/samba.git] / source3 / registry / reg_backend_db.c
index 2d7b97d7b8212b9e82c79c70a5621cb8fc9859a8..e0fe7c121151b23f70293f155de2c6ba788b4aa5 100644 (file)
 /* Implementation of internal registry database functions. */
 
 #include "includes.h"
-
+#include "system/filesys.h"
 #include "registry.h"
 #include "reg_db.h"
 #include "reg_util_internal.h"
 #include "reg_backend_db.h"
 #include "reg_objects.h"
 #include "nt_printing.h"
+#include "util_tdb.h"
 #include "dbwrap.h"
 
 #undef DBGC_CLASS
@@ -47,6 +48,8 @@ static int regdb_fetch_values_internal(struct db_context *db, const char* key,
 static bool regdb_store_values_internal(struct db_context *db, const char *key,
                                        struct regval_ctr *values);
 
+static NTSTATUS create_sorted_subkeys(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
@@ -104,7 +107,7 @@ static struct builtin_regkey_value builtin_registry_values[] = {
        { KEY_PRINTING_2K,
                "DefaultSpoolDirectory", REG_SZ, { "C:\\Windows\\System32\\Spool\\Printers" } },
        { KEY_EVENTLOG,
-               "DisplayName", REG_SZ, { "Event Log" } }, 
+               "DisplayName", REG_SZ, { "Event Log" } },
        { KEY_EVENTLOG,
                "ErrorControl", REG_DWORD, { (char*)0x00000001 } },
        { NULL, NULL, 0, { NULL } }
@@ -317,7 +320,7 @@ static NTSTATUS init_registry_data_action(struct db_context *db,
 
                /* preserve existing values across restarts. Only add new ones */
 
-               if (!regval_ctr_key_exists(values,
+               if (!regval_ctr_value_exists(values,
                                        builtin_registry_values[i].valuename))
                {
                        regdb_ctr_add_value(values,
@@ -361,7 +364,7 @@ WERROR init_registry_data(void)
                regdb_fetch_values_internal(regdb,
                                            builtin_registry_values[i].path,
                                            values);
-               if (!regval_ctr_key_exists(values,
+               if (!regval_ctr_value_exists(values,
                                        builtin_registry_values[i].valuename))
                {
                        TALLOC_FREE(values);
@@ -417,10 +420,8 @@ static int regdb_normalize_keynames_fn(struct db_record *rec,
                          (const char *) rec->key.dptr,
                          keyname));
 
-               new_rec.value.dptr = rec->value.dptr;
-               new_rec.value.dsize = rec->value.dsize;
-               new_rec.key.dptr = (unsigned char *) keyname;
-               new_rec.key.dsize = strlen(keyname);
+               new_rec.value = rec->value;
+               new_rec.key = string_term_tdb_data(keyname);
                new_rec.private_data = rec->private_data;
 
                /* Delete the original record and store the normalized key */
@@ -455,11 +456,11 @@ static WERROR regdb_store_regdb_version(uint32_t version)
 
        status = dbwrap_trans_store_int32(regdb, version_keyname, version);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("regdb_init: error storing %s = %d: %s\n",
+               DEBUG(1, ("regdb_store_regdb_version: error storing %s = %d: %s\n",
                          version_keyname, version, nt_errstr(status)));
                return ntstatus_to_werror(status);
        } else {
-               DEBUG(10, ("regdb_init: stored %s = %d\n",
+               DEBUG(10, ("regdb_store_regdb_version: stored %s = %d\n",
                          version_keyname, version));
                return WERR_OK;
        }
@@ -499,8 +500,8 @@ WERROR regdb_init(void)
        WERROR werr;
 
        if (regdb) {
-               DEBUG(10, ("regdb_init: incrementing refcount (%d)\n",
-                         regdb_refcount));
+               DEBUG(10, ("regdb_init: incrementing refcount (%d->%d)\n",
+                          regdb_refcount, regdb_refcount+1));
                regdb_refcount++;
                return WERR_OK;
        }
@@ -516,11 +517,13 @@ WERROR regdb_init(void)
                                state_path("registry.tdb"), strerror(errno) ));
                        return werr;
                }
-               
+
                DEBUG(10,("regdb_init: Successfully created registry tdb\n"));
        }
 
        regdb_refcount = 1;
+       DEBUG(10, ("regdb_init: registry db openend. refcount reset (%d)\n",
+                  regdb_refcount));
 
        expected_version = REGVER_V2;
 
@@ -576,25 +579,27 @@ WERROR regdb_open( void )
        WERROR result = WERR_OK;
 
        if ( regdb ) {
-               DEBUG(10,("regdb_open: incrementing refcount (%d)\n", regdb_refcount));
+               DEBUG(10, ("regdb_open: incrementing refcount (%d->%d)\n",
+                          regdb_refcount, regdb_refcount+1));
                regdb_refcount++;
                return WERR_OK;
        }
-       
+
        become_root();
 
        regdb = db_open(NULL, state_path("registry.tdb"), 0,
                              REG_TDB_FLAGS, O_RDWR, 0600);
        if ( !regdb ) {
                result = ntstatus_to_werror( map_nt_error_from_unix( errno ) );
-               DEBUG(0,("regdb_open: Failed to open %s! (%s)\n", 
+               DEBUG(0,("regdb_open: Failed to open %s! (%s)\n",
                        state_path("registry.tdb"), strerror(errno) ));
        }
 
        unbecome_root();
 
        regdb_refcount = 1;
-       DEBUG(10,("regdb_open: refcount reset (%d)\n", regdb_refcount));
+       DEBUG(10, ("regdb_open: registry db opened. refcount reset (%d)\n",
+                  regdb_refcount));
 
        return result;
 }
@@ -610,7 +615,8 @@ int regdb_close( void )
 
        regdb_refcount--;
 
-       DEBUG(10,("regdb_close: decrementing refcount (%d)\n", regdb_refcount));
+       DEBUG(10, ("regdb_close: decrementing refcount (%d->%d)\n",
+                  regdb_refcount+1, regdb_refcount));
 
        if ( regdb_refcount > 0 )
                return 0;
@@ -828,22 +834,9 @@ static WERROR regdb_store_keys_internal2(struct db_context *db,
        W_ERROR_NOT_OK_GOTO_DONE(werr);
 
        /*
-        * Delete a sorted subkey cache for regdb_key_exists, will be
-        * recreated automatically
+        * recreate the sorted subkey cache for regdb_key_exists()
         */
-       keyname = talloc_asprintf(ctx, "%s\\%s", REG_SORTED_SUBKEYS_PREFIX,
-                                 keyname);
-       if (keyname == NULL) {
-               werr = WERR_NOMEM;
-               goto done;
-       }
-
-       werr = ntstatus_to_werror(dbwrap_delete_bystring(db, keyname));
-
-       /* don't treat WERR_NOT_FOUND as an error here */
-       if (W_ERROR_EQUAL(werr, WERR_NOT_FOUND)) {
-               werr = WERR_OK;
-       }
+       werr = ntstatus_to_werror(create_sorted_subkeys(keyname));
 
 done:
        TALLOC_FREE(ctx);
@@ -991,7 +984,11 @@ static NTSTATUS regdb_store_keys_action(struct db_context *db,
                TALLOC_FREE(path);
        }
 
-       werr = WERR_OK;
+       /*
+        * Update the seqnum in the container to possibly
+        * prevent next read from going to disk
+        */
+       werr = regsubkey_ctr_set_seqnum(store_ctx->ctr, db->get_seqnum(db));
 
 done:
        talloc_free(mem_ctx);
@@ -1404,7 +1401,8 @@ done:
        return status;
 }
 
-static bool create_sorted_subkeys(const char *key, const char *sorted_keyname)
+static NTSTATUS create_sorted_subkeys_internal(const char *key,
+                                              const char *sorted_keyname)
 {
        NTSTATUS status;
        struct create_sorted_subkeys_context sorted_ctx;
@@ -1416,7 +1414,26 @@ static bool create_sorted_subkeys(const char *key, const char *sorted_keyname)
                                 create_sorted_subkeys_action,
                                 &sorted_ctx);
 
-       return NT_STATUS_IS_OK(status);
+       return status;
+}
+
+static NTSTATUS create_sorted_subkeys(const char *key)
+{
+       char *sorted_subkeys_keyname;
+       NTSTATUS status;
+
+       sorted_subkeys_keyname = talloc_asprintf(talloc_tos(), "%s\\%s",
+                                                REG_SORTED_SUBKEYS_PREFIX,
+                                                key);
+       if (sorted_subkeys_keyname == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       status = create_sorted_subkeys_internal(key, sorted_subkeys_keyname);
+
+done:
+       return status;
 }
 
 struct scan_subkey_state {
@@ -1496,13 +1513,21 @@ static bool scan_parent_subkeys(struct db_context *db, const char *parent,
        if (state.scanned) {
                result = state.found;
        } else {
+               NTSTATUS status;
+
                res = db->transaction_start(db);
                if (res != 0) {
-                       DEBUG(0, ("error starting transacion\n"));
+                       DEBUG(0, ("error starting transaction\n"));
                        goto fail;
                }
 
-               if (!create_sorted_subkeys(path, key)) {
+               DEBUG(2, (__location__ " WARNING: recreating the sorted "
+                         "subkeys cache for key '%s' from scan_parent_subkeys "
+                         "this should not happen (too frequently)...\n",
+                         path));
+
+               status = create_sorted_subkeys_internal(path, key);
+               if (!NT_STATUS_IS_OK(status)) {
                        res = db->transaction_cancel(db);
                        if (res != 0) {
                                smb_panic("Failed to cancel transaction.");
@@ -1593,8 +1618,6 @@ static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key,
 
        DEBUG(11,("regdb_fetch_keys: Enter key => [%s]\n", key ? key : "NULL"));
 
-       frame = talloc_stackframe();
-
        if (!regdb_key_exists(db, key)) {
                DEBUG(10, ("key [%s] not found\n", key));
                werr = WERR_NOT_FOUND;
@@ -1688,7 +1711,8 @@ static int regdb_unpack_values(struct regval_ctr *values, uint8 *buf, int buflen
                                (uint8_t *)data_p, size);
                SAFE_FREE(data_p); /* 'B' option to tdb_unpack does a malloc() */
 
-               DEBUG(8,("specific: [%s], len: %d\n", valuename, size));
+               DEBUG(10, ("regdb_unpack_values: value[%d]: name[%s] len[%d]\n",
+                          i, valuename, size));
        }
 
        return len;
@@ -1742,7 +1766,7 @@ static int regdb_fetch_values_internal(struct db_context *db, const char* key,
        TDB_DATA value;
        WERROR werr;
 
-       DEBUG(10,("regdb_fetch_values: Looking for value of key [%s] \n", key));
+       DEBUG(10,("regdb_fetch_values: Looking for values of key [%s]\n", key));
 
        if (!regdb_key_exists(db, key)) {
                goto done;
@@ -1785,8 +1809,9 @@ static bool regdb_store_values_internal(struct db_context *db, const char *key,
        int len;
        NTSTATUS status;
        bool result = false;
+       WERROR werr;
 
-       DEBUG(10,("regdb_store_values: Looking for value of key [%s] \n", key));
+       DEBUG(10,("regdb_store_values: Looking for values of key [%s]\n", key));
 
        if (!regdb_key_exists(db, key)) {
                goto done;
@@ -1827,8 +1852,17 @@ static bool regdb_store_values_internal(struct db_context *db, const char *key,
        }
 
        status = dbwrap_trans_store_bystring(db, keystr, data, TDB_REPLACE);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("regdb_store_values_internal: error storing: %s\n", nt_errstr(status)));
+               goto done;
+       }
 
-       result = NT_STATUS_IS_OK(status);
+       /*
+        * update the seqnum in the cache to prevent the next read
+        * from going to disk
+        */
+       werr = regval_ctr_set_seqnum(values, db->get_seqnum(db));
+       result = W_ERROR_IS_OK(status);
 
 done:
        TALLOC_FREE(ctx);
@@ -1942,10 +1976,10 @@ bool regdb_values_need_update(struct regval_ctr *values)
        return (regdb_get_seqnum() != regval_ctr_get_seqnum(values));
 }
 
-/* 
+/*
  * Table of function pointers for default access
  */
+
 struct registry_ops regdb_ops = {
        .fetch_subkeys = regdb_fetch_keys,
        .fetch_values = regdb_fetch_values,