static int compile_bind_mounts(
                const ExecContext *context,
                const ExecParameters *params,
                BindMount **ret_bind_mounts,
                size_t *ret_n_bind_mounts,
                char ***ret_empty_directories) {

        _cleanup_strv_free_ char **empty_directories = NULL;
        BindMount *bind_mounts;
        size_t n, h = 0, i;
        ExecDirectoryType t;
        int r;

        assert(context);
        assert(params);
        assert(ret_bind_mounts);
        assert(ret_n_bind_mounts);
        assert(ret_empty_directories);

        n = context->n_bind_mounts;
        for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
                if (!params->prefix[t])
                        continue;

                n += strv_length(context->directories[t].paths);
        }

        if (n <= 0) {
                *ret_bind_mounts = NULL;
                *ret_n_bind_mounts = 0;
                *ret_empty_directories = NULL;
                return 0;
        }

        bind_mounts = new(BindMount, n);
        if (!bind_mounts)
                return -ENOMEM;

        for (i = 0; i < context->n_bind_mounts; i++) {
                BindMount *item = context->bind_mounts + i;
                char *s, *d;

                s = strdup(item->source);
                if (!s) {
                        r = -ENOMEM;
                        goto finish;
                }

                d = strdup(item->destination);
                if (!d) {
                        free(s);
                        r = -ENOMEM;
                        goto finish;
                }

                bind_mounts[h++] = (BindMount) {
                        .source = s,
                        .destination = d,
                        .read_only = item->read_only,
                        .recursive = item->recursive,
                        .ignore_enoent = item->ignore_enoent,
                };
        }

        for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
                char **suffix;

                if (!params->prefix[t])
                        continue;

                if (strv_isempty(context->directories[t].paths))
                        continue;

                if (context->dynamic_user &&
                    !IN_SET(t, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION) &&
                    !(context->root_directory || context->root_image)) {
                        char *private_root;

                        /* So this is for a dynamic user, and we need to make sure the process can access its own
                         * directory. For that we overmount the usually inaccessible "private" subdirectory with a
                         * tmpfs that makes it accessible and is empty except for the submounts we do this for. */

                        private_root = strjoin(params->prefix[t], "/private");
                        if (!private_root) {
                                r = -ENOMEM;
                                goto finish;
                        }

                        r = strv_consume(&empty_directories, private_root);
                        if (r < 0)
                                goto finish;
                }

                STRV_FOREACH(suffix, context->directories[t].paths) {
                        char *s, *d;

                        if (context->dynamic_user &&
                            !IN_SET(t, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION))
                                s = strjoin(params->prefix[t], "/private/", *suffix);
                        else
                                s = strjoin(params->prefix[t], "/", *suffix);
                        if (!s) {
                                r = -ENOMEM;
                                goto finish;
                        }

                        if (context->dynamic_user &&
                            !IN_SET(t, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION) &&
                            (context->root_directory || context->root_image))
                                /* When RootDirectory= or RootImage= are set, then the symbolic link to the private
                                 * directory is not created on the root directory. So, let's bind-mount the directory
                                 * on the 'non-private' place. */
                                d = strjoin(params->prefix[t], "/", *suffix);
                        else
                                d = strdup(s);
                        if (!d) {
                                free(s);
                                r = -ENOMEM;
                                goto finish;
                        }

                        bind_mounts[h++] = (BindMount) {
                                .source = s,
                                .destination = d,
                                .read_only = false,
                                .nosuid = context->dynamic_user, /* don't allow suid/sgid when DynamicUser= is on */
                                .recursive = true,
                                .ignore_enoent = false,
                        };
                }
        }

        assert(h == n);

        *ret_bind_mounts = bind_mounts;
        *ret_n_bind_mounts = n;
        *ret_empty_directories = TAKE_PTR(empty_directories);

        return (int) n;

finish:
        bind_mount_free_many(bind_mounts, h);
        return r;
}