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 /* Open or create databases on the fly */
51 static GDBM_FILE db_for_resource(BuxtonLayer *layer)
54 _cleanup_free_ char *path = NULL;
61 if (layer->type == LAYER_USER) {
62 r = asprintf(&name, "%s-%d", layer->name.value, layer->uid);
64 r = asprintf(&name, "%s", layer->name.value);
70 db = hashmap_get(_resources, name);
72 path = get_layer_path(layer);
76 db = gdbm_open(path, 0, GDBM_WRCREAT, 0600, NULL);
79 buxton_log("Couldn't create db for path: %s\n", path);
82 r = hashmap_put(_resources, name, db);
87 db = (GDBM_FILE) hashmap_get(_resources, name);
94 static int set_value(BuxtonLayer *layer, _BuxtonKey *key, BuxtonData *data,
102 _cleanup_free_ uint8_t *data_store = NULL;
105 BuxtonData cdata = {0};
112 if (key->name.value) {
113 sz = key->group.length + key->name.length;
114 key_data.dptr = malloc(sz);
115 if (!key_data.dptr) {
119 /* size is string\0string\0 so just write, bonus for
120 nil seperator being added without extra work */
121 key_data.dsize = (int)sz;
122 memcpy(key_data.dptr, key->group.value, key->group.length);
123 memcpy(key_data.dptr + key->group.length, key->name.value,
126 key_data.dptr = malloc(key->group.length);
127 if (!key_data.dptr) {
131 memcpy(key_data.dptr, key->group.value, key->group.length);
132 key_data.dsize = (int)key->group.length;
135 db = db_for_resource(layer);
141 /* set_label will pass a NULL for data */
143 cvalue = gdbm_fetch(db, key_data);
144 if (cvalue.dsize < 0 || cvalue.dptr == NULL) {
149 data_store = (uint8_t*)cvalue.dptr;
150 buxton_deserialize(data_store, &cdata, &clabel);
156 size = buxton_serialize(data, label, &data_store);
158 value.dptr = (char *)data_store;
159 value.dsize = (int)size;
160 ret = gdbm_store(db, key_data, value, GDBM_REPLACE);
164 if (cdata.type == STRING) {
165 free(cdata.store.d_string.value);
173 static int get_value(BuxtonLayer *layer, _BuxtonKey *key, BuxtonData *data,
179 uint8_t *data_store = NULL;
185 if (key->name.value) {
186 sz = key->group.length + key->name.length;
187 key_data.dptr = malloc(sz);
188 if (!key_data.dptr) {
192 /* size is string\0string\0 so just write, bonus for
193 nil seperator being added without extra work */
194 key_data.dsize = (int)sz;
195 memcpy(key_data.dptr, key->group.value, key->group.length);
196 memcpy(key_data.dptr + key->group.length, key->name.value,
199 key_data.dptr = malloc(key->group.length);
200 if (!key_data.dptr) {
204 memcpy(key_data.dptr, key->group.value, key->group.length);
205 key_data.dsize = (int)key->group.length;
208 memzero(&value, sizeof(datum));
209 db = db_for_resource(layer);
212 * Set negative here to indicate layer not found
213 * rather than key not found, optimization for
220 value = gdbm_fetch(db, key_data);
221 if (value.dsize < 0 || value.dptr == NULL) {
226 data_store = (uint8_t*)value.dptr;
227 buxton_deserialize(data_store, data, label);
229 if (data->type != key->type) {
232 if (data->type == STRING) {
233 free(data->store.d_string.value);
234 data->store.d_string.value = NULL;
249 static int unset_value(BuxtonLayer *layer,
251 __attribute__((unused)) BuxtonData *data,
252 __attribute__((unused)) BuxtonString *label)
262 if (key->name.value) {
263 sz = key->group.length + key->name.length;
264 key_data.dptr = malloc(sz);
265 if (!key_data.dptr) {
269 /* size is string\0string\0 so just write, bonus for
270 nil seperator being added without extra work */
271 key_data.dsize = (int)sz;
272 memcpy(key_data.dptr, key->group.value, key->group.length);
273 memcpy(key_data.dptr + key->group.length, key->name.value,
276 key_data.dptr = malloc(key->group.length);
277 if (!key_data.dptr) {
281 memcpy(key_data.dptr, key->group.value, key->group.length);
282 key_data.dsize = (int)key->group.length;
285 db = db_for_resource(layer);
291 /* Negative value means the key wasn't found */
292 ret = gdbm_delete(db, key_data);
303 static bool list_keys(BuxtonLayer *layer,
308 BuxtonArray *k_list = NULL;
309 BuxtonData *current = NULL;
316 db = db_for_resource(layer);
321 k_list = buxton_array_new();
322 key = gdbm_firstkey(db);
323 /* Iterate through all of the keys */
325 /* Split the key name from the rest of the key */
326 in_key.value = (char*)key.dptr;
327 in_key.length = (uint32_t)key.dsize;
328 name = key_get_name(&in_key);
333 current = malloc0(sizeof(BuxtonData));
337 current->type = STRING;
338 current->store.d_string.value = strdup(name);
339 if (!current->store.d_string.value) {
342 current->store.d_string.length = (uint32_t)strlen(name) + 1;
343 if (!buxton_array_add(k_list, current)) {
347 /* Visit the next key */
348 nextkey = gdbm_nextkey(db, key);
353 /* Pass ownership of the array to the caller */
358 if (!ret && k_list) {
359 for (uint16_t i = 0; i < k_list->len; i++) {
360 current = buxton_array_get(k_list, i);
364 free(current->store.d_string.value);
367 buxton_array_free(&k_list, NULL);
372 _bx_export_ void buxton_module_destroy(void)
378 /* close all gdbm handles */
379 HASHMAP_FOREACH_KEY(db, key, _resources, iterator) {
380 hashmap_remove(_resources, key);
384 hashmap_free(_resources);
388 _bx_export_ bool buxton_module_init(BuxtonBackend *backend)
393 /* Point the struct methods back to our own */
394 backend->set_value = &set_value;
395 backend->get_value = &get_value;
396 backend->list_keys = &list_keys;
397 backend->unset_value = &unset_value;
398 backend->create_db = (module_db_init_func) &db_for_resource;
400 _resources = hashmap_new(string_hash_func, string_compare_func);
409 * Editor modelines - http://www.wireshark.org/tools/modelines.html
414 * indent-tabs-mode: t
417 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
418 * :indentSize=8:tabSize=8:noTabs=false: