ccache_read.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. #include "platform.h"
  2. #include <sys/mman.h>
  3. #include <sys/stat.h>
  4. #include <assert.h>
  5. #include <errno.h>
  6. #include <limits.h>
  7. #include <stdint.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include "asprintf.h"
  13. #include "ccache_internal.h"
  14. #include "multitape_internal.h"
  15. #include "patricia.h"
  16. #include "sysendian.h"
  17. #include "warnp.h"
  18. #include "ccache.h"
  19. /* Cookie structure passed to read_rec and callback_read_data. */
  20. struct ccache_read_internal {
  21. size_t N; /* Number of records. */
  22. char * s; /* File name. */
  23. FILE * f; /* File handle. */
  24. uint8_t * sbuf; /* Contains a NUL-terminated entry path. */
  25. size_t sbuflen; /* Allocation size of sbuf. */
  26. size_t slen; /* Length of string currently stored in sbuf. */
  27. size_t datalen; /* Sum of chunk header and trailer lengths. */
  28. uint8_t * data; /* Mmapped data. */
  29. };
  30. static struct ccache_record * read_rec(void * cookie);
  31. static int callback_read_data(void * cookie, uint8_t * s, size_t slen,
  32. void * rec);
  33. static int callback_free(void * cookie, uint8_t * s, size_t slen,
  34. void * rec);
  35. /* Read a cache record. */
  36. static struct ccache_record *
  37. read_rec(void * cookie)
  38. {
  39. struct ccache_record_external ccre;
  40. struct ccache_read_internal * R = cookie;
  41. struct ccache_record * ccr;
  42. size_t prefixlen, suffixlen;
  43. uint8_t * sbuf_new;
  44. /* Read a struct ccache_record_external. */
  45. if (fread(&ccre, sizeof(ccre), 1, R->f) != 1) {
  46. if (ferror(R->f))
  47. warnp("Error reading cache: %s", R->s);
  48. else
  49. warn0("Error reading cache: %s", R->s);
  50. goto err0;
  51. }
  52. /* Allocate memory for a record. */
  53. if ((ccr = malloc(sizeof(struct ccache_record))) == NULL)
  54. goto err0;
  55. /* Decode record. */
  56. ccr->ino = (ino_t)le64dec(ccre.ino);
  57. ccr->size = (off_t)le64dec(ccre.size);
  58. ccr->mtime = (time_t)le64dec(ccre.mtime);
  59. ccr->nch = (size_t)le64dec(ccre.nch);
  60. ccr->tlen = le32dec(ccre.tlen);
  61. ccr->tzlen = le32dec(ccre.tzlen);
  62. prefixlen = le32dec(ccre.prefixlen);
  63. suffixlen = le32dec(ccre.suffixlen);
  64. ccr->age = (int)le32dec(ccre.age);
  65. /* Zero other fields. */
  66. ccr->nchalloc = 0;
  67. ccr->chp = NULL;
  68. ccr->ztrailer = NULL;
  69. ccr->flags = 0;
  70. /* Sanity check some fields. */
  71. #if SIZE_MAX < UINT64_MAX
  72. if (le64dec(ccre.nch) > (uint64_t)SIZE_MAX) {
  73. warn0("Cache file is corrupt or too large for this "
  74. "platform: %s", R->s);
  75. goto err1;
  76. }
  77. #endif
  78. if ((prefixlen == 0 && suffixlen == 0) ||
  79. (ccr->nch > SIZE_MAX / sizeof(struct chunkheader)) ||
  80. (ccr->nch == 0 && ccr->tlen == 0) ||
  81. (ccr->tlen == 0 && ccr->tzlen != 0) ||
  82. (ccr->tlen != 0 && ccr->tzlen == 0) ||
  83. (ccr->age == INT_MAX))
  84. goto err2;
  85. /*
  86. * The prefix length must be <= the length of the previous path; and
  87. * the prefix length + suffix length must not overflow.
  88. */
  89. if ((prefixlen > R->slen) || (prefixlen > prefixlen + suffixlen))
  90. goto err2;
  91. /* Make sure we have enough space for the entry path. */
  92. if (prefixlen + suffixlen > R->sbuflen) {
  93. sbuf_new = realloc(R->sbuf, prefixlen + suffixlen);
  94. if (sbuf_new == NULL)
  95. goto err1;
  96. R->sbuf = sbuf_new;
  97. R->sbuflen = prefixlen + suffixlen;
  98. }
  99. /* Read the entry path suffix. */
  100. if (fread(R->sbuf + prefixlen, suffixlen, 1, R->f) != 1) {
  101. if (ferror(R->f))
  102. warnp("Error reading cache: %s", R->s);
  103. else
  104. warn0("Error reading cache: %s", R->s);
  105. goto err1;
  106. }
  107. R->slen = prefixlen + suffixlen;
  108. /* Add chunk header and trailer data lengths to datalen. */
  109. R->datalen += ccr->tzlen;
  110. if (R->datalen < ccr->tzlen)
  111. goto err2;
  112. R->datalen += ccr->nch * sizeof(struct chunkheader);
  113. if (R->datalen < ccr->nch * sizeof(struct chunkheader))
  114. goto err2;
  115. /* Success! */
  116. return (ccr);
  117. err2:
  118. warn0("Cache file is corrupt: %s", R->s);
  119. err1:
  120. free(ccr);
  121. err0:
  122. /* Failure! */
  123. return (NULL);
  124. }
  125. /* Read chunk headers and compressed entry trailer if appropriate. */
  126. static int
  127. callback_read_data(void * cookie, uint8_t * s, size_t slen, void * rec)
  128. {
  129. struct ccache_read_internal * R = cookie;
  130. struct ccache_record * ccr = rec;
  131. (void)s; /* UNUSED */
  132. (void)slen; /* UNUSED */
  133. /* Read chunk headers, if present. */
  134. if (ccr->nch) {
  135. ccr->chp = (struct chunkheader *)(R->data);
  136. R->data += ccr->nch * sizeof(struct chunkheader);
  137. }
  138. /* Read compressed trailer, if present. */
  139. if (ccr->tzlen) {
  140. ccr->ztrailer = R->data;
  141. R->data += ccr->tzlen;
  142. }
  143. /* Success! */
  144. return (0);
  145. }
  146. /* Callback to free a ccache_record structure. */
  147. static int
  148. callback_free(void * cookie, uint8_t * s, size_t slen, void * rec)
  149. {
  150. struct ccache_record * ccr = rec;
  151. (void)cookie; /* UNUSED */
  152. (void)s; /* UNUSED */
  153. (void)slen; /* UNUSED */
  154. /* Free chunkheader records, if they weren't mmapped. */
  155. if (ccr->nchalloc)
  156. free(ccr->chp);
  157. /* Free trailer, if not mmapped. */
  158. if (ccr->flags & CCR_ZTRAILER_MALLOC)
  159. free(ccr->ztrailer);
  160. /* Free cache record. */
  161. free(ccr);
  162. /* Success! */
  163. return (0);
  164. }
  165. /**
  166. * ccache_read(path):
  167. * Read the chunkification cache (if present) from the directory ${path};
  168. * return a Patricia tree mapping absolute paths to cache entries.
  169. */
  170. CCACHE *
  171. ccache_read(const char * path)
  172. {
  173. struct ccache_internal * C;
  174. struct ccache_read_internal R;
  175. struct ccache_record * ccr;
  176. #ifdef HAVE_MMAP
  177. struct stat sb;
  178. off_t fpos;
  179. long int pagesize;
  180. #endif
  181. size_t i;
  182. uint8_t N[4];
  183. /* The caller must pass a file name to be read. */
  184. assert(path != NULL);
  185. /* Allocate memory for the cache. */
  186. if ((C = malloc(sizeof(struct ccache_internal))) == NULL)
  187. goto err0;
  188. memset(C, 0, sizeof(struct ccache_internal));
  189. /* Create a Patricia tree to store cache entries. */
  190. if ((C->tree = patricia_init()) == NULL)
  191. goto err1;
  192. /* Construct the name of cache file. */
  193. if (asprintf(&R.s, "%s/cache", path) == -1) {
  194. warnp("asprintf");
  195. goto err2;
  196. }
  197. /* Open the cache file. */
  198. if ((R.f = fopen(R.s, "r")) == NULL) {
  199. /* ENOENT isn't an error. */
  200. if (errno != ENOENT) {
  201. warnp("fopen(%s)", R.s);
  202. goto err3;
  203. }
  204. /* No cache exists on disk; return an empty cache. */
  205. goto emptycache;
  206. }
  207. /*-
  208. * We read the cache file in three steps:
  209. * 1. Read a little-endian uint32_t which indicates the number of
  210. * records in the cache file.
  211. * 2. Read N (record, path suffix) pairs and insert them into a
  212. * Patricia tree.
  213. * 3. Iterate through the tree and read chunk headers and compressed
  214. * entry trailers.
  215. */
  216. /* Read the number of cache entries. */
  217. if (fread(N, 4, 1, R.f) != 1) {
  218. if (ferror(R.f))
  219. warnp("Error reading cache: %s", R.s);
  220. else
  221. warn0("Error reading cache: %s", R.s);
  222. goto err4;
  223. }
  224. R.N = le32dec(N);
  225. /* Read N (record, path suffix) pairs. */
  226. R.sbuf = NULL;
  227. R.sbuflen = R.slen = R.datalen = 0;
  228. for (i = 0; i < R.N; i++) {
  229. if ((ccr = read_rec(&R)) == NULL)
  230. goto err5;
  231. if (patricia_insert(C->tree, R.sbuf, R.slen, ccr))
  232. goto err5;
  233. C->chunksusage += ccr->nch * sizeof(struct chunkheader);
  234. C->trailerusage += ccr->tzlen;
  235. }
  236. #ifdef HAVE_MMAP
  237. /* Obtain page size, since mmapped regions must be page-aligned. */
  238. if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) {
  239. warnp("sysconf(_SC_PAGESIZE)");
  240. goto err5;
  241. }
  242. /* Map the remainder of the cache into memory. */
  243. fpos = ftello(R.f);
  244. if (fpos == -1) {
  245. warnp("ftello(%s)", R.s);
  246. goto err5;
  247. }
  248. if (fstat(fileno(R.f), &sb)) {
  249. warnp("fstat(%s)", R.s);
  250. goto err5;
  251. }
  252. if (sb.st_size != fpos + (off_t)R.datalen) {
  253. warn0("Cache has incorrect size (%jd, expected %jd)",
  254. (intmax_t)(sb.st_size),
  255. (intmax_t)(fpos + (off_t)R.datalen));
  256. goto err5;
  257. }
  258. C->datalen = R.datalen + (size_t)(fpos % pagesize);
  259. if ((C->data = mmap(NULL, C->datalen, PROT_READ,
  260. #ifdef MAP_NOCORE
  261. MAP_PRIVATE | MAP_NOCORE,
  262. #else
  263. MAP_PRIVATE,
  264. #endif
  265. fileno(R.f), fpos - (fpos % pagesize))) == MAP_FAILED) {
  266. warnp("mmap(%s)", R.s);
  267. goto err5;
  268. }
  269. R.data = (uint8_t *)C->data + (fpos % pagesize);
  270. #else
  271. /* Allocate space. */
  272. C->datalen = R.datalen;
  273. if (((C->data = malloc(C->datalen)) == NULL) && (C->datalen > 0))
  274. goto err5;
  275. if (fread(C->data, C->datalen, 1, R.f) != 1) {
  276. warnp("fread(%s)", R.s);
  277. goto err6;
  278. }
  279. R.data = (uint8_t *)C->data;
  280. #endif
  281. /* Iterate through the tree reading chunk headers and trailers. */
  282. if (patricia_foreach(C->tree, callback_read_data, &R)) {
  283. warnp("Error reading cache: %s", R.s);
  284. goto err6;
  285. }
  286. /* Free buffer used for storing paths. */
  287. free(R.sbuf);
  288. /* Close the cache file. */
  289. if (fclose(R.f))
  290. warnp("fclose");
  291. /* Free string allocated by asprintf. */
  292. free(R.s);
  293. /* Success! */
  294. return (C);
  295. emptycache:
  296. /* Nothing went wrong, but there's nothing on disk. */
  297. free(R.s);
  298. return (C);
  299. err6:
  300. #ifdef HAVE_MMAP
  301. if (C->datalen > 0)
  302. munmap(C->data, C->datalen);
  303. #else
  304. free(C->data);
  305. #endif
  306. err5:
  307. free(R.sbuf);
  308. patricia_foreach(C->tree, callback_free, NULL);
  309. err4:
  310. if (fclose(R.f))
  311. warnp("fclose");
  312. err3:
  313. free(R.s);
  314. err2:
  315. patricia_free(C->tree);
  316. err1:
  317. free(C);
  318. err0:
  319. /* Failure! */
  320. return (NULL);
  321. }
  322. /**
  323. * ccache_free(cache):
  324. * Free the cache and all of its entries.
  325. */
  326. void
  327. ccache_free(CCACHE * cache)
  328. {
  329. struct ccache_internal * C = cache;
  330. if (cache == NULL)
  331. return;
  332. /* Free all of the records in the patricia tree. */
  333. patricia_foreach(C->tree, callback_free, NULL);
  334. /* Free the patricia tree itself. */
  335. patricia_free(C->tree);
  336. /* Unmap memory. */
  337. #ifdef HAVE_MMAP
  338. if (C->datalen > 0 && munmap(C->data, C->datalen))
  339. warnp("munmap failed on cache data");
  340. #else
  341. free(C->data);
  342. #endif
  343. /* Free the cache. */
  344. free(C);
  345. }