2 * This file is part of buxton.
4 * Copyright (C) 2013 Intel Corporation
6 * buxton is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
24 #include "serialize.h"
28 * GDBM Database Module
32 static Hashmap *_resources = NULL;
34 static char *key_get_name(BuxtonString *key)
38 c = strchr(key->value, 0);
42 if (c - (key->value + (key->length - 1)) >= 0) {
50 static GDBM_FILE try_open_database(char *path, const int oflag)
52 GDBM_FILE db = gdbm_open(path, 0, oflag, S_IRUSR | S_IWUSR, NULL);
53 /* handle open under write mode failing by falling back to
55 if (!db && (gdbm_errno == GDBM_FILE_OPEN_ERROR)) {
56 db = gdbm_open(path, 0, GDBM_READER, S_IRUSR | S_IWUSR, NULL);
57 buxton_debug("Attempting to fallback to opening db as read-only\n");
63 /* Must do this as gdbm_open messes with errno */
69 /* Open or create databases on the fly */
70 static GDBM_FILE db_for_resource(BuxtonLayer *layer)
73 _cleanup_free_ char *path = NULL;
76 int oflag = layer->readonly ? GDBM_READER : GDBM_WRCREAT;
82 if (layer->type == LAYER_USER) {
83 r = asprintf(&name, "%s-%d", layer->name.value, layer->uid);
85 r = asprintf(&name, "%s", layer->name.value);
91 db = hashmap_get(_resources, name);
93 path = get_layer_path(layer);
98 db = try_open_database(path, oflag);
102 buxton_log("Couldn't create db for path: %s\n", path);
105 r = hashmap_put(_resources, name, db);
110 db = (GDBM_FILE) hashmap_get(_resources, name);
118 static int set_value(BuxtonLayer *layer, _BuxtonKey *key, BuxtonData *data,
126 _cleanup_free_ uint8_t *data_store = NULL;
129 BuxtonData cdata = {0};
136 if (key->name.value) {
137 sz = key->group.length + key->name.length;
138 key_data.dptr = malloc(sz);
139 if (!key_data.dptr) {
143 /* size is string\0string\0 so just write, bonus for
144 nil seperator being added without extra work */
145 key_data.dsize = (int)sz;
146 memcpy(key_data.dptr, key->group.value, key->group.length);
147 memcpy(key_data.dptr + key->group.length, key->name.value,
150 key_data.dptr = malloc(key->group.length);
151 if (!key_data.dptr) {
155 memcpy(key_data.dptr, key->group.value, key->group.length);
156 key_data.dsize = (int)key->group.length;
159 db = db_for_resource(layer);
165 /* set_label will pass a NULL for data */
167 cvalue = gdbm_fetch(db, key_data);
168 if (cvalue.dsize < 0 || cvalue.dptr == NULL) {
173 data_store = (uint8_t*)cvalue.dptr;
174 buxton_deserialize(data_store, &cdata, &clabel);
180 size = buxton_serialize(data, label, &data_store);
182 value.dptr = (char *)data_store;
183 value.dsize = (int)size;
184 ret = gdbm_store(db, key_data, value, GDBM_REPLACE);
185 if (ret && gdbm_errno == GDBM_READER_CANT_STORE) {
191 if (cdata.type == STRING) {
192 free(cdata.store.d_string.value);
200 static int get_value(BuxtonLayer *layer, _BuxtonKey *key, BuxtonData *data,
206 uint8_t *data_store = NULL;
212 if (key->name.value) {
213 sz = key->group.length + key->name.length;
214 key_data.dptr = malloc(sz);
215 if (!key_data.dptr) {
219 /* size is string\0string\0 so just write, bonus for
220 nil seperator being added without extra work */
221 key_data.dsize = (int)sz;
222 memcpy(key_data.dptr, key->group.value, key->group.length);
223 memcpy(key_data.dptr + key->group.length, key->name.value,
226 key_data.dptr = malloc(key->group.length);
227 if (!key_data.dptr) {
231 memcpy(key_data.dptr, key->group.value, key->group.length);
232 key_data.dsize = (int)key->group.length;
235 memzero(&value, sizeof(datum));
236 db = db_for_resource(layer);
239 * Set negative here to indicate layer not found
240 * rather than key not found, optimization for
247 value = gdbm_fetch(db, key_data);
248 if (value.dsize < 0 || value.dptr == NULL) {
253 data_store = (uint8_t*)value.dptr;
254 buxton_deserialize(data_store, data, label);
256 if (data->type != key->type) {
259 if (data->type == STRING) {
260 free(data->store.d_string.value);
261 data->store.d_string.value = NULL;
276 static int unset_value(BuxtonLayer *layer,
278 __attribute__((unused)) BuxtonData *data,
279 __attribute__((unused)) BuxtonString *label)
289 if (key->name.value) {
290 sz = key->group.length + key->name.length;
291 key_data.dptr = malloc(sz);
292 if (!key_data.dptr) {
296 /* size is string\0string\0 so just write, bonus for
297 nil seperator being added without extra work */
298 key_data.dsize = (int)sz;
299 memcpy(key_data.dptr, key->group.value, key->group.length);
300 memcpy(key_data.dptr + key->group.length, key->name.value,
303 key_data.dptr = malloc(key->group.length);
304 if (!key_data.dptr) {
308 memcpy(key_data.dptr, key->group.value, key->group.length);
309 key_data.dsize = (int)key->group.length;
313 db = db_for_resource(layer);
314 if (!db || gdbm_errno) {
319 ret = gdbm_delete(db, key_data);
321 if (gdbm_errno == GDBM_READER_CANT_DELETE) {
323 } else if (gdbm_errno == GDBM_ITEM_NOT_FOUND) {
336 static bool list_keys(BuxtonLayer *layer,
341 BuxtonArray *k_list = NULL;
342 BuxtonData *current = NULL;
349 db = db_for_resource(layer);
354 k_list = buxton_array_new();
355 key = gdbm_firstkey(db);
356 /* Iterate through all of the keys */
358 /* Split the key name from the rest of the key */
359 in_key.value = (char*)key.dptr;
360 in_key.length = (uint32_t)key.dsize;
361 name = key_get_name(&in_key);
366 current = malloc0(sizeof(BuxtonData));
370 current->type = STRING;
371 current->store.d_string.value = strdup(name);
372 if (!current->store.d_string.value) {
375 current->store.d_string.length = (uint32_t)strlen(name) + 1;
376 if (!buxton_array_add(k_list, current)) {
380 /* Visit the next key */
381 nextkey = gdbm_nextkey(db, key);
386 /* Pass ownership of the array to the caller */
391 if (!ret && k_list) {
392 for (uint16_t i = 0; i < k_list->len; i++) {
393 current = buxton_array_get(k_list, i);
397 free(current->store.d_string.value);
400 buxton_array_free(&k_list, NULL);
405 _bx_export_ void buxton_module_destroy(void)
411 /* close all gdbm handles */
412 HASHMAP_FOREACH_KEY(db, key, _resources, iterator) {
413 hashmap_remove(_resources, key);
417 hashmap_free(_resources);
421 _bx_export_ bool buxton_module_init(BuxtonBackend *backend)
426 /* Point the struct methods back to our own */
427 backend->set_value = &set_value;
428 backend->get_value = &get_value;
429 backend->list_keys = &list_keys;
430 backend->unset_value = &unset_value;
431 backend->create_db = (module_db_init_func) &db_for_resource;
433 _resources = hashmap_new(string_hash_func, string_compare_func);
442 * Editor modelines - http://www.wireshark.org/tools/modelines.html
447 * indent-tabs-mode: t
450 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
451 * :indentSize=8:tabSize=8:noTabs=false: