dovecot-2.2: lib-fs: Added "dict" backend, which is a wrapper to...

dovecot at dovecot.org dovecot at dovecot.org
Mon Aug 31 20:55:20 UTC 2015


details:   http://hg.dovecot.org/dovecot-2.2/rev/6adcfddd354d
changeset: 19053:6adcfddd354d
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Aug 31 23:54:24 2015 +0300
description:
lib-fs: Added "dict" backend, which is a wrapper to using lib-dict.

diffstat:

 src/lib-fs/Makefile.am      |    2 +
 src/lib-fs/fs-api-private.h |    1 +
 src/lib-fs/fs-api.c         |    1 +
 src/lib-fs/fs-dict.c        |  312 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 316 insertions(+), 0 deletions(-)

diffs (truncated from 355 to 300 lines):

diff -r 55cab04ef2af -r 6adcfddd354d src/lib-fs/Makefile.am
--- a/src/lib-fs/Makefile.am	Mon Aug 31 23:46:05 2015 +0300
+++ b/src/lib-fs/Makefile.am	Mon Aug 31 23:54:24 2015 +0300
@@ -2,11 +2,13 @@
 
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
+	-I$(top_srcdir)/src/lib-dict \
 	-I$(top_srcdir)/src/lib-ssl-iostream \
 	-DMODULE_DIR=\""$(moduledir)"\"
 
 libfs_la_SOURCES = \
 	fs-api.c \
+	fs-dict.c \
 	fs-metawrap.c \
 	fs-randomfail.c \
 	fs-posix.c \
diff -r 55cab04ef2af -r 6adcfddd354d src/lib-fs/fs-api-private.h
--- a/src/lib-fs/fs-api-private.h	Mon Aug 31 23:46:05 2015 +0300
+++ b/src/lib-fs/fs-api-private.h	Mon Aug 31 23:54:24 2015 +0300
@@ -151,6 +151,7 @@
 	void *async_context;
 };
 
+extern const struct fs fs_class_dict;
 extern const struct fs fs_class_posix;
 extern const struct fs fs_class_randomfail;
 extern const struct fs fs_class_metawrap;
diff -r 55cab04ef2af -r 6adcfddd354d src/lib-fs/fs-api.c
--- a/src/lib-fs/fs-api.c	Mon Aug 31 23:46:05 2015 +0300
+++ b/src/lib-fs/fs-api.c	Mon Aug 31 23:54:24 2015 +0300
@@ -63,6 +63,7 @@
 static void fs_classes_init(void)
 {
 	i_array_init(&fs_classes, 8);
+	fs_class_register(&fs_class_dict);
 	fs_class_register(&fs_class_posix);
 	fs_class_register(&fs_class_randomfail);
 	fs_class_register(&fs_class_metawrap);
diff -r 55cab04ef2af -r 6adcfddd354d src/lib-fs/fs-dict.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-fs/fs-dict.c	Mon Aug 31 23:54:24 2015 +0300
@@ -0,0 +1,312 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "buffer.h"
+#include "str.h"
+#include "guid.h"
+#include "base64.h"
+#include "istream.h"
+#include "ostream.h"
+#include "dict.h"
+#include "fs-api-private.h"
+
+enum fs_dict_value_encoding {
+	FS_DICT_VALUE_ENCODING_RAW,
+	FS_DICT_VALUE_ENCODING_BASE64
+};
+
+struct dict_fs {
+	struct fs fs;
+	struct dict *dict;
+	char *path_prefix;
+	enum fs_dict_value_encoding encoding;
+};
+
+struct dict_fs_file {
+	struct fs_file file;
+	pool_t pool;
+	const char *key, *value;
+	buffer_t *write_buffer;
+};
+
+struct dict_fs_iter {
+	struct fs_iter iter;
+	struct dict_iterate_context *dict_iter;
+};
+
+static struct fs *fs_dict_alloc(void)
+{
+	struct dict_fs *fs;
+
+	fs = i_new(struct dict_fs, 1);
+	fs->fs = fs_class_dict;
+	return &fs->fs;
+}
+
+static int
+fs_dict_init(struct fs *_fs, const char *args, const struct fs_settings *set)
+{
+	struct dict_fs *fs = (struct dict_fs *)_fs;
+	struct dict_settings dict_set;
+	const char *p, *encoding_str, *error;
+
+	p = strchr(args, ':');
+	if (p == NULL) {
+		fs_set_error(_fs, "':' missing in args");
+		return -1;
+	}
+	encoding_str = t_strdup_until(args, p++);
+	if (strcmp(encoding_str, "raw") == 0)
+		fs->encoding = FS_DICT_VALUE_ENCODING_RAW;
+	else if (strcmp(encoding_str, "base64") == 0)
+		fs->encoding = FS_DICT_VALUE_ENCODING_BASE64;
+	else {
+		fs_set_error(_fs, "Unknown value encoding '%s'", encoding_str);
+		return -1;
+	}
+
+	memset(&dict_set, 0, sizeof(dict_set));
+	dict_set.username = set->username;
+	dict_set.base_dir = set->base_dir;
+
+	if (dict_init_full(p, &dict_set, &fs->dict, &error) < 0) {
+		fs_set_error(_fs, "dict_init(%s) failed: %s", args, error);
+		return -1;
+	}
+	return 0;
+}
+
+static void fs_dict_deinit(struct fs *_fs)
+{
+	struct dict_fs *fs = (struct dict_fs *)_fs;
+
+	dict_deinit(&fs->dict);
+	i_free(fs);
+}
+
+static enum fs_properties fs_dict_get_properties(struct fs *fs ATTR_UNUSED)
+{
+	return FS_PROPERTY_ITER | FS_PROPERTY_RELIABLEITER;
+}
+
+static struct fs_file *
+fs_dict_file_init(struct fs *_fs, const char *path,
+		  enum fs_open_mode mode, enum fs_open_flags flags ATTR_UNUSED)
+{
+	struct dict_fs *fs = (struct dict_fs *)_fs;
+	struct dict_fs_file *file;
+	guid_128_t guid;
+	pool_t pool;
+
+	i_assert(mode != FS_OPEN_MODE_APPEND); /* not supported */
+	i_assert(mode != FS_OPEN_MODE_CREATE); /* not supported */
+
+	pool = pool_alloconly_create("fs dict file", 128);
+	file = p_new(pool, struct dict_fs_file, 1);
+	file->pool = pool;
+	file->file.fs = _fs;
+	if (mode != FS_OPEN_MODE_CREATE_UNIQUE_128)
+		file->file.path = p_strdup(pool, path);
+	else {
+		guid_128_generate(guid);
+		file->file.path = p_strdup_printf(pool, "%s/%s", path,
+						  guid_128_to_string(guid));
+	}
+	file->key = fs->path_prefix == NULL ?
+		p_strdup(pool, file->file.path) :
+		p_strconcat(pool, fs->path_prefix, file->file.path, NULL);
+	return &file->file;
+}
+
+static void fs_dict_file_deinit(struct fs_file *_file)
+{
+	struct dict_fs_file *file = (struct dict_fs_file *)_file;
+
+	i_assert(_file->output == NULL);
+
+	pool_unref(&file->pool);
+}
+
+static bool fs_dict_prefetch(struct fs_file *_file ATTR_UNUSED,
+			     uoff_t length ATTR_UNUSED)
+{
+	/* once async dict_lookup() is implemented, we want to start it here */
+	return TRUE;
+}
+
+static int fs_dict_lookup(struct dict_fs_file *file)
+{
+	struct dict_fs *fs = (struct dict_fs *)file->file.fs;
+	int ret;
+
+	if (file->value != NULL)
+		return 0;
+
+	ret = dict_lookup(fs->dict, file->pool, file->key, &file->value);
+	if (ret > 0)
+		return 0;
+	else if (ret < 0) {
+		errno = EIO;
+		fs_set_error(&fs->fs, "Dict lookup failed");
+		return -1;
+	} else {
+		errno = ENOENT;
+		fs_set_error(&fs->fs, "Dict key doesn't exist");
+		return -1;
+	}
+}
+
+static struct istream *
+fs_dict_read_stream(struct fs_file *_file, size_t max_buffer_size ATTR_UNUSED)
+{
+	struct dict_fs_file *file = (struct dict_fs_file *)_file;
+	struct istream *input;
+
+	if (fs_dict_lookup(file) < 0)
+		input = i_stream_create_error_str(errno, "%s", fs_last_error(_file->fs));
+	else
+		input = i_stream_create_from_data(file->value, strlen(file->value));
+	i_stream_set_name(input, file->key);
+	return input;
+}
+
+static void fs_dict_write_stream(struct fs_file *_file)
+{
+	struct dict_fs_file *file = (struct dict_fs_file *)_file;
+
+	i_assert(_file->output == NULL);
+
+	file->write_buffer = buffer_create_dynamic(file->pool, 128);
+	_file->output = o_stream_create_buffer(file->write_buffer);
+	o_stream_set_name(_file->output, file->key);
+}
+
+static int fs_dict_write_stream_finish(struct fs_file *_file, bool success)
+{
+	struct dict_fs_file *file = (struct dict_fs_file *)_file;
+	struct dict_fs *fs = (struct dict_fs *)_file->fs;
+	struct dict_transaction_context *trans;
+
+	o_stream_destroy(&_file->output);
+	if (!success)
+		return -1;
+
+	trans = dict_transaction_begin(fs->dict);
+	switch (fs->encoding) {
+	case FS_DICT_VALUE_ENCODING_RAW:
+		dict_set(trans, file->key, str_c(file->write_buffer));
+		break;
+	case FS_DICT_VALUE_ENCODING_BASE64: {
+		const unsigned int base64_size =
+			MAX_BASE64_ENCODED_SIZE(file->write_buffer->used);
+		string_t *base64 = t_str_new(base64_size);
+		base64_encode(file->write_buffer->data,
+			      file->write_buffer->used, base64);
+		dict_set(trans, file->key, str_c(base64));
+	}
+	}
+	if (dict_transaction_commit(&trans) < 0) {
+		errno = EIO;
+		fs_set_error(_file->fs, "Dict transaction commit failed");
+		return -1;
+	}
+	return 1;
+}
+
+static int fs_dict_stat(struct fs_file *_file, struct stat *st_r)
+{
+	struct dict_fs_file *file = (struct dict_fs_file *)_file;
+
+	memset(st_r, 0, sizeof(*st_r));
+
+	if (fs_dict_lookup(file) < 0)
+		return -1;
+	st_r->st_size = strlen(file->value);
+	return 0;
+}
+
+static int fs_dict_delete(struct fs_file *_file)
+{
+	struct dict_fs_file *file = (struct dict_fs_file *)_file;
+	struct dict_fs *fs = (struct dict_fs *)_file->fs;
+	struct dict_transaction_context *trans;
+
+	trans = dict_transaction_begin(fs->dict);
+	dict_unset(trans, file->key);
+	if (dict_transaction_commit(&trans) < 0) {
+		errno = EIO;
+		fs_set_error(_file->fs, "Dict transaction commit failed");
+		return -1;
+	}
+	return 0;
+}
+
+static struct fs_iter *
+fs_dict_iter_init(struct fs *_fs, const char *path, enum fs_iter_flags flags)
+{
+	struct dict_fs *fs = (struct dict_fs *)_fs;
+	struct dict_fs_iter *iter;
+
+	iter = i_new(struct dict_fs_iter, 1);
+	iter->iter.fs = _fs;
+	iter->iter.flags = flags;
+	if (fs->path_prefix != NULL)
+		path = t_strconcat(fs->path_prefix, path, NULL);
+
+	iter->dict_iter = dict_iterate_init(fs->dict, path, 0);
+	return &iter->iter;


More information about the dovecot-cvs mailing list