From: Timo Sirainen Date: Fri, 29 Nov 2019 15:01:26 +0000 (+0200) Subject: lib-fs: Replace fs error with file/iter-specific error X-Git-Tag: 2.3.10~205 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d2c3cf0d147321e69c80faae791cfe2dfd8ec7d0;p=thirdparty%2Fdovecot%2Fcore.git lib-fs: Replace fs error with file/iter-specific error Removed fs_last_error(), since it can't be used anymore. --- diff --git a/src/lib-fs/fs-api-private.h b/src/lib-fs/fs-api-private.h index 77ee85fa83..bfee8136d5 100644 --- a/src/lib-fs/fs-api-private.h +++ b/src/lib-fs/fs-api-private.h @@ -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; diff --git a/src/lib-fs/fs-api.c b/src/lib-fs/fs-api.c index 61b3bacd17..8fcd135fb9 100644 --- a/src/lib-fs/fs-api.c +++ b/src/lib-fs/fs-api.c @@ -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; diff --git a/src/lib-fs/fs-api.h b/src/lib-fs/fs-api.h index 8cd6f92591..6645675fb6 100644 --- a/src/lib-fs/fs-api.h +++ b/src/lib-fs/fs-api.h @@ -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