* Unix SMB/CIFS implementation.
* Virtual Windows Registry Layer
* Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2007-2009
*
* 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
static bool regdb_key_exists(struct db_context *db, const char *key);
static bool regdb_key_is_base_key(const char *key);
-static int regdb_fetch_keys_internal(struct db_context *db, const char *key,
- struct regsubkey_ctr *ctr);
+static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key,
+ struct regsubkey_ctr *ctr);
static bool regdb_store_keys_internal(struct db_context *db, const char *key,
struct regsubkey_ctr *ctr);
static int regdb_fetch_values_internal(struct db_context *db, const char* key,
goto fail;
}
- regdb_fetch_keys_internal(db, base, subkeys);
+ werr = regdb_fetch_keys_internal(db, base, subkeys);
+ if (!W_ERROR_IS_OK(werr) &&
+ !W_ERROR_EQUAL(werr, WERR_NOT_FOUND))
+ {
+ goto fail;
+ }
+
if (*subkeyname) {
werr = regsubkey_ctr_addkey(subkeys, subkeyname);
if (!W_ERROR_IS_OK(werr)) {
Open the registry data in the tdb
***********************************************************************/
-WERROR init_registry_data(void)
+static void regdb_ctr_add_value(struct regval_ctr *ctr,
+ struct builtin_regkey_value *value)
{
- WERROR werr;
+ switch(value->type) {
+ case REG_DWORD:
+ regval_ctr_addvalue(ctr, value->valuename, REG_DWORD,
+ (char*)&value->data.dw_value,
+ sizeof(uint32));
+ break;
+
+ case REG_SZ:
+ regval_ctr_addvalue_sz(ctr, value->valuename,
+ value->data.string);
+ break;
+
+ default:
+ DEBUG(0, ("regdb_ctr_add_value: invalid value type in "
+ "registry values [%d]\n", value->type));
+ }
+}
+
+static NTSTATUS init_registry_data_action(struct db_context *db,
+ void *private_data)
+{
+ NTSTATUS status;
TALLOC_CTX *frame = talloc_stackframe();
struct 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.
- */
+ /* loop over all of the predefined paths and add each component */
+
for (i=0; builtin_registry_paths[i] != NULL; i++) {
- if (!regdb_key_exists(regdb, builtin_registry_paths[i])) {
- goto do_init;
+ if (regdb_key_exists(db, builtin_registry_paths[i])) {
+ continue;
+ }
+ status = werror_to_ntstatus(init_registry_key_internal(db,
+ builtin_registry_paths[i]));
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
}
}
+ /* loop over all of the predefined values and add each component */
+
for (i=0; builtin_registry_values[i].path != NULL; i++) {
+
values = TALLOC_ZERO_P(frame, struct regval_ctr);
if (values == NULL) {
- werr = WERR_NOMEM;
+ status = NT_STATUS_NO_MEMORY;
goto done;
}
- regdb_fetch_values_internal(regdb,
+ regdb_fetch_values_internal(db,
builtin_registry_values[i].path,
values);
+
+ /* preserve existing values across restarts. Only add new ones */
+
if (!regval_ctr_key_exists(values,
builtin_registry_values[i].valuename))
{
- TALLOC_FREE(values);
- goto do_init;
+ regdb_ctr_add_value(values,
+ &builtin_registry_values[i]);
+ regdb_store_values_internal(db,
+ builtin_registry_values[i].path,
+ values);
}
-
TALLOC_FREE(values);
}
- werr = WERR_OK;
- goto done;
-
-do_init:
+ status = NT_STATUS_OK;
- /*
- * There are potentially quite a few store operations which are all
- * indiviually wrapped in tdb transactions. Wrapping them in a single
- * transaction gives just a single transaction_commit() to actually do
- * its fsync()s. See tdb/common/transaction.c for info about nested
- * transaction behaviour.
- */
+done:
- if (regdb->transaction_start(regdb) != 0) {
- DEBUG(0, ("init_registry_data: tdb_transaction_start "
- "failed\n"));
- werr = WERR_REG_IO_FAILURE;
- goto done;
- }
+ TALLOC_FREE(frame);
+ return status;
+}
- /* loop over all of the predefined paths and add each component */
+WERROR init_registry_data(void)
+{
+ WERROR werr;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct regval_ctr *values;
+ int i;
+ /*
+ * 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(regdb, builtin_registry_paths[i])) {
- continue;
- }
- werr = init_registry_key_internal(regdb,
- builtin_registry_paths[i]);
- if (!W_ERROR_IS_OK(werr)) {
- goto fail;
+ if (!regdb_key_exists(regdb, builtin_registry_paths[i])) {
+ goto do_init;
}
}
- /* loop over all of the predefined values and add each component */
-
for (i=0; builtin_registry_values[i].path != NULL; i++) {
-
values = TALLOC_ZERO_P(frame, struct regval_ctr);
if (values == NULL) {
werr = WERR_NOMEM;
- goto fail;
+ goto done;
}
regdb_fetch_values_internal(regdb,
builtin_registry_values[i].path,
values);
-
- /* preserve existing values across restarts. Only add new ones */
-
if (!regval_ctr_key_exists(values,
builtin_registry_values[i].valuename))
{
- switch(builtin_registry_values[i].type) {
- case REG_DWORD:
- regval_ctr_addvalue(values,
- builtin_registry_values[i].valuename,
- REG_DWORD,
- (char*)&builtin_registry_values[i].data.dw_value,
- sizeof(uint32));
- break;
-
- case REG_SZ:
- init_unistr2(&data,
- builtin_registry_values[i].data.string,
- UNI_STR_TERMINATE);
- regval_ctr_addvalue(values,
- builtin_registry_values[i].valuename,
- REG_SZ,
- (char*)data.buffer,
- data.uni_str_len*sizeof(uint16));
- break;
-
- default:
- DEBUG(0, ("init_registry_data: invalid value "
- "type in builtin_registry_values "
- "[%d]\n",
- builtin_registry_values[i].type));
- }
- regdb_store_values_internal(regdb,
- builtin_registry_values[i].path,
- values);
+ TALLOC_FREE(values);
+ goto do_init;
}
- TALLOC_FREE(values);
- }
- if (regdb->transaction_commit(regdb) != 0) {
- DEBUG(0, ("init_registry_data: Could not commit "
- "transaction\n"));
- werr = WERR_REG_IO_FAILURE;
- } else {
- werr = WERR_OK;
+ TALLOC_FREE(values);
}
+ werr = WERR_OK;
goto done;
-fail:
- if (regdb->transaction_cancel(regdb) != 0) {
- smb_panic("init_registry_data: tdb_transaction_cancel "
- "failed\n");
- }
+do_init:
+
+ /*
+ * There are potentially quite a few store operations which are all
+ * indiviually wrapped in tdb transactions. Wrapping them in a single
+ * transaction gives just a single transaction_commit() to actually do
+ * its fsync()s. See tdb/common/transaction.c for info about nested
+ * transaction behaviour.
+ */
+
+ werr = ntstatus_to_werror(dbwrap_trans_do(regdb,
+ init_registry_data_action,
+ NULL));
done:
TALLOC_FREE(frame);
fstrings
***********************************************************************/
-static bool regdb_store_keys_internal2(struct db_context *db,
- const char *key,
- struct regsubkey_ctr *ctr)
+static WERROR regdb_store_keys_internal2(struct db_context *db,
+ const char *key,
+ struct regsubkey_ctr *ctr)
{
TDB_DATA dbuf;
uint8 *buffer = NULL;
int i = 0;
uint32 len, buflen;
- bool ret = true;
uint32 num_subkeys = regsubkey_ctr_numkeys(ctr);
char *keyname = NULL;
TALLOC_CTX *ctx = talloc_stackframe();
- NTSTATUS status;
+ WERROR werr;
if (!key) {
- return false;
+ werr = WERR_INVALID_PARAM;
+ goto done;
}
keyname = talloc_strdup(ctx, key);
if (!keyname) {
- return false;
+ werr = WERR_NOMEM;
+ goto done;
}
+
keyname = normalize_reg_path(ctx, keyname);
+ if (!keyname) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
/* allocate some initial memory */
buffer = (uint8 *)SMB_MALLOC(1024);
if (buffer == NULL) {
- return false;
+ werr = WERR_NOMEM;
+ goto done;
}
buflen = 1024;
len = 0;
DEBUG(0, ("regdb_store_keys: Failed to realloc "
"memory of size [%u]\n",
(unsigned int)(len+thistime)*2));
- ret = false;
+ werr = WERR_NOMEM;
goto done;
}
buflen = (len+thistime)*2;
regsubkey_ctr_specific_key(ctr, i));
if (thistime2 != thistime) {
DEBUG(0, ("tdb_pack failed\n"));
- ret = false;
+ werr = WERR_CAN_NOT_COMPLETE;
goto done;
}
}
dbuf.dptr = buffer;
dbuf.dsize = len;
- status = dbwrap_store_bystring(db, keyname, dbuf, TDB_REPLACE);
- if (!NT_STATUS_IS_OK(status)) {
- ret = false;
- goto done;
- }
+ werr = ntstatus_to_werror(dbwrap_store_bystring(db, keyname, dbuf,
+ TDB_REPLACE));
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
/*
* Delete a sorted subkey cache for regdb_key_exists, will be
*/
keyname = talloc_asprintf(ctx, "%s/%s", REG_SORTED_SUBKEYS_PREFIX,
keyname);
- if (keyname != NULL) {
- dbwrap_delete_bystring(db, 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;
}
done:
TALLOC_FREE(ctx);
SAFE_FREE(buffer);
- return ret;
+ return werr;
}
/***********************************************************************
do not currently exist
***********************************************************************/
-static bool regdb_store_keys_internal(struct db_context *db, const char *key,
- struct regsubkey_ctr *ctr)
+struct regdb_store_keys_context {
+ const char *key;
+ struct regsubkey_ctr *ctr;
+};
+
+static NTSTATUS regdb_store_keys_action(struct db_context *db,
+ void *private_data)
{
- int num_subkeys, old_num_subkeys, i;
+ struct regdb_store_keys_context *store_ctx;
+ WERROR werr;
+ int num_subkeys, i;
char *path = NULL;
struct regsubkey_ctr *subkeys = NULL, *old_subkeys = NULL;
char *oldkeyname = NULL;
- TALLOC_CTX *ctx = talloc_stackframe();
- WERROR werr;
-
- if (!regdb_key_is_base_key(key) && !regdb_key_exists(db, key)) {
- goto fail;
- }
-
- /*
- * fetch a list of the old subkeys so we can determine if anything has
- * changed
- */
-
- werr = regsubkey_ctr_init(ctx, &old_subkeys);
- if (!W_ERROR_IS_OK(werr)) {
- DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
- return false;
- }
-
- regdb_fetch_keys_internal(db, key, old_subkeys);
-
- num_subkeys = regsubkey_ctr_numkeys(ctr);
- old_num_subkeys = regsubkey_ctr_numkeys(old_subkeys);
- if ((num_subkeys && old_num_subkeys) &&
- (num_subkeys == old_num_subkeys)) {
-
- for (i = 0; i < num_subkeys; i++) {
- if (strcmp(regsubkey_ctr_specific_key(ctr, i),
- regsubkey_ctr_specific_key(old_subkeys, i))
- != 0)
- {
- break;
- }
- }
- if (i == num_subkeys) {
- /*
- * Nothing changed, no point to even start a tdb
- * transaction
- */
- TALLOC_FREE(old_subkeys);
- return true;
- }
- }
-
- TALLOC_FREE(old_subkeys);
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
- if (db->transaction_start(db) != 0) {
- DEBUG(0, ("regdb_store_keys: transaction_start failed\n"));
- goto fail;
- }
+ store_ctx = (struct regdb_store_keys_context *)private_data;
/*
* Re-fetch the old keys inside the transaction
*/
- werr = regsubkey_ctr_init(ctx, &old_subkeys);
- if (!W_ERROR_IS_OK(werr)) {
- DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
- goto cancel;
- }
+ werr = regsubkey_ctr_init(mem_ctx, &old_subkeys);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
- regdb_fetch_keys_internal(db, key, old_subkeys);
+ werr = regdb_fetch_keys_internal(db, store_ctx->key, old_subkeys);
+ if (!W_ERROR_IS_OK(werr) &&
+ !W_ERROR_EQUAL(werr, WERR_NOT_FOUND))
+ {
+ goto done;
+ }
/*
* Make the store operation as safe as possible without transactions:
for (i=0; i<num_subkeys; i++) {
oldkeyname = regsubkey_ctr_specific_key(old_subkeys, i);
- if (regsubkey_ctr_key_exists(ctr, oldkeyname)) {
+ if (regsubkey_ctr_key_exists(store_ctx->ctr, oldkeyname)) {
/*
* It's still around, don't delete
*/
-
continue;
}
- path = talloc_asprintf(ctx, "%s/%s", key, oldkeyname);
+ path = talloc_asprintf(mem_ctx, "%s/%s", store_ctx->key,
+ oldkeyname);
if (!path) {
- goto cancel;
+ werr = WERR_NOMEM;
+ goto done;
}
werr = regdb_delete_key_lists(db, path);
- W_ERROR_NOT_OK_GOTO(werr, cancel);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
TALLOC_FREE(path);
}
/* (2) store the subkey list for the parent */
- if (!regdb_store_keys_internal2(db, key, ctr)) {
+ werr = regdb_store_keys_internal2(db, store_ctx->key, store_ctx->ctr);
+ if (!W_ERROR_IS_OK(werr)) {
DEBUG(0,("regdb_store_keys: Failed to store new subkey list "
- "for parent [%s]\n", key));
- goto cancel;
+ "for parent [%s]: %s\n", store_ctx->key,
+ win_errstr(werr)));
+ goto done;
}
/* (3) now create records for any subkeys that don't already exist */
- num_subkeys = regsubkey_ctr_numkeys(ctr);
+ num_subkeys = regsubkey_ctr_numkeys(store_ctx->ctr);
if (num_subkeys == 0) {
- werr = regsubkey_ctr_init(ctx, &subkeys);
- if (!W_ERROR_IS_OK(werr)) {
- DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
- goto cancel;
- }
+ werr = regsubkey_ctr_init(mem_ctx, &subkeys);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
- if (!regdb_store_keys_internal2(db, key, subkeys)) {
+ werr = regdb_store_keys_internal2(db, store_ctx->key, subkeys);
+ if (!W_ERROR_IS_OK(werr)) {
DEBUG(0,("regdb_store_keys: Failed to store "
- "new record for key [%s]\n", key));
- goto cancel;
+ "new record for key [%s]: %s\n",
+ store_ctx->key, win_errstr(werr)));
+ goto done;
}
TALLOC_FREE(subkeys);
-
}
for (i=0; i<num_subkeys; i++) {
- path = talloc_asprintf(ctx, "%s/%s",
- key,
- regsubkey_ctr_specific_key(ctr, i));
+ path = talloc_asprintf(mem_ctx, "%s/%s", store_ctx->key,
+ regsubkey_ctr_specific_key(store_ctx->ctr, i));
if (!path) {
- goto cancel;
- }
- werr = regsubkey_ctr_init(ctx, &subkeys);
- if (!W_ERROR_IS_OK(werr)) {
- DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
- goto cancel;
+ werr = WERR_NOMEM;
+ goto done;
}
+ werr = regsubkey_ctr_init(mem_ctx, &subkeys);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
- if (regdb_fetch_keys_internal(db, path, subkeys) == -1) {
+ werr = regdb_fetch_keys_internal(db, path, subkeys);
+ if (!W_ERROR_IS_OK(werr)) {
/* create a record with 0 subkeys */
- if (!regdb_store_keys_internal2(db, path, subkeys)) {
+ werr = regdb_store_keys_internal2(db, path, subkeys);
+ if (!W_ERROR_IS_OK(werr)) {
DEBUG(0,("regdb_store_keys: Failed to store "
- "new record for key [%s]\n", path));
- goto cancel;
+ "new record for key [%s]: %s\n", path,
+ win_errstr(werr)));
+ goto done;
}
}
TALLOC_FREE(path);
}
- if (db->transaction_commit(db) != 0) {
- DEBUG(0, ("regdb_store_keys: Could not commit transaction\n"));
- goto fail;
+ werr = WERR_OK;
+
+done:
+ talloc_free(mem_ctx);
+ return werror_to_ntstatus(werr);
+}
+
+static bool regdb_store_keys_internal(struct db_context *db, const char *key,
+ struct regsubkey_ctr *ctr)
+{
+ int num_subkeys, old_num_subkeys, i;
+ struct regsubkey_ctr *old_subkeys = NULL;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ WERROR werr;
+ bool ret = false;
+ struct regdb_store_keys_context store_ctx;
+
+ if (!regdb_key_is_base_key(key) && !regdb_key_exists(db, key)) {
+ goto done;
}
- TALLOC_FREE(ctx);
- return true;
+ /*
+ * fetch a list of the old subkeys so we can determine if anything has
+ * changed
+ */
-cancel:
- if (db->transaction_cancel(db) != 0) {
- smb_panic("regdb_store_keys: transaction_cancel failed\n");
+ werr = regsubkey_ctr_init(ctx, &old_subkeys);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
+ goto done;
}
-fail:
+ werr = regdb_fetch_keys_internal(db, key, old_subkeys);
+ if (!W_ERROR_IS_OK(werr) &&
+ !W_ERROR_EQUAL(werr, WERR_NOT_FOUND))
+ {
+ goto done;
+ }
+
+ num_subkeys = regsubkey_ctr_numkeys(ctr);
+ old_num_subkeys = regsubkey_ctr_numkeys(old_subkeys);
+ if ((num_subkeys && old_num_subkeys) &&
+ (num_subkeys == old_num_subkeys)) {
+
+ for (i = 0; i < num_subkeys; i++) {
+ if (strcmp(regsubkey_ctr_specific_key(ctr, i),
+ regsubkey_ctr_specific_key(old_subkeys, i))
+ != 0)
+ {
+ break;
+ }
+ }
+ if (i == num_subkeys) {
+ /*
+ * Nothing changed, no point to even start a tdb
+ * transaction
+ */
+
+ ret = true;
+ goto done;
+ }
+ }
+
+ TALLOC_FREE(old_subkeys);
+
+ store_ctx.key = key;
+ store_ctx.ctr = ctr;
+
+ werr = ntstatus_to_werror(dbwrap_trans_do(db,
+ regdb_store_keys_action,
+ &store_ctx));
+
+ ret = W_ERROR_IS_OK(werr);
+
+done:
TALLOC_FREE(ctx);
- return false;
+ return ret;
}
bool regdb_store_keys(const char *key, struct regsubkey_ctr *ctr)
return regdb_store_keys_internal(regdb, key, ctr);
}
+/**
+ * create a subkey of a given key
+ */
+
+struct regdb_create_subkey_context {
+ const char *key;
+ const char *subkey;
+};
+
+static NTSTATUS regdb_create_subkey_action(struct db_context *db,
+ void *private_data)
+{
+ WERROR werr;
+ struct regdb_create_subkey_context *create_ctx;
+ struct regsubkey_ctr *subkeys;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ create_ctx = (struct regdb_create_subkey_context *)private_data;
+
+ werr = regsubkey_ctr_init(mem_ctx, &subkeys);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = regdb_fetch_keys_internal(db, create_ctx->key, subkeys);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = regsubkey_ctr_addkey(subkeys, create_ctx->subkey);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = regdb_store_keys_internal2(db, create_ctx->key, subkeys);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0, (__location__ " failed to store new subkey list for "
+ "parent key %s: %s\n", create_ctx->key,
+ win_errstr(werr)));
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return werror_to_ntstatus(werr);
+}
+
static WERROR regdb_create_subkey(const char *key, const char *subkey)
{
WERROR werr;
struct regsubkey_ctr *subkeys;
TALLOC_CTX *mem_ctx = talloc_stackframe();
+ struct regdb_create_subkey_context create_ctx;
if (!regdb_key_is_base_key(key) && !regdb_key_exists(regdb, key)) {
werr = WERR_NOT_FOUND;
werr = regsubkey_ctr_init(mem_ctx, &subkeys);
W_ERROR_NOT_OK_GOTO_DONE(werr);
- if (regdb_fetch_keys_internal(regdb, key, subkeys) < 0) {
- werr = WERR_REG_IO_FAILURE;
- goto done;
- }
+ werr = regdb_fetch_keys_internal(regdb, key, subkeys);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
if (regsubkey_ctr_key_exists(subkeys, subkey)) {
werr = WERR_OK;
talloc_free(subkeys);
- if (regdb->transaction_start(regdb) != 0) {
- werr = WERR_REG_IO_FAILURE;
- goto done;
- }
+ create_ctx.key = key;
+ create_ctx.subkey = subkey;
- werr = regsubkey_ctr_init(mem_ctx, &subkeys);
- W_ERROR_NOT_OK_GOTO(werr, cancel);
+ werr = ntstatus_to_werror(dbwrap_trans_do(regdb,
+ regdb_create_subkey_action,
+ &create_ctx));
- if (regdb_fetch_keys_internal(regdb, key, subkeys) < 0) {
- werr = WERR_REG_IO_FAILURE;
- goto cancel;
- }
+done:
+ talloc_free(mem_ctx);
+ return werr;
+}
- werr = regsubkey_ctr_addkey(subkeys, subkey);
- W_ERROR_NOT_OK_GOTO(werr, cancel);
+/**
+ * create a subkey of a given key
+ */
- if (!regdb_store_keys_internal2(regdb, key, subkeys)) {
- DEBUG(0, (__location__ " failed to store new subkey list for "
- "parent key %s\n", key));
- werr = WERR_REG_IO_FAILURE;
- goto cancel;
- }
+struct regdb_delete_subkey_context {
+ const char *key;
+ const char *subkey;
+ const char *path;
+};
- if (regdb->transaction_commit(regdb) != 0) {
- werr = WERR_REG_IO_FAILURE;
- DEBUG(0, (__location__ " failed to commit transaction\n"));
- }
+static NTSTATUS regdb_delete_subkey_action(struct db_context *db,
+ void *private_data)
+{
+ WERROR werr;
+ struct regdb_delete_subkey_context *delete_ctx;
+ struct regsubkey_ctr *subkeys;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
- goto done;
+ delete_ctx = (struct regdb_delete_subkey_context *)private_data;
+
+ werr = regdb_delete_key_lists(db, delete_ctx->path);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = regsubkey_ctr_init(mem_ctx, &subkeys);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = regdb_fetch_keys_internal(db, delete_ctx->key, subkeys);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+ werr = regsubkey_ctr_delkey(subkeys, delete_ctx->subkey);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
-cancel:
- if (regdb->transaction_cancel(regdb) != 0) {
- smb_panic("regdb_create_subkey: transaction_cancel failed\n");
+ werr = regdb_store_keys_internal2(db, delete_ctx->key, subkeys);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0, (__location__ " failed to store new subkey_list for "
+ "parent key %s: %s\n", delete_ctx->key,
+ win_errstr(werr)));
}
done:
talloc_free(mem_ctx);
- return werr;
+ return werror_to_ntstatus(werr);
}
static WERROR regdb_delete_subkey(const char *key, const char *subkey)
{
WERROR werr;
- struct regsubkey_ctr *subkeys;
char *path;
+ struct regdb_delete_subkey_context delete_ctx;
TALLOC_CTX *mem_ctx = talloc_stackframe();
if (!regdb_key_is_base_key(key) && !regdb_key_exists(regdb, key)) {
goto done;
}
- if (regdb->transaction_start(regdb) != 0) {
- werr = WERR_REG_IO_FAILURE;
- goto done;
- }
-
- werr = regdb_delete_key_lists(regdb, path);
- W_ERROR_NOT_OK_GOTO(werr, cancel);
-
- werr = regsubkey_ctr_init(mem_ctx, &subkeys);
- W_ERROR_NOT_OK_GOTO(werr, cancel);
-
- if (regdb_fetch_keys_internal(regdb, key, subkeys) < 0) {
- werr = WERR_REG_IO_FAILURE;
- goto cancel;
- }
-
- werr = regsubkey_ctr_delkey(subkeys, subkey);
- W_ERROR_NOT_OK_GOTO(werr, cancel);
+ delete_ctx.key = key;
+ delete_ctx.subkey = subkey;
+ delete_ctx.path = path;
- if (!regdb_store_keys_internal2(regdb, key, subkeys)) {
- DEBUG(0, (__location__ " failed to store new subkey_list for "
- "parent key %s\n", key));
- werr = WERR_REG_IO_FAILURE;
- goto cancel;
- }
-
- if (regdb->transaction_commit(regdb) != 0) {
- DEBUG(0, (__location__ " failed to commit transaction\n"));
- werr = WERR_REG_IO_FAILURE;
- }
-
- goto done;
-
-cancel:
- if (regdb->transaction_cancel(regdb) != 0) {
- smb_panic("regdb_delete_subkey: transaction_cancel failed\n");
- }
+ werr = ntstatus_to_werror(dbwrap_trans_do(regdb,
+ regdb_delete_subkey_action,
+ &delete_ctx));
done:
talloc_free(mem_ctx);
return StrCaseCmp(*((char **)p1), *((char **)p2));
}
-static bool create_sorted_subkeys(const char *key, const char *sorted_keyname)
+struct create_sorted_subkeys_context {
+ const char *key;
+ const char *sorted_keyname;
+};
+
+static NTSTATUS create_sorted_subkeys_action(struct db_context *db,
+ void *private_data)
{
char **sorted_subkeys;
struct regsubkey_ctr *ctr;
- bool result = false;
NTSTATUS status;
char *buf;
char *p;
- int i, res;
+ int i;
size_t len;
int num_subkeys;
- WERROR werr;
+ struct create_sorted_subkeys_context *sorted_ctx;
- if (regdb->transaction_start(regdb) != 0) {
- DEBUG(0, ("create_sorted_subkeys: transaction_start "
- "failed\n"));
- return false;
- }
+ sorted_ctx = (struct create_sorted_subkeys_context *)private_data;
- werr = regsubkey_ctr_init(talloc_tos(), &ctr);
- if (!W_ERROR_IS_OK(werr)) {
- goto fail;
+ /*
+ * In this function, we only treat failing of the actual write to
+ * the db as a real error. All preliminary errors, at a stage when
+ * nothing has been written to the DB yet are treated as success
+ * to be committed (as an empty transaction).
+ *
+ * The reason is that this (disposable) call might be nested in other
+ * transactions. Doing a cancel here would destroy the possibility of
+ * a transaction_commit for transactions that we might be wrapped in.
+ */
+
+ status = werror_to_ntstatus(regsubkey_ctr_init(talloc_tos(), &ctr));
+ if (!NT_STATUS_IS_OK(status)) {
+ /* don't treat this as an error */
+ status = NT_STATUS_OK;
+ goto done;
}
- res = regdb_fetch_keys_internal(regdb, key, ctr);
- if (res == -1) {
- goto fail;
+ status = werror_to_ntstatus(regdb_fetch_keys_internal(db,
+ sorted_ctx->key,
+ ctr));
+ if (!NT_STATUS_IS_OK(status)) {
+ /* don't treat this as an error */
+ status = NT_STATUS_OK;
+ goto done;
}
num_subkeys = regsubkey_ctr_numkeys(ctr);
sorted_subkeys = talloc_array(ctr, char *, num_subkeys);
if (sorted_subkeys == NULL) {
- goto fail;
+ /* don't treat this as an error */
+ goto done;
}
len = 4 + 4*num_subkeys;
sorted_subkeys[i] = talloc_strdup_upper(sorted_subkeys,
regsubkey_ctr_specific_key(ctr, i));
if (sorted_subkeys[i] == NULL) {
- goto fail;
+ /* don't treat this as an error */
+ goto done;
}
len += strlen(sorted_subkeys[i])+1;
}
buf = talloc_array(ctr, char, len);
if (buf == NULL) {
- goto fail;
+ /* don't treat this as an error */
+ goto done;
}
p = buf + 4 + 4*num_subkeys;
}
status = dbwrap_store_bystring(
- regdb, sorted_keyname, make_tdb_data((uint8_t *)buf, len),
+ db, sorted_ctx->sorted_keyname, make_tdb_data((uint8_t *)buf,
+ len),
TDB_REPLACE);
- if (!NT_STATUS_IS_OK(status)) {
- /*
- * Don't use a "goto fail;" here, this would commit the broken
- * transaction. See below for an explanation.
- */
- if (regdb->transaction_cancel(regdb) == -1) {
- smb_panic("create_sorted_subkeys: transaction_cancel "
- "failed\n");
- }
- TALLOC_FREE(ctr);
- return false;
- }
- result = true;
- fail:
- /*
- * We only get here via the "goto fail" when we did not write anything
- * yet. Using transaction_commit even in a failure case is necessary
- * because this (disposable) call might be nested in other
- * transactions. Doing a cancel here would destroy the possibility of
- * a transaction_commit for transactions that we might be wrapped in.
- */
- if (regdb->transaction_commit(regdb) == -1) {
- DEBUG(0, ("create_sorted_subkeys: transaction_commit "
- "failed\n"));
- result = false;
- }
+done:
+ talloc_free(ctr);
+ return status;
+}
- TALLOC_FREE(ctr);
- return result;
+static bool create_sorted_subkeys(const char *key, const char *sorted_keyname)
+{
+ NTSTATUS status;
+ struct create_sorted_subkeys_context sorted_ctx;
+
+ sorted_ctx.key = key;
+ sorted_ctx.sorted_keyname = sorted_keyname;
+
+ status = dbwrap_trans_do(regdb,
+ create_sorted_subkeys_action,
+ &sorted_ctx);
+
+ return NT_STATUS_IS_OK(status);
}
struct scan_subkey_state {
if (state.scanned) {
result = state.found;
} else {
+ res = db->transaction_start(db);
+ if (res != 0) {
+ DEBUG(0, ("error starting transacion\n"));
+ goto fail;
+ }
+
if (!create_sorted_subkeys(path, key)) {
+ res = db->transaction_cancel(db);
+ if (res != 0) {
+ smb_panic("Failed to cancel transaction.");
+ }
goto fail;
}
+
res = db->parse_record(db, string_term_tdb_data(key),
parent_subkey_scanner, &state);
if ((res == 0) && (state.scanned)) {
result = state.found;
}
+
+ res = db->transaction_commit(db);
+ if (res != 0) {
+ DEBUG(0, ("error committing transaction\n"));
+ result = false;
+ }
}
fail:
released by the caller.
***********************************************************************/
-static int regdb_fetch_keys_internal(struct db_context *db, const char *key,
- struct regsubkey_ctr *ctr)
+static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key,
+ struct regsubkey_ctr *ctr)
{
WERROR werr;
- uint32 num_items;
+ uint32_t num_items;
uint8 *buf;
uint32 buflen, len;
int i;
fstring subkeyname;
- int ret = -1;
TALLOC_CTX *frame = talloc_stackframe();
TDB_DATA value;
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;
goto done;
}
werr = regsubkey_ctr_set_seqnum(ctr, db->get_seqnum(db));
- if (!W_ERROR_IS_OK(werr)) {
- goto done;
- }
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
value = regdb_fetch_key_internal(db, frame, key);
- if (value.dptr == NULL) {
+ if (value.dsize == 0 || value.dptr == NULL) {
DEBUG(10, ("regdb_fetch_keys: no subkeys found for key [%s]\n",
key));
- ret = 0;
goto done;
}
buf = value.dptr;
buflen = value.dsize;
len = tdb_unpack( buf, buflen, "d", &num_items);
+ if (len == (uint32_t)-1) {
+ werr = WERR_NOT_FOUND;
+ goto done;
+ }
+
+ werr = regsubkey_ctr_reinit(ctr);
+ W_ERROR_NOT_OK_GOTO_DONE(werr);
for (i=0; i<num_items; i++) {
len += tdb_unpack(buf+len, buflen-len, "f", subkeyname);
if (!W_ERROR_IS_OK(werr)) {
DEBUG(5, ("regdb_fetch_keys: regsubkey_ctr_addkey "
"failed: %s\n", win_errstr(werr)));
+ num_items = 0;
goto done;
}
}
DEBUG(11,("regdb_fetch_keys: Exit [%d] items\n", num_items));
- ret = num_items;
done:
TALLOC_FREE(frame);
- return ret;
+ return werr;
}
int regdb_fetch_keys(const char *key, struct regsubkey_ctr *ctr)
{
- return regdb_fetch_keys_internal(regdb, key, ctr);
+ WERROR werr;
+
+ werr = regdb_fetch_keys_internal(regdb, key, ctr);
+ if (!W_ERROR_IS_OK(werr)) {
+ return -1;
+ }
+
+ return regsubkey_ctr_numkeys(ctr);
}
/****************************************************************************