fncache.c 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Manage a cache of file names' existence */
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <linux/list.h>
  7. #include "fncache.h"
  8. struct fncache {
  9. struct hlist_node nd;
  10. bool res;
  11. char name[];
  12. };
  13. #define FNHSIZE 61
  14. static struct hlist_head fncache_hash[FNHSIZE];
  15. unsigned shash(const unsigned char *s)
  16. {
  17. unsigned h = 0;
  18. while (*s)
  19. h = 65599 * h + *s++;
  20. return h ^ (h >> 16);
  21. }
  22. static bool lookup_fncache(const char *name, bool *res)
  23. {
  24. int h = shash((const unsigned char *)name) % FNHSIZE;
  25. struct fncache *n;
  26. hlist_for_each_entry(n, &fncache_hash[h], nd) {
  27. if (!strcmp(n->name, name)) {
  28. *res = n->res;
  29. return true;
  30. }
  31. }
  32. return false;
  33. }
  34. static void update_fncache(const char *name, bool res)
  35. {
  36. struct fncache *n = malloc(sizeof(struct fncache) + strlen(name) + 1);
  37. int h = shash((const unsigned char *)name) % FNHSIZE;
  38. if (!n)
  39. return;
  40. strcpy(n->name, name);
  41. n->res = res;
  42. hlist_add_head(&n->nd, &fncache_hash[h]);
  43. }
  44. /* No LRU, only use when bounded in some other way. */
  45. bool file_available(const char *name)
  46. {
  47. bool res;
  48. if (lookup_fncache(name, &res))
  49. return res;
  50. res = access(name, R_OK) == 0;
  51. update_fncache(name, res);
  52. return res;
  53. }