]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-fs: Always keep the error in the parentmost fs.
authorTimo Sirainen <tss@iki.fi>
Wed, 27 Mar 2013 12:45:14 +0000 (14:45 +0200)
committerTimo Sirainen <tss@iki.fi>
Wed, 27 Mar 2013 12:45:14 +0000 (14:45 +0200)
This fixes problems with getting the correct error message when wrapper
filesystems are used.

src/lib-fs/fs-api-private.h
src/lib-fs/fs-api.c
src/lib-fs/fs-metawrap.c

index f07b2e478332b36f666eebc663be0daebf09c72b..96bba1988a895e61fc9f914b241845f4a85e5373 100644 (file)
@@ -53,6 +53,7 @@ struct fs_vfuncs {
 };
 
 struct fs {
+       struct fs *parent; /* for wrapper filesystems */
        const char *name;
        struct fs_vfuncs v;
        char *temp_path_prefix;
index fb62b6398df849021c676beb6b5094882cc3d8fb..909a36feb2cc9afc353a09fca7cb7bbb764d9fca 100644 (file)
@@ -227,8 +227,24 @@ const char *fs_file_path(struct fs_file *file)
                file->fs->v.get_path(file);
 }
 
+static void ATTR_FORMAT(2, 0)
+fs_set_verror(struct fs *fs, const char *fmt, va_list args)
+{
+       /* the error is always kept in the parentmost fs */
+       if (fs->parent != NULL)
+               fs_set_verror(fs->parent, fmt, args);
+       else {
+               str_truncate(fs->last_error, 0);
+               str_vprintfa(fs->last_error, fmt, args);
+       }
+}
+
 const char *fs_last_error(struct fs *fs)
 {
+       /* the error is always kept in the parentmost fs */
+       if (fs->parent != NULL)
+               return fs_last_error(fs->parent);
+
        if (str_len(fs->last_error) == 0)
                return "BUG: Unknown fs error";
        return str_c(fs->last_error);
@@ -529,8 +545,7 @@ void fs_set_error(struct fs *fs, const char *fmt, ...)
        va_list args;
 
        va_start(args, fmt);
-       str_truncate(fs->last_error, 0);
-       str_vprintfa(fs->last_error, fmt, args);
+       fs_set_verror(fs, fmt, args);
        va_end(args);
 }
 
@@ -539,9 +554,9 @@ void fs_set_critical(struct fs *fs, const char *fmt, ...)
        va_list args;
 
        va_start(args, fmt);
-       str_truncate(fs->last_error, 0);
-       str_vprintfa(fs->last_error, fmt, args);
-       i_error("fs-%s: %s", fs->name, str_c(fs->last_error));
+       fs_set_verror(fs, fmt, args);
+
+       i_error("fs-%s: %s", fs->name, fs_last_error(fs));
        va_end(args);
 }
 
index 4b8fad59e0d89f6f93d122a37dd33a43f01e4970..be82cad1819e556198daca34e1817a20b42656e2 100644 (file)
@@ -15,7 +15,6 @@
 
 struct metawrap_fs {
        struct fs fs;
-       struct fs *super;
        bool wrap_metadata;
 };
 
@@ -29,18 +28,6 @@ struct metawrap_fs_file {
        bool metadata_read;
 };
 
-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;
@@ -70,11 +57,11 @@ fs_metawrap_init(struct fs *_fs, const char *args, const
                parent_name = t_strdup_until(args, parent_args);
                parent_args++;
        }
-       if (fs_init(parent_name, parent_args, set, &fs->super, &error) < 0) {
+       if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) {
                fs_set_error(_fs, "%s: %s", parent_name, error);
                return -1;
        }
-       if ((fs_get_properties(fs->super) & FS_PROPERTY_METADATA) == 0)
+       if ((fs_get_properties(_fs->parent) & FS_PROPERTY_METADATA) == 0)
                fs->wrap_metadata = TRUE;
        return 0;
 }
@@ -83,8 +70,8 @@ static void fs_metawrap_deinit(struct fs *_fs)
 {
        struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
 
-       if (fs->super != NULL)
-               fs_deinit(&fs->super);
+       if (_fs->parent != NULL)
+               fs_deinit(&_fs->parent);
        i_free(fs);
 }
 
@@ -93,7 +80,7 @@ static enum fs_properties fs_metawrap_get_properties(struct fs *_fs)
        const struct metawrap_fs *fs = (const struct metawrap_fs *)_fs;
        enum fs_properties props;
 
-       props = fs_get_properties(fs->super);
+       props = fs_get_properties(_fs->parent);
        if (fs->wrap_metadata) {
                /* we don't have a quick stat() to see the file's size,
                   because of the metadata header */
@@ -118,12 +105,12 @@ fs_metawrap_file_init(struct fs *_fs, const char *path,
        /* avoid unnecessarily creating two seekable streams */
        flags &= ~FS_OPEN_FLAG_SEEKABLE;
 
-       file->super = fs_file_init(fs->super, path, mode | flags);
+       file->super = fs_file_init(_fs->parent, path, mode | flags);
        if (file->fs->wrap_metadata && 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->super, path, mode | flags |
+               file->super_read = fs_file_init(_fs->parent, path, mode | flags |
                                                FS_OPEN_FLAG_ASYNC);
        } else {
                file->super_read = file->super;
@@ -164,13 +151,7 @@ fs_metawrap_set_async_callback(struct fs_file *_file,
 
 static int fs_metawrap_wait_async(struct fs *_fs)
 {
-       struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
-
-       if (fs_wait_async(fs->super) < 0) {
-               fs_metawrap_copy_error(fs);
-               return -1;
-       }
-       return 0;
+       return fs_wait_async(_fs->parent);
 }
 
 static void
@@ -192,13 +173,8 @@ fs_metawrap_get_metadata(struct fs_file *_file,
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
        char c;
 
-       if (!file->fs->wrap_metadata) {
-               if (fs_get_metadata(file->super, metadata_r) < 0) {
-                       fs_metawrap_file_copy_error(file);
-                       return -1;
-               }
-               return 0;
-       }
+       if (!file->fs->wrap_metadata)
+               return fs_get_metadata(file->super, metadata_r);
 
        if (!file->metadata_read) {
                if (fs_read(_file, &c, 1) < 0)
@@ -221,13 +197,9 @@ static bool fs_metawrap_prefetch(struct fs_file *_file, uoff_t length)
 static ssize_t fs_metawrap_read(struct fs_file *_file, void *buf, size_t size)
 {
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
-       ssize_t ret;
 
-       if (!file->fs->wrap_metadata) {
-               if ((ret = fs_read(file->super, buf, size)) < 0)
-                       fs_metawrap_file_copy_error(file);
-               return ret;
-       }
+       if (!file->fs->wrap_metadata)
+               return fs_read(file->super, buf, size);
        return fs_read_via_stream(_file, buf, size);
 }
 
@@ -275,13 +247,8 @@ static int fs_metawrap_write(struct fs_file *_file, const void *data, size_t siz
 {
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
-       if (!file->fs->wrap_metadata) {
-               if (fs_write(file->super, data, size) < 0) {
-                       fs_metawrap_file_copy_error(file);
-                       return -1;
-               }
-               return 0;
-       }
+       if (!file->fs->wrap_metadata)
+               return fs_write(file->super, data, size);
        return fs_write_via_stream(_file, data, size);
 }
 
@@ -343,9 +310,6 @@ static int fs_metawrap_write_stream_finish(struct fs_file *_file, bool success)
        } else {
                ret = fs_write_stream_finish(file->super, &file->super_output);
        }
-
-       if (ret < 0)
-               fs_metawrap_file_copy_error(file);
        return ret;
 }
 
@@ -354,11 +318,7 @@ fs_metawrap_lock(struct fs_file *_file, unsigned int secs, struct fs_lock **lock
 {
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
-       if (fs_lock(file->super, secs, lock_r) < 0) {
-               fs_metawrap_file_copy_error(file);
-               return -1;
-       }
-       return 0;
+       return fs_lock(file->super, secs, lock_r);
 }
 
 static void fs_metawrap_unlock(struct fs_lock *_lock ATTR_UNUSED)
@@ -370,11 +330,7 @@ static int fs_metawrap_exists(struct fs_file *_file)
 {
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
-       if (fs_exists(file->super) < 0) {
-               fs_metawrap_copy_error(file->fs);
-               return -1;
-       }
-       return 0;
+       return fs_exists(file->super);
 }
 
 static int fs_metawrap_stat(struct fs_file *_file, struct stat *st_r)
@@ -384,13 +340,8 @@ static int fs_metawrap_stat(struct fs_file *_file, struct stat *st_r)
        uoff_t input_size;
        ssize_t ret;
 
-       if (!file->fs->wrap_metadata) {
-               if (fs_stat(file->super, st_r) < 0) {
-                       fs_metawrap_copy_error(file->fs);
-                       return -1;
-               }
-               return 0;
-       }
+       if (!file->fs->wrap_metadata)
+               return fs_stat(file->super, st_r);
        input = fs_read_stream(_file, IO_BLOCK_SIZE);
        if ((ret = i_stream_get_size(input, TRUE, &input_size)) < 0) {
                fs_set_error(_file->fs, "i_stream_get_size(%s) failed: %m",
@@ -406,7 +357,6 @@ static int fs_metawrap_stat(struct fs_file *_file, struct stat *st_r)
 
        if (fs_stat(file->super, st_r) < 0) {
                i_assert(errno != EAGAIN); /* read should have caught this */
-               fs_metawrap_copy_error(file->fs);
                return -1;
        }
        st_r->st_size = input_size;
@@ -418,13 +368,8 @@ static int fs_metawrap_copy(struct fs_file *_src, struct fs_file *_dest)
        struct metawrap_fs_file *src = (struct metawrap_fs_file *)_src;
        struct metawrap_fs_file *dest = (struct metawrap_fs_file *)_dest;
 
-       if (!dest->fs->wrap_metadata) {
-               if (fs_copy(src->super, dest->super) < 0) {
-                       fs_metawrap_copy_error(src->fs);
-                       return -1;
-               }
-               return 0;
-       }
+       if (!dest->fs->wrap_metadata)
+               return fs_copy(src->super, dest->super);
        return fs_default_copy(_src, _dest);
 }
 
@@ -433,31 +378,21 @@ static int fs_metawrap_rename(struct fs_file *_src, struct fs_file *_dest)
        struct metawrap_fs_file *src = (struct metawrap_fs_file *)_src;
        struct metawrap_fs_file *dest = (struct metawrap_fs_file *)_dest;
 
-       if (fs_rename(src->super, dest->super) < 0) {
-               fs_metawrap_copy_error(src->fs);
-               return -1;
-       }
-       return 0;
+       return fs_rename(src->super, dest->super);
 }
 
 static int fs_metawrap_delete(struct fs_file *_file)
 {
        struct metawrap_fs_file *file = (struct metawrap_fs_file *)_file;
 
-       if (fs_delete(file->super) < 0) {
-               fs_metawrap_copy_error(file->fs);
-               return -1;
-       }
-       return 0;
+       return fs_delete(file->super);
 }
 
 static struct fs_iter *
 fs_metawrap_iter_init(struct fs *_fs, const char *path,
                          enum fs_iter_flags flags)
 {
-       struct metawrap_fs *fs = (struct metawrap_fs *)_fs;
-
-       return fs_iter_init(fs->super, path, flags);
+       return fs_iter_init(_fs->parent, path, flags);
 }
 
 const struct fs fs_class_metawrap = {