bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 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"
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen#include "llist.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "str.h"
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen#include "hash-method.h"
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen#include "istream.h"
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen#include "istream-seekable.h"
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen#include "ostream.h"
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#include "stats-dist.h"
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen#include "time-util.h"
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen#include "istream-fs-stats.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "fs-api-private.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainenstruct fs_api_module_register fs_api_module_register = { 0 };
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic struct module *fs_modules = NULL;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic ARRAY(const struct fs *) fs_classes;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainenstatic void fs_classes_init(void);
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo 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();
70f202ae74b6981ced5776a69b1070274313c6c8Timo Sirainen fs->refcount = 1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs->last_error = str_new(default_pool, 64);
12d31981c521a7e5520423b2960acc602fb669b7Timo Sirainen fs->set.debug = set->debug;
12d31981c521a7e5520423b2960acc602fb669b7Timo Sirainen fs->set.enable_timing = set->enable_timing;
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen i_array_init(&fs->module_contexts, 5);
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));
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen fs_unref(&fs);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
02cc28525a97ee60cb512c8eb15908082743bfe9Timo Sirainen fs->username = i_strdup(set->username);
02cc28525a97ee60cb512c8eb15908082743bfe9Timo Sirainen fs->session_id = i_strdup(set->session_id);
463072825056eabcbed7aaa943c98655ce173ce5Timo Sirainen *fs_r = fs;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainenvoid fs_class_register(const struct fs *fs_class)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainen if (!array_is_created(&fs_classes))
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainen fs_classes_init();
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen array_append(&fs_classes, &fs_class, 1);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen}
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainenstatic void fs_classes_deinit(void)
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen{
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen array_free(&fs_classes);
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen}
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_classes_init(void)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen i_array_init(&fs_classes, 8);
6c0d8dc7cad70a336b01bd1978b3eee84a63b3b7Timo Sirainen fs_class_register(&fs_class_dict);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_class_register(&fs_class_posix);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_class_register(&fs_class_randomfail);
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);
140afad728d78c56fb4c0256f94eb81a213688dbTimo Sirainen fs_class_register(&fs_class_test);
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen lib_atexit(fs_classes_deinit);
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
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainenstatic const char *fs_driver_module_name(const char *driver)
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen{
e0593474ae2d8b1d4ec8c70c4fd84ea2bfede75aTimo Sirainen return t_str_replace(driver, '-', '_');
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen}
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_try_load_plugin(const char *driver)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen{
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen const char *module_name =
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen t_strdup_printf("fs_%s", fs_driver_module_name(driver));
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen struct module *module;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen struct module_dir_load_settings mod_set;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen const struct fs *fs_class;
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&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 :
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen module_get_symbol(module, t_strdup_printf(
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen "fs_class_%s", fs_driver_module_name(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
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainenstatic struct event *fs_create_event(struct fs *fs, struct event *parent)
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen{
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen struct event *event;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen event = event_create(parent);
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen event_set_append_log_prefix(event,
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen t_strdup_printf("fs-%s: ", fs->name));
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen return event;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen}
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo 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;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen (*fs_r)->event = fs_create_event(*fs_r, set->event);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen temp_file_prefix = set->temp_file_prefix != NULL ?
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen set->temp_file_prefix : ".temp.dovecot";
3927a2114ac30fcc747741dc08151fe70e400463Baofeng Wang if(set->temp_dir == NULL)
3927a2114ac30fcc747741dc08151fe70e400463Baofeng Wang (*fs_r)->temp_path_prefix = i_strconcat("/tmp/",
3927a2114ac30fcc747741dc08151fe70e400463Baofeng Wang temp_file_prefix, NULL);
3927a2114ac30fcc747741dc08151fe70e400463Baofeng Wang else
3927a2114ac30fcc747741dc08151fe70e400463Baofeng Wang (*fs_r)->temp_path_prefix = i_strconcat(set->temp_dir, "/",
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen temp_file_prefix, NULL);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomiint fs_init_from_string(const char *str, const struct fs_settings *set,
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi struct fs **fs_r, const char **error_r)
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi{
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi const char *args = strpbrk(str, " :");
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi if (args == NULL)
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi args = "";
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi else
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi str = t_strdup_until(str, args++);
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi return fs_init(str, args, set, fs_r, error_r);
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi}
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomi
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainenvoid fs_deinit(struct fs **fs)
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen{
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen fs_unref(fs);
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen}
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainenvoid fs_ref(struct fs *fs)
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen{
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen i_assert(fs->refcount > 0);
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen fs->refcount++;
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen}
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainenvoid fs_unref(struct fs **_fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs *fs = *_fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen string_t *last_error = fs->last_error;
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen struct array module_contexts_arr = fs->module_contexts.arr;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen unsigned int i;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen i_assert(fs->refcount > 0);
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *_fs = NULL;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen if (--fs->refcount > 0)
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen return;
e853125eceafe8c3e286ce9b4176f6df4b806aceTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs->files_open_count > 0) {
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen i_panic("fs-%s: %u files still open (first = %s)",
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen fs->name, fs->files_open_count, fs_file_path(fs->files));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen i_assert(fs->files == NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen event_unref(&fs->event);
02cc28525a97ee60cb512c8eb15908082743bfe9Timo Sirainen i_free(fs->username);
02cc28525a97ee60cb512c8eb15908082743bfe9Timo Sirainen i_free(fs->session_id);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_free(fs->temp_path_prefix);
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen for (i = 0; i < FS_OP_COUNT; i++) {
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen if (fs->stats.timings[i] != NULL)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen stats_dist_deinit(&fs->stats.timings[i]);
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen }
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen T_BEGIN {
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen fs->v.deinit(fs);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen } T_END;
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen array_free_i(&module_contexts_arr);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen str_free(&last_error);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainenstruct fs *fs_get_parent(struct fs *fs)
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen{
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen return fs->parent;
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen}
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainenconst char *fs_get_driver(struct fs *fs)
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen{
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen return fs->name;
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen}
4c827a0925f5f77d1067e646fc2f615678c50d66Timo Sirainen
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainenconst char *fs_get_root_driver(struct fs *fs)
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen{
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen while (fs->parent != NULL)
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen fs = fs->parent;
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen return fs->name;
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen}
75a2a8361aafd27d01eef00c23d784e329b695c2Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstruct fs_file *fs_file_init(struct fs *fs, const char *path, int mode_flags)
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen{
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen return fs_file_init_with_event(fs, fs->event, path, mode_flags);
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen}
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainenstruct fs_file *fs_file_init_with_event(struct fs *fs, struct event *event,
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen const char *path, int mode_flags)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs_file *file;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(path != NULL);
60fe2f162e61eae1c2821bf9705c7ff7987c8adeTimo Sirainen i_assert((mode_flags & FS_OPEN_FLAG_ASYNC_NOQUEUE) == 0 ||
60fe2f162e61eae1c2821bf9705c7ff7987c8adeTimo Sirainen (mode_flags & FS_OPEN_FLAG_ASYNC) != 0);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen T_BEGIN {
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen file = fs->v.file_alloc();
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen file->fs = fs;
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen file->flags = mode_flags & ~FS_OPEN_MODE_MASK;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen file->event = fs_create_event(fs, event);
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen fs->v.file_init(file, path, mode_flags & FS_OPEN_MODE_MASK,
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen mode_flags & ~FS_OPEN_MODE_MASK);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } T_END;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs->files_open_count++;
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen DLLIST_PREPEND(&fs->files, file);
15fa038377f9e3da24d088aa8a908919581c60a6Timo Sirainen
15fa038377f9e3da24d088aa8a908919581c60a6Timo Sirainen fs_set_metadata(file, FS_METADATA_ORIG_PATH, path);
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;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen struct event *event = file->event;
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
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen fs_file_close(file);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen DLLIST_REMOVE(&file->fs->files, file);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen file->fs->files_open_count--;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen T_BEGIN {
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen file->fs->v.file_deinit(file);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen } T_END;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen event_unref(&event);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen if (metadata_pool != NULL)
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen pool_unref(&metadata_pool);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen}
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainenvoid fs_file_close(struct fs_file *file)
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen{
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen i_assert(!file->writing_stream);
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen i_assert(file->output == NULL);
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen
ef064b29e237d6093727e18f997f680881567771Timo Sirainen if (file->pending_read_input != NULL)
ef064b29e237d6093727e18f997f680881567771Timo Sirainen i_stream_unref(&file->pending_read_input);
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen if (file->seekable_input != NULL)
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen i_stream_unref(&file->seekable_input);
ef064b29e237d6093727e18f997f680881567771Timo Sirainen
ef064b29e237d6093727e18f997f680881567771Timo Sirainen if (file->copy_input != NULL) {
ef064b29e237d6093727e18f997f680881567771Timo Sirainen i_stream_unref(&file->copy_input);
6d035effc27b2556393e6b26fbe1a846741cdb8eAki Tuomi fs_write_stream_abort_error(file, &file->copy_output, "fs_file_close(%s)",
6d035effc27b2556393e6b26fbe1a846741cdb8eAki Tuomi o_stream_get_name(file->copy_output));
ef064b29e237d6093727e18f997f680881567771Timo Sirainen }
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen i_free_and_null(file->write_digest);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen if (file->fs->v.file_close != NULL) T_BEGIN {
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen file->fs->v.file_close(file);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen /* check this only after closing, because some of the fs backends keep
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen the istream internally open and don't call the destroy-callback
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen until after file_close() */
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen i_assert(!file->istream_open);
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) {
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen i_assert(!array_is_created(&file->metadata));
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
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainenvoid fs_metadata_init_or_clear(struct fs_file *file)
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen{
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen if (file->metadata_pool == NULL)
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen fs_metadata_init(file);
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen else T_BEGIN {
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen const struct fs_metadata *md;
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen ARRAY_TYPE(fs_metadata) internal_metadata;
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen t_array_init(&internal_metadata, 4);
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen array_foreach(&file->metadata, md) {
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen if (strncmp(md->key, FS_METADATA_INTERNAL_PREFIX,
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen strlen(FS_METADATA_INTERNAL_PREFIX)) == 0)
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen array_append(&internal_metadata, md, 1);
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen }
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen array_clear(&file->metadata);
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen array_append_array(&file->metadata, &internal_metadata);
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen } T_END;
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen}
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainenstatic struct fs_metadata *
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainenfs_metadata_find_md(const ARRAY_TYPE(fs_metadata) *metadata,
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen const char *key)
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen{
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen struct fs_metadata *md;
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen array_foreach_modifiable(metadata, md) {
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen if (strcmp(md->key, key) == 0)
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen return md;
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen }
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen return NULL;
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen}
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo 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);
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen metadata = fs_metadata_find_md(&file->metadata, key);
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen if (metadata == NULL) {
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen metadata = array_append_space(&file->metadata);
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen metadata->key = p_strdup(file->metadata_pool, key);
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata->value = p_strdup(file->metadata_pool, value);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen}
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen
5b302b077a61204beb6852b89927952840458ccbTimo Sirainenconst char *fs_metadata_find(const ARRAY_TYPE(fs_metadata) *metadata,
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen const char *key)
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen{
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen const struct fs_metadata *md;
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen
8add900109e3782e6441d820d8808b72b20600fbTimo Sirainen if (!array_is_created(metadata))
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen return NULL;
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen md = fs_metadata_find_md(metadata, key);
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen return md == NULL ? NULL : md->value;
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen}
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_set_metadata(struct fs_file *file, const char *key, const char *value)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
3b4b517a554cdaa004c583b6f330893b94188d5eTimo Sirainen i_assert(key != NULL);
3b4b517a554cdaa004c583b6f330893b94188d5eTimo Sirainen i_assert(value != NULL);
3b4b517a554cdaa004c583b6f330893b94188d5eTimo Sirainen
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen if (file->fs->v.set_metadata != NULL) T_BEGIN {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs->v.set_metadata(file, key, value);
4c649f0338c2031afdd62a503c336e3f74bc9954Timo Sirainen if (strncmp(key, FS_METADATA_INTERNAL_PREFIX,
4c649f0338c2031afdd62a503c336e3f74bc9954Timo Sirainen strlen(FS_METADATA_INTERNAL_PREFIX)) == 0) {
4c649f0338c2031afdd62a503c336e3f74bc9954Timo Sirainen /* internal metadata change, which isn't stored. */
4c649f0338c2031afdd62a503c336e3f74bc9954Timo Sirainen } else {
4c649f0338c2031afdd62a503c336e3f74bc9954Timo Sirainen file->metadata_changed = TRUE;
4c649f0338c2031afdd62a503c336e3f74bc9954Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenstatic void fs_file_timing_start(struct fs_file *file, enum fs_op op)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen{
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!file->fs->set.enable_timing)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen return;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (file->timing_start[op].tv_sec == 0) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (gettimeofday(&file->timing_start[op], NULL) < 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen i_fatal("gettimeofday() failed: %m");
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen}
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenstatic void
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenfs_timing_end(struct stats_dist **timing, const struct timeval *start_tv)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen{
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen struct timeval now;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen long long diff;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (gettimeofday(&now, NULL) < 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen i_fatal("gettimeofday() failed: %m");
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen diff = timeval_diff_usecs(&now, start_tv);
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen if (diff > 0) {
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen if (*timing == NULL)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen *timing = stats_dist_init();
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen stats_dist_add(*timing, diff);
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen }
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen}
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenvoid fs_file_timing_end(struct fs_file *file, enum fs_op op)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen{
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!file->fs->set.enable_timing || file->timing_start[op].tv_sec == 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen return;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen fs_timing_end(&file->fs->stats.timings[op], &file->timing_start[op]);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* don't count this again */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen file->timing_start[op].tv_sec = 0;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen}
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_get_metadata(struct fs_file *file,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const ARRAY_TYPE(fs_metadata) **metadata_r)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen int ret;
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo 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 }
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted &&
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen !file->lookup_metadata_counted) {
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->lookup_metadata_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.lookup_metadata_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_METADATA);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen T_BEGIN {
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen ret = file->fs->v.get_metadata(file, metadata_r);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN))
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_METADATA);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainenint fs_lookup_metadata(struct fs_file *file, const char *key,
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen const char **value_r)
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen{
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen const ARRAY_TYPE(fs_metadata) *metadata;
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen if (fs_get_metadata(file, &metadata) < 0)
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen return -1;
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen *value_r = fs_metadata_find(metadata, key);
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen return *value_r != NULL ? 1 : 0;
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen}
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo 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
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainenstruct fs *fs_file_fs(struct fs_file *file)
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen{
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen return file->fs;
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen}
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainenstruct event *fs_file_event(struct fs_file *file)
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen{
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen return file->event;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen}
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainenstatic void ATTR_FORMAT(2, 0)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainenfs_set_verror(struct fs *fs, const char *fmt, va_list args)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen{
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen if (fs->parent != NULL)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen fs_set_verror(fs->parent, fmt, args);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen else {
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen str_truncate(fs->last_error, 0);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen str_vprintfa(fs->last_error, fmt, args);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen }
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen}
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_last_error(struct fs *fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen if (fs->parent != NULL)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen return fs_last_error(fs->parent);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo 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{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen bool ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted) {
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen file->read_or_prefetch_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.prefetch_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_PREFETCH);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.prefetch(file, length);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_PREFETCH);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
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);
573424407a2d3c1453638a643583a7cf10c129e1Phil Carmody ret = i_stream_read_bytes(file->pending_read_input, &data,
573424407a2d3c1453638a643583a7cf10c129e1Phil Carmody &data_size, size);
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) {
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen fs_set_error(file->fs, "read(%s) failed: %s",
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen i_stream_get_name(file->pending_read_input),
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen i_stream_get_error(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{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted) {
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen file->read_or_prefetch_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.read_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_READ);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen if (file->fs->v.read != NULL) {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.read(file, buf, size);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN))
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_READ);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen }
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
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainenstatic void fs_file_istream_destroyed(struct fs_file *file)
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen{
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen i_assert(file->istream_open);
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen file->istream_open = FALSE;
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen}
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo 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
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted) {
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen file->read_or_prefetch_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.read_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_READ);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen if (file->seekable_input != NULL) {
db5d7fbdb3eaf8b588633f874190aa34363e5597Timo Sirainen /* allow multiple open streams, each in a different position */
db5d7fbdb3eaf8b588633f874190aa34363e5597Timo Sirainen input = i_stream_create_limit(file->seekable_input, (uoff_t)-1);
db5d7fbdb3eaf8b588633f874190aa34363e5597Timo Sirainen i_stream_seek(input, 0);
db5d7fbdb3eaf8b588633f874190aa34363e5597Timo Sirainen return input;
4948718872b7dacb239e7db20393cd232bf4568bTimo Sirainen }
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen i_assert(!file->istream_open);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen input = file->fs->v.read_stream(file, max_buffer_size);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (input->stream_errno != 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read failed already */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_READ);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen return input;
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (file->fs->set.enable_timing) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen struct istream *input2 = i_stream_create_fs_stats(input, file);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen i_stream_unref(&input);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen input = input2;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo 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 }
0ed8bcc501d6f4839076353081408ee1a7710106Timo Sirainen file->seekable_input = input;
0ed8bcc501d6f4839076353081408ee1a7710106Timo Sirainen i_stream_ref(file->seekable_input);
0ed8bcc501d6f4839076353081408ee1a7710106Timo Sirainen
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read the whole input stream before returning */
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody while ((ret = i_stream_read_more(input, &data, &size)) >= 0) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_skip(input, size);
d34b8a75f3b74e26adc85b6436d033b1dcfaf9daTimo Sirainen if (ret == 0)
d34b8a75f3b74e26adc85b6436d033b1dcfaf9daTimo Sirainen fs_wait_async(file->fs);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_seek(input, 0);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen }
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen file->istream_open = TRUE;
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen i_stream_add_destroy_callback(input, fs_file_istream_destroyed, file);
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;
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi fs_write_stream_abort_error(file, &output, "fs_write(%s) failed: %s",
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi o_stream_get_name(output),
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi o_stream_get_error(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{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen if (file->fs->v.write != NULL) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_WRITE);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.write(file, data, size);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN)) {
b76b97a5b240ecfdd38d34645caa930d0de2ff27Timo Sirainen file->fs->stats.write_count++;
507dcd9fee9b8f032a60af3ea35de4da0e5653c9Timo Sirainen file->fs->stats.write_bytes += size;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_WRITE);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen }
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{
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen i_assert(!file->writing_stream);
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen i_assert(file->output == NULL);
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen file->writing_stream = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.write_count++;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen file->fs->v.write_stream(file);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(file->output != NULL);
af8e9722500efbba1bb58a96302a71977e1dbe92Timo Sirainen o_stream_cork(file->output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return file->output;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainenstatic int fs_write_stream_finish_int(struct fs_file *file, bool success)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen i_assert(file->writing_stream);
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_WRITE);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen T_BEGIN {
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen ret = file->fs->v.write_stream_finish(file, success);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen } T_END;
8f8858ba3f4b14d3f651e091b5790f633e7f9fe5Timo Sirainen if (ret != 0) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_WRITE);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen file->metadata_changed = FALSE;
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen } else {
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen /* write didn't finish yet. this shouldn't happen if we
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen indicated a failure. */
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen i_assert(success);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen }
98ff8998f6ddd019d22db541cdb316df2c37f15dTimo Sirainen if (ret != 0) {
98ff8998f6ddd019d22db541cdb316df2c37f15dTimo Sirainen i_assert(file->output == NULL);
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen file->writing_stream = FALSE;
98ff8998f6ddd019d22db541cdb316df2c37f15dTimo Sirainen }
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return ret;
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen}
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainenint fs_write_stream_finish(struct fs_file *file, struct ostream **output)
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen{
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen bool success = TRUE;
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
f6754d90ea6bbe1386eb4d39f603cf01edde4ef1Timo Sirainen i_assert(*output == file->output || *output == NULL);
98ff8998f6ddd019d22db541cdb316df2c37f15dTimo Sirainen i_assert(output != &file->output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *output = NULL;
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen if (file->output != NULL) {
526af69146c11a7a2c429f026e69fd66be845949Timo Sirainen o_stream_uncork(file->output);
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen if ((ret = o_stream_finish(file->output)) <= 0) {
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen i_assert(ret < 0);
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen fs_set_error(file->fs, "write(%s) failed: %s",
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen o_stream_get_name(file->output),
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen o_stream_get_error(file->output));
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen success = FALSE;
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen }
507dcd9fee9b8f032a60af3ea35de4da0e5653c9Timo Sirainen file->fs->stats.write_bytes += file->output->offset;
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen }
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return fs_write_stream_finish_int(file, success);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainenint fs_write_stream_finish_async(struct fs_file *file)
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen{
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return fs_write_stream_finish_int(file, TRUE);
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen}
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomistatic void fs_write_stream_abort(struct fs_file *file, struct ostream **output)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
a0cf7d3924dec409e6eadaf3237fcecd4194ec75Timo Sirainen int ret;
a0cf7d3924dec409e6eadaf3237fcecd4194ec75Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(*output == file->output);
a0cf7d3924dec409e6eadaf3237fcecd4194ec75Timo Sirainen i_assert(file->output != NULL);
a0cf7d3924dec409e6eadaf3237fcecd4194ec75Timo Sirainen i_assert(output != &file->output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *output = NULL;
0a222deffd3f48e43aa61ceb73a4faeeeea5e12cTimo Sirainen o_stream_abort(file->output);
eaac2584903d75da935eeee5098a7baa904f1afdTimo Sirainen /* make sure we don't have an old error lying around */
a0cf7d3924dec409e6eadaf3237fcecd4194ec75Timo Sirainen ret = fs_write_stream_finish_int(file, FALSE);
a0cf7d3924dec409e6eadaf3237fcecd4194ec75Timo Sirainen i_assert(ret != 0);
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi}
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomivoid fs_write_stream_abort_error(struct fs_file *file, struct ostream **output, const char *error_fmt, ...)
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi{
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi va_list args;
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi va_start(args, error_fmt);
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi fs_set_verror(file->fs, error_fmt, args);
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi fs_write_stream_abort(file, output);
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi va_end(args);
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi}
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomivoid fs_write_stream_abort_parent(struct fs_file *file, struct ostream **output)
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi{
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi i_assert(file->parent != NULL);
72e25ec1e51eeeaf038584835171fcad0203497fTimo Sirainen i_assert(fs_file_last_error(file->parent) != NULL);
1d8622b44b8ba6009429cd500eee03d20a7ad118Aki Tuomi fs_write_stream_abort(file->parent, output);
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi}
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomi
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainenvoid fs_write_set_hash(struct fs_file *file, const struct hash_method *method,
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen const void *digest)
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen{
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen file->write_digest_method = method;
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen i_free(file->write_digest);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen file->write_digest = i_malloc(method->digest_size);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen memcpy(file->write_digest, digest, method->digest_size);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen}
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo 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
d34b8a75f3b74e26adc85b6436d033b1dcfaf9daTimo Sirainenvoid fs_wait_async(struct fs *fs)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen /* recursion not allowed */
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen i_assert(fs->prev_ioloop == NULL);
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen
d34b8a75f3b74e26adc85b6436d033b1dcfaf9daTimo Sirainen if (fs->v.wait_async != NULL) T_BEGIN {
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen fs->prev_ioloop = current_ioloop;
d34b8a75f3b74e26adc85b6436d033b1dcfaf9daTimo Sirainen fs->v.wait_async(fs);
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen i_assert(current_ioloop == fs->prev_ioloop);
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen fs->prev_ioloop = NULL;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainenbool fs_switch_ioloop(struct fs *fs)
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen{
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen bool ret = FALSE;
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen if (fs->v.switch_ioloop != NULL) {
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen T_BEGIN {
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen ret = fs->v.switch_ioloop(fs);
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen } T_END;
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen } else if (fs->parent != NULL) {
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen ret = fs_switch_ioloop(fs->parent);
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen }
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen return ret;
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen}
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint fs_lock(struct fs_file *file, unsigned int secs, struct fs_lock **lock_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.lock(file, secs, lock_r);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
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;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen lock->file->fs->v.unlock(lock);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_exists(struct fs_file *file)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen struct stat st;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen if (file->fs->v.exists == NULL) {
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen /* fallback to stat() */
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen if (fs_stat(file, &st) == 0)
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen return 1;
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen else
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen return errno == ENOENT ? 0 : -1;
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen }
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_EXISTS);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.exists(file);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen if (!(ret < 0 && errno == EAGAIN)) {
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen file->fs->stats.exists_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_EXISTS);
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_stat(struct fs_file *file, struct stat *st_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen if (file->fs->v.stat == NULL) {
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen fs_set_error(file->fs, "fs_stat() not supported");
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen return -1;
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen }
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen
4dfd8a717fe2e1c01aeddd2992bc9745ca8e0abbTimo Sirainen if (!file->read_or_prefetch_counted &&
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen !file->lookup_metadata_counted && !file->stat_counted) {
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->stat_counted = TRUE;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen file->fs->stats.stat_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_STAT);
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.stat(file, st_r);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN))
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_STAT);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainenint fs_get_nlinks(struct fs_file *file, nlink_t *nlinks_r)
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen{
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen int ret;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen if (file->fs->v.get_nlinks == NULL) {
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen struct stat st;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen if (fs_stat(file, &st) < 0)
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen return -1;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen *nlinks_r = st.st_nlink;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen return 0;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen }
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen if (!file->read_or_prefetch_counted &&
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen !file->lookup_metadata_counted && !file->stat_counted) {
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen file->stat_counted = TRUE;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen file->fs->stats.stat_count++;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen fs_file_timing_start(file, FS_OP_STAT);
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen }
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen T_BEGIN {
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen ret = file->fs->v.get_nlinks(file, nlinks_r);
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen } T_END;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen if (!(ret < 0 && errno == EAGAIN))
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen fs_file_timing_end(file, FS_OP_STAT);
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen return ret;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen}
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_default_copy(struct fs_file *src, struct fs_file *dest)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen{
fdef08644ba66b9db8fe4fc041ecc31a1ec9524bAki Tuomi int tmp_errno;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen /* we're going to be counting this as read+write, so remove the
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen copy_count we just added */
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen dest->fs->stats.copy_count--;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo 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);
3010259e7834bdad8cb77e8bcbb9fc5c700897a2Timo 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 }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen switch (o_stream_send_istream(dest->copy_output, dest->copy_input)) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen break;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
d04f3e064ceb2ba1d734182937a7115739ebadbeTimo Sirainen fs_set_error_async(dest->fs);
d04f3e064ceb2ba1d734182937a7115739ebadbeTimo Sirainen return -1;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi fs_write_stream_abort_error(dest, &dest->copy_output,
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi "read(%s) failed: %s",
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi i_stream_get_name(dest->copy_input),
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi i_stream_get_error(dest->copy_input));
72e25ec1e51eeeaf038584835171fcad0203497fTimo Sirainen errno = dest->copy_input->stream_errno;
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen i_stream_unref(&dest->copy_input);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
fdef08644ba66b9db8fe4fc041ecc31a1ec9524bAki Tuomi /* errno might not survive abort error */
fdef08644ba66b9db8fe4fc041ecc31a1ec9524bAki Tuomi tmp_errno = dest->copy_output->stream_errno;
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi fs_write_stream_abort_error(dest, &dest->copy_output,
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi "write(%s) failed: %s",
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi o_stream_get_name(dest->copy_output),
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi o_stream_get_error(dest->copy_output));
fdef08644ba66b9db8fe4fc041ecc31a1ec9524bAki Tuomi errno = tmp_errno;
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen i_stream_unref(&dest->copy_input);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen return -1;
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen }
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_stream_unref(&dest->copy_input);
3010259e7834bdad8cb77e8bcbb9fc5c700897a2Timo 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{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(src->fs == dest->fs);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen if (src->fs->v.copy == NULL) {
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen fs_set_error(src->fs, "fs_copy() not supported");
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen return -1;
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen }
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(dest, FS_OP_COPY);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = src->fs->v.copy(src, dest);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN)) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(dest, FS_OP_COPY);
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen dest->fs->stats.copy_count++;
392538eef147981f6d818cd14cabc94cf8049d8eTimo Sirainen dest->metadata_changed = FALSE;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainenint fs_copy_finish_async(struct fs_file *dest)
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = dest->fs->v.copy(NULL, dest);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!(ret < 0 && errno == EAGAIN)) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(dest, FS_OP_COPY);
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen dest->fs->stats.copy_count++;
392538eef147981f6d818cd14cabc94cf8049d8eTimo Sirainen dest->metadata_changed = FALSE;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen}
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_rename(struct fs_file *src, struct fs_file *dest)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(src->fs == dest->fs);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(dest, FS_OP_RENAME);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = src->fs->v.rename(src, dest);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen if (!(ret < 0 && errno == EAGAIN)) {
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen dest->fs->stats.rename_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(dest, FS_OP_RENAME);
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_delete(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen i_assert(!file->writing_stream);
d4a85e170c276969ba14c598a3efdbfaf33c7fc6Timo Sirainen
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_start(file, FS_OP_DELETE);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.delete_file(file);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen if (!(ret < 0 && errno == EAGAIN)) {
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen file->fs->stats.delete_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen fs_file_timing_end(file, FS_OP_DELETE);
fece64e92adf33622ff6238f4050100f305fc007Timo Sirainen }
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenstruct fs_iter *
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenfs_iter_init(struct fs *fs, const char *path, enum fs_iter_flags flags)
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen{
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen return fs_iter_init_with_event(fs, fs->event, path, flags);
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen}
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainenstruct fs_iter *
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainenfs_iter_init_with_event(struct fs *fs, struct event *event,
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen const char *path, enum fs_iter_flags flags)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen struct fs_iter *iter;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen struct timeval now = ioloop_timeval;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen i_assert((flags & FS_ITER_FLAG_OBJECTIDS) == 0 ||
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen (fs_get_properties(fs) & FS_PROPERTY_OBJECTIDS) != 0);
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen fs->stats.iter_count++;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (fs->set.enable_timing) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (gettimeofday(&now, NULL) < 0)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen i_fatal("gettimeofday() failed: %m");
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen if (fs->v.iter_init == NULL) {
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen iter = i_new(struct fs_iter, 1);
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen iter->fs = fs;
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen } else T_BEGIN {
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen iter = fs->v.iter_alloc();
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen iter->fs = fs;
4110f968c96680d61ca47bd7a903a254b911addaTimo Sirainen iter->flags = flags;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen iter->event = fs_create_event(fs, event);
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen fs->v.iter_init(iter, path, flags);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen iter->start_time = now;
e13e798694ba1b0d0a5cf471600168eeaa8d2af4Timo Sirainen DLLIST_PREPEND(&fs->iters, iter);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return iter;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_iter_deinit(struct fs_iter **_iter)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs_iter *iter = *_iter;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen struct event *event = iter->event;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen int ret;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen *_iter = NULL;
e13e798694ba1b0d0a5cf471600168eeaa8d2af4Timo Sirainen DLLIST_REMOVE(&iter->fs->iters, iter);
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen if (iter->fs->v.iter_deinit == NULL) {
7603577788c59274c81dd9e4f6661dfdb5f87f4fAki Tuomi fs_set_error(iter->fs, "FS iteration not supported");
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen i_free(iter);
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen ret = -1;
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen } else T_BEGIN {
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = iter->fs->v.iter_deinit(iter);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen } T_END;
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen event_unref(&event);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenconst char *fs_iter_next(struct fs_iter *iter)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen const char *ret;
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen if (iter->fs->v.iter_next == NULL)
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen return NULL;
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen T_BEGIN {
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen ret = iter->fs->v.iter_next(iter);
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen } T_END;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (iter->start_time.tv_sec != 0 &&
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen (ret != NULL || !fs_iter_have_more(iter))) {
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* first result returned - count this as the finish time, since
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen we don't want to count the time caller spends on this
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen iteration. */
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen fs_timing_end(&iter->fs->stats.timings[FS_OP_ITER], &iter->start_time);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* don't count this again */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen iter->start_time.tv_sec = 0;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen }
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainenvoid fs_iter_set_async_callback(struct fs_iter *iter,
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen fs_file_async_callback_t *callback,
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen void *context)
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen{
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen iter->async_callback = callback;
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen iter->async_context = context;
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen}
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainenbool fs_iter_have_more(struct fs_iter *iter)
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen{
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen return iter->async_have_more;
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen}
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainen
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainenconst struct fs_stats *fs_get_stats(struct fs *fs)
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen{
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen return &fs->stats;
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen}
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo 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);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen fs_set_verror(fs, 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);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen fs_set_verror(fs, fmt, args);
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen e_error(fs->event, "%s", fs_last_error(fs));
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}
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainen
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainenstatic uint64_t
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainenfs_stats_count_ops(const struct fs_stats *stats, const enum fs_op ops[],
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen unsigned int ops_count)
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen{
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen uint64_t ret = 0;
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen for (unsigned int i = 0; i < ops_count; i++) {
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen if (stats->timings[ops[i]] != NULL)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen ret += stats_dist_get_sum(stats->timings[ops[i]]);
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen }
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen return ret;
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen}
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainenuint64_t fs_stats_get_read_usecs(const struct fs_stats *stats)
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainen{
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen const enum fs_op read_ops[] = {
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen FS_OP_METADATA, FS_OP_PREFETCH, FS_OP_READ, FS_OP_EXISTS,
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen FS_OP_STAT, FS_OP_ITER
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen };
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen return fs_stats_count_ops(stats, read_ops, N_ELEMENTS(read_ops));
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainen}
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainen
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainenuint64_t fs_stats_get_write_usecs(const struct fs_stats *stats)
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainen{
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen const enum fs_op write_ops[] = {
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen FS_OP_WRITE, FS_OP_COPY, FS_OP_DELETE
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen };
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen return fs_stats_count_ops(stats, write_ops, N_ELEMENTS(write_ops));
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainen}
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainenstruct fs_file *
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainenfs_file_init_parent(struct fs_file *parent, const char *path, int mode_flags)
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen{
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen return fs_file_init_with_event(parent->fs->parent, parent->event,
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen path, mode_flags);
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen}
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainenstruct fs_iter *
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainenfs_iter_init_parent(struct fs_iter *parent,
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen const char *path, enum fs_iter_flags flags)
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen{
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen return fs_iter_init_with_event(parent->fs->parent, parent->event,
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen path, flags);
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen}