]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
fs-metawrap: Don't assert-crash when trying to write an empty file.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 10 Oct 2016 20:53:55 +0000 (23:53 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 13 Oct 2016 08:27:33 +0000 (10:27 +0200)
Fixes:
Panic: file fs-metawrap.c: line 401 (fs_metawrap_write_stream_finish): assertion failed: (file->super_output->offset > 0 || file->super_output->stream_errno != 0)

src/lib-fs/fs-metawrap.c
src/lib-fs/test-fs-metawrap.c

index 6c893838741604c34293396f83b855e30c9937a9..f4af7d4e1c338cb294b21af5143b3bd444f206a6 100644 (file)
@@ -288,23 +288,31 @@ fs_metawrap_append_metadata(struct metawrap_fs_file *file, string_t *str)
        str_append_c(str, '\n');
 }
 
-static void fs_metawrap_write_metadata(void *context)
+static void
+fs_metawrap_write_metadata_to(struct metawrap_fs_file *file,
+                             struct ostream *output)
 {
-       struct metawrap_fs_file *file = context;
        string_t *str = t_str_new(256);
        ssize_t ret;
 
        fs_metawrap_append_metadata(file, str);
        file->metadata_write_size = str_len(str);
 
-       ret = o_stream_send(file->file.output, str_data(str), str_len(str));
+       ret = o_stream_send(output, str_data(str), str_len(str));
        if (ret < 0)
-               o_stream_close(file->file.output);
+               o_stream_close(output);
        else
                i_assert((size_t)ret == str_len(str));
        file->metadata_changed_since_write = FALSE;
 }
 
+static void fs_metawrap_write_metadata(void *context)
+{
+       struct metawrap_fs_file *file = context;
+
+       fs_metawrap_write_metadata_to(file, file->file.output);
+}
+
 static void fs_metawrap_write_stream(struct fs_file *_file)
 {
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
@@ -384,6 +392,10 @@ static int fs_metawrap_write_stream_finish(struct fs_file *_file, bool success)
                return fs_write_stream_finish_async(_file->parent);
        }
        /* finish writing the temporary file */
+       if (file->temp_output->offset == 0) {
+               /* empty file */
+               fs_metawrap_write_metadata_to(file, file->temp_output);
+       }
        input = iostream_temp_finish(&file->temp_output, IO_BLOCK_SIZE);
        if (file->metadata_changed_since_write) {
                /* we'll need to recreate the metadata. do this by creating a
index 6b1f52db7a71557d390d384a52b563a3bb88337e..211d884ff824c86fb0cb28f860e0366df1a02535 100644 (file)
@@ -6,9 +6,10 @@
 #include "fs-test.h"
 #include "test-common.h"
 
+static const struct fs_settings fs_set;
+
 static void test_fs_metawrap_stat(void)
 {
-       struct fs_settings fs_set;
        struct fs *fs;
        struct fs_file *file;
        struct test_fs_file *test_file;
@@ -19,7 +20,6 @@ static void test_fs_metawrap_stat(void)
 
        test_begin("fs metawrap stat");
 
-       memset(&fs_set, 0, sizeof(fs_set));
        if (fs_init("metawrap", "test", &fs_set, &fs, &error) < 0)
                i_fatal("fs_init() failed: %s", error);
 
@@ -53,11 +53,28 @@ static void test_fs_metawrap_async(void)
        test_fs_async("double-metawrap", FS_PROPERTY_METADATA, "metawrap", "metawrap:test");
 }
 
+static void test_fs_metawrap_write_empty(void)
+{
+       struct fs *fs;
+       const char *error;
+
+       test_begin("fs metawrap write empty file");
+       if (fs_init("metawrap", "test", &fs_set, &fs, &error) < 0)
+               i_fatal("fs_init() failed: %s", error);
+       struct fs_file *file = fs_file_init(fs, "foo", FS_OPEN_MODE_REPLACE);
+       struct ostream *output = fs_write_stream(file);
+       test_assert(fs_write_stream_finish(file, &output) > 0);
+       fs_file_deinit(&file);
+       fs_deinit(&fs);
+       test_end();
+}
+
 int main(void)
 {
        static void (*test_functions[])(void) = {
                test_fs_metawrap_stat,
                test_fs_metawrap_async,
+               test_fs_metawrap_write_empty,
                NULL
        };
        return test_run(test_functions);