ccache_write.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. #include "platform.h"
  2. #include <sys/stat.h>
  3. #include <assert.h>
  4. #include <errno.h>
  5. #include <stdint.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include "asprintf.h"
  11. #include "ccache_internal.h"
  12. #include "dirutil.h"
  13. #include "multitape_internal.h"
  14. #include "patricia.h"
  15. #include "sysendian.h"
  16. #include "warnp.h"
  17. #include "ccache.h"
  18. /* Cookie structure passed to callback_count and callback_write_*. */
  19. struct ccache_write_internal {
  20. size_t N; /* Number of records. */
  21. char * s; /* File name. */
  22. FILE * f; /* File handle. */
  23. char * sbuf; /* Contains a NUL-terminated entry path. */
  24. size_t sbuflen; /* Allocation size of sbuf. */
  25. };
  26. static int callback_count(void * cookie, uint8_t * s, size_t slen,
  27. void * rec);
  28. static int callback_write_rec(void * cookie, uint8_t * s, size_t slen,
  29. void * rec);
  30. static int callback_write_data(void * cookie, uint8_t * s, size_t slen,
  31. void * rec);
  32. /* Should we skip this record? */
  33. static int
  34. skiprecord(struct ccache_record * ccr)
  35. {
  36. /*
  37. * Don't write an entry if there are no chunks and no trailer; if
  38. * there's no data, we don't accomplish anything by having a record
  39. * of the file in our cache.
  40. */
  41. if ((ccr->nch == 0) && (ccr->tlen == 0))
  42. return (1);
  43. /*
  44. * Don't write an entry if it hasn't been used recently; people often
  45. * run several sets of archives covering different directories, so we
  46. * don't want to drop cache entries as soon as they're not used in an
  47. * archive, but we don't want to keep them for too long either so that
  48. * we don't waste time / memory / disk space keeping track of a file
  49. * which we'll never archive again.
  50. */
  51. if (ccr->age > MAXAGE)
  52. return (1);
  53. /*
  54. * Don't write an entry if it has negative mtime. It is very unlikely
  55. * to be correct, and if something is mangling a file's modification
  56. * time there's too much of a risk that we'd rely on the modification
  57. * time and incorrectly conclude that it hasn't been modified since
  58. * the last time we looked at it.
  59. */
  60. if (ccr->mtime < 0)
  61. return (1);
  62. /* This record looks reasonable; write it out. */
  63. return (0);
  64. }
  65. /* Callback to count the number of records which will be written. */
  66. static int
  67. callback_count(void * cookie, uint8_t * s, size_t slen, void * rec)
  68. {
  69. struct ccache_write_internal * W = cookie;
  70. struct ccache_record * ccr = rec;
  71. (void)s; /* UNUSED */
  72. (void)slen; /* UNUSED */
  73. /* Count records we're not skipping. */
  74. if (!skiprecord(ccr))
  75. W->N += 1;
  76. /* Success! */
  77. return (0);
  78. }
  79. /* Callback to write a record and path suffix to disk. */
  80. static int
  81. callback_write_rec(void * cookie, uint8_t * s, size_t slen, void * rec)
  82. {
  83. struct ccache_record_external ccre;
  84. struct ccache_write_internal * W = cookie;
  85. struct ccache_record * ccr = rec;
  86. size_t plen;
  87. /* Skip records which we don't want stored. */
  88. if (skiprecord(ccr))
  89. goto done;
  90. /* Sanity checks. */
  91. assert(slen <= UINT32_MAX);
  92. assert((ccr->size >= 0) && ((uintmax_t)ccr->size <= UINT64_MAX));
  93. assert((uintmax_t)ccr->mtime <= UINT64_MAX);
  94. assert((uintmax_t)ccr->ino <= UINT64_MAX);
  95. /* Figure out how much prefix is shared. */
  96. for (plen = 0; plen < slen && plen < W->sbuflen; plen++) {
  97. if (s[plen] != W->sbuf[plen])
  98. break;
  99. }
  100. /* Convert integers to portable format. */
  101. le64enc(ccre.ino, (uint64_t)ccr->ino);
  102. le64enc(ccre.size, (uint64_t)ccr->size);
  103. le64enc(ccre.mtime, (uint64_t)ccr->mtime);
  104. le64enc(ccre.nch, (uint64_t)ccr->nch);
  105. le32enc(ccre.tlen, (uint32_t)ccr->tlen);
  106. le32enc(ccre.tzlen, (uint32_t)ccr->tzlen);
  107. le32enc(ccre.prefixlen, (uint32_t)plen);
  108. le32enc(ccre.suffixlen, (uint32_t)(slen - plen));
  109. le32enc(ccre.age, (uint32_t)(ccr->age + 1));
  110. /* Write cache entry header to disk. */
  111. if (fwrite(&ccre, sizeof(ccre), 1, W->f) != 1)
  112. goto err0;
  113. /* Write path suffix to disk. */
  114. if (fwrite(s + plen, slen - plen, 1, W->f) != 1)
  115. goto err0;
  116. /* Enlarge last-path buffer if needed. */
  117. if (W->sbuflen < slen + 1) {
  118. free(W->sbuf);
  119. W->sbuflen = slen + 1;
  120. if ((W->sbuf = malloc(W->sbuflen)) == NULL) {
  121. W->sbuflen = 0;
  122. goto err0;
  123. }
  124. memcpy(W->sbuf, s, slen);
  125. } else
  126. memcpy(W->sbuf + plen, s + plen, slen - plen);
  127. W->sbuf[slen] = 0;
  128. done:
  129. /* Success! */
  130. return (0);
  131. err0:
  132. /* Failure! */
  133. return (-1);
  134. }
  135. /* Callback to write chunk headers and compressed entry trailers to disk. */
  136. static int
  137. callback_write_data(void * cookie, uint8_t * s, size_t slen, void * rec)
  138. {
  139. struct ccache_write_internal * W = cookie;
  140. struct ccache_record * ccr = rec;
  141. (void)s; /* UNUSED */
  142. (void)slen; /* UNUSED */
  143. /* Skip records which we don't want stored. */
  144. if (skiprecord(ccr))
  145. goto done;
  146. /* Write chunkheader records to disk, if any. */
  147. if (ccr->chp != NULL) {
  148. if (fwrite(ccr->chp, sizeof(struct chunkheader),
  149. ccr->nch, W->f) != ccr->nch)
  150. goto err0;
  151. }
  152. /* Write compressed trailer to disk, if any. */
  153. if (ccr->ztrailer != NULL) {
  154. if (fwrite(ccr->ztrailer, ccr->tzlen, 1, W->f) != 1)
  155. goto err0;
  156. }
  157. done:
  158. /* Success! */
  159. return (0);
  160. err0:
  161. /* Failure! */
  162. return (-1);
  163. }
  164. /**
  165. * ccache_write(cache, path):
  166. * Write the given chunkification cache into the directory ${path}.
  167. */
  168. int
  169. ccache_write(CCACHE * cache, const char * path)
  170. {
  171. struct ccache_internal * C = cache;
  172. struct ccache_write_internal W;
  173. uint8_t N[4];
  174. char * s_old;
  175. /* The caller must pass a file name to be written. */
  176. assert(path != NULL);
  177. /* Construct name of temporary cache file. */
  178. if (asprintf(&W.s, "%s/cache.new", path) == -1) {
  179. warnp("asprintf");
  180. goto err0;
  181. }
  182. /* Open the cache file for writing. */
  183. if ((W.f = fopen(W.s, "w")) == NULL) {
  184. warnp("fopen(%s)", W.s);
  185. goto err1;
  186. }
  187. /*-
  188. * We make three passes through the cache tree:
  189. * 1. Counting the number of records which will be written to disk.
  190. * This is necessary since records in the cache which are too old
  191. * will not be written, but the on-disk cache format starts with
  192. * the number of records.
  193. * 2. Writing the records and suffixes.
  194. * 3. Writing the cached chunk headers and compressed entry trailers.
  195. */
  196. /* Count the number of records which need to be written. */
  197. W.N = 0;
  198. if (patricia_foreach(C->tree, callback_count, &W)) {
  199. warnp("patricia_foreach");
  200. goto err2;
  201. }
  202. /* Check that we don't have too many cache records. */
  203. if (W.N > UINT32_MAX) {
  204. warn0("Programmer error: "
  205. "The cache cannot contain more than 2^32-1 entries");
  206. goto err2;
  207. }
  208. /* Write the number of records to the file. */
  209. le32enc(N, (uint32_t)W.N);
  210. if (fwrite(N, 4, 1, W.f) != 1) {
  211. warnp("fwrite(%s)", W.s);
  212. goto err2;
  213. }
  214. /* Write the records and suffixes. */
  215. W.sbuf = NULL;
  216. W.sbuflen = 0;
  217. if (patricia_foreach(C->tree, callback_write_rec, &W)) {
  218. warnp("Error writing cache to %s", W.s);
  219. goto err2;
  220. }
  221. free(W.sbuf);
  222. /* Write the chunk headers and compressed entry trailers. */
  223. if (patricia_foreach(C->tree, callback_write_data, &W)) {
  224. warnp("Error writing cache to %s", W.s);
  225. goto err2;
  226. }
  227. /* Finish writing the file. */
  228. if (dirutil_fsync(W.f, W.s))
  229. goto err2;
  230. /* Close the file. */
  231. if (fclose(W.f))
  232. warnp("fclose");
  233. /* Construct the name of the old cache file. */
  234. if (asprintf(&s_old, "%s/cache", path) == -1) {
  235. warnp("asprintf");
  236. goto err1;
  237. }
  238. /* Delete the old file, if it exists. */
  239. if (unlink(s_old)) {
  240. if (errno != ENOENT) {
  241. warnp("unlink(%s)", s_old);
  242. free(s_old);
  243. goto err1;
  244. }
  245. }
  246. /* Move the new cache file into place. */
  247. if (rename(W.s, s_old)) {
  248. warnp("rename(%s, %s)", W.s, s_old);
  249. free(s_old);
  250. goto err1;
  251. }
  252. /* Free strings allocated by asprintf. */
  253. free(s_old);
  254. free(W.s);
  255. /* Success! */
  256. return (0);
  257. err2:
  258. if (fclose(W.f))
  259. warnp("fclose");
  260. err1:
  261. free(W.s);
  262. err0:
  263. /* Failure! */
  264. return (-1);
  265. }
  266. /**
  267. * ccache_remove(path):
  268. * Delete the chunkification cache from the directory ${path}.
  269. */
  270. int
  271. ccache_remove(const char * path)
  272. {
  273. char * s;
  274. /* The caller must pass a file name to be deleted. */
  275. assert(path != NULL);
  276. /* Construct the name of the cache file. */
  277. if (asprintf(&s, "%s/cache", path) == -1) {
  278. warnp("asprintf");
  279. goto err1;
  280. }
  281. /* Delete the file if it exists. */
  282. if (unlink(s)) {
  283. if (errno != ENOENT) {
  284. warnp("unlink(%s)", s);
  285. goto err1;
  286. }
  287. }
  288. /* Free string allocated by asprintf. */
  289. free(s);
  290. /* Success! */
  291. return (0);
  292. err1:
  293. free(s);
  294. /* Failure! */
  295. return (-1);
  296. }