]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-fs: Replace fs error with file/iter-specific error
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Fri, 29 Nov 2019 15:01:26 +0000 (17:01 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Wed, 11 Dec 2019 10:12:30 +0000 (10:12 +0000)
Removed fs_last_error(), since it can't be used anymore.

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

index 77ee85fa8346113c22d4e9f30e63cfcebaa2d908..bfee8136d55e37e110f3d72a464d5ed309998645 100644 (file)
@@ -87,7 +87,6 @@ struct fs {
        char *username, *session_id;
 
        struct fs_settings set;
-       char *last_error;
 
        /* may be used by fs_wait_async() to do the waiting */
        struct ioloop *wait_ioloop, *prev_ioloop;
@@ -111,6 +110,7 @@ struct fs_file {
        struct ostream *output;
        struct event *event;
        char *path;
+       char *last_error;
        enum fs_open_flags flags;
 
        struct istream *seekable_input;
@@ -150,6 +150,7 @@ struct fs_iter {
        struct event *event;
        enum fs_iter_flags flags;
        struct timeval start_time;
+       char *last_error;
 
        bool async_have_more;
        fs_file_async_callback_t *async_callback;
index 61b3bacd17f9a75f8e37861500c2495715f6fa6a..8fcd135fb9b9d8af1bb983237fb1fa4b659ae519 100644 (file)
@@ -225,7 +225,6 @@ void fs_unref(struct fs **_fs)
        i_free(fs->username);
        i_free(fs->session_id);
        i_free(fs->temp_path_prefix);
-       i_free(fs->last_error);
        for (i = 0; i < FS_OP_COUNT; i++) {
                if (fs->stats.timings[i] != NULL)
                        stats_dist_deinit(&fs->stats.timings[i]);
@@ -310,6 +309,7 @@ void fs_file_free(struct fs_file *file)
        fs_file_deinit(&file->parent);
        event_unref(&file->event);
        pool_unref(&file->metadata_pool);
+       i_free(file->last_error);
 }
 
 void fs_file_close(struct fs_file *file)
@@ -521,44 +521,58 @@ struct event *fs_file_event(struct fs_file *file)
        return file->event;
 }
 
+static struct fs_file *fs_file_get_error_file(struct fs_file *file)
+{
+       /* the error is always kept in the parentmost file */
+       while (file->parent != NULL)
+               file = file->parent;
+       return file;
+}
+
 static void ATTR_FORMAT(2, 0)
 fs_set_verror(struct event *event, const char *fmt, va_list args)
 {
        struct event *fs_event = event;
-       struct fs *fs;
+       struct fs_file *file;
+       struct fs_iter *iter;
 
        /* NOTE: the event might be a passthrough event. We must log it exactly
           once so it gets freed. */
 
-       while ((fs = event_get_ptr(fs_event, FS_EVENT_FIELD_FS)) == NULL) {
+       /* figure out if the error is for a file or iter */
+       while ((file = event_get_ptr(fs_event, FS_EVENT_FIELD_FILE)) == NULL &&
+              (iter = event_get_ptr(fs_event, FS_EVENT_FIELD_ITER)) == NULL) {
                fs_event = event_get_parent(fs_event);
                i_assert(fs_event != NULL);
        }
 
-       /* the error is always kept in the parentmost fs */
-       while (fs->parent != NULL)
-               fs = fs->parent;
-       char *old_error = fs->last_error;
-       fs->last_error = i_strdup_vprintf(fmt, args);
-       i_free(old_error);
-
-       e_debug(event, "%s", fs->last_error);
-}
+       char *new_error = i_strdup_vprintf(fmt, args);
+       e_debug(event, "%s", new_error);
 
-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);
+       /* free old error after strdup in case args point to the old error */
+       if (file != NULL) {
+               file = fs_file_get_error_file(file);
 
-       if (fs->last_error == NULL)
-               return "BUG: Unknown fs error";
-       return fs->last_error;
+               i_free(file->last_error);
+               file->last_error = new_error;
+       } else {
+               i_assert(iter != NULL);
+               /* Preserve the first error for iters. That's the first
+                  thing that went wrong and broke the iteration. */
+               if (iter->last_error == NULL)
+                       iter->last_error = new_error;
+               else
+                       i_free(new_error);
+       }
 }
 
 const char *fs_file_last_error(struct fs_file *file)
 {
-       return fs_last_error(file->fs);
+       struct fs_file *error_file = fs_file_get_error_file(file);
+
+       if (error_file->last_error == NULL)
+               return "BUG: Unknown file error";
+       return error_file->last_error;
 }
 
 bool fs_prefetch(struct fs_file *file, uoff_t length)
@@ -1184,7 +1198,8 @@ int fs_iter_deinit(struct fs_iter **_iter, const char **error_r)
                ret = iter->fs->v.iter_deinit(iter);
        } T_END;
        if (ret < 0)
-               *error_r = fs_last_error(fs);
+               *error_r = t_strdup(iter->last_error);
+       i_free(iter->last_error);
        i_free(iter);
        event_unref(&event);
        return ret;
index 8cd6f92591f8ae35a20e8f5a3b8107158e88051b..6645675fb64411ed0bbbe6312bfdf192a9f238ac 100644 (file)
@@ -256,9 +256,9 @@ struct fs *fs_file_fs(struct fs_file *file);
 /* Returns the file's event. */
 struct event *fs_file_event(struct fs_file *file);
 
-/* Return the error message for the last failed operation. */
-const char *fs_last_error(struct fs *fs);
-/* Convenience function for the above. Errors aren't preserved across files. */
+/* Return the error message for the last failed file operation. Each file
+   keeps track of its own errors. For failed copy/rename operations the "dest"
+   file contains the error. */
 const char *fs_file_last_error(struct fs_file *file);
 
 /* Try to asynchronously prefetch file into memory. Returns TRUE if file is
@@ -330,12 +330,13 @@ int fs_stat(struct fs_file *file, struct stat *st_r);
 int fs_get_nlinks(struct fs_file *file, nlink_t *nlinks_r);
 /* Copy an object with possibly updated metadata. Destination parent
    directories are created automatically. Returns 0 if ok, -1 if error
-   occurred. */
+   occurred. The "dest" file contains the error. */
 int fs_copy(struct fs_file *src, struct fs_file *dest);
 /* Try to finish asynchronous fs_copy(). Returns the same as fs_copy(). */
 int fs_copy_finish_async(struct fs_file *dest);
 /* Atomically rename a file. Destination parent directories are created
-   automatically. Returns 0 if ok, -1 if error occurred. */
+   automatically. Returns 0 if ok, -1 if error occurred. The "dest" file
+   contains the error. */
 int fs_rename(struct fs_file *src, struct fs_file *dest);
 
 /* Exclusively lock a file. If file is already locked, wait for it for given