dovecot-2.2: lib-fs: Added "metawrap" wrapper to implement metad...

dovecot at dovecot.org dovecot at dovecot.org
Mon Jan 21 14:43:14 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/5818d8f488c1
changeset: 15655:5818d8f488c1
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Jan 21 14:43:09 2013 +0200
description:
lib-fs: Added "metawrap" wrapper to implement metadata as headers in the file content.

diffstat:

 src/lib-fs/Makefile.am        |    3 +
 src/lib-fs/fs-api-private.h   |   15 +
 src/lib-fs/fs-api.c           |   96 ++++++++-
 src/lib-fs/fs-metawrap.c      |  429 ++++++++++++++++++++++++++++++++++++++++++
 src/lib-fs/istream-metawrap.c |   79 +++++++
 src/lib-fs/istream-metawrap.h |   14 +
 6 files changed, 625 insertions(+), 11 deletions(-)

diffs (truncated from 765 to 300 lines):

diff -r ee177df07178 -r 5818d8f488c1 src/lib-fs/Makefile.am
--- a/src/lib-fs/Makefile.am	Mon Jan 21 14:42:10 2013 +0200
+++ b/src/lib-fs/Makefile.am	Mon Jan 21 14:43:09 2013 +0200
@@ -8,16 +8,19 @@
 
 libfs_la_SOURCES = \
 	fs-api.c \
+	fs-metawrap.c \
 	fs-posix.c \
 	fs-sis.c \
 	fs-sis-common.c \
 	fs-sis-queue.c \
+	istream-metawrap.c \
 	ostream-cmp.c
 
 headers = \
 	fs-api.h \
 	fs-api-private.h \
 	fs-sis-common.h \
+	istream-metawrap.h \
 	ostream-cmp.h
 
 fs_test_SOURCES = fs-test.c
diff -r ee177df07178 -r 5818d8f488c1 src/lib-fs/fs-api-private.h
--- a/src/lib-fs/fs-api-private.h	Mon Jan 21 14:42:10 2013 +0200
+++ b/src/lib-fs/fs-api-private.h	Mon Jan 21 14:43:09 2013 +0200
@@ -69,6 +69,13 @@
 
 	struct istream *pending_read_input;
 	bool write_pending;
+
+	pool_t metadata_pool;
+	ARRAY_TYPE(fs_metadata) metadata;
+
+	struct fs_file *copy_src;
+	struct istream *copy_input;
+	struct ostream *copy_output;
 };
 
 struct fs_lock {
@@ -81,6 +88,7 @@
 };
 
 extern const struct fs fs_class_posix;
+extern const struct fs fs_class_metawrap;
 extern const struct fs fs_class_sis;
 extern const struct fs fs_class_sis_queue;
 
@@ -89,4 +97,11 @@
 
 void fs_set_error_async(struct fs *fs);
 
+ssize_t fs_read_via_stream(struct fs_file *file, void *buf, size_t size);
+int fs_write_via_stream(struct fs_file *file, const void *data, size_t size);
+void fs_metadata_init(struct fs_file *file);
+void fs_default_set_metadata(struct fs_file *file,
+			     const char *key, const char *value);
+int fs_default_copy(struct fs_file *src, struct fs_file *dest);
+
 #endif
diff -r ee177df07178 -r 5818d8f488c1 src/lib-fs/fs-api.c
--- a/src/lib-fs/fs-api.c	Mon Jan 21 14:42:10 2013 +0200
+++ b/src/lib-fs/fs-api.c	Mon Jan 21 14:43:09 2013 +0200
@@ -46,6 +46,7 @@
 {
 	i_array_init(&fs_classes, 8);
 	fs_class_register(&fs_class_posix);
+	fs_class_register(&fs_class_metawrap);
 	fs_class_register(&fs_class_sis);
 	fs_class_register(&fs_class_sis_queue);
 }
@@ -146,6 +147,7 @@
 void fs_file_deinit(struct fs_file **_file)
 {
 	struct fs_file *file = *_file;
+	pool_t metadata_pool = file->metadata_pool;
 
 	i_assert(file->fs->files_open_count > 0);
 
@@ -153,6 +155,9 @@
 
 	file->fs->files_open_count--;
 	file->fs->v.file_deinit(file);
+
+	if (metadata_pool != NULL)
+		pool_unref(&metadata_pool);
 }
 
 enum fs_properties fs_get_properties(struct fs *fs)
@@ -160,6 +165,25 @@
 	return fs->v.get_properties(fs);
 }
 
+void fs_metadata_init(struct fs_file *file)
+{
+	if (file->metadata_pool == NULL) {
+		file->metadata_pool = pool_alloconly_create("fs metadata", 1024);
+		p_array_init(&file->metadata, file->metadata_pool, 8);
+	}
+}
+
+void fs_default_set_metadata(struct fs_file *file,
+			     const char *key, const char *value)
+{
+	struct fs_metadata *metadata;
+
+	fs_metadata_init(file);
+	metadata = array_append_space(&file->metadata);
+	metadata->key = p_strdup(file->metadata_pool, key);
+	metadata->value = p_strdup(file->metadata_pool, value);
+}
+
 void fs_set_metadata(struct fs_file *file, const char *key, const char *value)
 {
 	if (file->fs->v.set_metadata != NULL)
@@ -199,17 +223,14 @@
 	return file->fs->v.prefetch(file, length);
 }
 
-ssize_t fs_read(struct fs_file *file, void *buf, size_t size)
+ssize_t fs_read_via_stream(struct fs_file *file, void *buf, size_t size)
 {
 	const unsigned char *data;
 	size_t data_size;
 	ssize_t ret;
 
-	if (file->fs->v.read != NULL)
-		return file->fs->v.read(file, buf, size);
+	i_assert(size > 0);
 
-	/* backend didn't bother to implement read(), but we can do it with
-	   streams. */
 	if (file->pending_read_input == NULL)
 		file->pending_read_input = fs_read_stream(file, size+1);
 	ret = i_stream_read_data(file->pending_read_input,
@@ -229,22 +250,27 @@
 	return ret;
 }
 
+ssize_t fs_read(struct fs_file *file, void *buf, size_t size)
+{
+	if (file->fs->v.read != NULL)
+		return file->fs->v.read(file, buf, size);
+
+	/* backend didn't bother to implement read(), but we can do it with
+	   streams. */
+	return fs_read_via_stream(file, buf, size);
+}
+
 struct istream *fs_read_stream(struct fs_file *file, size_t max_buffer_size)
 {
 	return file->fs->v.read_stream(file, max_buffer_size);
 }
 
-int fs_write(struct fs_file *file, const void *data, size_t size)
+int fs_write_via_stream(struct fs_file *file, const void *data, size_t size)
 {
 	struct ostream *output;
 	ssize_t ret;
 	int err;
 
-	if (file->fs->v.write != NULL)
-		return file->fs->v.write(file, data, size);
-
-	/* backend didn't bother to implement write(), but we can do it with
-	   streams. */
 	if (!file->write_pending) {
 		output = fs_write_stream(file);
 		if ((ret = o_stream_send(output, data, size)) < 0) {
@@ -269,6 +295,16 @@
 	return ret < 0 ? -1 : 0;
 }
 
+int fs_write(struct fs_file *file, const void *data, size_t size)
+{
+	if (file->fs->v.write != NULL)
+		return file->fs->v.write(file, data, size);
+
+	/* backend didn't bother to implement write(), but we can do it with
+	   streams. */
+	return fs_write_via_stream(file, data, size);
+}
+
 struct ostream *fs_write_stream(struct fs_file *file)
 {
 	file->fs->v.write_stream(file);
@@ -338,6 +374,44 @@
 	return file->fs->v.stat(file, st_r);
 }
 
+int fs_default_copy(struct fs_file *src, struct fs_file *dest)
+{
+	if (dest->copy_src != NULL) {
+		i_assert(src == NULL || src == dest->copy_src);
+		if (dest->copy_output == NULL) {
+			i_assert(dest->copy_input == NULL);
+			if (fs_write_stream_finish_async(dest) < 0)
+				return -1;
+			dest->copy_src = NULL;
+			return 0;
+		}
+	} else {
+		dest->copy_src = src;
+		dest->copy_input = fs_read_stream(src, IO_BLOCK_SIZE);
+		dest->copy_output = fs_write_stream(dest);
+	}
+	while (o_stream_send_istream(dest->copy_output, dest->copy_input) > 0) ;
+	if (dest->copy_input->stream_errno != 0) {
+		fs_set_error(dest->fs, "read(%s) failed: %m",
+			     i_stream_get_name(dest->copy_input));
+		return -1;
+	}
+	if (dest->copy_output->stream_errno != 0) {
+		fs_set_error(dest->fs, "write(%s) failed: %m",
+			     o_stream_get_name(dest->copy_output));
+		return -1;
+	}
+	if (!dest->copy_input->eof) {
+		fs_set_error_async(dest->fs);
+		return -1;
+	}
+	i_stream_unref(&dest->copy_input);
+	if (fs_write_stream_finish(dest, &dest->copy_output) < 0)
+		return -1;
+	dest->copy_src = NULL;
+	return 0;
+}
+
 int fs_copy(struct fs_file *src, struct fs_file *dest)
 {
 	i_assert(src->fs == dest->fs);
diff -r ee177df07178 -r 5818d8f488c1 src/lib-fs/fs-metawrap.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-fs/fs-metawrap.c	Mon Jan 21 14:43:09 2013 +0200
@@ -0,0 +1,429 @@
+/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "strescape.h"
+#include "istream.h"
+#include "istream-private.h"
+#include "istream-metawrap.h"
+#include "ostream.h"
+#include "fs-api-private.h"
+
+struct metawrap_fs {
+	struct fs fs;
+	struct fs *super;
+	bool wrap_metadata;
+};
+
+struct metawrap_fs_file {
+	struct fs_file file;
+	struct metawrap_fs *fs;
+	struct fs_file *super;
+	enum fs_open_mode open_mode;
+};
+
+static void fs_metawrap_copy_error(struct metawrap_fs *fs)
+{
+	fs_set_error(&fs->fs, "%s", fs_last_error(fs->super));
+}
+
+static void fs_metawrap_file_copy_error(struct metawrap_fs_file *file)
+{
+	struct metawrap_fs *fs = (struct metawrap_fs *)file->file.fs;
+
+	fs_metawrap_copy_error(fs);
+}
+
+static struct fs *fs_metawrap_alloc(void)
+{
+	struct metawrap_fs *fs;
+
+	fs = i_new(struct metawrap_fs, 1);
+	fs->fs = fs_class_metawrap;
+	return &fs->fs;
+}
+
+static int
+fs_metawrap_init(struct fs *_fs, const char *args, const
+		 struct fs_settings *set)
+{
+	struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
+	const char *parent_name, *parent_args, *error;
+
+	if (*args == '\0') {
+		fs_set_error(_fs, "Parent filesystem not given as parameter");
+		return -1;
+	}
+
+	parent_args = strchr(args, ':');
+	if (parent_args == NULL) {
+		parent_name = args;
+		parent_args = "";
+	} else {
+		parent_name = t_strdup_until(args, parent_args);
+		parent_args++;


More information about the dovecot-cvs mailing list