fs-api.c revision 459b43463e1d652e5e2b8274246f1fa5ecf54d32
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2010-2013 Dovecot authors, see the included COPYING file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "lib.h"
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen#include "array.h"
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen#include "module-dir.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "str.h"
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen#include "istream.h"
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen#include "istream-seekable.h"
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen#include "ostream.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "fs-api-private.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic struct module *fs_modules = NULL;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic ARRAY(const struct fs *) fs_classes;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainenstatic int
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_alloc(const struct fs *fs_class, const char *args,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const struct fs_settings *set, struct fs **fs_r, const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs *fs;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen int ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs = fs_class->v.alloc();
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs->last_error = str_new(default_pool, 64);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen T_BEGIN {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen ret = fs_class->v.init(fs, args, set);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen } T_END;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (ret < 0) {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen /* a bit kludgy way to allow data stack frame usage in normal
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen conditions but still be able to return error message from
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen data stack. */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen *error_r = t_strdup_printf("%s: %s", fs_class->name,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_last_error(fs));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_deinit(&fs);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
463072825056eabcbed7aaa943c98655ce173ce5Timo Sirainen *fs_r = fs;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_register(const struct fs *fs_class)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen array_append(&fs_classes, &fs_class, 1);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_classes_init(void)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen i_array_init(&fs_classes, 8);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_register(&fs_class_posix);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen fs_class_register(&fs_class_metawrap);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_register(&fs_class_sis);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_register(&fs_class_sis_queue);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic const struct fs *fs_class_find(const char *driver)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen const struct fs *const *classp;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (!array_is_created(&fs_classes))
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_classes_init();
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen array_foreach(&fs_classes, classp) {
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (strcmp((*classp)->name, driver) == 0)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen return *classp;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen }
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen return NULL;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_deinit_modules(void)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module_dir_unload(&fs_modules);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_try_load_plugin(const char *driver)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen const char *module_name = t_strdup_printf("fs_%s", driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen struct module *module;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen struct module_dir_load_settings mod_set;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen const struct fs *fs_class;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen memset(&mod_set, 0, sizeof(mod_set));
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen mod_set.abi_version = DOVECOT_ABI_VERSION;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen mod_set.ignore_missing = TRUE;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_modules = module_dir_load_missing(fs_modules, MODULE_DIR,
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module_name, &mod_set);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module_dir_init(fs_modules);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module = module_dir_find(fs_modules, module_name);
898e99166f46b4f37ae45fe5594ed952b5befe6dTimo Sirainen fs_class = module == NULL ? NULL :
898e99166f46b4f37ae45fe5594ed952b5befe6dTimo Sirainen module_get_symbol(module, t_strdup_printf("fs_class_%s", driver));
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (fs_class != NULL)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_register(fs_class);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen lib_atexit(fs_class_deinit_modules);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainenint fs_init(const char *driver, const char *args,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const struct fs_settings *set,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen struct fs **fs_r, const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen const struct fs *fs_class;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen const char *temp_file_prefix;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class = fs_class_find(driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (fs_class == NULL) {
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen T_BEGIN {
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_try_load_plugin(driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen } T_END;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class = fs_class_find(driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen }
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen if (fs_class == NULL) {
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen *error_r = t_strdup_printf("Unknown fs driver: %s", driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (fs_alloc(fs_class, args, set, fs_r, error_r) < 0)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return -1;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen temp_file_prefix = set->temp_file_prefix != NULL ?
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen set->temp_file_prefix : ".temp.dovecot";
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen (*fs_r)->temp_path_prefix = i_strconcat(set->temp_dir, "/",
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen temp_file_prefix, NULL);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_deinit(struct fs **_fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs *fs = *_fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen string_t *last_error = fs->last_error;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *_fs = NULL;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs->files_open_count > 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_panic("fs-%s: %u files still open",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs->name, fs->files_open_count);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_free(fs->temp_path_prefix);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs->v.deinit(fs);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen str_free(&last_error);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstruct fs_file *fs_file_init(struct fs *fs, const char *path, int mode_flags)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs_file *file;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(path != NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen T_BEGIN {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file = fs->v.file_init(fs, path, mode_flags & FS_OPEN_MODE_MASK,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen mode_flags & ~FS_OPEN_MODE_MASK);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } T_END;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen file->flags = mode_flags & ~FS_OPEN_MODE_MASK;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs->files_open_count++;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_file_deinit(struct fs_file **_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs_file *file = *_file;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen pool_t metadata_pool = file->metadata_pool;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(file->fs->files_open_count > 0);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *_file = NULL;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ef064b29e237d6093727e18f997f680881567771Timo Sirainen if (file->pending_read_input != NULL)
ef064b29e237d6093727e18f997f680881567771Timo Sirainen i_stream_unref(&file->pending_read_input);
ef064b29e237d6093727e18f997f680881567771Timo Sirainen
ef064b29e237d6093727e18f997f680881567771Timo Sirainen if (file->copy_input != NULL) {
ef064b29e237d6093727e18f997f680881567771Timo Sirainen i_stream_unref(&file->copy_input);
ef064b29e237d6093727e18f997f680881567771Timo Sirainen (void)fs_write_stream_abort(file, &file->copy_output);
ef064b29e237d6093727e18f997f680881567771Timo Sirainen }
ef064b29e237d6093727e18f997f680881567771Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->fs->files_open_count--;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs->v.file_deinit(file);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (metadata_pool != NULL)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen pool_unref(&metadata_pool);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenenum fs_properties fs_get_properties(struct fs *fs)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return fs->v.get_properties(fs);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenvoid fs_metadata_init(struct fs_file *file)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (file->metadata_pool == NULL) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen file->metadata_pool = pool_alloconly_create("fs metadata", 1024);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen p_array_init(&file->metadata, file->metadata_pool, 8);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenvoid fs_default_set_metadata(struct fs_file *file,
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen const char *key, const char *value)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen struct fs_metadata *metadata;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen fs_metadata_init(file);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata = array_append_space(&file->metadata);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata->key = p_strdup(file->metadata_pool, key);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata->value = p_strdup(file->metadata_pool, value);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_set_metadata(struct fs_file *file, const char *key, const char *value)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fs->v.set_metadata != NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs->v.set_metadata(file, key, value);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_get_metadata(struct fs_file *file,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const ARRAY_TYPE(fs_metadata) **metadata_r)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fs->v.get_metadata == NULL) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(file->fs, "Metadata not supported by backend");
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return file->fs->v.get_metadata(file, metadata_r);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_file_path(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
3dcb9fd82c1edd40bea1ad572ed39f024686e463Timo Sirainen return file->fs->v.get_path == NULL ? file->path :
3dcb9fd82c1edd40bea1ad572ed39f024686e463Timo Sirainen file->fs->v.get_path(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_last_error(struct fs *fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (str_len(fs->last_error) == 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return "BUG: Unknown fs error";
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return str_c(fs->last_error);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_file_last_error(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return fs_last_error(file->fs);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenbool fs_prefetch(struct fs_file *file, uoff_t length)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return file->fs->v.prefetch(file, length);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read_via_stream(struct fs_file *file, void *buf, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen const unsigned char *data;
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen size_t data_size;
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen ssize_t ret;
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_assert(size > 0);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen if (file->pending_read_input == NULL)
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen file->pending_read_input = fs_read_stream(file, size+1);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen ret = i_stream_read_data(file->pending_read_input,
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen &data, &data_size, size-1);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen if (ret == 0) {
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen fs_set_error_async(file->fs);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen return -1;
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen }
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen if (ret < 0 && file->pending_read_input->stream_errno != 0) {
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen fs_set_error(file->fs, "read(%s) failed: %m",
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen i_stream_get_name(file->pending_read_input));
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen } else {
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen ret = I_MIN(size, data_size);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen memcpy(buf, data, ret);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen }
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen i_stream_unref(&file->pending_read_input);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read(struct fs_file *file, void *buf, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (file->fs->v.read != NULL)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return file->fs->v.read(file, buf, size);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement read(), but we can do it with
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen streams. */
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return fs_read_via_stream(file, buf, size);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct istream *fs_read_stream(struct fs_file *file, size_t max_buffer_size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen struct istream *input, *inputs[2];
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen const unsigned char *data;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen size_t size;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen ssize_t ret;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen bool want_seekable = FALSE;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input = file->fs->v.read_stream(file, max_buffer_size);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (input->stream_errno != 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read failed already */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return input;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_SEEKABLE) != 0)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen want_seekable = TRUE;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen else if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen want_seekable = TRUE;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (want_seekable && !input->seekable) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* need to make the stream seekable */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen inputs[0] = input;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen inputs[1] = NULL;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input = i_stream_create_seekable_path(inputs, max_buffer_size,
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen file->fs->temp_path_prefix);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_set_name(input, i_stream_get_name(inputs[0]));
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_unref(&inputs[0]);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read the whole input stream before returning */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen while ((ret = i_stream_read_data(input, &data, &size, 0)) >= 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_skip(input, size);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (ret == 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (fs_wait_async(file->fs) < 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input->stream_errno = errno;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input->eof = TRUE;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen break;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_seek(input, 0);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return input;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write_via_stream(struct fs_file *file, const void *data, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen struct ostream *output;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen ssize_t ret;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen int err;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen if (!file->write_pending) {
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen output = fs_write_stream(file);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen if ((ret = o_stream_send(output, data, size)) < 0) {
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen err = errno;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen fs_set_error(file->fs, "fs_write(%s) failed: %m",
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen o_stream_get_name(output));
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen fs_write_stream_abort(file, &output);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen errno = err;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen return -1;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen }
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen i_assert((size_t)ret == size);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen ret = fs_write_stream_finish(file, &output);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen } else {
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen ret = fs_write_stream_finish_async(file);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen }
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen if (ret == 0) {
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen fs_set_error_async(file->fs);
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen file->write_pending = TRUE;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen return -1;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen }
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen file->write_pending = FALSE;
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen return ret < 0 ? -1 : 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write(struct fs_file *file, const void *data, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (file->fs->v.write != NULL)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return file->fs->v.write(file, data, size);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement write(), but we can do it with
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen streams. */
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return fs_write_via_stream(file, data, size);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct ostream *fs_write_stream(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->fs->v.write_stream(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(file->output != NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return file->output;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint fs_write_stream_finish(struct fs_file *file, struct ostream **output)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
f6754d90ea6bbe1386eb4d39f603cf01edde4ef1Timo Sirainen i_assert(*output == file->output || *output == NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *output = NULL;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return file->fs->v.write_stream_finish(file, TRUE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainenint fs_write_stream_finish_async(struct fs_file *file)
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen{
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen return file->fs->v.write_stream_finish(file, TRUE);
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen}
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_write_stream_abort(struct fs_file *file, struct ostream **output)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(*output == file->output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *output = NULL;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen (void)file->fs->v.write_stream_finish(file, FALSE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_file_set_async_callback(struct fs_file *file,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_file_async_callback_t *callback,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen void *context)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fs->v.set_async_callback != NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs->v.set_async_callback(file, callback, context);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen else
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen callback(context);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
2766f1de8141c09767a959d2d2c3065c5a300bf0Timo Sirainenint fs_wait_async(struct fs *fs)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
2766f1de8141c09767a959d2d2c3065c5a300bf0Timo Sirainen if (fs->v.wait_async == NULL)
2766f1de8141c09767a959d2d2c3065c5a300bf0Timo Sirainen return 0;
2766f1de8141c09767a959d2d2c3065c5a300bf0Timo Sirainen else
2766f1de8141c09767a959d2d2c3065c5a300bf0Timo Sirainen return fs->v.wait_async(fs);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint fs_lock(struct fs_file *file, unsigned int secs, struct fs_lock **lock_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return file->fs->v.lock(file, secs, lock_r);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_unlock(struct fs_lock **_lock)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs_lock *lock = *_lock;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *_lock = NULL;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lock->file->fs->v.unlock(lock);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_exists(struct fs_file *file)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return file->fs->v.exists(file);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_stat(struct fs_file *file, struct stat *st_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return file->fs->v.stat(file, st_r);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_default_copy(struct fs_file *src, struct fs_file *dest)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (dest->copy_src != NULL) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_assert(src == NULL || src == dest->copy_src);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (dest->copy_output == NULL) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_assert(dest->copy_input == NULL);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (fs_write_stream_finish_async(dest) < 0)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_src = NULL;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return 0;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen } else {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_src = src;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_input = fs_read_stream(src, IO_BLOCK_SIZE);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_output = fs_write_stream(dest);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen while (o_stream_send_istream(dest->copy_output, dest->copy_input) > 0) ;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (dest->copy_input->stream_errno != 0) {
459b43463e1d652e5e2b8274246f1fa5ecf54d32Timo Sirainen errno = dest->copy_input->stream_errno;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen fs_set_error(dest->fs, "read(%s) failed: %m",
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_stream_get_name(dest->copy_input));
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (dest->copy_output->stream_errno != 0) {
459b43463e1d652e5e2b8274246f1fa5ecf54d32Timo Sirainen errno = dest->copy_output->stream_errno;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen fs_set_error(dest->fs, "write(%s) failed: %m",
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen o_stream_get_name(dest->copy_output));
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (!dest->copy_input->eof) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen fs_set_error_async(dest->fs);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_stream_unref(&dest->copy_input);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen if (fs_write_stream_finish(dest, &dest->copy_output) < 0)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_src = NULL;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return 0;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_copy(struct fs_file *src, struct fs_file *dest)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(src->fs == dest->fs);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return src->fs->v.copy(src, dest);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainenint fs_copy_finish_async(struct fs_file *dest)
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen{
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen return dest->fs->v.copy(NULL, dest);
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen}
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_rename(struct fs_file *src, struct fs_file *dest)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(src->fs == dest->fs);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return src->fs->v.rename(src, dest);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_delete(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return file->fs->v.delete_file(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenstruct fs_iter *
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenfs_iter_init(struct fs *fs, const char *path, enum fs_iter_flags flags)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen return fs->v.iter_init(fs, path, flags);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_iter_deinit(struct fs_iter **_iter)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs_iter *iter = *_iter;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen *_iter = NULL;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return iter->fs->v.iter_deinit(iter);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenconst char *fs_iter_next(struct fs_iter *iter)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return iter->fs->v.iter_next(iter);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_error(struct fs *fs, const char *fmt, ...)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_list args;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_start(args, fmt);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_truncate(fs->last_error, 0);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_vprintfa(fs->last_error, fmt, args);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_end(args);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_critical(struct fs *fs, const char *fmt, ...)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_list args;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_start(args, fmt);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_truncate(fs->last_error, 0);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_vprintfa(fs->last_error, fmt, args);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_error("fs-%s: %s", fs->name, str_c(fs->last_error));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen va_end(args);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_set_error_async(struct fs *fs)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(fs, "Asynchronous operation in progress");
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen errno = EAGAIN;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}