2 Unix SMB/CIFS implementation.
3 Transparent registry backend handling
4 Copyright (C) Jelmer Vernooij 2003-2004.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "lib/registry/common/registry.h"
25 #define DBGC_CLASS DBGC_REGISTRY
27 /* List of available backends */
28 static struct reg_init_function_entry *backends = NULL;
30 static struct reg_init_function_entry *reg_find_backend_entry(const char *name);
32 /* Register new backend */
33 NTSTATUS registry_register(void *_function)
35 REG_OPS *functions = _function;
36 struct reg_init_function_entry *entry = backends;
38 if (!functions || !functions->name) {
39 return NT_STATUS_INVALID_PARAMETER;
42 DEBUG(5,("Attempting to register registry backend %s\n", functions->name));
44 /* Check for duplicates */
45 if (reg_find_backend_entry(functions->name)) {
46 DEBUG(0,("There already is a registry backend registered with the name %s!\n", functions->name));
47 return NT_STATUS_OBJECT_NAME_COLLISION;
50 entry = malloc(sizeof(struct reg_init_function_entry));
51 entry->functions = functions;
53 DLIST_ADD(backends, entry);
54 DEBUG(5,("Successfully added registry backend '%s'\n", functions->name));
59 /* Find a backend in the list of available backends */
60 static struct reg_init_function_entry *reg_find_backend_entry(const char *name)
62 struct reg_init_function_entry *entry = backends;
65 if (strcmp(entry->functions->name, name)==0) return entry;
72 /* Open a registry file/host/etc */
73 REG_HANDLE *reg_open(const char *backend, const char *location, BOOL try_full_load)
75 struct reg_init_function_entry *entry;
76 static BOOL reg_first_init = True;
80 if (!NT_STATUS_IS_OK(register_subsystem("registry", registry_register))) {
85 reg_first_init = False;
88 entry = reg_find_backend_entry(backend);
91 DEBUG(0, ("No such registry backend '%s' loaded!\n", backend));
95 ret = malloc(sizeof(REG_HANDLE));
97 ret->location = location?strdup(location):NULL;
98 ret->functions = entry->functions;
99 ret->backend_data = NULL;
101 if(!entry->functions->open_registry) {
105 if(entry->functions->open_registry(ret, location, try_full_load))
113 REG_KEY *reg_open_key(REG_KEY *parent, const char *name)
119 DEBUG(0, ("Invalid parent key specified"));
123 if(!parent->handle->functions->open_key &&
124 (parent->handle->functions->get_subkey_by_name ||
125 parent->handle->functions->get_subkey_by_index)) {
126 char *orig = strdup(name),
128 *curend = strchr(orig, '\\');
129 REG_KEY *curkey = parent;
131 while(curbegin && *curbegin) {
132 if(curend)*curend = '\0';
133 curkey = reg_key_get_subkey_by_name(curkey, curbegin);
134 if(!curkey) return NULL;
136 curbegin = curend + 1;
137 curend = strchr(curbegin, '\\');
143 asprintf(&fullname, "%s%s%s", parent->path, parent->path[strlen(parent->path)-1] == '\\'?"":"\\", name);
145 if(!parent->handle->functions->open_key) {
146 DEBUG(0, ("Registry backend doesn't have get_subkey_by_name nor open_key!\n"));
150 ret = parent->handle->functions->open_key(parent->handle, fullname);
153 ret->handle = parent->handle;
154 ret->path = fullname;
161 REG_VAL *reg_key_get_value_by_index(REG_KEY *key, int idx)
165 if(!key) return NULL;
167 if(!key->handle->functions->get_value_by_index) {
168 if(!key->cache_values)
169 key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
171 if(idx < key->cache_values_count && idx >= 0) {
172 ret = reg_val_dup(key->cache_values[idx]);
177 ret = key->handle->functions->get_value_by_index(key, idx);
182 ret->handle = key->handle;
188 int reg_key_num_subkeys(REG_KEY *key)
190 if(!key->handle->functions->num_subkeys) {
191 if(!key->cache_subkeys)
192 key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
194 return key->cache_subkeys_count;
197 return key->handle->functions->num_subkeys(key);
200 int reg_key_num_values(REG_KEY *key)
205 if(!key->handle->functions->num_values) {
206 if(!key->handle->functions->fetch_values) {
207 DEBUG(1, ("Backend '%s' doesn't support enumerating values\n", key->handle->functions->name));
211 if(!key->cache_values)
212 key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
214 return key->cache_values_count;
218 return key->handle->functions->num_values(key);
221 REG_KEY *reg_key_get_subkey_by_index(REG_KEY *key, int idx)
225 if(!key) return NULL;
227 if(!key->handle->functions->get_subkey_by_index) {
228 if(!key->cache_subkeys)
229 key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
231 if(idx < key->cache_subkeys_count) {
232 ret = reg_key_dup(key->cache_subkeys[idx]);
238 ret = key->handle->functions->get_subkey_by_index(key, idx);
241 if(ret && !ret->path) {
242 asprintf(&ret->path, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name);
243 ret->handle = key->handle;
249 REG_KEY *reg_key_get_subkey_by_name(REG_KEY *key, const char *name)
254 if(!key) return NULL;
256 if(key->handle->functions->get_subkey_by_name) {
257 ret = key->handle->functions->get_subkey_by_name(key,name);
259 max = reg_key_num_subkeys(key);
260 for(i = 0; i < max; i++) {
261 REG_KEY *v = reg_key_get_subkey_by_index(key, i);
262 if(v && !strcmp(v->name, name)) {
270 if(ret && !ret->path) {
271 asprintf(&ret->path, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name);
272 ret->handle = key->handle;
278 REG_VAL *reg_key_get_value_by_name(REG_KEY *key, const char *name)
283 if(!key) return NULL;
285 if(key->handle->functions->get_value_by_name) {
286 ret = key->handle->functions->get_value_by_name(key,name);
288 max = reg_key_num_values(key);
289 for(i = 0; i < max; i++) {
290 REG_VAL *v = reg_key_get_value_by_index(key, i);
291 if(v && StrCaseCmp(v->name, name)) {
301 ret->handle = key->handle;
307 BOOL reg_key_del(REG_KEY *key)
309 if(key->handle->functions->del_key)
310 return key->handle->functions->del_key(key);
315 BOOL reg_sync(REG_HANDLE *h, const char *location)
317 if(!h->functions->sync)
320 return h->functions->sync(h, location);
323 BOOL reg_key_del_recursive(REG_KEY *key)
328 /* Delete all values for specified key */
329 for(i = 0; i < reg_key_num_values(key); i++) {
330 if(!reg_val_del(reg_key_get_value_by_index(key, i)))
334 /* Delete all keys below this one */
335 for(i = 0; i < reg_key_num_subkeys(key); i++) {
336 if(!reg_key_del_recursive(reg_key_get_subkey_by_index(key, i)))
340 if(succeed)reg_key_del(key);
345 BOOL reg_val_del(REG_VAL *val)
347 if (!val->handle->functions->del_value) {
348 DEBUG(1, ("Backend '%s' doesn't support method del_value\n", val->handle->functions->name));
352 return val->handle->functions->del_value(val);
355 BOOL reg_key_add_name(REG_KEY *parent, const char *name)
357 if (!parent->handle->functions->add_key) {
358 DEBUG(1, ("Backend '%s' doesn't support method add_key\n", parent->handle->functions->name));
362 return parent->handle->functions->add_key(parent, name);
365 BOOL reg_val_update(REG_VAL *val, int type, void *data, int len)
367 /* A 'real' update function has preference */
368 if (val->handle->functions->update_value)
369 return val->handle->functions->update_value(val, type, data, len);
371 /* Otherwise, just remove and add again */
372 if (val->handle->functions->add_value &&
373 val->handle->functions->del_value) {
375 if(!val->handle->functions->del_value(val))
378 new = val->handle->functions->add_value(val->parent, val->name, type, data, len);
379 memcpy(val, new, sizeof(REG_VAL));
383 DEBUG(1, ("Backend '%s' doesn't support method update_value\n", val->handle->functions->name));
387 void reg_free(REG_HANDLE *h)
389 if(!h->functions->close_registry) return;
391 h->functions->close_registry(h);
394 REG_KEY *reg_get_root(REG_HANDLE *h)
397 if(h->functions->open_root_key) {
398 ret = h->functions->open_root_key(h);
399 } else if(h->functions->open_key) {
400 ret = h->functions->open_key(h, "\\");
402 DEBUG(0, ("Backend '%s' has neither open_root_key nor open_key method implemented\n", h->functions->name));
407 ret->path = strdup("\\");
413 REG_VAL *reg_key_add_value(REG_KEY *key, const char *name, int type, void *value, size_t vallen)
416 if(!key->handle->functions->add_value)
419 ret = key->handle->functions->add_value(key, name, type, value, vallen);
421 ret->handle = key->handle;