archive_multitape.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #include "platform.h"
  2. #include <sys/types.h>
  3. #include <assert.h>
  4. #include <errno.h>
  5. #include <limits.h>
  6. #include "archive.h"
  7. #include "multitape.h"
  8. #include "tsnetwork.h"
  9. #include "warnp.h"
  10. #include "archive_multitape.h"
  11. static ssize_t read_read(struct archive *, void *, const void **);
  12. static off_t read_skip(struct archive *, void *, off_t);
  13. static int read_close(struct archive *, void *);
  14. static ssize_t write_write(struct archive *, void *, const void *, size_t);
  15. static int write_close(struct archive *, void *);
  16. static ssize_t
  17. read_read(struct archive * a, void * cookie, const void ** buffer)
  18. {
  19. struct multitape_read_internal * d = cookie;
  20. ssize_t lenread;
  21. lenread = readtape_read(d, buffer);
  22. if (lenread < 0) {
  23. archive_set_error(a, errno, "Error reading archive");
  24. return (ARCHIVE_FATAL);
  25. } else
  26. return (lenread);
  27. }
  28. static off_t
  29. read_skip(struct archive * a, void * cookie, off_t request)
  30. {
  31. struct multitape_read_internal * d = cookie;
  32. off_t skiplen;
  33. skiplen = readtape_skip(d, request);
  34. if (skiplen < 0) {
  35. archive_set_error(a, errno, "Error reading archive");
  36. return (ARCHIVE_FATAL);
  37. } else
  38. return (skiplen);
  39. }
  40. static int
  41. read_close(struct archive * a, void * cookie)
  42. {
  43. struct multitape_read_internal * d = cookie;
  44. if (readtape_close(d)) {
  45. archive_set_error(a, errno, "Error closing archive");
  46. return (ARCHIVE_FATAL);
  47. } else
  48. return (ARCHIVE_OK);
  49. }
  50. static ssize_t
  51. write_write(struct archive * a, void * cookie, const void * buffer,
  52. size_t nbytes)
  53. {
  54. struct multitape_write_internal * d = cookie;
  55. ssize_t writelen;
  56. /* Sanity check. */
  57. assert(nbytes <= SSIZE_MAX);
  58. writelen = writetape_write(d, buffer, nbytes);
  59. if (writelen < 0) {
  60. archive_set_error(a, errno, "Error writing archive");
  61. return (ARCHIVE_FATAL);
  62. } else if (writelen == 0) {
  63. archive_clear_error(a);
  64. archive_set_error(a, 0, "Archive truncated");
  65. return (ARCHIVE_WARN);
  66. } else
  67. return ((ssize_t)nbytes);
  68. }
  69. static int
  70. write_close(struct archive * a, void * cookie)
  71. {
  72. struct multitape_write_internal * d = cookie;
  73. if (writetape_close(d)) {
  74. archive_set_error(a, errno, "Error closing archive");
  75. return (ARCHIVE_FATAL);
  76. } else
  77. return (ARCHIVE_OK);
  78. }
  79. /**
  80. * archive_read_open_multitape(a, machinenum, tapename):
  81. * Open the multitape tape ${tapename} for reading (and skipping) and
  82. * associate it with the archive ${a}. Return a cookie which can be passed
  83. * to the multitape layer.
  84. */
  85. void *
  86. archive_read_open_multitape(struct archive * a, uint64_t machinenum,
  87. const char * tapename)
  88. {
  89. struct multitape_read_internal * d;
  90. /* Clear any error messages from the archive. */
  91. archive_clear_error(a);
  92. if ((d = readtape_open(machinenum, tapename)) == NULL) {
  93. archive_set_error(a, errno, "Error opening archive");
  94. return (NULL);
  95. }
  96. if (archive_read_open2(a, d, NULL, read_read, read_skip, read_close))
  97. return (NULL);
  98. else
  99. return (d);
  100. }
  101. /**
  102. * archive_write_open_multitape(a, machinenum, cachedir, tapename, argc,
  103. * argv, printstats, dryrun, creationtime, csv_filename, storage_modified):
  104. * Open the multitape tape ${tapename} for writing and associate it with the
  105. * archive ${a}. If ${printstats} is non-zero, print archive statistics when
  106. * the tape is closed. If ${dryrun} is non-zero, perform a dry run.
  107. * Record ${creationtime} as the creation time in the archive metadata.
  108. * If ${csv_filename} is given, write statistics in CSV format. If the
  109. * data on the server has been modified, set ${*storage_modified} to 1.
  110. * Return a cookie which can be passed to the multitape layer.
  111. */
  112. void *
  113. archive_write_open_multitape(struct archive * a, uint64_t machinenum,
  114. const char * cachedir, const char * tapename, int argc,
  115. char ** argv, int printstats, int dryrun, time_t creationtime,
  116. const char * csv_filename, int * storage_modified)
  117. {
  118. struct multitape_write_internal * d;
  119. /* Clear any error messages from the archive. */
  120. archive_clear_error(a);
  121. if ((d = writetape_open(machinenum, cachedir, tapename,
  122. argc, argv, printstats, dryrun, creationtime,
  123. csv_filename, storage_modified)) == NULL) {
  124. archive_set_error(a, errno, "Error creating new archive");
  125. return (NULL);
  126. }
  127. if (archive_write_open(a, d, NULL, write_write, write_close)) {
  128. writetape_free(d);
  129. return (NULL);
  130. } else
  131. return (d);
  132. }
  133. /**
  134. * archive_write_multitape_setmode(a, cookie, mode):
  135. * Set the tape mode to 0 (HEADER), 1 (DATA), or 2 (finished archive entry).
  136. */
  137. int
  138. archive_write_multitape_setmode(struct archive * a, void * cookie, int mode)
  139. {
  140. struct multitape_write_internal * d = cookie;
  141. if (writetape_setmode(d, mode)) {
  142. archive_set_error(a, errno, "Error writing archive");
  143. return (ARCHIVE_FATAL);
  144. } else
  145. return (ARCHIVE_OK);
  146. }
  147. /**
  148. * archive_write_multitape_checkpoint(cookie):
  149. * Create a checkpoint in the archive associated with the write cookie
  150. * ${cookie}.
  151. */
  152. int
  153. archive_write_multitape_checkpoint(void * cookie)
  154. {
  155. struct multitape_write_internal * d = cookie;
  156. return (writetape_checkpoint(d));
  157. }
  158. /**
  159. * archive_write_multitape_truncate(cookie):
  160. * Record that the archive associated with the write cookie ${cookie}
  161. * should be truncated at the current position.
  162. */
  163. void
  164. archive_write_multitape_truncate(void * cookie)
  165. {
  166. struct multitape_write_internal * d = cookie;
  167. writetape_truncate(d);
  168. }
  169. /**
  170. * archive_multitape_copy(ina, read_cookie, a, write_cookie):
  171. * Copy the data for an entry from one archive to another.
  172. */
  173. int
  174. archive_multitape_copy(struct archive * ina, void * read_cookie,
  175. struct archive * a, void * write_cookie)
  176. {
  177. char buff[64*1024];
  178. struct chunkheader * ch;
  179. ssize_t lenread;
  180. ssize_t writelen;
  181. off_t entrylen;
  182. ssize_t backloglen;
  183. /* Compute the entry size. */
  184. if ((entrylen = archive_read_get_entryleft(ina)) < 0) {
  185. archive_set_error(ina, ENOSYS,
  186. "read_get_entryleft not supported");
  187. return (-2);
  188. }
  189. /* Copy data. */
  190. while (entrylen > 0) {
  191. /* Is there data buffered by libarchive? */
  192. if ((backloglen = archive_read_get_backlog(ina)) < 0) {
  193. warn0("Error reading libarchive data backlog");
  194. return (-2);
  195. }
  196. if (backloglen > 0) {
  197. /* Drain some data from libarchive. */
  198. if ((size_t)backloglen > sizeof(buff))
  199. lenread = sizeof(buff);
  200. else
  201. lenread = backloglen;
  202. lenread = archive_read_data(ina, buff, (size_t)lenread);
  203. if (lenread == 0) {
  204. warn0("libarchive claims data backlog,"
  205. " but no data can be read?");
  206. return (-2);
  207. }
  208. if (lenread < 0)
  209. return (-2);
  210. /* Write it out to the new archive. */
  211. writelen = archive_write_data(a, buff, (size_t)lenread);
  212. if (writelen < lenread)
  213. return (-1);
  214. /* Adjust the remaining entry length and continue. */
  215. entrylen -= lenread;
  216. continue;
  217. }
  218. /* Attempt to read a chunk for fast-pathing. */
  219. lenread = readtape_readchunk(read_cookie, &ch);
  220. if (lenread < 0)
  221. return (-2);
  222. if (lenread > entrylen) {
  223. warn0("readchunk returned chunk beyond end"
  224. " of archive entry?");
  225. return (-2);
  226. }
  227. if (lenread == 0)
  228. goto nochunk;
  229. /* Attempt to write the chunk via the fast path. */
  230. writelen = writetape_writechunk(write_cookie, ch);
  231. if (writelen < 0)
  232. return (-1);
  233. if (writelen == 0)
  234. goto nochunk;
  235. if (writelen != lenread) {
  236. warn0("chunk write size != chunk read size?");
  237. return (-1);
  238. }
  239. /*
  240. * Advance libarchive pointers. Do the write pointer
  241. * first since a failure there is fatal.
  242. */
  243. if (archive_write_skip(a, writelen))
  244. return (-1);
  245. if (archive_read_advance(ina, lenread))
  246. return (-2);
  247. /* We don't need to see this chunk again. */
  248. if (readtape_skip(read_cookie, lenread) != lenread) {
  249. warn0("could not skip read data?");
  250. return (-2);
  251. }
  252. /* We've done part of the entry. */
  253. entrylen -= lenread;
  254. continue;
  255. nochunk:
  256. /*
  257. * We have no data buffered in libarchive, and we can't copy
  258. * an intact chunk. We need to read some data, but we have
  259. * no idea how much the multitape layer wants to provide to
  260. * libarchive next; and we don't want to read too much data
  261. * since we might waste time reading and writing chunked data
  262. * which could be fast-pathed. Simple solution: Read and
  263. * write one byte. Libarchive will almost certainly get more
  264. * than one byte from the multitape layer, but when we return
  265. * to the start of this loop and handle backlogged data we
  266. * will pick up the rest of the data. (Also, this is always
  267. * where we end up when we hit the end of an archive entry,
  268. * in which case archive_read_data returns 0 and we exit the
  269. * loop.)
  270. */
  271. lenread = archive_read_data(ina, buff, 1);
  272. if (lenread == 0)
  273. break;
  274. if (lenread < 0)
  275. return (-2);
  276. writelen = archive_write_data(a, buff, 1);
  277. if (writelen < 1)
  278. return (-1);
  279. }
  280. /* Success! */
  281. return (0);
  282. }