From: Timo Sirainen Date: Tue, 2 Jan 2024 22:24:28 +0000 (-0500) Subject: lib-fs, global: Redesign how fs hierarchy is configured X-Git-Tag: 2.4.1~1085 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1d1e45d1fe2146a77de0d11279138c935c8c35e2;p=thirdparty%2Fdovecot%2Fcore.git lib-fs, global: Redesign how fs hierarchy is configured The new way is to use e.g.: fs metawrap { } fs posix { } This tells metawrap to use the next fs list filter (= posix) as the next fs. It's also possible to configure the same fs multiple times by using different names for them: fs metawrap1 { fs_driver = metawrap } fs metawrap2 { fs_driver = metawrap } --- diff --git a/src/lib-dict-extra/test-dict-fs.c b/src/lib-dict-extra/test-dict-fs.c index 6cb15f876d..5211936c20 100644 --- a/src/lib-dict-extra/test-dict-fs.c +++ b/src/lib-dict-extra/test-dict-fs.c @@ -40,7 +40,8 @@ static void test_dict_fs_set_get(void) struct dict *dict; const char *const settings[] = { "dict_driver", "fs", - "fs_driver", "posix", + "fs", "posix", + "fs/posix/fs_driver", "posix", "fs_posix_prefix", ".test-dict/", NULL }; diff --git a/src/lib-fs/fs-api-private.h b/src/lib-fs/fs-api-private.h index 6cabfde8cb..edd92fcf6f 100644 --- a/src/lib-fs/fs-api-private.h +++ b/src/lib-fs/fs-api-private.h @@ -92,7 +92,10 @@ struct fs { struct fs_vfuncs v; char *temp_path_prefix; int refcount; - unsigned int child_count; + + /* Set only during initialization: */ + const ARRAY_TYPE(const_string) *init_fs_list; + unsigned int init_fs_list_idx; char *username, *session_id; diff --git a/src/lib-fs/fs-api.c b/src/lib-fs/fs-api.c index f633a6bd5f..60b415e80c 100644 --- a/src/lib-fs/fs-api.c +++ b/src/lib-fs/fs-api.c @@ -15,18 +15,24 @@ #include "istream-fs-stats.h" #include "fs-api-private.h" +static bool fs_settings_check(void *_set, pool_t pool, const char **error_r); + #undef DEF #define DEF(type, name) \ SETTING_DEFINE_STRUCT_##type(#name, name, struct fs_settings) static const struct setting_define fs_setting_defines[] = { + DEF(STR, fs_name), DEF(STR, fs_driver), - { .type = SET_FILTER_HIERARCHY, .key = "fs_parent", - .required_setting = "fs_driver", }, + { .type = SET_FILTER_ARRAY, .key = "fs", + .offset = offsetof(struct fs_settings, fs), + .filter_array_field_name = "fs_name", }, SETTING_DEFINE_LIST_END }; static const struct fs_settings fs_default_settings = { + .fs_name = "", .fs_driver = "", + .fs = ARRAY_INIT, }; const struct setting_parser_info fs_setting_parser_info = { .name = "fs", @@ -36,6 +42,8 @@ const struct setting_parser_info fs_setting_parser_info = { .struct_size = sizeof(struct fs_settings), .pool_offset1 = 1 + offsetof(struct fs_settings, pool), + + .check_func = fs_settings_check, }; static struct event_category event_category_fs = { @@ -203,20 +211,50 @@ int fs_legacy_init(const char *driver, const char *args, return 0; } -static int fs_init(const char *fs_driver, struct event *event, +static bool fs_settings_check(void *_set, pool_t pool ATTR_UNUSED, + const char **error_r ATTR_UNUSED) +{ + struct fs_settings *set = _set; + + if (set->fs_driver[0] == '\0' && set->fs_name[0] != '\0') { + /* default an empty fs_driver to fs_name, so it's possible to + configure simply: fs driver { .. }, but to still allow the + same driver to be used multiple times if necessary. */ + set->fs_driver = set->fs_name; + } + return TRUE; +} + +static int fs_init(struct event *event, const struct fs_parameters *params, - unsigned int child_count, + const ARRAY_TYPE(const_string) *fs_list, + unsigned int fs_list_idx, struct fs **fs_r, const char **error_r) { + const struct fs_settings *fs_set; struct fs *fs; - const char *error; + const char *fs_name, *error; int ret; - ret = fs_alloc(fs_driver, event, params, &fs, error_r); + fs_name = array_idx_elem(fs_list, fs_list_idx); + if (settings_get_filter(event, "fs", fs_name, &fs_setting_parser_info, + 0, &fs_set, error_r) < 0) + return -1; + + if (fs_set->fs_driver[0] == '\0') { + *error_r = "fs_driver is empty"; + settings_free(fs_set); + return -1; + } + + event_add_str(event, "fs", fs_name); + ret = fs_alloc(fs_set->fs_driver, event, params, &fs, error_r); + settings_free(fs_set); if (ret < 0) return -1; - fs->child_count = child_count; + fs->init_fs_list = fs_list; + fs->init_fs_list_idx = fs_list_idx; T_BEGIN { ret = fs->v.init(fs, params, &error); } T_END_PASS_STR_IF(ret < 0, &error); @@ -225,6 +263,7 @@ static int fs_init(const char *fs_driver, struct event *event, fs_unref(&fs); return -1; } + fs->init_fs_list = NULL; *fs_r = fs; return 0; } @@ -232,19 +271,19 @@ static int fs_init(const char *fs_driver, struct event *event, int fs_init_auto(struct event *event, const struct fs_parameters *params, struct fs **fs_r, const char **error_r) { - struct fs_settings *fs_set; + const struct fs_settings *fs_set; int ret; if (settings_get(event, &fs_setting_parser_info, 0, &fs_set, error_r) < 0) return -1; - if (fs_set->fs_driver[0] == '\0') { + if (array_is_empty(&fs_set->fs)) { settings_free(fs_set); - *error_r = "fs_driver is empty"; + *error_r = "fs { .. } named list filter is missing"; return 0; } - ret = fs_init(fs_set->fs_driver, event, params, 0, fs_r, error_r); + ret = fs_init(event, params, &fs_set->fs, 0, fs_r, error_r); settings_free(fs_set); return ret < 0 ? -1 : 1; } @@ -252,36 +291,17 @@ int fs_init_auto(struct event *event, const struct fs_parameters *params, int fs_init_parent(struct fs *fs, const struct fs_parameters *params, const char **error_r) { - string_t *filter_path = t_str_new(64); - str_append(filter_path, "fs_parent"); - for (unsigned int i = 0; i < fs->child_count; i++) - str_append(filter_path, "/fs_parent"); - - /* Lookup the fs_parent/.../fs_driver setting for the exact filter path. - The settings used by the fs drivers don't need to use the exact same - filter path. */ - struct fs_settings *fs_set; - int ret = settings_try_get(fs->event, str_c(filter_path), - &fs_setting_parser_info, 0, - &fs_set, error_r); - if (ret < 0) { - settings_free(fs_set); - return -1; - } - if (ret == 0 || fs_set->fs_driver[0] == '\0') { - settings_free(fs_set); - *error_r = "fs_parent { fs_driver } missing"; + if (fs->init_fs_list_idx + 1 >= array_count(fs->init_fs_list)) { + *error_r = "Next fs { .. } named list filter is missing"; return -1; } struct event *event = event_create(fs->event); /* Drop the parent "fs-name: " prefix */ event_drop_parent_log_prefixes(event, 1); - event_set_ptr(event, SETTINGS_EVENT_FILTER_NAME, - p_strdup(event_get_pool(event), str_c(filter_path))); - ret = fs_init(fs_set->fs_driver, event, params, - fs->child_count + 1, &fs->parent, error_r); - settings_free(fs_set); + int ret = fs_init(event, params, + fs->init_fs_list, fs->init_fs_list_idx + 1, + &fs->parent, error_r); event_unref(&event); return ret; } diff --git a/src/lib-fs/fs-api.h b/src/lib-fs/fs-api.h index cc08410aaf..9aebe99a91 100644 --- a/src/lib-fs/fs-api.h +++ b/src/lib-fs/fs-api.h @@ -152,7 +152,9 @@ struct fs_parameters { struct fs_settings { pool_t pool; + const char *fs_name; const char *fs_driver; + ARRAY_TYPE(const_string) fs; }; extern const struct setting_parser_info fs_setting_parser_info; @@ -206,8 +208,8 @@ typedef void fs_file_async_callback_t(void *context); /* Initialize the fs by pulling settings automatically using the event. The event parameter is used as the parent event. Returns 1 if ok, 0 if - fs_driver setting is empty (error_r is also set), -1 if settings lookup or - driver initialization failed. */ + fs { .. } named list filter is missing (error_r is also set), -1 if settings + lookup or driver initialization failed. */ int fs_init_auto(struct event *event, const struct fs_parameters *params, struct fs **fs_r, const char **error_r); /* event_parent can be overridden by fs_file_init_with_event() */ diff --git a/src/lib-fs/test-fs-metawrap.c b/src/lib-fs/test-fs-metawrap.c index 6f16c68b9e..c56306c6d4 100644 --- a/src/lib-fs/test-fs-metawrap.c +++ b/src/lib-fs/test-fs-metawrap.c @@ -12,8 +12,9 @@ static const struct fs_parameters fs_params; static struct settings_simple test_set; static const char *const set_metawrap_test[] = { - "fs_parent/fs_driver", "test", - "fs_driver", "metawrap", + "fs", "metawrap test", + "fs/metawrap/fs_driver", "metawrap", + "fs/test/fs_driver", "test", NULL }; @@ -57,9 +58,10 @@ static void test_fs_metawrap_stat(void) static void test_fs_metawrap_async(void) { static const char *const set_metawrap_metawrap_test[] = { - "fs_parent/fs_parent/fs_driver", "test", - "fs_parent/fs_driver", "metawrap", - "fs_driver", "metawrap", + "fs", "metawrap1 metawrap2 test", + "fs/metawrap1/fs_driver", "metawrap", + "fs/metawrap2/fs_driver", "metawrap", + "fs/test/fs_name", "test", NULL }; diff --git a/src/lib-fs/test-fs-posix.c b/src/lib-fs/test-fs-posix.c index 511522de2c..48a9757be9 100644 --- a/src/lib-fs/test-fs-posix.c +++ b/src/lib-fs/test-fs-posix.c @@ -35,7 +35,8 @@ static void test_fs_posix(void) i_zero(&fs_params); const char *const settings[] = { - "fs_driver", "posix", + "fs", "posix", + "fs/posix/fs_driver", "posix", "fs_posix_prefix", t_strconcat(testdir, "/", NULL), NULL }; diff --git a/src/lib-storage/mail-storage-settings.c b/src/lib-storage/mail-storage-settings.c index b2347ad7e5..765ea455d4 100644 --- a/src/lib-storage/mail-storage-settings.c +++ b/src/lib-storage/mail-storage-settings.c @@ -34,7 +34,7 @@ static const struct setting_define mail_storage_setting_defines[] = { { .type = SET_FILTER_NAME, .key = "layout_imapdir" }, { .type = SET_FILTER_NAME, .key = "layout_fs" }, { .type = SET_FILTER_NAME, .key = "mail_ext_attachment", - .required_setting = "fs_driver", }, + .required_setting = "fs", }, DEF(STR, mail_ext_attachment_path), DEF(STR_NOVARS_HIDDEN, mail_ext_attachment_hash), DEF(SIZE, mail_ext_attachment_min_size), diff --git a/src/lib-storage/mail-storage.c b/src/lib-storage/mail-storage.c index 43144ff183..63a8514a3a 100644 --- a/src/lib-storage/mail-storage.c +++ b/src/lib-storage/mail-storage.c @@ -533,7 +533,10 @@ mail_storage_create_real(struct mail_namespace *ns, struct event *set_event, storage->mailboxes_fs_set_instance = settings_instance_dup(set_instance); settings_override(storage->mailboxes_fs_set_instance, - "*/fs_driver", "posix", + "*/fs", "__posix", + SETTINGS_OVERRIDE_TYPE_CODE); + settings_override(storage->mailboxes_fs_set_instance, + "fs/__posix/fs_driver", "posix", SETTINGS_OVERRIDE_TYPE_CODE); struct event *event = event_create(storage->event); diff --git a/src/plugins/mail-crypt/test-fs-crypt.c b/src/plugins/mail-crypt/test-fs-crypt.c index 7b8e23f123..78606b0772 100644 --- a/src/plugins/mail-crypt/test-fs-crypt.c +++ b/src/plugins/mail-crypt/test-fs-crypt.c @@ -47,8 +47,9 @@ static void test_fs_crypt_read_write(void) struct fs *fs; const char *const test_settings[] = { - "fs_parent/fs_driver", "posix", - "fs_driver", "crypt", + "fs", "crypt posix", + "fs/crypt/fs_driver", "crypt", + "fs/posix/fs_driver", "posix", "crypt_global_public_key", PUBLIC_KEY_PEM, "crypt_global_private_key", "main", "crypt_global_private_key/main/crypt_private_key", PRIVATE_KEY_PEM, @@ -105,8 +106,9 @@ static void test_fs_crypt_read_write_0(void) struct fs *fs; const char *const test_settings[] = { - "fs_parent/fs_driver", "posix", - "fs_driver", "crypt", + "fs", "crypt posix", + "fs/crypt/fs_driver", "crypt", + "fs/posix/fs_driver", "posix", "crypt_global_public_key", PUBLIC_KEY_PEM, "crypt_global_private_key", "main", "crypt_global_private_key/main/crypt_private_key", PRIVATE_KEY_PEM, @@ -155,8 +157,9 @@ static void test_fs_crypt_read_write_unencrypted(void) struct fs *fs; const char *const test_settings[] = { - "fs_parent/fs_driver", "posix", - "fs_driver", "crypt", + "fs", "crypt posix", + "fs/crypt/fs_driver", "crypt", + "fs/posix/fs_driver", "posix", "fs_crypt_read_plain_fallback", "yes", "crypt_write_algorithm", "", "crypt_global_private_key", "main", @@ -206,8 +209,9 @@ static void test_fs_crypt_read_write_unencrypted(void) settings_simple_deinit(&test_set); const char *const test_settings2[] = { - "fs_parent/fs_driver", "posix", - "fs_driver", "crypt", + "fs", "crypt posix", + "fs/crypt/fs_driver", "crypt", + "fs/posix/fs_driver", "posix", "fs_crypt_read_plain_fallback", "yes", "crypt_write_algorithm", "", "crypt_global_public_key", PUBLIC_KEY_PEM,