// SPDX-License-Identifier: GPL-2.0-only /* Manage a cache of file names' existence */ #include <stdlib.h> #include <unistd.h> #include <string.h> #include <linux/list.h> #include "fncache.h" struct fncache { struct hlist_node nd; bool res; char name[]; }; #define FNHSIZE 61 static struct hlist_head fncache_hash[FNHSIZE]; unsigned shash(const unsigned char *s) { unsigned h = 0; while (*s) h = 65599 * h + *s++; return h ^ (h >> 16); } static bool lookup_fncache(const char *name, bool *res) { int h = shash((const unsigned char *)name) % FNHSIZE; struct fncache *n; hlist_for_each_entry(n, &fncache_hash[h], nd) { if (!strcmp(n->name, name)) { *res = n->res; return true; } } return false; } static void update_fncache(const char *name, bool res) { struct fncache *n = malloc(sizeof(struct fncache) + strlen(name) + 1); int h = shash((const unsigned char *)name) % FNHSIZE; if (!n) return; strcpy(n->name, name); n->res = res; hlist_add_head(&n->nd, &fncache_hash[h]); } /* 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; }