| // SPDX-License-Identifier: GPL-2.0-only |
| /* Manage a cache of file names' existence */ |
| #include <pthread.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <linux/compiler.h> |
| #include "fncache.h" |
| #include "hashmap.h" |
| |
| static struct hashmap *fncache; |
| |
| static size_t fncache__hash(long key, void *ctx __maybe_unused) |
| { |
| return str_hash((const char *)key); |
| } |
| |
| static bool fncache__equal(long key1, long key2, void *ctx __maybe_unused) |
| { |
| return strcmp((const char *)key1, (const char *)key2) == 0; |
| } |
| |
| static void fncache__init(void) |
| { |
| fncache = hashmap__new(fncache__hash, fncache__equal, /*ctx=*/NULL); |
| } |
| |
| static struct hashmap *fncache__get(void) |
| { |
| static pthread_once_t fncache_once = PTHREAD_ONCE_INIT; |
| |
| pthread_once(&fncache_once, fncache__init); |
| |
| return fncache; |
| } |
| |
| static bool lookup_fncache(const char *name, bool *res) |
| { |
| long val; |
| |
| if (!hashmap__find(fncache__get(), name, &val)) |
| return false; |
| |
| *res = (val != 0); |
| return true; |
| } |
| |
| static void update_fncache(const char *name, bool res) |
| { |
| char *old_key = NULL, *key = strdup(name); |
| |
| if (key) { |
| hashmap__set(fncache__get(), key, res, &old_key, /*old_value*/NULL); |
| free(old_key); |
| } |
| } |
| |
| /* No LRU, only use when bounded in some other way. */ |
| bool file_available(const char *name) |
| { |
| bool res; |
| |
| if (lookup_fncache(name, &res)) |
| return res; |
| res = access(name, R_OK) == 0; |
| update_fncache(name, res); |
| return res; |
| } |