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);

Reply via email to