/* * Copyright © 2014 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifdef ENABLE_SHADER_CACHE #if DETECT_OS_WINDOWS /* TODO: implement disk cache support on windows */ #else #include #include #include #include #include #include #include #include #include #include "util/disk_cache.h" #include "util/disk_cache_os.h" #include "util/ralloc.h" /* Create a directory named 'path' if it does not already exist. * * Returns: 0 if path already exists as a directory or if created. * -1 in all other cases. */ static int mkdir_if_needed(const char *path) { struct stat sb; /* If the path exists already, then our work is done if it's a * directory, but it's an error if it is not. */ if (stat(path, &sb) == 0) { if (S_ISDIR(sb.st_mode)) { return 0; } else { fprintf(stderr, "Cannot use %s for shader cache (not a directory)" "---disabling.\n", path); return -1; } } int ret = mkdir(path, 0755); if (ret == 0 || (ret == -1 && errno == EEXIST)) return 0; fprintf(stderr, "Failed to create %s for shader cache (%s)---disabling.\n", path, strerror(errno)); return -1; } /* 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'). * * Returns NULL on any error, such as: * * does not exist or is not a directory * / exists but is not a directory * / cannot be created as a directory */ static char * concatenate_and_mkdir(void *ctx, const char *path, const char *name) { char *new_path; struct stat sb; if (stat(path, &sb) != 0 || ! S_ISDIR(sb.st_mode)) return NULL; new_path = ralloc_asprintf(ctx, "%s/%s", path, name); if (mkdir_if_needed(new_path) == 0) return new_path; else return NULL; } /* Determine path for cache based on the first defined name as follows: * * $MESA_GLSL_CACHE_DIR * $XDG_CACHE_HOME/mesa_shader_cache * /.cache/mesa_shader_cache */ char * disk_cache_generate_cache_dir(void *mem_ctx) { char *path = getenv("MESA_GLSL_CACHE_DIR"); if (path) { if (mkdir_if_needed(path) == -1) return NULL; path = concatenate_and_mkdir(mem_ctx, path, CACHE_DIR_NAME); if (!path) return NULL; } if (path == NULL) { char *xdg_cache_home = getenv("XDG_CACHE_HOME"); if (xdg_cache_home) { if (mkdir_if_needed(xdg_cache_home) == -1) return NULL; path = concatenate_and_mkdir(mem_ctx, xdg_cache_home, CACHE_DIR_NAME); if (!path) return NULL; } } if (!path) { char *buf; size_t buf_size; struct passwd pwd, *result; buf_size = sysconf(_SC_GETPW_R_SIZE_MAX); if (buf_size == -1) buf_size = 512; /* Loop until buf_size is large enough to query the directory */ while (1) { buf = ralloc_size(mem_ctx, buf_size); getpwuid_r(getuid(), &pwd, buf, buf_size, &result); if (result) break; if (errno == ERANGE) { ralloc_free(buf); buf = NULL; buf_size *= 2; } else { return NULL; } } path = concatenate_and_mkdir(mem_ctx, pwd.pw_dir, ".cache"); if (!path) return NULL; path = concatenate_and_mkdir(mem_ctx, path, CACHE_DIR_NAME); if (!path) return NULL; } return path; } #endif #endif /* ENABLE_SHADER_CACHE */