bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenfs_sis_init(struct fs *_fs, const char *args, const struct fs_settings *set)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const char *parent_name, *parent_args, *error;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_fs, "Parent filesystem not given as parameter");
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen parent_name = t_strdup_until(args, parent_args);
e597ab14b6fc01a602b35d26177d09643af8fed5Timo Sirainen if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if ((props & FS_SIS_REQUIRED_PROPS) != FS_SIS_REQUIRED_PROPS) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_fs, "%s backend can't be used with SIS",
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct sis_fs_file *file = i_new(struct sis_fs_file, 1);
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenfs_sis_file_init(struct fs_file *_file, const char *path,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen enum fs_open_mode mode, enum fs_open_flags flags)
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct sis_fs *fs = (struct sis_fs *)_file->fs;
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen fs_set_error(_file->fs, "APPEND mode not supported");
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen if (fs_sis_path_parse(_file->fs, path, &dir, &hash) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* if hashes/<hash> already exists, open it */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->hash_path = i_strdup_printf("%s/"HASH_DIR_NAME"/%s", dir, hash);
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen file->hash_file = fs_file_init_parent(_file, file->hash_path,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->hash_input = fs_read_stream(file->hash_file, IO_BLOCK_SIZE);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* doesn't exist */
b254b8ec1ea03f400f1390ec24afd826a8c335d9Timo Sirainen e_error(file->file.event, "Couldn't read hash file %s: %m",
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen file->file.parent = fs_file_init_parent(_file, path, mode | flags);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic void fs_sis_file_deinit(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainenstatic void fs_sis_file_close(struct fs_file *_file)
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic bool fs_sis_try_link(struct sis_fs_file *file)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (i_stream_stat(file->hash_input, FALSE, &st) < 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* we can use the existing file */
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (fs_copy(file->hash_file, file->file.parent) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* failed to use link(), continue as if it hadn't been equal */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* the hashes/ file was already replaced with something else */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_replace_hash_file(struct sis_fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* hash file didn't exist previously. we should be able to
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen create it with link() */
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (fs_copy(file->file.parent, file->hash_file) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* the file was just created. it's probably
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen a duplicate, but it's too much trouble
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen trying to deduplicate it anymore */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* replace existing hash file atomically */
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen temp_file = fs_file_init_parent(&file->file, str_c(temp_path),
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* either someone's racing us or it's a stale file.
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen try to continue. */
b254b8ec1ea03f400f1390ec24afd826a8c335d9Timo Sirainen e_error(file->file.event, "%s", fs_last_error(super_fs));
b254b8ec1ea03f400f1390ec24afd826a8c335d9Timo Sirainen e_error(file->file.event, "%s", fs_last_error(super_fs));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (fs_rename(temp_file, file->hash_file) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* apparently someone else just renamed it. ignore. */
b254b8ec1ea03f400f1390ec24afd826a8c335d9Timo Sirainen e_error(file->file.event, "%s", fs_last_error(super_fs));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_write(struct fs_file *_file, const void *data, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen stream_cmp_block(file->hash_input, data, size) &&
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* try to use existing file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_write_stream(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen _file->output = o_stream_create_error_str(EINVAL, "%s",
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen file->fs_output = fs_write_stream(_file->parent);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* compare if files are equal */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen _file->output = o_stream_create_cmp(file->fs_output,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen o_stream_set_name(_file->output, _file->path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_write_stream_finish(struct fs_file *_file, bool success)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
b8f4e3aa58caa7ee16cf21a21f92521bf05cbdc4Aki Tuomi fs_write_stream_abort_parent(_file, &file->fs_output);
b8f4e3aa58caa7ee16cf21a21f92521bf05cbdc4Aki Tuomi fs_write_stream_abort_parent(_file, &file->fs_output);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (fs_write_stream_finish(_file->parent, &file->fs_output) < 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_sis_delete(struct fs_file *_file)