fs-sis.c revision d4c3d55021bcbf2b062f4782b1cde9115d35aefc
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_copy_error(struct sis_fs *fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(&fs->fs, "%s", fs_last_error(fs->super));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_file_copy_error(struct sis_fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs *fs = (struct sis_fs *)file->file.fs;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainenfs_sis_init(const char *args, const struct fs_settings *set,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const char *parent_name, *parent_args, *error;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen *error_r = "Parent filesystem not given as parameter";
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen parent_name = t_strdup_until(args, parent_args);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (fs_init(parent_name, parent_args, set, &fs->super, &error) < 0) {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen *error_r = t_strdup_printf("%s: %s", parent_name, error);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_sis_open(struct fs *_fs, const char *path, enum fs_open_mode mode,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen enum fs_open_flags flags, struct fs_file **file_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(_fs, "APPEND mode not supported");
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_open(fs->super, path, mode | flags, &super) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_sis_path_parse(_fs, path, &dir, &hash) < 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->file.path = i_strdup(fs_file_path(super));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* if hashes/<hash> already exists, open it */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->hash_path = i_strdup_printf("%s/"HASH_DIR_NAME"/%s", dir, hash);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_open(fs->super, file->hash_path, FS_OPEN_MODE_RDONLY,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_error("fs-sis: Couldn't open hash file: %s",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_read_stream(file->hash_file, IO_BLOCK_SIZE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_close(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic ssize_t fs_sis_read(struct fs_file *_file, void *buf, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if ((ret = fs_read(file->super, buf, size)) < 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic struct istream *
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_sis_read_stream(struct fs_file *_file, size_t max_buffer_size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return fs_read_stream(file->super, max_buffer_size);
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 */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_link(file->super->fs, file->hash_path, path) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_error("fs-sis: %s", fs_last_error(file->super->fs));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* failed to use link(), continue as if it hadn't been equal */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_stat(file->super->fs, path, &st2) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_error("fs-sis: %s", fs_last_error(file->super->fs));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_error("fs-sis: %s", fs_last_error(file->super->fs));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* the hashes/ file was already replaced with something else */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_error("fs-sis: %s", fs_last_error(file->super->fs));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_replace_hash_file(struct sis_fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const char *hash_fname, *path = fs_file_path(&file->file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* hash file didn't exist previously. we should be able to
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen create it with link() */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_link(super_fs, path, file->hash_path) < 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 i_error("fs-sis: %s", fs_last_error(super_fs));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* replace existing hash file atomically */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = fs_link(super_fs, path, str_c(temp_path));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* either someone's racing us or it's a stale file.
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen try to continue. */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_unlink(super_fs, str_c(temp_path)) < 0 &&
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_error("fs-sis: %s", fs_last_error(super_fs));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = fs_link(super_fs, path, str_c(temp_path));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_error("fs-sis: %s", fs_last_error(super_fs));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_rename(super_fs, str_c(temp_path), file->hash_path) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* apparently someone else just renamed it. ignore. */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_error("fs-sis: %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;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->fs_output = fs_write_stream(file->super);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* compare if files are equal */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen _file->output = o_stream_create_cmp(file->fs_output,
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;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_write_stream_abort(file->super, &file->fs_output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_write_stream_abort(file->super, &file->fs_output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fs_write_stream_finish(file->super, &file->fs_output) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_sis_lock(struct fs_file *_file, unsigned int secs, struct fs_lock **lock_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_sis_unlock(struct fs_lock *_lock ATTR_UNUSED)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_fdatasync(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct sis_fs_file *file = (struct sis_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_exists(struct fs *_fs, const char *path)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_stat(struct fs *_fs, const char *path, struct stat *st_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_link(struct fs *_fs, const char *src, const char *dest)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_rename(struct fs *_fs, const char *src, const char *dest)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_unlink(struct fs *_fs, const char *path)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_sis_try_unlink_hash_file(&fs->fs, fs->super, path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_sis_rmdir(struct fs *_fs, const char *path)