0001
0002
0003 #include <stdlib.h>
0004 #include <unistd.h>
0005 #include <string.h>
0006 #include <linux/list.h>
0007 #include "fncache.h"
0008
0009 struct fncache {
0010 struct hlist_node nd;
0011 bool res;
0012 char name[];
0013 };
0014
0015 #define FNHSIZE 61
0016
0017 static struct hlist_head fncache_hash[FNHSIZE];
0018
0019 unsigned shash(const unsigned char *s)
0020 {
0021 unsigned h = 0;
0022 while (*s)
0023 h = 65599 * h + *s++;
0024 return h ^ (h >> 16);
0025 }
0026
0027 static bool lookup_fncache(const char *name, bool *res)
0028 {
0029 int h = shash((const unsigned char *)name) % FNHSIZE;
0030 struct fncache *n;
0031
0032 hlist_for_each_entry(n, &fncache_hash[h], nd) {
0033 if (!strcmp(n->name, name)) {
0034 *res = n->res;
0035 return true;
0036 }
0037 }
0038 return false;
0039 }
0040
0041 static void update_fncache(const char *name, bool res)
0042 {
0043 struct fncache *n = malloc(sizeof(struct fncache) + strlen(name) + 1);
0044 int h = shash((const unsigned char *)name) % FNHSIZE;
0045
0046 if (!n)
0047 return;
0048 strcpy(n->name, name);
0049 n->res = res;
0050 hlist_add_head(&n->nd, &fncache_hash[h]);
0051 }
0052
0053
0054 bool file_available(const char *name)
0055 {
0056 bool res;
0057
0058 if (lookup_fncache(name, &res))
0059 return res;
0060 res = access(name, R_OK) == 0;
0061 update_fncache(name, res);
0062 return res;
0063 }