Mercurial > dovecot > core-2.2
changeset 20851:c2c1190aa566
fs-metawrap: Don't assert-crash when trying to write an empty file.
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)
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Mon, 10 Oct 2016 23:53:55 +0300 |
parents | 1d96b08f9c78 |
children | 1c4be30c9e9b |
files | src/lib-fs/fs-metawrap.c src/lib-fs/test-fs-metawrap.c |
diffstat | 2 files changed, 35 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-fs/fs-metawrap.c Tue Oct 11 00:31:17 2016 +0300 +++ b/src/lib-fs/fs-metawrap.c Mon Oct 10 23:53:55 2016 +0300 @@ -288,23 +288,31 @@ 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 @@ 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
--- a/src/lib-fs/test-fs-metawrap.c Tue Oct 11 00:31:17 2016 +0300 +++ b/src/lib-fs/test-fs-metawrap.c Mon Oct 10 23:53:55 2016 +0300 @@ -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 @@ 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 @@ 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);