pathcache.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * Copyright (c) 2011-2012 Nokia Corporation and/or its subsidiary(-ies).
  3. * All rights reserved.
  4. * This component and the accompanying materials are made available
  5. * under the terms of the License "Eclipse Public License v1.0"
  6. * which accompanies this distribution, and is available
  7. * at the URL "http://www.eclipse.org/legal/epl-v10.html".
  8. *
  9. * Initial Contributors:
  10. * Nokia Corporation - initial contribution.
  11. *
  12. * Contributors:
  13. *
  14. * Description:
  15. *
  16. * pathcache.c - maps between the lowercase of a filename and the actual
  17. * name on the filesystem.
  18. */
  19. #include <alloca.h>
  20. #include <string.h>
  21. #include <errno.h>
  22. #include <dirent.h>
  23. #include <ctype.h>
  24. #include <assert.h>
  25. #include "pathcache.h"
  26. #include "debug.h"
  27. HashTable *caseless_ht = NULL;
  28. long caseless_cache_hits = 0;
  29. long caseless_cache_misses = 0;
  30. void caseless_cache_init(const char rootpath[])
  31. {
  32. assert(rootpath);
  33. caseless_ht = hashtable_new(MAX_FILENAME_CACHE);
  34. cache_subtree(rootpath, caseless_ht);
  35. }
  36. /*
  37. Record a file in the cach using the lowercased absolute path as a key
  38. */
  39. void caseless_cache_path(const char path[])
  40. {
  41. assert(path);
  42. char * lowercase_path = alloca(strlen(path)+1);
  43. int i;
  44. for (i = 0; path[i] != '\0'; i++)
  45. {
  46. lowercase_path[i] = tolower(path[i]);
  47. }
  48. lowercase_path[i] = '\0';
  49. hashtable_store(caseless_ht, lowercase_path, path);
  50. }
  51. /*
  52. Mark a file as not existing in the cache so it's quick to answer "stat" operaions
  53. that look for files which are not there - e.g. when make is running.
  54. */
  55. void caseless_cache_missing(const char path[])
  56. {
  57. assert(path);
  58. char * lowercase_path = alloca(strlen(path)+1);
  59. int i;
  60. for (i = 0; path[i] != '\0'; i++)
  61. {
  62. lowercase_path[i] = tolower(path[i]);
  63. }
  64. lowercase_path[i] = '\0';
  65. hashtable_store(caseless_ht, lowercase_path, "");
  66. }
  67. /*
  68. see if a file is in the cache without regarding the case of the filename
  69. - return the absolute "real" name of the file on disc (ie. with correct case)
  70. or NULL if the file doesn't exist.
  71. */
  72. char *caseless_cache_lookup(const char path[])
  73. {
  74. assert(path);
  75. char *lowercase_path = alloca(strlen(path)+1);
  76. int i;
  77. for (i = 0; path[i] != '\0'; i++)
  78. {
  79. lowercase_path[i] = tolower(path[i]);
  80. }
  81. lowercase_path[i] = '\0';
  82. return hashtable_lookup(caseless_ht, lowercase_path);
  83. }
  84. /*
  85. cache_subtree
  86. path - path to start from
  87. dircache - hashtable to add case insensitive mappings to.
  88. Recursive function to pre-fill the cache with all files and directories
  89. from the source subtree down. This would usually be done once when the
  90. filesystem is first mounted to populate the cache with existing files.
  91. The open, create, unlink etc function calls are then supposed to keep
  92. the cache uptodate.
  93. */
  94. int cache_subtree(const char path[], HashTable *dircache)
  95. {
  96. DIR *d = NULL;
  97. struct dirent entry;
  98. struct dirent *index;
  99. assert(path);
  100. int path_len = strlen(path) + NAME_MAX + 2;
  101. char * subpath = alloca(path_len);
  102. assert(dircache);
  103. d = opendir(path);
  104. debug(">>cache_subtree: opened %s, result=%d\n",path,(size_t)d);
  105. if (!d)
  106. return errno;
  107. readdir_r(d, &entry, &index);
  108. debug(">>cache_subtree: initial readdir %s\n",entry.d_name);
  109. while (index == &entry)
  110. {
  111. if (strcmp(entry.d_name,".") == 0 ||
  112. strcmp(entry.d_name,"..") == 0)
  113. {
  114. readdir_r(d, &entry, &index);
  115. continue;
  116. }
  117. strcpy(subpath, path);
  118. strcat(subpath, "/");
  119. strcat(subpath, entry.d_name);
  120. caseless_cache_path(subpath);
  121. if (entry.d_type == DT_DIR)
  122. {
  123. cache_subtree(subpath, dircache);
  124. }
  125. readdir_r(d, &entry, &index);
  126. }
  127. caseless_cache_path(path);
  128. closedir(d);
  129. return 0;
  130. }
  131. /*
  132. Locates files and caches the results for future use. Records
  133. as missing those files that are looked for but not found.
  134. The input parameter is modified to contain the actual filename
  135. so must be big enough to hold any possible absolute filename.
  136. returns 0 if the file is found, non-zero if it isn't.
  137. */
  138. int cached_findcaseless(char *path)
  139. {
  140. int fcr = 0;
  141. char *cached;
  142. assert(path);
  143. cached = caseless_cache_lookup(path);
  144. debug("caseless: cache_hit sought '%s', found '%s'\n", path, cached);
  145. if (cached)
  146. {
  147. if (cached[0] == '\0')
  148. {
  149. debug("caseless: file known to not exist '%s'\n", path);
  150. fcr = 1;
  151. } else {
  152. strcpy(path,cached); // dest should be big enough
  153. }
  154. caseless_cache_hits = (caseless_cache_hits+1) % 2000000000;
  155. } else {
  156. debug("caseless: cache_miss '%s'\n", path);
  157. caseless_cache_missing(path);
  158. fcr = 1;
  159. }
  160. return fcr;
  161. }