static int fs_sis_init(struct fs *_fs, const char *args, const struct fs_settings *set) { enum fs_properties props; const char *parent_name, *parent_args, *error; if (*args == '\0') { fs_set_error(_fs, "Parent filesystem not given as parameter"); return -1; } parent_args = strchr(args, ':'); if (parent_args == NULL) { parent_name = args; parent_args = ""; } else { parent_name = t_strdup_until(args, parent_args); parent_args++; } if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) { fs_set_error(_fs, "%s", error); return -1; } props = fs_get_properties(_fs->parent); if ((props & FS_SIS_REQUIRED_PROPS) != FS_SIS_REQUIRED_PROPS) { fs_set_error(_fs, "%s backend can't be used with SIS", parent_name); return -1; } return 0; }
static int fs_sis_queue_init(struct fs *_fs, const char *args, const struct fs_settings *set) { struct sis_queue_fs *fs = (struct sis_queue_fs *)_fs; const char *p, *parent_name, *parent_args, *error; /* <queue_dir>:<parent fs>[:<args>] */ p = strchr(args, ':'); if (p == NULL || p[1] == '\0') { fs_set_error(_fs, "Parent filesystem not given as parameter"); return -1; } fs->queue_dir = i_strdup_until(args, p); parent_name = p + 1; parent_args = strchr(parent_name, ':'); if (parent_args == NULL) parent_args = ""; else parent_name = t_strdup_until(parent_name, parent_args++); if (fs_init(parent_name, parent_args, set, &fs->super, &error) < 0) { fs_set_error(_fs, "%s: %s", parent_name, error); return -1; } return 0; }
static int fs_compress_init(struct fs *_fs, const char *args, const struct fs_settings *set) { struct compress_fs *fs = (struct compress_fs *)_fs; const char *p, *compression_name, *level_str, *error; const char *parent_name, *parent_args; /* get compression handler name */ p = strchr(args, ':'); if (p == NULL) { fs_set_error(_fs, "Compression method not given as parameter"); return -1; } compression_name = t_strdup_until(args, p++); args = p; /* get compression level */ p = strchr(args, ':'); if (p == NULL || p[1] == '\0') { fs_set_error(_fs, "Parent filesystem not given as parameter"); return -1; } level_str = t_strdup_until(args, p++); if (str_to_uint(level_str, &fs->compress_level) < 0 || fs->compress_level < 1 || fs->compress_level > 9) { fs_set_error(_fs, "Invalid compression level parameter '%s'", level_str); return -1; } args = p; fs->handler = compression_lookup_handler(compression_name); if (fs->handler == NULL) { fs_set_error(_fs, "Compression method '%s' not support", compression_name); return -1; } parent_args = strchr(args, ':'); if (parent_args == NULL) { parent_name = args; parent_args = ""; } else { parent_name = t_strdup_until(args, parent_args); parent_args++; } if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) { fs_set_error(_fs, "%s: %s", parent_name, error); return -1; } return 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; }
static struct fs_file * fs_sis_file_init(struct fs *_fs, const char *path, enum fs_open_mode mode, enum fs_open_flags flags) { struct sis_fs *fs = (struct sis_fs *)_fs; struct sis_fs_file *file; const char *dir, *hash; file = i_new(struct sis_fs_file, 1); file->file.fs = _fs; file->file.path = i_strdup(path); file->fs = fs; file->open_mode = mode; if (mode == FS_OPEN_MODE_APPEND) { fs_set_error(_fs, "APPEND mode not supported"); return &file->file; } if (fs_sis_path_parse(_fs, path, &dir, &hash) < 0) { fs_set_error(_fs, "Invalid path"); return &file->file; } /* if hashes/<hash> already exists, open it */ file->hash_path = i_strdup_printf("%s/"HASH_DIR_NAME"/%s", dir, hash); file->hash_file = fs_file_init(_fs->parent, file->hash_path, FS_OPEN_MODE_READONLY); file->hash_input = fs_read_stream(file->hash_file, IO_BLOCK_SIZE); if (i_stream_read(file->hash_input) == -1) { /* doesn't exist */ if (errno != ENOENT) { i_error("fs-sis: Couldn't read hash file %s: %m", file->hash_path); } i_stream_destroy(&file->hash_input); } file->super = fs_file_init(_fs->parent, path, mode | flags); return &file->file; }
static struct fs_file * fs_sis_queue_file_init(struct fs *_fs, const char *path, enum fs_open_mode mode, enum fs_open_flags flags) { struct sis_queue_fs *fs = (struct sis_queue_fs *)_fs; struct sis_queue_fs_file *file; file = i_new(struct sis_queue_fs_file, 1); file->file.fs = _fs; file->file.path = i_strdup(path); file->fs = fs; if (mode == FS_OPEN_MODE_APPEND) fs_set_error(_fs, "APPEND mode not supported"); else file->super = fs_file_init(fs->super, path, mode | flags); return &file->file; }
int fs_sis_path_parse(struct fs *fs, const char *path, const char **dir_r, const char **hash_r) { const char *fname, *p; fname = strrchr(path, '/'); if (fname == NULL) { *dir_r = "."; fname = path; } else { *dir_r = t_strdup_until(path, fname); fname++; } /* assume filename begins with "<hash>-" */ p = strchr(fname, '-'); if (p == NULL) { fs_set_error(fs, "open(%s) failed: " "Filenames must begin with '<hash>-'", path); return -1; } *hash_r = t_strdup_until(fname, p); return 0; }
static void fs_sis_queue_copy_error(struct sis_queue_fs *fs) { fs_set_error(&fs->fs, "%s", fs_last_error(fs->super)); }
static void fs_sis_copy_error(struct sis_fs *fs) { fs_set_error(&fs->fs, "%s", fs_last_error(fs->fs.parent)); }
static int fs_crypt_init(struct fs *_fs, const char *args, const struct fs_settings *set) { struct crypt_fs *fs = (struct crypt_fs *)_fs; const char *enc_algo, *set_prefix; const char *p, *arg, *value, *error, *parent_name, *parent_args; const char *public_key_path = "", *private_key_path = "", *password = ""; random_init(); if (!dcrypt_initialize("openssl", NULL, &error)) i_fatal("dcrypt_initialize(): %s", error); /* [algo=<s>:][set_prefix=<n>:][public_key_path=<s>:] [private_key_path=<s>:[password=<s>:]]<parent fs> */ set_prefix = "mail_crypt_global"; enc_algo = "aes-256-gcm-sha256"; for (;;) { p = strchr(args, ':'); if (p == NULL) { fs_set_error(_fs, "Missing parameters"); return -1; } arg = t_strdup_until(args, p); if ((value = strchr(arg, '=')) == NULL) break; arg = t_strdup_until(arg, value++); args = p+1; if (strcmp(arg, "algo") == 0) enc_algo = value; else if (strcmp(arg, "set_prefix") == 0) set_prefix = value; else if (strcmp(arg, "public_key_path") == 0) public_key_path = value; else if (strcmp(arg, "private_key_path") == 0) private_key_path = value; else if (strcmp(arg, "password") == 0) password = value; else { fs_set_error(_fs, "Invalid parameter '%s'", arg); return -1; } } parent_args = strchr(args, ':'); if (parent_args == NULL) { parent_name = args; parent_args = ""; } else { parent_name = t_strdup_until(args, parent_args); parent_args++; } if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) { fs_set_error(_fs, "%s: %s", parent_name, error); return -1; } fs->enc_algo = i_strdup(enc_algo); fs->set_prefix = i_strdup(set_prefix); fs->public_key_path = i_strdup_empty(public_key_path); fs->private_key_path = i_strdup_empty(private_key_path); fs->password = i_strdup_empty(password); return 0; }