/usr.bin/tar/read.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 450 lines · 328 code · 42 blank · 80 comment · 102 complexity · 797fbda91c828031c16e2f50b35abe0c MD5 · raw file

  1. /*-
  2. * Copyright (c) 2003-2007 Tim Kientzle
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "bsdtar_platform.h"
  26. __FBSDID("$FreeBSD$");
  27. #ifdef HAVE_SYS_TYPES_H
  28. #include <sys/types.h>
  29. #endif
  30. #ifdef HAVE_SYS_PARAM_H
  31. #include <sys/param.h>
  32. #endif
  33. #ifdef HAVE_SYS_STAT_H
  34. #include <sys/stat.h>
  35. #endif
  36. #ifdef HAVE_ERRNO_H
  37. #include <errno.h>
  38. #endif
  39. #ifdef HAVE_GRP_H
  40. #include <grp.h>
  41. #endif
  42. #ifdef HAVE_LIMITS_H
  43. #include <limits.h>
  44. #endif
  45. #ifdef HAVE_PWD_H
  46. #include <pwd.h>
  47. #endif
  48. #ifdef HAVE_STDINT_H
  49. #include <stdint.h>
  50. #endif
  51. #include <stdio.h>
  52. #ifdef HAVE_STDLIB_H
  53. #include <stdlib.h>
  54. #endif
  55. #ifdef HAVE_STRING_H
  56. #include <string.h>
  57. #endif
  58. #ifdef HAVE_TIME_H
  59. #include <time.h>
  60. #endif
  61. #ifdef HAVE_UNISTD_H
  62. #include <unistd.h>
  63. #endif
  64. #include "bsdtar.h"
  65. #include "err.h"
  66. struct progress_data {
  67. struct bsdtar *bsdtar;
  68. struct archive *archive;
  69. struct archive_entry *entry;
  70. };
  71. static void list_item_verbose(struct bsdtar *, FILE *,
  72. struct archive_entry *);
  73. static void read_archive(struct bsdtar *bsdtar, char mode);
  74. void
  75. tar_mode_t(struct bsdtar *bsdtar)
  76. {
  77. read_archive(bsdtar, 't');
  78. if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0)
  79. bsdtar->return_value = 1;
  80. }
  81. void
  82. tar_mode_x(struct bsdtar *bsdtar)
  83. {
  84. read_archive(bsdtar, 'x');
  85. if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0)
  86. bsdtar->return_value = 1;
  87. }
  88. static void
  89. progress_func(void *cookie)
  90. {
  91. struct progress_data *progress_data = cookie;
  92. struct bsdtar *bsdtar = progress_data->bsdtar;
  93. struct archive *a = progress_data->archive;
  94. struct archive_entry *entry = progress_data->entry;
  95. uint64_t comp, uncomp;
  96. int compression;
  97. if (!need_report())
  98. return;
  99. if (bsdtar->verbose)
  100. fprintf(stderr, "\n");
  101. if (a != NULL) {
  102. comp = archive_position_compressed(a);
  103. uncomp = archive_position_uncompressed(a);
  104. if (comp > uncomp)
  105. compression = 0;
  106. else
  107. compression = (int)((uncomp - comp) * 100 / uncomp);
  108. fprintf(stderr,
  109. "In: %s bytes, compression %d%%;",
  110. tar_i64toa(comp), compression);
  111. fprintf(stderr, " Out: %d files, %s bytes\n",
  112. archive_file_count(a), tar_i64toa(uncomp));
  113. }
  114. if (entry != NULL) {
  115. safe_fprintf(stderr, "Current: %s",
  116. archive_entry_pathname(entry));
  117. fprintf(stderr, " (%s bytes)\n",
  118. tar_i64toa(archive_entry_size(entry)));
  119. }
  120. }
  121. /*
  122. * Handle 'x' and 't' modes.
  123. */
  124. static void
  125. read_archive(struct bsdtar *bsdtar, char mode)
  126. {
  127. struct progress_data progress_data;
  128. FILE *out;
  129. struct archive *a;
  130. struct archive_entry *entry;
  131. const struct stat *st;
  132. int r;
  133. while (*bsdtar->argv) {
  134. lafe_include(&bsdtar->matching, *bsdtar->argv);
  135. bsdtar->argv++;
  136. }
  137. if (bsdtar->names_from_file != NULL)
  138. lafe_include_from_file(&bsdtar->matching,
  139. bsdtar->names_from_file, bsdtar->option_null);
  140. a = archive_read_new();
  141. if (bsdtar->compress_program != NULL)
  142. archive_read_support_compression_program(a, bsdtar->compress_program);
  143. else
  144. archive_read_support_compression_all(a);
  145. archive_read_support_format_all(a);
  146. if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options))
  147. lafe_errc(1, 0, "%s", archive_error_string(a));
  148. if (archive_read_open_file(a, bsdtar->filename,
  149. bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block :
  150. DEFAULT_BYTES_PER_BLOCK))
  151. lafe_errc(1, 0, "Error opening archive: %s",
  152. archive_error_string(a));
  153. do_chdir(bsdtar);
  154. if (mode == 'x') {
  155. /* Set an extract callback so that we can handle SIGINFO. */
  156. progress_data.bsdtar = bsdtar;
  157. progress_data.archive = a;
  158. archive_read_extract_set_progress_callback(a, progress_func,
  159. &progress_data);
  160. }
  161. if (mode == 'x' && bsdtar->option_chroot) {
  162. #if HAVE_CHROOT
  163. if (chroot(".") != 0)
  164. lafe_errc(1, errno, "Can't chroot to \".\"");
  165. #else
  166. lafe_errc(1, 0,
  167. "chroot isn't supported on this platform");
  168. #endif
  169. }
  170. for (;;) {
  171. /* Support --fast-read option */
  172. if (bsdtar->option_fast_read &&
  173. lafe_unmatched_inclusions(bsdtar->matching) == 0)
  174. break;
  175. r = archive_read_next_header(a, &entry);
  176. progress_data.entry = entry;
  177. if (r == ARCHIVE_EOF)
  178. break;
  179. if (r < ARCHIVE_OK)
  180. lafe_warnc(0, "%s", archive_error_string(a));
  181. if (r <= ARCHIVE_WARN)
  182. bsdtar->return_value = 1;
  183. if (r == ARCHIVE_RETRY) {
  184. /* Retryable error: try again */
  185. lafe_warnc(0, "Retrying...");
  186. continue;
  187. }
  188. if (r == ARCHIVE_FATAL)
  189. break;
  190. if (bsdtar->uid >= 0) {
  191. archive_entry_set_uid(entry, bsdtar->uid);
  192. archive_entry_set_uname(entry, NULL);
  193. }
  194. if (bsdtar->gid >= 0) {
  195. archive_entry_set_gid(entry, bsdtar->gid);
  196. archive_entry_set_gname(entry, NULL);
  197. }
  198. if (bsdtar->uname)
  199. archive_entry_set_uname(entry, bsdtar->uname);
  200. if (bsdtar->gname)
  201. archive_entry_set_gname(entry, bsdtar->gname);
  202. /*
  203. * Exclude entries that are too old.
  204. */
  205. st = archive_entry_stat(entry);
  206. if (bsdtar->newer_ctime_sec > 0) {
  207. if (st->st_ctime < bsdtar->newer_ctime_sec)
  208. continue; /* Too old, skip it. */
  209. if (st->st_ctime == bsdtar->newer_ctime_sec
  210. && ARCHIVE_STAT_CTIME_NANOS(st)
  211. <= bsdtar->newer_ctime_nsec)
  212. continue; /* Too old, skip it. */
  213. }
  214. if (bsdtar->newer_mtime_sec > 0) {
  215. if (st->st_mtime < bsdtar->newer_mtime_sec)
  216. continue; /* Too old, skip it. */
  217. if (st->st_mtime == bsdtar->newer_mtime_sec
  218. && ARCHIVE_STAT_MTIME_NANOS(st)
  219. <= bsdtar->newer_mtime_nsec)
  220. continue; /* Too old, skip it. */
  221. }
  222. /*
  223. * Note that pattern exclusions are checked before
  224. * pathname rewrites are handled. This gives more
  225. * control over exclusions, since rewrites always lose
  226. * information. (For example, consider a rewrite
  227. * s/foo[0-9]/foo/. If we check exclusions after the
  228. * rewrite, there would be no way to exclude foo1/bar
  229. * while allowing foo2/bar.)
  230. */
  231. if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry)))
  232. continue; /* Excluded by a pattern test. */
  233. if (mode == 't') {
  234. /* Perversely, gtar uses -O to mean "send to stderr"
  235. * when used with -t. */
  236. out = bsdtar->option_stdout ? stderr : stdout;
  237. /*
  238. * TODO: Provide some reasonable way to
  239. * preview rewrites. gtar always displays
  240. * the unedited path in -t output, which means
  241. * you cannot easily preview rewrites.
  242. */
  243. if (bsdtar->verbose < 2)
  244. safe_fprintf(out, "%s",
  245. archive_entry_pathname(entry));
  246. else
  247. list_item_verbose(bsdtar, out, entry);
  248. fflush(out);
  249. r = archive_read_data_skip(a);
  250. if (r == ARCHIVE_WARN) {
  251. fprintf(out, "\n");
  252. lafe_warnc(0, "%s",
  253. archive_error_string(a));
  254. }
  255. if (r == ARCHIVE_RETRY) {
  256. fprintf(out, "\n");
  257. lafe_warnc(0, "%s",
  258. archive_error_string(a));
  259. }
  260. if (r == ARCHIVE_FATAL) {
  261. fprintf(out, "\n");
  262. lafe_warnc(0, "%s",
  263. archive_error_string(a));
  264. bsdtar->return_value = 1;
  265. break;
  266. }
  267. fprintf(out, "\n");
  268. } else {
  269. /* Note: some rewrite failures prevent extraction. */
  270. if (edit_pathname(bsdtar, entry))
  271. continue; /* Excluded by a rewrite failure. */
  272. if (bsdtar->option_interactive &&
  273. !yes("extract '%s'", archive_entry_pathname(entry)))
  274. continue;
  275. /*
  276. * Format here is from SUSv2, including the
  277. * deferred '\n'.
  278. */
  279. if (bsdtar->verbose) {
  280. safe_fprintf(stderr, "x %s",
  281. archive_entry_pathname(entry));
  282. fflush(stderr);
  283. }
  284. // TODO siginfo_printinfo(bsdtar, 0);
  285. if (bsdtar->option_stdout)
  286. r = archive_read_data_into_fd(a, 1);
  287. else
  288. r = archive_read_extract(a, entry,
  289. bsdtar->extract_flags);
  290. if (r != ARCHIVE_OK) {
  291. if (!bsdtar->verbose)
  292. safe_fprintf(stderr, "%s",
  293. archive_entry_pathname(entry));
  294. safe_fprintf(stderr, ": %s",
  295. archive_error_string(a));
  296. if (!bsdtar->verbose)
  297. fprintf(stderr, "\n");
  298. bsdtar->return_value = 1;
  299. }
  300. if (bsdtar->verbose)
  301. fprintf(stderr, "\n");
  302. if (r == ARCHIVE_FATAL)
  303. break;
  304. }
  305. }
  306. r = archive_read_close(a);
  307. if (r != ARCHIVE_OK)
  308. lafe_warnc(0, "%s", archive_error_string(a));
  309. if (r <= ARCHIVE_WARN)
  310. bsdtar->return_value = 1;
  311. if (bsdtar->verbose > 2)
  312. fprintf(stdout, "Archive Format: %s, Compression: %s\n",
  313. archive_format_name(a), archive_compression_name(a));
  314. archive_read_finish(a);
  315. }
  316. /*
  317. * Display information about the current file.
  318. *
  319. * The format here roughly duplicates the output of 'ls -l'.
  320. * This is based on SUSv2, where 'tar tv' is documented as
  321. * listing additional information in an "unspecified format,"
  322. * and 'pax -l' is documented as using the same format as 'ls -l'.
  323. */
  324. static void
  325. list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
  326. {
  327. char tmp[100];
  328. size_t w;
  329. const char *p;
  330. const char *fmt;
  331. time_t tim;
  332. static time_t now;
  333. /*
  334. * We avoid collecting the entire list in memory at once by
  335. * listing things as we see them. However, that also means we can't
  336. * just pre-compute the field widths. Instead, we start with guesses
  337. * and just widen them as necessary. These numbers are completely
  338. * arbitrary.
  339. */
  340. if (!bsdtar->u_width) {
  341. bsdtar->u_width = 6;
  342. bsdtar->gs_width = 13;
  343. }
  344. if (!now)
  345. time(&now);
  346. fprintf(out, "%s %d ",
  347. archive_entry_strmode(entry),
  348. archive_entry_nlink(entry));
  349. /* Use uname if it's present, else uid. */
  350. p = archive_entry_uname(entry);
  351. if ((p == NULL) || (*p == '\0')) {
  352. sprintf(tmp, "%lu ",
  353. (unsigned long)archive_entry_uid(entry));
  354. p = tmp;
  355. }
  356. w = strlen(p);
  357. if (w > bsdtar->u_width)
  358. bsdtar->u_width = w;
  359. fprintf(out, "%-*s ", (int)bsdtar->u_width, p);
  360. /* Use gname if it's present, else gid. */
  361. p = archive_entry_gname(entry);
  362. if (p != NULL && p[0] != '\0') {
  363. fprintf(out, "%s", p);
  364. w = strlen(p);
  365. } else {
  366. sprintf(tmp, "%lu",
  367. (unsigned long)archive_entry_gid(entry));
  368. w = strlen(tmp);
  369. fprintf(out, "%s", tmp);
  370. }
  371. /*
  372. * Print device number or file size, right-aligned so as to make
  373. * total width of group and devnum/filesize fields be gs_width.
  374. * If gs_width is too small, grow it.
  375. */
  376. if (archive_entry_filetype(entry) == AE_IFCHR
  377. || archive_entry_filetype(entry) == AE_IFBLK) {
  378. sprintf(tmp, "%lu,%lu",
  379. (unsigned long)archive_entry_rdevmajor(entry),
  380. (unsigned long)archive_entry_rdevminor(entry));
  381. } else {
  382. strcpy(tmp, tar_i64toa(archive_entry_size(entry)));
  383. }
  384. if (w + strlen(tmp) >= bsdtar->gs_width)
  385. bsdtar->gs_width = w+strlen(tmp)+1;
  386. fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp);
  387. /* Format the time using 'ls -l' conventions. */
  388. tim = archive_entry_mtime(entry);
  389. #define HALF_YEAR (time_t)365 * 86400 / 2
  390. #if defined(_WIN32) && !defined(__CYGWIN__)
  391. #define DAY_FMT "%d" /* Windows' strftime function does not support %e format. */
  392. #else
  393. #define DAY_FMT "%e" /* Day number without leading zeros */
  394. #endif
  395. if (tim < now - HALF_YEAR || tim > now + HALF_YEAR)
  396. fmt = bsdtar->day_first ? DAY_FMT " %b %Y" : "%b " DAY_FMT " %Y";
  397. else
  398. fmt = bsdtar->day_first ? DAY_FMT " %b %H:%M" : "%b " DAY_FMT " %H:%M";
  399. strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
  400. fprintf(out, " %s ", tmp);
  401. safe_fprintf(out, "%s", archive_entry_pathname(entry));
  402. /* Extra information for links. */
  403. if (archive_entry_hardlink(entry)) /* Hard link */
  404. safe_fprintf(out, " link to %s",
  405. archive_entry_hardlink(entry));
  406. else if (archive_entry_symlink(entry)) /* Symbolic link */
  407. safe_fprintf(out, " -> %s", archive_entry_symlink(entry));
  408. }