]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-fs, global: Redesign how fs hierarchy is configured
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Tue, 2 Jan 2024 22:24:28 +0000 (17:24 -0500)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 12 Feb 2025 10:34:11 +0000 (12:34 +0200)
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
}

src/lib-dict-extra/test-dict-fs.c
src/lib-fs/fs-api-private.h
src/lib-fs/fs-api.c
src/lib-fs/fs-api.h
src/lib-fs/test-fs-metawrap.c
src/lib-fs/test-fs-posix.c
src/lib-storage/mail-storage-settings.c
src/lib-storage/mail-storage.c
src/plugins/mail-crypt/test-fs-crypt.c

index 6cb15f876d9583a879ba58eac1b383d67e99194c..5211936c20d07b3aadb9cadaa957e8a181e54d2f 100644 (file)
@@ -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
        };
index 6cabfde8cb4387363cea4101b15799157f6d9d0d..edd92fcf6f78e5793e366a2dff95cd7f69e1e661 100644 (file)
@@ -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;
 
index f633a6bd5f2bd244bac219d70181a2a315688486..60b415e80c7189fac1182b95f62c4256370b3182 100644 (file)
 #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;
 }
index cc08410aaf82f769a649580b7f2cc4c12b8e458b..9aebe99a917f8eb2a5ff3c7ca41ce924bdca3c74 100644 (file)
@@ -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() */
index 6f16c68b9ed91fcc5f7e96b3aae9aaa9cfaec173..c56306c6d4c03229d927180f20eadc84e11114fd 100644 (file)
@@ -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
        };
 
index 511522de2c2e132f11377008bdf6a1355ea68bc0..48a9757be9835801893c519854b27fe1dbd11da1 100644 (file)
@@ -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
        };
index b2347ad7e5fe6aa8fefd1b3231b424e6fc97abc5..765ea455d4ee955f68747fff0c3c6045cc79ddb9 100644 (file)
@@ -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),
index 43144ff183ec1532a5f10b12d148a651e2a64e1c..63a8514a3a4f01e75d08218cc0e82539dc0b1f8d 100644 (file)
@@ -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);
index 7b8e23f12371fcc783047e294f310f35aebdfb85..78606b0772b735c40eb3da1081a2dda6bf697912 100644 (file)
@@ -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,