18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* Manage a cache of file names' existence */ 38c2ecf20Sopenharmony_ci#include <stdlib.h> 48c2ecf20Sopenharmony_ci#include <unistd.h> 58c2ecf20Sopenharmony_ci#include <string.h> 68c2ecf20Sopenharmony_ci#include <linux/list.h> 78c2ecf20Sopenharmony_ci#include "fncache.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_cistruct fncache { 108c2ecf20Sopenharmony_ci struct hlist_node nd; 118c2ecf20Sopenharmony_ci bool res; 128c2ecf20Sopenharmony_ci char name[]; 138c2ecf20Sopenharmony_ci}; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define FNHSIZE 61 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic struct hlist_head fncache_hash[FNHSIZE]; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciunsigned shash(const unsigned char *s) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci unsigned h = 0; 228c2ecf20Sopenharmony_ci while (*s) 238c2ecf20Sopenharmony_ci h = 65599 * h + *s++; 248c2ecf20Sopenharmony_ci return h ^ (h >> 16); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic bool lookup_fncache(const char *name, bool *res) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci int h = shash((const unsigned char *)name) % FNHSIZE; 308c2ecf20Sopenharmony_ci struct fncache *n; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci hlist_for_each_entry(n, &fncache_hash[h], nd) { 338c2ecf20Sopenharmony_ci if (!strcmp(n->name, name)) { 348c2ecf20Sopenharmony_ci *res = n->res; 358c2ecf20Sopenharmony_ci return true; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci return false; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void update_fncache(const char *name, bool res) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct fncache *n = malloc(sizeof(struct fncache) + strlen(name) + 1); 448c2ecf20Sopenharmony_ci int h = shash((const unsigned char *)name) % FNHSIZE; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (!n) 478c2ecf20Sopenharmony_ci return; 488c2ecf20Sopenharmony_ci strcpy(n->name, name); 498c2ecf20Sopenharmony_ci n->res = res; 508c2ecf20Sopenharmony_ci hlist_add_head(&n->nd, &fncache_hash[h]); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* No LRU, only use when bounded in some other way. */ 548c2ecf20Sopenharmony_cibool file_available(const char *name) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci bool res; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (lookup_fncache(name, &res)) 598c2ecf20Sopenharmony_ci return res; 608c2ecf20Sopenharmony_ci res = access(name, R_OK) == 0; 618c2ecf20Sopenharmony_ci update_fncache(name, res); 628c2ecf20Sopenharmony_ci return res; 638c2ecf20Sopenharmony_ci} 64