Mercurial > dovecot > core-2.2
changeset 18620:7799886e017a
Moved fs-compress to a separate plugin directory.
Mainly because I couldn't figure out how to make automake dependencies work
on "make install" stage. It was trying to link fs-compress.so using
-ldovecot-storage, but libdovecot-storage.so was also concurrently being
installed.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 09 May 2015 20:26:06 +0300 |
parents | 49f5131a502e |
children | da685736985a |
files | configure.ac src/lib-compression/Makefile.am src/lib-compression/fs-compress.c src/plugins/Makefile.am src/plugins/fs-compress/Makefile.am src/plugins/fs-compress/fs-compress.c |
diffstat | 6 files changed, 434 insertions(+), 429 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.ac Sat May 09 19:58:59 2015 +0300 +++ b/configure.ac Sat May 09 20:26:06 2015 +0300 @@ -2944,6 +2944,7 @@ src/plugins/imap-acl/Makefile src/plugins/autocreate/Makefile src/plugins/expire/Makefile +src/plugins/fs-compress/Makefile src/plugins/fts/Makefile src/plugins/fts-lucene/Makefile src/plugins/fts-solr/Makefile
--- a/src/lib-compression/Makefile.am Sat May 09 19:58:59 2015 +0300 +++ b/src/lib-compression/Makefile.am Sat May 09 20:26:06 2015 +0300 @@ -1,12 +1,7 @@ noinst_LTLIBRARIES = libcompression.la -fs_moduledir = $(moduledir) -fs_module_LTLIBRARIES = \ - libfs_compress.la - AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ - -I$(top_srcdir)/src/lib-fs \ -I$(top_srcdir)/src/lib-test libcompression_la_SOURCES = \ @@ -35,11 +30,6 @@ libdovecot_compression_la_DEPENDENCIES = libcompression.la ../lib-dovecot/libdovecot.la libdovecot_compression_la_LDFLAGS = -export-dynamic -libfs_compress_la_SOURCES = fs-compress.c -libfs_compress_la_LIBADD = libdovecot-compression.la -libfs_compress_la_DEPENDENCIES = libdovecot-compression.la -libfs_compress_la_LDFLAGS = -module -avoid-version - test_programs = \ test-compression
--- a/src/lib-compression/fs-compress.c Sat May 09 19:58:59 2015 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,418 +0,0 @@ -/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "array.h" -#include "istream.h" -#include "ostream.h" -#include "iostream-temp.h" -#include "compression.h" -#include "fs-api-private.h" - -struct compress_fs { - struct fs fs; - const struct compression_handler *handler; - unsigned int compress_level; -}; - -struct compress_fs_file { - struct fs_file file; - struct compress_fs *fs; - struct fs_file *super, *super_read; - enum fs_open_mode open_mode; - struct istream *input; - - struct ostream *super_output; - struct ostream *temp_output; -}; - -struct compress_fs_iter { - struct fs_iter iter; - struct fs_iter *super; -}; - -extern const struct fs fs_class_compress; - -static struct fs *fs_compress_alloc(void) -{ - struct compress_fs *fs; - - fs = i_new(struct compress_fs, 1); - fs->fs = fs_class_compress; - return &fs->fs; -} - -static int -fs_compress_init(struct fs *_fs, const char *args, const - struct fs_settings *set) -{ - struct compress_fs *fs = (struct compress_fs *)_fs; - const char *p, *compression_name, *level_str, *error; - const char *parent_name, *parent_args; - - /* get compression handler name */ - p = strchr(args, ':'); - if (p == NULL) { - fs_set_error(_fs, "Compression method not given as parameter"); - return -1; - } - compression_name = t_strdup_until(args, p++); - args = p; - - /* get compression level */ - p = strchr(args, ':'); - if (p == NULL || p[1] == '\0') { - fs_set_error(_fs, "Parent filesystem not given as parameter"); - return -1; - } - - level_str = t_strdup_until(args, p++); - if (str_to_uint(level_str, &fs->compress_level) < 0 || - fs->compress_level < 1 || fs->compress_level > 9) { - fs_set_error(_fs, "Invalid compression level parameter '%s'", level_str); - return -1; - } - args = p; - - fs->handler = compression_lookup_handler(compression_name); - if (fs->handler == NULL) { - fs_set_error(_fs, "Compression method '%s' not support", compression_name); - 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++; - } - if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) { - fs_set_error(_fs, "%s: %s", parent_name, error); - return -1; - } - return 0; -} - -static void fs_compress_deinit(struct fs *_fs) -{ - struct compress_fs *fs = (struct compress_fs *)_fs; - - if (_fs->parent != NULL) - fs_deinit(&_fs->parent); - i_free(fs); -} - -static enum fs_properties fs_compress_get_properties(struct fs *_fs) -{ - return fs_get_properties(_fs->parent); -} - -static struct fs_file * -fs_compress_file_init(struct fs *_fs, const char *path, - enum fs_open_mode mode, enum fs_open_flags flags) -{ - struct compress_fs *fs = (struct compress_fs *)_fs; - struct compress_fs_file *file; - - file = i_new(struct compress_fs_file, 1); - file->file.fs = _fs; - file->file.path = i_strdup(path); - file->fs = fs; - file->open_mode = mode; - - /* avoid unnecessarily creating two seekable streams */ - flags &= ~FS_OPEN_FLAG_SEEKABLE; - - file->super = fs_file_init(_fs->parent, path, mode | flags); - if (mode == FS_OPEN_MODE_READONLY && - (flags & FS_OPEN_FLAG_ASYNC) == 0) { - /* use async stream for super, so fs_read_stream() won't create - another seekable stream unneededly */ - file->super_read = fs_file_init(_fs->parent, path, mode | flags | - FS_OPEN_FLAG_ASYNC); - } else { - file->super_read = file->super; - } - return &file->file; -} - -static void fs_compress_file_deinit(struct fs_file *_file) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - if (file->super_read != file->super && file->super_read != NULL) - fs_file_deinit(&file->super_read); - fs_file_deinit(&file->super); - i_free(file->file.path); - i_free(file); -} - -static void fs_compress_file_close(struct fs_file *_file) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - if (file->input != NULL) - i_stream_unref(&file->input); - if (file->super_read != NULL) - fs_file_close(file->super_read); - if (file->super != NULL) - fs_file_close(file->super); -} - -static const char *fs_compress_file_get_path(struct fs_file *_file) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - return fs_file_path(file->super); -} - -static void -fs_compress_set_async_callback(struct fs_file *_file, - fs_file_async_callback_t *callback, - void *context) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - fs_file_set_async_callback(file->super, callback, context); -} - -static int fs_compress_wait_async(struct fs *_fs) -{ - return fs_wait_async(_fs->parent); -} - -static void -fs_compress_set_metadata(struct fs_file *_file, const char *key, - const char *value) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - fs_set_metadata(file->super, key, value); -} - -static int -fs_compress_get_metadata(struct fs_file *_file, - const ARRAY_TYPE(fs_metadata) **metadata_r) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - return fs_get_metadata(file->super, metadata_r); -} - -static bool fs_compress_prefetch(struct fs_file *_file, uoff_t length) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - return fs_prefetch(file->super, length); -} - -static struct istream * -fs_compress_read_stream(struct fs_file *_file, size_t max_buffer_size) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - struct istream *input; - - if (file->input != NULL) { - i_stream_ref(file->input); - i_stream_seek(file->input, 0); - return file->input; - } - - input = fs_read_stream(file->super_read, max_buffer_size); - file->input = file->fs->handler->create_istream(input, FALSE); - i_stream_unref(&input); - i_stream_ref(file->input); - return file->input; -} - -static void fs_compress_write_stream(struct fs_file *_file) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - i_assert(_file->output == NULL); - - file->temp_output = - iostream_temp_create_named(_file->fs->temp_path_prefix, - IOSTREAM_TEMP_FLAG_TRY_FD_DUP, - fs_file_path(_file)); - _file->output = file->fs->handler-> - create_ostream(file->temp_output, file->fs->compress_level); -} - -static int fs_compress_write_stream_finish(struct fs_file *_file, bool success) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - struct istream *input; - int ret; - - if (_file->output != NULL) { - if (_file->output->closed) - success = FALSE; - if (_file->output == file->super_output) - _file->output = NULL; - else - o_stream_unref(&_file->output); - } - if (!success) { - if (file->temp_output != NULL) - o_stream_destroy(&file->temp_output); - if (file->super_output != NULL) - fs_write_stream_abort(file->super, &file->super_output); - return -1; - } - - if (file->super_output != NULL) { - i_assert(file->temp_output == NULL); - return fs_write_stream_finish(file->super, &file->super_output); - } - if (file->temp_output == NULL) { - /* finishing up */ - i_assert(file->super_output == NULL); - return fs_write_stream_finish(file->super, &file->temp_output); - } - /* finish writing the temporary file */ - input = iostream_temp_finish(&file->temp_output, IO_BLOCK_SIZE); - file->super_output = fs_write_stream(file->super); - if (o_stream_send_istream(file->super_output, input) >= 0) - ret = fs_write_stream_finish(file->super, &file->super_output); - else if (input->stream_errno != 0) { - fs_set_error(_file->fs, "read(%s) failed: %s", - i_stream_get_name(input), - i_stream_get_error(input)); - fs_write_stream_abort(file->super, &file->super_output); - ret = -1; - } else { - i_assert(file->super_output->stream_errno != 0); - fs_set_error(_file->fs, "write(%s) failed: %s", - o_stream_get_name(file->super_output), - o_stream_get_error(file->super_output)); - fs_write_stream_abort(file->super, &file->super_output); - ret = -1; - } - i_stream_unref(&input); - return ret; -} - -static int -fs_compress_lock(struct fs_file *_file, unsigned int secs, struct fs_lock **lock_r) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - return fs_lock(file->super, secs, lock_r); -} - -static void fs_compress_unlock(struct fs_lock *_lock ATTR_UNUSED) -{ - i_unreached(); -} - -static int fs_compress_exists(struct fs_file *_file) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - return fs_exists(file->super); -} - -static int fs_compress_stat(struct fs_file *_file, struct stat *st_r) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - return fs_stat(file->super, st_r); -} - -static int fs_compress_copy(struct fs_file *_src, struct fs_file *_dest) -{ - struct compress_fs_file *src = (struct compress_fs_file *)_src; - struct compress_fs_file *dest = (struct compress_fs_file *)_dest; - - if (_src != NULL) - return fs_copy(src->super, dest->super); - else - return fs_copy_finish_async(dest->super); -} - -static int fs_compress_rename(struct fs_file *_src, struct fs_file *_dest) -{ - struct compress_fs_file *src = (struct compress_fs_file *)_src; - struct compress_fs_file *dest = (struct compress_fs_file *)_dest; - - return fs_rename(src->super, dest->super); -} - -static int fs_compress_delete(struct fs_file *_file) -{ - struct compress_fs_file *file = (struct compress_fs_file *)_file; - - return fs_delete(file->super); -} - -static struct fs_iter * -fs_compress_iter_init(struct fs *_fs, const char *path, - enum fs_iter_flags flags) -{ - struct compress_fs_iter *iter; - - iter = i_new(struct compress_fs_iter, 1); - iter->iter.fs = _fs; - iter->iter.flags = flags; - iter->super = fs_iter_init(_fs->parent, path, flags); - return &iter->iter; -} - -static const char *fs_compress_iter_next(struct fs_iter *_iter) -{ - struct compress_fs_iter *iter = (struct compress_fs_iter *)_iter; - const char *fname; - - iter->super->async_callback = _iter->async_callback; - iter->super->async_context = _iter->async_context; - - fname = fs_iter_next(iter->super); - _iter->async_have_more = iter->super->async_have_more; - return fname; -} - -static int fs_compress_iter_deinit(struct fs_iter *_iter) -{ - struct compress_fs_iter *iter = (struct compress_fs_iter *)_iter; - int ret; - - ret = fs_iter_deinit(&iter->super); - i_free(iter); - return ret; -} - -const struct fs fs_class_compress = { - .name = "compress", - .v = { - fs_compress_alloc, - fs_compress_init, - fs_compress_deinit, - fs_compress_get_properties, - fs_compress_file_init, - fs_compress_file_deinit, - fs_compress_file_close, - fs_compress_file_get_path, - fs_compress_set_async_callback, - fs_compress_wait_async, - fs_compress_set_metadata, - fs_compress_get_metadata, - fs_compress_prefetch, - fs_read_via_stream, - fs_compress_read_stream, - fs_write_via_stream, - fs_compress_write_stream, - fs_compress_write_stream_finish, - fs_compress_lock, - fs_compress_unlock, - fs_compress_exists, - fs_compress_stat, - fs_compress_copy, - fs_compress_rename, - fs_compress_delete, - fs_compress_iter_init, - fs_compress_iter_next, - fs_compress_iter_deinit - } -};
--- a/src/plugins/Makefile.am Sat May 09 19:58:59 2015 +0300 +++ b/src/plugins/Makefile.am Sat May 09 20:26:06 2015 +0300 @@ -35,4 +35,5 @@ virtual \ $(ZLIB) \ $(FTS_LUCENE) \ - $(FTS_SOLR) + $(FTS_SOLR) \ + fs-compress
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/fs-compress/Makefile.am Sat May 09 20:26:06 2015 +0300 @@ -0,0 +1,13 @@ +fs_moduledir = $(moduledir) +fs_module_LTLIBRARIES = \ + libfs_compress.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-compression \ + -I$(top_srcdir)/src/lib-fs + +libfs_compress_la_SOURCES = fs-compress.c +libfs_compress_la_LIBADD = ../../lib-compression/libdovecot-compression.la +libfs_compress_la_DEPENDENCIES = ../../lib-compression/libdovecot-compression.la +libfs_compress_la_LDFLAGS = -module -avoid-version
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/fs-compress/fs-compress.c Sat May 09 20:26:06 2015 +0300 @@ -0,0 +1,418 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "istream.h" +#include "ostream.h" +#include "iostream-temp.h" +#include "compression.h" +#include "fs-api-private.h" + +struct compress_fs { + struct fs fs; + const struct compression_handler *handler; + unsigned int compress_level; +}; + +struct compress_fs_file { + struct fs_file file; + struct compress_fs *fs; + struct fs_file *super, *super_read; + enum fs_open_mode open_mode; + struct istream *input; + + struct ostream *super_output; + struct ostream *temp_output; +}; + +struct compress_fs_iter { + struct fs_iter iter; + struct fs_iter *super; +}; + +extern const struct fs fs_class_compress; + +static struct fs *fs_compress_alloc(void) +{ + struct compress_fs *fs; + + fs = i_new(struct compress_fs, 1); + fs->fs = fs_class_compress; + return &fs->fs; +} + +static int +fs_compress_init(struct fs *_fs, const char *args, const + struct fs_settings *set) +{ + struct compress_fs *fs = (struct compress_fs *)_fs; + const char *p, *compression_name, *level_str, *error; + const char *parent_name, *parent_args; + + /* get compression handler name */ + p = strchr(args, ':'); + if (p == NULL) { + fs_set_error(_fs, "Compression method not given as parameter"); + return -1; + } + compression_name = t_strdup_until(args, p++); + args = p; + + /* get compression level */ + p = strchr(args, ':'); + if (p == NULL || p[1] == '\0') { + fs_set_error(_fs, "Parent filesystem not given as parameter"); + return -1; + } + + level_str = t_strdup_until(args, p++); + if (str_to_uint(level_str, &fs->compress_level) < 0 || + fs->compress_level < 1 || fs->compress_level > 9) { + fs_set_error(_fs, "Invalid compression level parameter '%s'", level_str); + return -1; + } + args = p; + + fs->handler = compression_lookup_handler(compression_name); + if (fs->handler == NULL) { + fs_set_error(_fs, "Compression method '%s' not support", compression_name); + 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++; + } + if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) { + fs_set_error(_fs, "%s: %s", parent_name, error); + return -1; + } + return 0; +} + +static void fs_compress_deinit(struct fs *_fs) +{ + struct compress_fs *fs = (struct compress_fs *)_fs; + + if (_fs->parent != NULL) + fs_deinit(&_fs->parent); + i_free(fs); +} + +static enum fs_properties fs_compress_get_properties(struct fs *_fs) +{ + return fs_get_properties(_fs->parent); +} + +static struct fs_file * +fs_compress_file_init(struct fs *_fs, const char *path, + enum fs_open_mode mode, enum fs_open_flags flags) +{ + struct compress_fs *fs = (struct compress_fs *)_fs; + struct compress_fs_file *file; + + file = i_new(struct compress_fs_file, 1); + file->file.fs = _fs; + file->file.path = i_strdup(path); + file->fs = fs; + file->open_mode = mode; + + /* avoid unnecessarily creating two seekable streams */ + flags &= ~FS_OPEN_FLAG_SEEKABLE; + + file->super = fs_file_init(_fs->parent, path, mode | flags); + if (mode == FS_OPEN_MODE_READONLY && + (flags & FS_OPEN_FLAG_ASYNC) == 0) { + /* use async stream for super, so fs_read_stream() won't create + another seekable stream unneededly */ + file->super_read = fs_file_init(_fs->parent, path, mode | flags | + FS_OPEN_FLAG_ASYNC); + } else { + file->super_read = file->super; + } + return &file->file; +} + +static void fs_compress_file_deinit(struct fs_file *_file) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + if (file->super_read != file->super && file->super_read != NULL) + fs_file_deinit(&file->super_read); + fs_file_deinit(&file->super); + i_free(file->file.path); + i_free(file); +} + +static void fs_compress_file_close(struct fs_file *_file) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + if (file->input != NULL) + i_stream_unref(&file->input); + if (file->super_read != NULL) + fs_file_close(file->super_read); + if (file->super != NULL) + fs_file_close(file->super); +} + +static const char *fs_compress_file_get_path(struct fs_file *_file) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + return fs_file_path(file->super); +} + +static void +fs_compress_set_async_callback(struct fs_file *_file, + fs_file_async_callback_t *callback, + void *context) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + fs_file_set_async_callback(file->super, callback, context); +} + +static int fs_compress_wait_async(struct fs *_fs) +{ + return fs_wait_async(_fs->parent); +} + +static void +fs_compress_set_metadata(struct fs_file *_file, const char *key, + const char *value) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + fs_set_metadata(file->super, key, value); +} + +static int +fs_compress_get_metadata(struct fs_file *_file, + const ARRAY_TYPE(fs_metadata) **metadata_r) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + return fs_get_metadata(file->super, metadata_r); +} + +static bool fs_compress_prefetch(struct fs_file *_file, uoff_t length) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + return fs_prefetch(file->super, length); +} + +static struct istream * +fs_compress_read_stream(struct fs_file *_file, size_t max_buffer_size) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + struct istream *input; + + if (file->input != NULL) { + i_stream_ref(file->input); + i_stream_seek(file->input, 0); + return file->input; + } + + input = fs_read_stream(file->super_read, max_buffer_size); + file->input = file->fs->handler->create_istream(input, FALSE); + i_stream_unref(&input); + i_stream_ref(file->input); + return file->input; +} + +static void fs_compress_write_stream(struct fs_file *_file) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + i_assert(_file->output == NULL); + + file->temp_output = + iostream_temp_create_named(_file->fs->temp_path_prefix, + IOSTREAM_TEMP_FLAG_TRY_FD_DUP, + fs_file_path(_file)); + _file->output = file->fs->handler-> + create_ostream(file->temp_output, file->fs->compress_level); +} + +static int fs_compress_write_stream_finish(struct fs_file *_file, bool success) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + struct istream *input; + int ret; + + if (_file->output != NULL) { + if (_file->output->closed) + success = FALSE; + if (_file->output == file->super_output) + _file->output = NULL; + else + o_stream_unref(&_file->output); + } + if (!success) { + if (file->temp_output != NULL) + o_stream_destroy(&file->temp_output); + if (file->super_output != NULL) + fs_write_stream_abort(file->super, &file->super_output); + return -1; + } + + if (file->super_output != NULL) { + i_assert(file->temp_output == NULL); + return fs_write_stream_finish(file->super, &file->super_output); + } + if (file->temp_output == NULL) { + /* finishing up */ + i_assert(file->super_output == NULL); + return fs_write_stream_finish(file->super, &file->temp_output); + } + /* finish writing the temporary file */ + input = iostream_temp_finish(&file->temp_output, IO_BLOCK_SIZE); + file->super_output = fs_write_stream(file->super); + if (o_stream_send_istream(file->super_output, input) >= 0) + ret = fs_write_stream_finish(file->super, &file->super_output); + else if (input->stream_errno != 0) { + fs_set_error(_file->fs, "read(%s) failed: %s", + i_stream_get_name(input), + i_stream_get_error(input)); + fs_write_stream_abort(file->super, &file->super_output); + ret = -1; + } else { + i_assert(file->super_output->stream_errno != 0); + fs_set_error(_file->fs, "write(%s) failed: %s", + o_stream_get_name(file->super_output), + o_stream_get_error(file->super_output)); + fs_write_stream_abort(file->super, &file->super_output); + ret = -1; + } + i_stream_unref(&input); + return ret; +} + +static int +fs_compress_lock(struct fs_file *_file, unsigned int secs, struct fs_lock **lock_r) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + return fs_lock(file->super, secs, lock_r); +} + +static void fs_compress_unlock(struct fs_lock *_lock ATTR_UNUSED) +{ + i_unreached(); +} + +static int fs_compress_exists(struct fs_file *_file) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + return fs_exists(file->super); +} + +static int fs_compress_stat(struct fs_file *_file, struct stat *st_r) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + return fs_stat(file->super, st_r); +} + +static int fs_compress_copy(struct fs_file *_src, struct fs_file *_dest) +{ + struct compress_fs_file *src = (struct compress_fs_file *)_src; + struct compress_fs_file *dest = (struct compress_fs_file *)_dest; + + if (_src != NULL) + return fs_copy(src->super, dest->super); + else + return fs_copy_finish_async(dest->super); +} + +static int fs_compress_rename(struct fs_file *_src, struct fs_file *_dest) +{ + struct compress_fs_file *src = (struct compress_fs_file *)_src; + struct compress_fs_file *dest = (struct compress_fs_file *)_dest; + + return fs_rename(src->super, dest->super); +} + +static int fs_compress_delete(struct fs_file *_file) +{ + struct compress_fs_file *file = (struct compress_fs_file *)_file; + + return fs_delete(file->super); +} + +static struct fs_iter * +fs_compress_iter_init(struct fs *_fs, const char *path, + enum fs_iter_flags flags) +{ + struct compress_fs_iter *iter; + + iter = i_new(struct compress_fs_iter, 1); + iter->iter.fs = _fs; + iter->iter.flags = flags; + iter->super = fs_iter_init(_fs->parent, path, flags); + return &iter->iter; +} + +static const char *fs_compress_iter_next(struct fs_iter *_iter) +{ + struct compress_fs_iter *iter = (struct compress_fs_iter *)_iter; + const char *fname; + + iter->super->async_callback = _iter->async_callback; + iter->super->async_context = _iter->async_context; + + fname = fs_iter_next(iter->super); + _iter->async_have_more = iter->super->async_have_more; + return fname; +} + +static int fs_compress_iter_deinit(struct fs_iter *_iter) +{ + struct compress_fs_iter *iter = (struct compress_fs_iter *)_iter; + int ret; + + ret = fs_iter_deinit(&iter->super); + i_free(iter); + return ret; +} + +const struct fs fs_class_compress = { + .name = "compress", + .v = { + fs_compress_alloc, + fs_compress_init, + fs_compress_deinit, + fs_compress_get_properties, + fs_compress_file_init, + fs_compress_file_deinit, + fs_compress_file_close, + fs_compress_file_get_path, + fs_compress_set_async_callback, + fs_compress_wait_async, + fs_compress_set_metadata, + fs_compress_get_metadata, + fs_compress_prefetch, + fs_read_via_stream, + fs_compress_read_stream, + fs_write_via_stream, + fs_compress_write_stream, + fs_compress_write_stream_finish, + fs_compress_lock, + fs_compress_unlock, + fs_compress_exists, + fs_compress_stat, + fs_compress_copy, + fs_compress_rename, + fs_compress_delete, + fs_compress_iter_init, + fs_compress_iter_next, + fs_compress_iter_deinit + } +};