bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "lib.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "str.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "istream.h"
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#include "ostream.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "fs-sis-common.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#define QUEUE_DIR_NAME "queue"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct sis_queue_fs {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen char *queue_dir;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct sis_queue_fs_file {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs_file file;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct sis_queue_fs *fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic struct fs *fs_sis_queue_alloc(void)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_queue_fs *fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs = i_new(struct sis_queue_fs, 1);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs->fs = fs_class_sis_queue;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return &fs->fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenfs_sis_queue_init(struct fs *_fs, const char *args,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const struct fs_settings *set)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct sis_queue_fs *fs = (struct sis_queue_fs *)_fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const char *p, *parent_name, *parent_args, *error;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* <queue_dir>:<parent fs>[:<args>] */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen p = strchr(args, ':');
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (p == NULL || p[1] == '\0') {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_fs, "Parent filesystem not given as parameter");
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs->queue_dir = i_strdup_until(args, p);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen parent_name = p + 1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen parent_args = strchr(parent_name, ':');
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (parent_args == NULL)
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen parent_args = "";
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen else
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen parent_name = t_strdup_until(parent_name, parent_args++);
e597ab14b6fc01a602b35d26177d09643af8fed5Timo Sirainen if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) {
1cc7a6c6a986b972fdb7eac146f4ca8036aca4e6Timo Sirainen fs_set_error(_fs, "%s", error);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_queue_deinit(struct fs *_fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_queue_fs *fs = (struct sis_queue_fs *)_fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
e597ab14b6fc01a602b35d26177d09643af8fed5Timo Sirainen if (_fs->parent != NULL)
e597ab14b6fc01a602b35d26177d09643af8fed5Timo Sirainen fs_deinit(&_fs->parent);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(fs->queue_dir);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(fs);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenstatic struct fs_file *fs_sis_queue_file_alloc(void)
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen{
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct sis_queue_fs_file *file = i_new(struct sis_queue_fs_file, 1);
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen return &file->file;
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen}
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenstatic void
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenfs_sis_queue_file_init(struct fs_file *_file, const char *path,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen enum fs_open_mode mode, enum fs_open_flags flags)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct sis_queue_fs_file *file = (struct sis_queue_fs_file *)_file;
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct sis_queue_fs *fs = (struct sis_queue_fs *)_file->fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->file.path = i_strdup(path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs = fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (mode == FS_OPEN_MODE_APPEND)
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen fs_set_error(_file->fs, "APPEND mode not supported");
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen else
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen file->file.parent = fs_file_init_parent(_file, path, mode | flags);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic void fs_sis_queue_file_deinit(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_queue_fs_file *file = (struct sis_queue_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (_file->parent != NULL)
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_file_deinit(&_file->parent);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(file->file.path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_queue_add(struct sis_queue_fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_queue_fs *fs = (struct sis_queue_fs *)file->file.fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs_file *queue_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const char *fname, *path, *queue_path;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen path = fs_file_path(&file->file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fname = strrchr(path, '/');
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fname != NULL)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fname++;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen else
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fname = path;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen queue_path = t_strdup_printf("%s/%s", fs->queue_dir, fname);
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen queue_file = fs_file_init_parent(&file->file, queue_path, FS_OPEN_MODE_CREATE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_write(queue_file, "", 0) < 0 && errno != EEXIST)
b254b8ec1ea03f400f1390ec24afd826a8c335d9Timo Sirainen e_error(file->file.event, "%s", fs_file_last_error(queue_file));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_file_deinit(&queue_file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_queue_write(struct fs_file *_file, const void *data, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_queue_fs_file *file = (struct sis_queue_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (_file->parent == NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return -1;
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (fs_write(_file->parent, data, size) < 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen T_BEGIN {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_sis_queue_add(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } T_END;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_queue_write_stream(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(_file->output == NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (_file->parent == NULL) {
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen _file->output = o_stream_create_error_str(EINVAL, "%s",
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen fs_file_last_error(_file));
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen } else {
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen _file->output = fs_write_stream(_file->parent);
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen o_stream_set_name(_file->output, _file->path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_queue_write_stream_finish(struct fs_file *_file, bool success)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_queue_fs_file *file = (struct sis_queue_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (!success) {
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (_file->parent != NULL)
b8f4e3aa58caa7ee16cf21a21f92521bf05cbdc4Aki Tuomi fs_write_stream_abort_parent(_file, &_file->output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (fs_write_stream_finish(_file->parent, &_file->output) < 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen T_BEGIN {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_sis_queue_add(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } T_END;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_sis_queue_delete(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen T_BEGIN {
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_sis_try_unlink_hash_file(_file->fs, _file->parent);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } T_END;
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen return fs_delete(_file->parent);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenconst struct fs fs_class_sis_queue = {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen .name = "sis-queue",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen .v = {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_sis_queue_alloc,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_sis_queue_init,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_sis_queue_deinit,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_get_properties,
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen fs_sis_queue_file_alloc,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_sis_queue_file_init,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_sis_queue_file_deinit,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_file_close,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_file_get_path,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_set_async_callback,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_wait_async,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_set_metadata,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_get_metadata,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_prefetch,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_read,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_read_stream,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_sis_queue_write,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_sis_queue_write_stream,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_sis_queue_write_stream_finish,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_lock,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_unlock,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_exists,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_stat,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_copy,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_rename,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_sis_queue_delete,
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen fs_wrapper_iter_alloc,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen fs_wrapper_iter_init,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen NULL,
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen NULL,
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen NULL,
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen fs_wrapper_get_nlinks,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};