Module: Mesa Branch: main Commit: 481e737fe0414b5992acbad653f27902b249ae01 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=481e737fe0414b5992acbad653f27902b249ae01
Author: Michael Catanzaro <mcatanz...@redhat.com> Date: Thu Oct 26 13:28:22 2023 -0500 util: create parents of disk cache directory if needed Currently the shader cache is broken when running under flatpak-spawn because the shader cache's parent directory will not exist. For example, the shader cache directory might be: /home/mcatanzaro/.var/app/org.gnome.Epiphany.Devel/cache If /home/mcatanzaro/.var/app/org.gnome.Epiphany.Devel/ does not already exist, we fail. Let's create the directories recursively, as if by 'mkdir -p', rather than just fail. Fixes #8294 Reviewed-by: Adam Jackson <a...@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25925> --- src/util/disk_cache_os.c | 42 +++++++++++++++++++++++++++++++++++++++++- src/util/tests/cache_test.cpp | 9 ++++++--- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/util/disk_cache_os.c b/src/util/disk_cache_os.c index 3ec1acda56e..f116a0c8de4 100644 --- a/src/util/disk_cache_os.c +++ b/src/util/disk_cache_os.c @@ -27,6 +27,7 @@ #include <stdbool.h> #include <stddef.h> #include <stdlib.h> +#include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -134,6 +135,45 @@ mkdir_if_needed(const char *path) return -1; } +/* Create a directory named 'path' if it does not already exist, + * including parent directories if required. + * + * Returns: 0 if path already exists as a directory or if created. + * -1 in all other cases. + */ +static int +mkdir_with_parents_if_needed(const char *path) +{ + char *p; + const char *end; + + if (path[0] == '\0') + return -1; + + p = strdup(path); + end = p + strlen(p) + 1; /* end points to the \0 terminator */ + for (char *q = p; q != end; q++) { + if (*q == '/' || q == end - 1) { + if (q == p) { + /* Skip the first / of an absolute path. */ + continue; + } + + *q = '\0'; + + if (mkdir_if_needed(p) == -1) { + free(p); + return -1; + } + + *q = '/'; + } + } + free(p); + + return 0; +} + /* Concatenate an existing path and a new name to form a new path. If the new * path does not exist as a directory, create it then return the resulting * name of the new path (ralloc'ed off of 'ctx'). @@ -861,7 +901,7 @@ disk_cache_generate_cache_dir(void *mem_ctx, const char *gpu_name, } if (path) { - if (mkdir_if_needed(path) == -1) + if (mkdir_with_parents_if_needed(path) == -1) return NULL; path = concatenate_and_mkdir(mem_ctx, path, cache_dir_name); diff --git a/src/util/tests/cache_test.cpp b/src/util/tests/cache_test.cpp index 892a0c343af..23732e325fe 100644 --- a/src/util/tests/cache_test.cpp +++ b/src/util/tests/cache_test.cpp @@ -226,18 +226,21 @@ test_disk_cache_create(void *mem_ctx, const char *cache_dir_name, setenv("MESA_SHADER_CACHE_DIR", CACHE_TEST_TMP "/mesa-shader-cache-dir", 1); cache = disk_cache_create("test", driver_id, 0); - EXPECT_FALSE(cache_exists(cache)) + EXPECT_TRUE(cache_exists(cache)) << "disk_cache_create with MESA_SHADER_CACHE_DIR set with a non-existing parent directory"; + disk_cache_destroy(cache); + rmrf_local(CACHE_TEST_TMP); + EXPECT_EQ(err, 0) << "Removing " CACHE_TEST_TMP; + err = mkdir(CACHE_TEST_TMP, 0755); if (err != 0) { fprintf(stderr, "Error creating %s: %s\n", CACHE_TEST_TMP, strerror(errno)); GTEST_FAIL(); } - disk_cache_destroy(cache); cache = disk_cache_create("test", driver_id, 0); - EXPECT_TRUE(cache_exists(cache)) << "disk_cache_create with MESA_SHADER_CACHE_DIR set"; + EXPECT_TRUE(cache_exists(cache)) << "disk_cache_create with MESA_SHADER_CACHE_DIR set with existing parent directory"; path = ralloc_asprintf( mem_ctx, "%s%s", CACHE_TEST_TMP "/mesa-shader-cache-dir/", cache_dir_name);