fs-api.c revision a8c5a86d183db25a57bf193c06b41e092ec2e151
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2010-2014 Dovecot authors, see the included COPYING file */
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)
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,
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_register(const struct fs *fs_class)
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainenstatic void fs_classes_deinit(void)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_classes_init(void)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic const struct fs *fs_class_find(const char *driver)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_try_load_plugin(const char *driver)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen const char *module_name = t_strdup_printf("fs_%s", driver);
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_modules = module_dir_load_missing(fs_modules, MODULE_DIR,
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module = module_dir_find(fs_modules, module_name);
898e99166f46b4f37ae45fe5594ed952b5befe6dTimo Sirainen module_get_symbol(module, t_strdup_printf("fs_class_%s", driver));
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainenint fs_init(const char *driver, const char *args,
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen *error_r = t_strdup_printf("Unknown fs driver: %s", driver);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (fs_alloc(fs_class, args, set, fs_r, error_r) < 0)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen temp_file_prefix = set->temp_file_prefix != NULL ?
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen (*fs_r)->temp_path_prefix = i_strconcat(set->temp_dir, "/",
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstruct fs_file *fs_file_init(struct fs *fs, const char *path, int mode_flags)
60fe2f162e61eae1c2821bf9705c7ff7987c8adeTimo Sirainen i_assert((mode_flags & FS_OPEN_FLAG_ASYNC_NOQUEUE) == 0 ||
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file = fs->v.file_init(fs, path, mode_flags & FS_OPEN_MODE_MASK,
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen file->flags = mode_flags & ~FS_OPEN_MODE_MASK;
ef064b29e237d6093727e18f997f680881567771Timo Sirainen (void)fs_write_stream_abort(file, &file->copy_output);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenenum fs_properties fs_get_properties(struct fs *fs)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen file->metadata_pool = pool_alloconly_create("fs metadata", 1024);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen p_array_init(&file->metadata, file->metadata_pool, 8);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenvoid fs_default_set_metadata(struct fs_file *file,
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata = array_append_space(&file->metadata);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata->key = p_strdup(file->metadata_pool, key);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata->value = p_strdup(file->metadata_pool, value);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_set_metadata(struct fs_file *file, const char *key, const char *value)
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen if (file->fs->v.set_metadata != NULL) T_BEGIN {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(file->fs, "Metadata not supported by backend");
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return file->fs->v.get_metadata(file, metadata_r);
3dcb9fd82c1edd40bea1ad572ed39f024686e463Timo Sirainen return file->fs->v.get_path == NULL ? file->path :
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainenfs_set_verror(struct fs *fs, const char *fmt, va_list args)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return "BUG: Unknown fs error";
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_file_last_error(struct fs_file *file)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenbool fs_prefetch(struct fs_file *file, uoff_t length)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read_via_stream(struct fs_file *file, void *buf, size_t size)
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen const unsigned char *data;
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen file->pending_read_input = fs_read_stream(file, size+1);
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen ret = i_stream_read_data(file->pending_read_input,
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen if (ret < 0 && file->pending_read_input->stream_errno != 0) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read(struct fs_file *file, void *buf, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement read(), but we can do it with
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct istream *fs_read_stream(struct fs_file *file, size_t max_buffer_size)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen const unsigned char *data;
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen input = file->fs->v.read_stream(file, max_buffer_size);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read failed already */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_SEEKABLE) != 0)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen else if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* need to make the stream seekable */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input = i_stream_create_seekable_path(inputs, max_buffer_size,
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_set_name(input, i_stream_get_name(inputs[0]));
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read the whole input stream before returning */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen while ((ret = i_stream_read_data(input, &data, &size, 0)) >= 0) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write_via_stream(struct fs_file *file, const void *data, size_t size)
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen if ((ret = o_stream_send(output, data, size)) < 0) {
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen fs_set_error(file->fs, "fs_write(%s) failed: %m",
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write(struct fs_file *file, const void *data, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement write(), but we can do it with
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct ostream *fs_write_stream(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint fs_write_stream_finish(struct fs_file *file, struct ostream **output)
f6754d90ea6bbe1386eb4d39f603cf01edde4ef1Timo Sirainen i_assert(*output == file->output || *output == NULL);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.write_stream_finish(file, TRUE);
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainenint fs_write_stream_finish_async(struct fs_file *file)
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen ret = file->fs->v.write_stream_finish(file, TRUE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_write_stream_abort(struct fs_file *file, struct ostream **output)
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen (void)file->fs->v.write_stream_finish(file, FALSE);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainenvoid fs_write_set_hash(struct fs_file *file, const struct hash_method *method,
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen file->write_digest = i_malloc(method->digest_size);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen memcpy(file->write_digest, digest, method->digest_size);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_file_set_async_callback(struct fs_file *file,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs->v.set_async_callback(file, callback, context);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint fs_lock(struct fs_file *file, unsigned int secs, struct fs_lock **lock_r)
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen /* fallback to stat() */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_stat(struct fs_file *file, struct stat *st_r)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_default_copy(struct fs_file *src, struct fs_file *dest)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_assert(src == NULL || src == dest->copy_src);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_input = fs_read_stream(src, IO_BLOCK_SIZE);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen while (o_stream_send_istream(dest->copy_output, dest->copy_input) > 0) ;
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen fs_write_stream_abort(dest, &dest->copy_output);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen fs_set_error(dest->fs, "write(%s) failed: %m",
1424de6d63c9166d8091a3b3ea3c1c15e5beda1eTimo Sirainen fs_write_stream_abort(dest, &dest->copy_output);
3010259e7834bdad8cb77e8bcbb9fc5c700897a2Timo Sirainen if (fs_write_stream_finish(dest, &dest->copy_output) <= 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_copy(struct fs_file *src, struct fs_file *dest)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_rename(struct fs_file *src, struct fs_file *dest)
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenfs_iter_init(struct fs *fs, const char *path, enum fs_iter_flags flags)
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainenvoid fs_iter_set_async_callback(struct fs_iter *iter,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_error(struct fs *fs, const char *fmt, ...)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_critical(struct fs *fs, const char *fmt, ...)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen i_error("fs-%s: %s", fs->name, fs_last_error(fs));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(fs, "Asynchronous operation in progress");