* 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)) {
static void regdb_ctr_add_value(struct regval_ctr *ctr,
struct builtin_regkey_value *value)
{
- UNISTR2 data;
-
switch(value->type) {
case REG_DWORD:
regval_ctr_addvalue(ctr, value->valuename, REG_DWORD,
break;
case REG_SZ:
- init_unistr2(&data, value->data.string, UNI_STR_TERMINATE);
- regval_ctr_addvalue(ctr, value->valuename, REG_SZ,
- (char*)data.buffer,
- data.uni_str_len*sizeof(uint16));
+ regval_ctr_addvalue_sz(ctr, value->valuename,
+ value->data.string);
break;
default:
werr = regsubkey_ctr_init(mem_ctx, &old_subkeys);
W_ERROR_NOT_OK_GOTO_DONE(werr);
- regdb_fetch_keys_internal(db, store_ctx->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:
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 */
werr = regdb_store_keys_internal2(db, path, subkeys);
if (!W_ERROR_IS_OK(werr)) {
goto done;
}
- regdb_fetch_keys_internal(db, key, old_subkeys);
+ 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);
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;
werr = regsubkey_ctr_init(mem_ctx, &subkeys);
W_ERROR_NOT_OK_GOTO_DONE(werr);
- if (regdb_fetch_keys_internal(db, create_ctx->key, subkeys) < 0) {
- werr = WERR_REG_IO_FAILURE;
- goto done;
- }
+ 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 = 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;
return werr;
}
-static WERROR regdb_delete_subkey(const char *key, const char *subkey)
+/**
+ * create a subkey of a given key
+ */
+
+struct regdb_delete_subkey_context {
+ const char *key;
+ const char *subkey;
+ const char *path;
+};
+
+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();
+
+ 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);
+
+ 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 werror_to_ntstatus(werr);
+}
+
+static WERROR regdb_delete_subkey(const char *key, const char *subkey)
+{
+ WERROR werr;
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);
-
- werr = regdb_store_keys_internal2(regdb, key, subkeys);
- if (!W_ERROR_IS_OK(werr)) {
- DEBUG(0, (__location__ " failed to store new subkey_list for "
- "parent key %s: %s\n", key, win_errstr(werr)));
- goto cancel;
- }
-
- if (regdb->transaction_commit(regdb) != 0) {
- DEBUG(0, (__location__ " failed to commit transaction\n"));
- werr = WERR_REG_IO_FAILURE;
- }
+ delete_ctx.key = key;
+ delete_ctx.subkey = subkey;
+ delete_ctx.path = path;
- 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 {
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) {
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);
}
/****************************************************************************