summaryrefslogtreecommitdiff
path: root/backend/gdbm.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/gdbm.c')
-rw-r--r--backend/gdbm.c323
1 files changed, 323 insertions, 0 deletions
diff --git a/backend/gdbm.c b/backend/gdbm.c
new file mode 100644
index 0000000..1525166
--- /dev/null
+++ b/backend/gdbm.c
@@ -0,0 +1,323 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <gdbm.h>
+
+#include "backend.h"
+#include "log.h"
+
+static GHashTable *dbs;
+
+static void free_db(GDBM_FILE db)
+{
+ if (!db)
+ return;
+
+ gdbm_close(db);
+}
+
+static GDBM_FILE open_gdbm(const char *dbpath)
+{
+ GDBM_FILE db;
+ char *nm;
+
+ assert(dbpath);
+
+ if (!dbs) {
+ errno = ENODEV;
+ return NULL;
+ }
+
+ db = g_hash_table_lookup(dbs, dbpath);
+ if (db)
+ return db;
+
+ db = gdbm_open(dbpath, 0, GDBM_WRCREAT, S_IRUSR | S_IWUSR, NULL);
+ if (!db) {
+ bxt_err("Open '%s' failed: %s", dbpath,
+ gdbm_strerror(gdbm_errno));
+ errno = EIO;
+ return NULL;
+ }
+
+ nm = strdup(dbpath);
+ if (!nm) {
+ gdbm_close(db);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ g_hash_table_insert(dbs, nm, db);
+
+ bxt_dbg("Open '%s'", dbpath);
+
+ return db;
+}
+
+static int open_db(const char *dbpath)
+{
+ GDBM_FILE db;
+
+ if (!dbpath || !*dbpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ db = open_gdbm(dbpath);
+ if (!db)
+ return -1;
+
+ return 0;
+}
+
+static int remove_db(const char *dbpath)
+{
+ GDBM_FILE db;
+ int r;
+
+ if (!dbpath || !*dbpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!dbs) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ db = g_hash_table_lookup(dbs, dbpath);
+ if (db)
+ g_hash_table_remove(dbs, dbpath);
+
+ r = unlink(dbpath);
+ if (r == -1) {
+ bxt_err("Remove '%s' failed: %d", dbpath, errno);
+ return -1;
+ }
+
+ bxt_dbg("Remove '%s'", dbpath);
+
+ return 0;
+}
+
+static int set_value(const char *dbpath, const char *key, const void *data,
+ int dlen)
+{
+ GDBM_FILE db;
+ int r;
+ datum d_key;
+ datum d_data;
+
+ if (!dbpath || !*dbpath || !key || !*key || !data || dlen <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ db = open_gdbm(dbpath);
+ if (!db)
+ return -1;
+
+ d_key.dptr = (char *)key;
+ d_key.dsize = strlen(key) + 1;
+
+ d_data.dptr = (char *)data;
+ d_data.dsize = dlen;
+
+ r = gdbm_store(db, d_key, d_data, GDBM_REPLACE);
+ if (r) {
+ if (gdbm_errno == GDBM_READER_CANT_STORE)
+ errno = EROFS;
+
+ bxt_err("Set '%s' failed: %s", key,
+ gdbm_strerror(gdbm_errno));
+
+ return -1;
+ }
+
+ bxt_dbg("Set '%s' Key '%s'", dbpath, key);
+
+ return 0;
+}
+
+static int get_value(const char *dbpath, const char *key, void **data,
+ int *dlen)
+{
+ GDBM_FILE db;
+ datum d_key;
+ datum d_data;
+
+ if (!dbpath || !*dbpath || !key || !*key || !data || !dlen) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ db = open_gdbm(dbpath);
+ if (!db)
+ return -1;
+
+ d_key.dptr = (char *)key;
+ d_key.dsize = strlen(key) + 1;
+
+ d_data = gdbm_fetch(db, d_key);
+ if (d_data.dptr == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ *data = d_data.dptr;
+ *dlen = d_data.dsize;
+
+ bxt_dbg("Get '%s' Key '%s'", dbpath, key);
+
+ return 0;
+}
+
+static int unset_value(const char *dbpath, const char *key)
+{
+ GDBM_FILE db;
+ int r;
+ datum d_key;
+
+ if (!dbpath || !*dbpath || !key || !*key) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ db = open_gdbm(dbpath);
+ if (!db)
+ return -1;
+
+ d_key.dptr = (char *)key;
+ d_key.dsize = strlen(key) + 1;
+
+ r = gdbm_delete(db, d_key);
+ if (r) {
+ switch (gdbm_errno) {
+ case GDBM_READER_CANT_DELETE:
+ errno = EROFS;
+ break;
+ case GDBM_ITEM_NOT_FOUND:
+ errno = ENOENT;
+ break;
+ default:
+ errno = EIO;
+ break;
+ }
+
+ return -1;
+ }
+
+ bxt_dbg("Unset '%s' Key '%s'", dbpath, key);
+
+ return 0;
+}
+
+static int list_keys(const char *dbpath, char ***keys, unsigned int *klen)
+{
+ GDBM_FILE db;
+ GList *list;
+ GList *l;
+ datum d_key;
+ int i;
+ unsigned int _klen;
+ char **_keys;
+
+ if (!dbpath || !*dbpath || !keys) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ db = open_gdbm(dbpath);
+ if (!db)
+ return -1;
+
+ _klen = 0;
+ list = NULL;
+ d_key = gdbm_firstkey(db);
+ while (d_key.dptr) {
+ list = g_list_append(list, d_key.dptr);
+ _klen++;
+ d_key = gdbm_nextkey(db, d_key);
+ }
+
+ /* +1 for NULL terminated */
+ _keys = malloc(sizeof(void *) * (_klen + 1));
+ if (!_keys) {
+ g_list_free_full(list, (GDestroyNotify)free);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ for (i = 0, l = list; l && i < _klen; l = g_list_next(l), i++)
+ _keys[i] = l->data;
+
+ /* NULL terminated */
+ _keys[i] = NULL;
+
+ g_list_free(list);
+
+ *keys = _keys;
+
+ if (klen)
+ *klen = _klen;
+
+ bxt_dbg("List '%s'", dbpath);
+
+ return 0;
+}
+
+static void module_exit(void)
+{
+ g_hash_table_destroy(dbs);
+ dbs = NULL;
+}
+
+static int module_init(void)
+{
+ dbs = g_hash_table_new_full(g_str_hash, g_str_equal,
+ (GDestroyNotify)free, (GDestroyNotify)free_db);
+ if (!dbs) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+DEFINE_BUXTON_BACKEND = {
+ .name = "gdbm",
+
+ .module_init = module_init,
+ .module_exit = module_exit,
+
+ .open_db = open_db,
+ .remove_db = remove_db,
+ .set_value = set_value,
+ .get_value = get_value,
+ .unset_value = unset_value,
+ .list_keys = list_keys,
+};
+