Exemplo n.º 1
0
static bool fs_sis_try_link(struct sis_fs_file *file)
{
	const char *path = fs_file_path(&file->file);
	const struct stat *st;
	struct stat st2;

	st = i_stream_stat(file->hash_input, FALSE);

	/* we can use the existing file */
	if (fs_link(file->super->fs, file->hash_path, path) < 0) {
		if (errno != ENOENT && errno != EMLINK)
			i_error("fs-sis: %s", fs_last_error(file->super->fs));
		/* failed to use link(), continue as if it hadn't been equal */
		return FALSE;
	}
	if (fs_stat(file->super->fs, path, &st2) < 0) {
		i_error("fs-sis: %s", fs_last_error(file->super->fs));
		if (fs_unlink(file->super->fs, path) < 0)
			i_error("fs-sis: %s", fs_last_error(file->super->fs));
		return FALSE;
	}
	if (st->st_ino != st2.st_ino) {
		/* the hashes/ file was already replaced with something else */
		if (fs_unlink(file->super->fs, path) < 0)
			i_error("fs-sis: %s", fs_last_error(file->super->fs));
		return FALSE;
	}
	return TRUE;
}
Exemplo n.º 2
0
static void fs_sis_replace_hash_file(struct sis_fs_file *file)
{
	const char *hash_fname, *path = fs_file_path(&file->file);
	struct fs *super_fs = file->super->fs;
	string_t *temp_path;
	int ret;

	if (file->hash_input == NULL) {
		/* hash file didn't exist previously. we should be able to
		   create it with link() */
		if (fs_link(super_fs, path, file->hash_path) < 0) {
			if (errno == EEXIST) {
				/* the file was just created. it's probably
				   a duplicate, but it's too much trouble
				   trying to deduplicate it anymore */
			} else {
				i_error("fs-sis: %s", fs_last_error(super_fs));
			}
		}
		return;
	}

	temp_path = t_str_new(256);
	hash_fname = strrchr(file->hash_path, '/');
	if (hash_fname == NULL)
		hash_fname = file->hash_path;
	else {
		str_append_n(temp_path, file->hash_path,
			     (hash_fname-file->hash_path) + 1);
		hash_fname++;
	}
	str_printfa(temp_path, "%s%s.tmp",
		    super_fs->set.temp_file_prefix, hash_fname);

	/* replace existing hash file atomically */
	ret = fs_link(super_fs, path, str_c(temp_path));
	if (ret < 0 && errno == EEXIST) {
		/* either someone's racing us or it's a stale file.
		   try to continue. */
		if (fs_unlink(super_fs, str_c(temp_path)) < 0 &&
		    errno != ENOENT)
			i_error("fs-sis: %s", fs_last_error(super_fs));
		ret = fs_link(super_fs, path, str_c(temp_path));
	}
	if (ret < 0) {
		i_error("fs-sis: %s", fs_last_error(super_fs));
		return;
	}
	if (fs_rename(super_fs, str_c(temp_path), file->hash_path) < 0) {
		if (errno == ENOENT) {
			/* apparently someone else just renamed it. ignore. */
		} else {
			i_error("fs-sis: %s", fs_last_error(super_fs));
		}
		(void)fs_unlink(super_fs, str_c(temp_path));
	}
}
Exemplo n.º 3
0
static int
fs_sis_open(struct fs *_fs, const char *path, enum fs_open_mode mode,
	    enum fs_open_flags flags, struct fs_file **file_r)
{
	struct sis_fs *fs = (struct sis_fs *)_fs;
	struct sis_fs_file *file;
	struct fs_file *super;
	const char *dir, *hash;

	if (mode == FS_OPEN_MODE_APPEND) {
		fs_set_error(_fs, "APPEND mode not supported");
		return -1;
	}

	if (fs_open(fs->super, path, mode | flags, &super) < 0) {
		fs_sis_copy_error(fs);
		return -1;
	}

	switch (mode) {
	case FS_OPEN_MODE_RDONLY:
		*file_r = super;
		return 0;
	case FS_OPEN_MODE_CREATE:
	case FS_OPEN_MODE_REPLACE:
		break;
	case FS_OPEN_MODE_APPEND:
		i_unreached();
	}

	if (fs_sis_path_parse(_fs, path, &dir, &hash) < 0)
		return -1;

	file = i_new(struct sis_fs_file, 1);
	file->file.fs = _fs;
	file->file.path = i_strdup(fs_file_path(super));
	file->super = super;
	file->open_mode = mode;
	file->hash = i_strdup(hash);

	/* if hashes/<hash> already exists, open it */
	file->hash_path = i_strdup_printf("%s/"HASH_DIR_NAME"/%s", dir, hash);
	if (fs_open(fs->super, file->hash_path, FS_OPEN_MODE_RDONLY,
		    &file->hash_file) < 0 && errno != ENOENT) {
		i_error("fs-sis: Couldn't open hash file: %s",
			fs_last_error(fs->super));
	}
	if (file->hash_file != NULL) {
		file->hash_input =
			fs_read_stream(file->hash_file, IO_BLOCK_SIZE);
	}

	*file_r = &file->file;
	return 0;
}
Exemplo n.º 4
0
static void fs_compress_write_stream(struct fs_file *_file)
{
	struct compress_fs_file *file = (struct compress_fs_file *)_file;

	i_assert(_file->output == NULL);

	file->temp_output =
		iostream_temp_create_named(_file->fs->temp_path_prefix,
					   IOSTREAM_TEMP_FLAG_TRY_FD_DUP,
					   fs_file_path(_file));
	_file->output = file->fs->handler->
		create_ostream(file->temp_output, file->fs->compress_level);
}
Exemplo n.º 5
0
static void fs_crypt_write_stream(struct fs_file *_file)
{
	struct crypt_fs_file *file = (struct crypt_fs_file *)_file;
	const char *error;

	i_assert(_file->output == NULL);

	if (fs_crypt_load_keys(file->fs, &error) < 0) {
		_file->output = o_stream_create_error_str(EIO,
			"Couldn't read settings: %s", error);
		return;
	}

	if (file->fs->keys.public_key == NULL) {
		if (_file->fs->set.debug)
			i_debug("No public key provided, "
				"NOT encrypting stream %s",
				 fs_file_path(_file));
		file->super_output = fs_write_stream(_file->parent);
		_file->output = file->super_output;
		return;
	}

	enum io_stream_encrypt_flags flags;
	if (strstr(file->fs->enc_algo, "gcm") != NULL ||
	    strstr(file->fs->enc_algo, "ccm") != NULL) {
		flags = IO_STREAM_ENC_INTEGRITY_AEAD;
	} else {
		flags = IO_STREAM_ENC_INTEGRITY_HMAC;
	}

	file->temp_output =
		iostream_temp_create_named(_file->fs->temp_path_prefix,
					   IOSTREAM_TEMP_FLAG_TRY_FD_DUP,
					   fs_file_path(_file));
	_file->output = o_stream_create_encrypt(file->temp_output,
		file->fs->enc_algo, file->fs->keys.public_key,
		flags);
}
Exemplo n.º 6
0
struct istream *
i_stream_create_fs_file(struct fs_file **file, size_t max_buffer_size)
{
    struct fs_file_istream *fstream;
    struct istream *input;

    fstream = i_new(struct fs_file_istream, 1);
    fstream->file = *file;
    fstream->istream.iostream.close = i_stream_fs_file_close;
    fstream->istream.max_buffer_size = max_buffer_size;
    fstream->istream.read = i_stream_fs_file_read;
    fstream->istream.stream_size_passthrough = TRUE;

    fstream->istream.istream.blocking =
        ((*file)->flags & FS_OPEN_FLAG_ASYNC) == 0;
    fstream->istream.istream.seekable =
        ((*file)->flags & FS_OPEN_FLAG_SEEKABLE) != 0;

    input = i_stream_create(&fstream->istream, NULL, -1);
    i_stream_set_name(input, fs_file_path(*file));
    *file = NULL;
    return input;
}
Exemplo n.º 7
0
static const char *fs_sis_queue_file_get_path(struct fs_file *_file)
{
	struct sis_queue_fs_file *file = (struct sis_queue_fs_file *)_file;

	return fs_file_path(file->super);
}
Exemplo n.º 8
0
const char *fs_wrapper_file_get_path(struct fs_file *file)
{
	return fs_file_path(file->parent);
}
Exemplo n.º 9
0
static const char *fs_compress_file_get_path(struct fs_file *_file)
{
	struct compress_fs_file *file = (struct compress_fs_file *)_file;

	return fs_file_path(file->super);
}