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 <ajax@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25925>
This commit is contained in:
Michael Catanzaro 2023-10-26 13:28:22 -05:00 committed by Marge Bot
parent a0fab95bc0
commit 481e737fe0
2 changed files with 47 additions and 4 deletions

View file

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

View file

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