]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-dict: Added "fs" wrapper dict backend, which uses lib-fs.
authorTimo Sirainen <tss@iki.fi>
Sun, 8 Dec 2013 19:13:22 +0000 (21:13 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 8 Dec 2013 19:13:22 +0000 (21:13 +0200)
Each dict key is a separate file where the file's contents are the dict
value.

src/lib-dict/Makefile.am
src/lib-dict/dict-fs.c [new file with mode: 0644]
src/lib-dict/dict-private.h
src/lib-dict/dict-register.c [new file with mode: 0644]
src/lib-dict/dict.c

index 63bb0c486504fdbc2d4e7d5fec8c0fdc28d84368..36733774d0acac1fe20437b7d1a768a2a4c20766 100644 (file)
@@ -6,6 +6,7 @@ dict_drivers = @dict_drivers@
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
        -I$(top_srcdir)/src/lib-test \
+       -I$(top_srcdir)/src/lib-fs \
        -I$(top_srcdir)/src/lib-sql \
        -I$(top_srcdir)/src/lib-settings \
        $(SQL_CFLAGS)
@@ -15,9 +16,11 @@ base_sources = \
        dict-client.c \
        dict-file.c \
        dict-cdb.c \
+       dict-fs.c \
        dict-memcached.c \
        dict-memcached-ascii.c \
        dict-redis.c \
+       dict-register.c \
        dict-transaction-memory.c
 
 libdict_la_SOURCES = \
diff --git a/src/lib-dict/dict-fs.c b/src/lib-dict/dict-fs.c
new file mode 100644 (file)
index 0000000..1a8374b
--- /dev/null
@@ -0,0 +1,201 @@
+/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "fs-api.h"
+#include "istream.h"
+#include "str.h"
+#include "dict-transaction-memory.h"
+#include "dict-private.h"
+
+struct fs_dict {
+       struct dict dict;
+       struct fs *fs;
+       char *username;
+};
+
+static int
+fs_dict_init(struct dict *driver, const char *uri,
+            enum dict_data_type value_type ATTR_UNUSED,
+            const char *username,
+            const char *base_dir, struct dict **dict_r,
+            const char **error_r)
+{
+       struct fs_settings fs_set;
+       struct fs *fs;
+       struct fs_dict *dict;
+       const char *p, *fs_driver, *fs_args;
+
+       p = strchr(uri, ':');
+       if (p == NULL) {
+               fs_driver = uri;
+               fs_args = "";
+       } else {
+               fs_driver = t_strdup_until(uri, p);
+               fs_args = p+1;
+       }
+
+       memset(&fs_set, 0, sizeof(fs_set));
+       fs_set.base_dir = base_dir;
+       if (fs_init(fs_driver, fs_args, &fs_set, &fs, error_r) < 0)
+               return -1;
+
+       dict = i_new(struct fs_dict, 1);
+       dict->dict = *driver;
+       dict->fs = fs;
+       dict->username = i_strdup(username);
+
+       *dict_r = &dict->dict;
+       return 0;
+}
+
+static void fs_dict_deinit(struct dict *_dict)
+{
+       struct fs_dict *dict = (struct fs_dict *)_dict;
+
+       fs_deinit(&dict->fs);
+       i_free(dict->username);
+       i_free(dict);
+}
+
+static const char *fs_dict_get_full_key(struct fs_dict *dict, const char *key)
+{
+       if (strncmp(key, DICT_PATH_SHARED, strlen(DICT_PATH_SHARED)) == 0)
+               return key + strlen(DICT_PATH_SHARED);
+       else if (strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE)) == 0) {
+               return t_strdup_printf("%s/%s", dict->username,
+                                      key + strlen(DICT_PATH_PRIVATE));
+       } else {
+               i_unreached();
+       }
+}
+
+static int fs_dict_lookup(struct dict *_dict, pool_t pool,
+                         const char *key, const char **value_r)
+{
+       struct fs_dict *dict = (struct fs_dict *)_dict;
+       struct fs_file *file;
+       struct istream *input;
+       const unsigned char *data;
+       size_t size;
+       string_t *str;
+       int ret;
+
+       file = fs_file_init(dict->fs, fs_dict_get_full_key(dict, key),
+                           FS_OPEN_MODE_READONLY);
+       input = fs_read_stream(file, IO_BLOCK_SIZE);
+       i_stream_read(input);
+
+       str = str_new(pool, i_stream_get_data_size(input)+1);
+       while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
+               str_append_n(str, data, size);
+               i_stream_skip(input, size);
+       }
+       i_assert(ret == -1);
+
+       if (input->stream_errno == 0) {
+               *value_r = str_c(str);
+               ret = 1;
+       } else {
+               *value_r = NULL;
+               if (input->stream_errno == ENOENT)
+                       ret = 0;
+       }
+
+       i_stream_unref(&input);
+       fs_file_deinit(&file);
+       return ret;
+}
+
+static struct dict_transaction_context *
+fs_dict_transaction_init(struct dict *_dict)
+{
+       struct dict_transaction_memory_context *ctx;
+       pool_t pool;
+
+       pool = pool_alloconly_create("file dict transaction", 2048);
+       ctx = p_new(pool, struct dict_transaction_memory_context, 1);
+       dict_transaction_memory_init(ctx, _dict, pool);
+       return &ctx->ctx;
+}
+
+static int fs_dict_write_changes(struct dict_transaction_memory_context *ctx)
+{
+       struct fs_dict *dict = (struct fs_dict *)ctx->ctx.dict;
+       struct fs_file *file;
+       const struct dict_transaction_memory_change *change;
+       const char *key;
+       int ret = 0;
+
+       array_foreach(&ctx->changes, change) {
+               key = fs_dict_get_full_key(dict, change->key);
+               switch (change->type) {
+               case DICT_CHANGE_TYPE_SET:
+                       file = fs_file_init(dict->fs, key,
+                                           FS_OPEN_MODE_REPLACE);
+                       if (fs_write(file, change->value.str, strlen(change->value.str)) < 0) {
+                               i_error("fs_write(%s) failed: %s", key,
+                                       fs_file_last_error(file));
+                               ret = -1;
+                       }
+                       fs_file_deinit(&file);
+                       break;
+               case DICT_CHANGE_TYPE_UNSET:
+                       file = fs_file_init(dict->fs, key, FS_OPEN_MODE_READONLY);
+                       if (fs_delete(file) < 0) {
+                               i_error("fs_delete(%s) failed: %s", key,
+                                       fs_file_last_error(file));
+                               ret = -1;
+                       }
+                       fs_file_deinit(&file);
+                       break;
+               case DICT_CHANGE_TYPE_APPEND:
+               case DICT_CHANGE_TYPE_INC:
+                       i_unreached();
+               }
+               if (ret < 0)
+                       return -1;
+       }
+       return 0;
+}
+
+static int
+fs_dict_transaction_commit(struct dict_transaction_context *_ctx,
+                          bool async ATTR_UNUSED,
+                          dict_transaction_commit_callback_t *callback,
+                          void *context)
+{
+       struct dict_transaction_memory_context *ctx =
+               (struct dict_transaction_memory_context *)_ctx;
+       int ret;
+
+       if (fs_dict_write_changes(ctx) < 0)
+               ret = -1;
+       else
+               ret = 1;
+       pool_unref(&ctx->pool);
+
+       if (callback != NULL)
+               callback(ret, context);
+       return ret;
+}
+
+struct dict dict_driver_fs = {
+       .name = "fs",
+       {
+               fs_dict_init,
+               fs_dict_deinit,
+               NULL,
+               fs_dict_lookup,
+               NULL,
+               NULL,
+               NULL,
+               fs_dict_transaction_init,
+               fs_dict_transaction_commit,
+               dict_transaction_memory_rollback,
+               dict_transaction_memory_set,
+               dict_transaction_memory_unset,
+               NULL,
+               NULL
+       }
+};
index 067716ca9255a4f69da732cc89ed7ae983d05fd7..02cd83fab8e3a42df594b964c2b2c85c30fecb6a 100644 (file)
@@ -56,6 +56,7 @@ struct dict_transaction_context {
 
 extern struct dict dict_driver_client;
 extern struct dict dict_driver_file;
+extern struct dict dict_driver_fs;
 extern struct dict dict_driver_memcached;
 extern struct dict dict_driver_memcached_ascii;
 extern struct dict dict_driver_redis;
diff --git a/src/lib-dict/dict-register.c b/src/lib-dict/dict-register.c
new file mode 100644 (file)
index 0000000..326fec0
--- /dev/null
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "dict-private.h"
+
+void dict_drivers_register_builtin(void)
+{
+       dict_driver_register(&dict_driver_client);
+       dict_driver_register(&dict_driver_file);
+       dict_driver_register(&dict_driver_fs);
+       dict_driver_register(&dict_driver_memcached);
+       dict_driver_register(&dict_driver_memcached_ascii);
+       dict_driver_register(&dict_driver_redis);
+}
+
+void dict_drivers_unregister_builtin(void)
+{
+       dict_driver_unregister(&dict_driver_client);
+       dict_driver_unregister(&dict_driver_file);
+       dict_driver_unregister(&dict_driver_fs);
+       dict_driver_unregister(&dict_driver_memcached);
+       dict_driver_unregister(&dict_driver_memcached_ascii);
+       dict_driver_unregister(&dict_driver_redis);
+}
index 33ecfab203bc9cd15b707f33af529bbbdf9d1fce..f3d48c8bd6b07bb91c1510c51f35556cb36800cc 100644 (file)
@@ -52,24 +52,6 @@ void dict_driver_unregister(struct dict *driver)
                array_free(&dict_drivers);
 }
 
-void dict_drivers_register_builtin(void)
-{
-       dict_driver_register(&dict_driver_client);
-       dict_driver_register(&dict_driver_file);
-       dict_driver_register(&dict_driver_memcached);
-       dict_driver_register(&dict_driver_memcached_ascii);
-       dict_driver_register(&dict_driver_redis);
-}
-
-void dict_drivers_unregister_builtin(void)
-{
-       dict_driver_unregister(&dict_driver_client);
-       dict_driver_unregister(&dict_driver_file);
-       dict_driver_unregister(&dict_driver_memcached);
-       dict_driver_unregister(&dict_driver_memcached_ascii);
-       dict_driver_unregister(&dict_driver_redis);
-}
-
 int dict_init(const char *uri, enum dict_data_type value_type,
              const char *username, const char *base_dir, struct dict **dict_r,
              const char **error_r)