util.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. /*-
  2. * Copyright 2006-2025 Tarsnap Backup Inc.
  3. * All rights reserved.
  4. *
  5. * Portions of the file below are covered by the following license:
  6. *
  7. * Copyright (c) 2003-2007 Tim Kientzle
  8. * All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  20. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. #include "bsdtar_platform.h"
  31. __FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.23 2008/12/15 06:00:25 kientzle Exp $");
  32. #ifdef HAVE_SYS_STAT_H
  33. #include <sys/stat.h>
  34. #endif
  35. #ifdef HAVE_SYS_TYPES_H
  36. #include <sys/types.h> /* Linux doesn't define mode_t, etc. in sys/stat.h. */
  37. #endif
  38. #ifdef MAJOR_IN_MKDEV
  39. #include <sys/mkdev.h>
  40. #elif defined(MAJOR_IN_SYSMACROS)
  41. #include <sys/sysmacros.h>
  42. #endif
  43. #include <ctype.h>
  44. #ifdef HAVE_ERRNO_H
  45. #include <errno.h>
  46. #endif
  47. #ifdef HAVE_STDARG_H
  48. #include <stdarg.h>
  49. #endif
  50. #include <stdio.h>
  51. #ifdef HAVE_STDLIB_H
  52. #include <stdlib.h>
  53. #endif
  54. #ifdef HAVE_STRING_H
  55. #include <string.h>
  56. #endif
  57. #ifdef HAVE_WCTYPE_H
  58. #include <wctype.h>
  59. #else
  60. /* If we don't have wctype, we need to hack up some version of iswprint(). */
  61. #define iswprint isprint
  62. #endif
  63. #include <assert.h>
  64. #include "print_separator.h"
  65. #include "bsdtar.h"
  66. static void bsdtar_vwarnc(struct bsdtar *, int code,
  67. const char *fmt, va_list ap);
  68. static size_t bsdtar_expand_char(char *, size_t, char);
  69. static const char *strip_components(const char *path, int elements);
  70. /* TODO: Hack up a version of mbtowc for platforms with no wide
  71. * character support at all. I think the following might suffice,
  72. * but it needs careful testing.
  73. * #if !HAVE_MBTOWC
  74. * #define mbtowc(wcp, p, n) ((*wcp = *p), 1)
  75. * #endif
  76. */
  77. /*
  78. * Print a string, taking care with any non-printable characters.
  79. *
  80. * Note that we use a stack-allocated buffer to receive the formatted
  81. * string if we can. This is partly performance (avoiding a call to
  82. * malloc()), partly out of expedience (we have to call vsnprintf()
  83. * before malloc() anyway to find out how big a buffer we need; we may
  84. * as well point that first call at a small local buffer in case it
  85. * works), but mostly for safety (so we can use this to print messages
  86. * about out-of-memory conditions).
  87. */
  88. void
  89. safe_fprintf(FILE *f, const char *fmt, ...)
  90. {
  91. char fmtbuff_stack[256]; /* Place to format the printf() string. */
  92. char outbuff[256]; /* Buffer for outgoing characters. */
  93. char *fmtbuff_heap; /* If fmtbuff_stack is too small, we use malloc */
  94. char *fmtbuff; /* Pointer to fmtbuff_stack or fmtbuff_heap. */
  95. int fmtbuff_length;
  96. int length;
  97. va_list ap;
  98. const char *p;
  99. unsigned i;
  100. wchar_t wc;
  101. char try_wc;
  102. /* Use a stack-allocated buffer if we can, for speed and safety. */
  103. fmtbuff_heap = NULL;
  104. fmtbuff_length = sizeof(fmtbuff_stack);
  105. fmtbuff = fmtbuff_stack;
  106. /* Try formatting into the stack buffer. */
  107. va_start(ap, fmt);
  108. length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
  109. va_end(ap);
  110. /* If the result was too large, allocate a buffer on the heap. */
  111. if (length >= fmtbuff_length) {
  112. fmtbuff_length = length+1;
  113. fmtbuff_heap = malloc(fmtbuff_length);
  114. /* Reformat the result into the heap buffer if we can. */
  115. if (fmtbuff_heap != NULL) {
  116. fmtbuff = fmtbuff_heap;
  117. va_start(ap, fmt);
  118. length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
  119. va_end(ap);
  120. } else {
  121. /* Leave fmtbuff pointing to the truncated
  122. * string in fmtbuff_stack. */
  123. length = sizeof(fmtbuff_stack) - 1;
  124. }
  125. }
  126. /* Note: mbrtowc() has a cleaner API, but mbtowc() seems a bit
  127. * more portable, so we use that here instead. */
  128. mbtowc(NULL, NULL, 0); /* Reset the shift state. */
  129. /* Write data, expanding unprintable characters. */
  130. p = fmtbuff;
  131. i = 0;
  132. try_wc = 1;
  133. while (*p != '\0') {
  134. int n;
  135. /* Convert to wide char, test if the wide
  136. * char is printable in the current locale. */
  137. if (try_wc && (n = mbtowc(&wc, p, length)) != -1) {
  138. length -= n;
  139. if (iswprint(wc) && wc != L'\\') {
  140. /* Printable, copy the bytes through. */
  141. while (n-- > 0)
  142. outbuff[i++] = *p++;
  143. } else {
  144. /* Not printable, format the bytes. */
  145. while (n-- > 0)
  146. i += bsdtar_expand_char(
  147. outbuff, i, *p++);
  148. }
  149. } else {
  150. /* After any conversion failure, don't bother
  151. * trying to convert the rest. */
  152. i += bsdtar_expand_char(outbuff, i, *p++);
  153. try_wc = 0;
  154. }
  155. /* If our output buffer is full, dump it and keep going. */
  156. if (i > (sizeof(outbuff) - 20)) {
  157. outbuff[i++] = '\0';
  158. fprintf(f, "%s", outbuff);
  159. i = 0;
  160. }
  161. }
  162. outbuff[i++] = '\0';
  163. fprintf(f, "%s", outbuff);
  164. /* If we allocated a heap-based formatting buffer, free it now. */
  165. if (fmtbuff_heap != NULL)
  166. free(fmtbuff_heap);
  167. }
  168. /*
  169. * Render an arbitrary sequence of bytes into printable ASCII characters.
  170. */
  171. static size_t
  172. bsdtar_expand_char(char *buff, size_t offset, char c)
  173. {
  174. size_t i = offset;
  175. if (isprint((unsigned char)c) && c != '\\')
  176. buff[i++] = c;
  177. else {
  178. buff[i++] = '\\';
  179. switch (c) {
  180. case '\a': buff[i++] = 'a'; break;
  181. case '\b': buff[i++] = 'b'; break;
  182. case '\f': buff[i++] = 'f'; break;
  183. case '\n': buff[i++] = 'n'; break;
  184. #if '\r' != '\n'
  185. /* On some platforms, \n and \r are the same. */
  186. case '\r': buff[i++] = 'r'; break;
  187. #endif
  188. case '\t': buff[i++] = 't'; break;
  189. case '\v': buff[i++] = 'v'; break;
  190. case '\\': buff[i++] = '\\'; break;
  191. default:
  192. sprintf(buff + i, "%03o", 0xFF & (int)c);
  193. i += 3;
  194. }
  195. }
  196. return (i - offset);
  197. }
  198. static void
  199. bsdtar_vwarnc(struct bsdtar *bsdtar, int code, const char *fmt, va_list ap)
  200. {
  201. fprintf(stderr, "%s: ", bsdtar->progname);
  202. vfprintf(stderr, fmt, ap);
  203. if (code != 0)
  204. fprintf(stderr, ": %s", strerror(code));
  205. fprintf(stderr, "\n");
  206. }
  207. void
  208. bsdtar_warnc(struct bsdtar *bsdtar, int code, const char *fmt, ...)
  209. {
  210. va_list ap;
  211. va_start(ap, fmt);
  212. bsdtar_vwarnc(bsdtar, code, fmt, ap);
  213. va_end(ap);
  214. }
  215. void
  216. bsdtar_errc(struct bsdtar *bsdtar, int eval, int code, const char *fmt, ...)
  217. {
  218. va_list ap;
  219. va_start(ap, fmt);
  220. bsdtar_vwarnc(bsdtar, code, fmt, ap);
  221. va_end(ap);
  222. exit(eval);
  223. }
  224. int
  225. yes(const char *fmt, ...)
  226. {
  227. char buff[32];
  228. char *p;
  229. ssize_t l;
  230. va_list ap;
  231. va_start(ap, fmt);
  232. vfprintf(stderr, fmt, ap);
  233. va_end(ap);
  234. fprintf(stderr, " (y/N)? ");
  235. fflush(stderr);
  236. l = read(2, buff, sizeof(buff) - 1);
  237. if (l <= 0)
  238. return (0);
  239. buff[l] = 0;
  240. for (p = buff; *p != '\0'; p++) {
  241. if (isspace((unsigned char)*p))
  242. continue;
  243. switch(*p) {
  244. case 'y': case 'Y':
  245. return (1);
  246. case 'n': case 'N':
  247. return (0);
  248. default:
  249. return (0);
  250. }
  251. }
  252. return (0);
  253. }
  254. /*
  255. * Read lines from file and do something with each one. If null
  256. * is set, lines are terminated with zero bytes; otherwise, they're
  257. * terminated with newlines.
  258. *
  259. * This uses a self-sizing buffer to handle arbitrarily-long lines.
  260. * If the "process" function returns non-zero for any line, this
  261. * function will return non-zero after attempting to process all
  262. * remaining lines.
  263. */
  264. int
  265. process_lines(struct bsdtar *bsdtar, const char *pathname,
  266. int (*process)(struct bsdtar *, const char *), int null)
  267. {
  268. FILE *f;
  269. char *buff, *buff_end, *line_start, *line_end, *p;
  270. size_t buff_length, new_buff_length, bytes_read, bytes_wanted;
  271. size_t buff_end_pos;
  272. size_t line_end_pos;
  273. const char * separator;
  274. size_t seplen;
  275. int lastcharwasr = 0;
  276. int ret;
  277. int fread_errno;
  278. if (null) {
  279. separator = "";
  280. seplen = 1;
  281. } else {
  282. separator = "\012\015";
  283. seplen = 2;
  284. }
  285. ret = 0;
  286. if (strcmp(pathname, "-") == 0)
  287. f = stdin;
  288. else
  289. f = fopen(pathname, "r");
  290. if (f == NULL)
  291. bsdtar_errc(bsdtar, 1, errno, "Couldn't open %s", pathname);
  292. /* Record pointer for freeing upon error. */
  293. bsdtar->conffile_actual = f;
  294. buff_length = 8192;
  295. buff = malloc(buff_length);
  296. if (buff == NULL)
  297. bsdtar_errc(bsdtar, 1, ENOMEM, "Can't read %s", pathname);
  298. /* Record pointer for freeing upon error. */
  299. bsdtar->conffile_buffer = buff;
  300. line_start = line_end = buff_end = buff;
  301. for (;;) {
  302. /* Get some more data into the buffer. */
  303. bytes_wanted = buff + buff_length - buff_end;
  304. bytes_read = fread(buff_end, 1, bytes_wanted, f);
  305. fread_errno = errno;
  306. buff_end += bytes_read;
  307. /* Process all complete lines in the buffer. */
  308. while (line_end < buff_end) {
  309. if ((lastcharwasr != 0) && (*line_end == '\012')) {
  310. /*
  311. * Skip this \n character -- it belongs to
  312. * a \r\n pair.
  313. */
  314. line_start++;
  315. line_end++;
  316. lastcharwasr = 0;
  317. continue;
  318. }
  319. lastcharwasr = 0;
  320. if (memchr(separator, *line_end, seplen) != NULL) {
  321. if (*line_end == '\015')
  322. lastcharwasr = 1;
  323. *line_end = '\0';
  324. if ((*process)(bsdtar, line_start) != 0)
  325. ret = -1;
  326. line_start = line_end + 1;
  327. line_end = line_start;
  328. } else
  329. line_end++;
  330. }
  331. if (feof(f)) {
  332. /* fread() should not set EOF unless this is true. */
  333. assert(bytes_read < bytes_wanted);
  334. break;
  335. }
  336. if (ferror(f))
  337. bsdtar_errc(bsdtar, 1, fread_errno,
  338. "Can't read %s", pathname);
  339. if (line_start > buff) {
  340. /* Move a leftover fractional line to the beginning. */
  341. memmove(buff, line_start, buff_end - line_start);
  342. buff_end -= line_start - buff;
  343. line_end -= line_start - buff;
  344. line_start = buff;
  345. } else {
  346. /* Line is too big; enlarge the buffer. */
  347. new_buff_length = buff_length * 2;
  348. if (new_buff_length <= buff_length)
  349. bsdtar_errc(bsdtar, 1, ENOMEM,
  350. "Line too long in %s", pathname);
  351. buff_length = new_buff_length;
  352. buff_end_pos = buff_end - buff;
  353. line_end_pos = line_end - buff;
  354. p = realloc(buff, buff_length);
  355. if (p == NULL)
  356. bsdtar_errc(bsdtar, 1, ENOMEM,
  357. "Line too long in %s", pathname);
  358. buff_end = p + buff_end_pos;
  359. line_end = p + line_end_pos;
  360. line_start = buff = p;
  361. bsdtar->conffile_buffer = buff;
  362. }
  363. }
  364. /* At end-of-file, handle the final line. */
  365. if (line_end > line_start) {
  366. *line_end = '\0';
  367. if ((*process)(bsdtar, line_start) != 0)
  368. ret = -1;
  369. }
  370. free(buff);
  371. if (f != stdin)
  372. fclose(f);
  373. /* Memory has been freed. */
  374. bsdtar->conffile_actual = NULL;
  375. bsdtar->conffile_buffer = NULL;
  376. return (ret);
  377. }
  378. /*-
  379. * The logic here for -C <dir> attempts to avoid
  380. * chdir() as long as possible. For example:
  381. * "-C /foo -C /bar file" needs chdir("/bar") but not chdir("/foo")
  382. * "-C /foo -C bar file" needs chdir("/foo/bar")
  383. * "-C /foo -C bar /file1" does not need chdir()
  384. * "-C /foo -C bar /file1 file2" needs chdir("/foo/bar") before file2
  385. *
  386. * The only correct way to handle this is to record a "pending" chdir
  387. * request and combine multiple requests intelligently until we
  388. * need to process a non-absolute file. set_chdir() adds the new dir
  389. * to the pending list; do_chdir() actually executes any pending chdir.
  390. *
  391. * This way, programs that build tar command lines don't have to worry
  392. * about -C with non-existent directories; such requests will only
  393. * fail if the directory must be accessed.
  394. */
  395. void
  396. set_chdir(struct bsdtar *bsdtar, const char *newdir)
  397. {
  398. if (newdir[0] == '/') {
  399. /* The -C /foo -C /bar case; dump first one. */
  400. free(bsdtar->pending_chdir);
  401. bsdtar->pending_chdir = NULL;
  402. }
  403. if (bsdtar->pending_chdir == NULL)
  404. /* Easy case: no previously-saved dir. */
  405. bsdtar->pending_chdir = strdup(newdir);
  406. else {
  407. /* The -C /foo -C bar case; concatenate */
  408. char *old_pending = bsdtar->pending_chdir;
  409. size_t old_len = strlen(old_pending);
  410. bsdtar->pending_chdir = malloc(old_len + strlen(newdir) + 2);
  411. if (old_pending[old_len - 1] == '/')
  412. old_pending[old_len - 1] = '\0';
  413. if (bsdtar->pending_chdir != NULL)
  414. sprintf(bsdtar->pending_chdir, "%s/%s",
  415. old_pending, newdir);
  416. free(old_pending);
  417. }
  418. if (bsdtar->pending_chdir == NULL)
  419. bsdtar_errc(bsdtar, 1, errno, "No memory");
  420. }
  421. void
  422. do_chdir(struct bsdtar *bsdtar)
  423. {
  424. if (bsdtar->pending_chdir == NULL)
  425. return;
  426. if (chdir(bsdtar->pending_chdir) != 0) {
  427. bsdtar_errc(bsdtar, 1, 0, "could not chdir to '%s'\n",
  428. bsdtar->pending_chdir);
  429. }
  430. free(bsdtar->pending_chdir);
  431. bsdtar->pending_chdir = NULL;
  432. }
  433. const char *
  434. strip_components(const char *path, int elements)
  435. {
  436. const char *p = path;
  437. while (elements > 0) {
  438. switch (*p++) {
  439. case '/':
  440. elements--;
  441. path = p;
  442. break;
  443. case '\0':
  444. /* Path is too short, skip it. */
  445. return (NULL);
  446. }
  447. }
  448. while (*path == '/')
  449. ++path;
  450. if (*path == '\0')
  451. return (NULL);
  452. return (path);
  453. }
  454. /*
  455. * Handle --strip-components and any future path-rewriting options.
  456. * Returns non-zero if the pathname should not be extracted.
  457. *
  458. * TODO: Support pax-style regex path rewrites.
  459. */
  460. int
  461. edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
  462. {
  463. const char *name = archive_entry_pathname(entry);
  464. #if HAVE_REGEX_H
  465. char *subst_name;
  466. int r;
  467. #endif
  468. #if HAVE_REGEX_H
  469. r = apply_substitution(bsdtar, name, &subst_name, 0);
  470. if (r == -1) {
  471. bsdtar_warnc(bsdtar, 0, "Invalid substitution, skipping entry");
  472. return 1;
  473. }
  474. if (r == 1) {
  475. archive_entry_copy_pathname(entry, subst_name);
  476. if (*subst_name == '\0') {
  477. free(subst_name);
  478. return -1;
  479. } else
  480. free(subst_name);
  481. name = archive_entry_pathname(entry);
  482. }
  483. if (archive_entry_hardlink(entry)) {
  484. r = apply_substitution(bsdtar, archive_entry_hardlink(entry), &subst_name, 1);
  485. if (r == -1) {
  486. bsdtar_warnc(bsdtar, 0, "Invalid substitution, skipping entry");
  487. return 1;
  488. }
  489. if (r == 1) {
  490. archive_entry_copy_hardlink(entry, subst_name);
  491. free(subst_name);
  492. }
  493. }
  494. if (archive_entry_symlink(entry) != NULL) {
  495. r = apply_substitution(bsdtar, archive_entry_symlink(entry), &subst_name, 1);
  496. if (r == -1) {
  497. bsdtar_warnc(bsdtar, 0, "Invalid substitution, skipping entry");
  498. return 1;
  499. }
  500. if (r == 1) {
  501. archive_entry_copy_symlink(entry, subst_name);
  502. free(subst_name);
  503. }
  504. }
  505. #endif
  506. /* Strip leading dir names as per --strip-components option. */
  507. if (bsdtar->strip_components > 0) {
  508. const char *linkname = archive_entry_hardlink(entry);
  509. name = strip_components(name, bsdtar->strip_components);
  510. if (name == NULL)
  511. return (1);
  512. if (linkname != NULL) {
  513. linkname = strip_components(linkname,
  514. bsdtar->strip_components);
  515. if (linkname == NULL)
  516. return (1);
  517. archive_entry_copy_hardlink(entry, linkname);
  518. }
  519. }
  520. /* By default, don't write or restore absolute pathnames. */
  521. if (!bsdtar->option_absolute_paths) {
  522. const char *rp, *p = name;
  523. int slashonly = 1;
  524. /* Remove leading "//./" or "//?/" or "//?/UNC/"
  525. * (absolute path prefixes used by Windows API) */
  526. if ((p[0] == '/' || p[0] == '\\') &&
  527. (p[1] == '/' || p[1] == '\\') &&
  528. (p[2] == '.' || p[2] == '?') &&
  529. (p[3] == '/' || p[3] == '\\'))
  530. {
  531. if (p[2] == '?' &&
  532. (p[4] == 'U' || p[4] == 'u') &&
  533. (p[5] == 'N' || p[5] == 'n') &&
  534. (p[6] == 'C' || p[6] == 'c') &&
  535. (p[7] == '/' || p[7] == '\\'))
  536. p += 8;
  537. else
  538. p += 4;
  539. slashonly = 0;
  540. }
  541. do {
  542. rp = p;
  543. /* Remove leading drive letter from archives created
  544. * on Windows. */
  545. if (((p[0] >= 'a' && p[0] <= 'z') ||
  546. (p[0] >= 'A' && p[0] <= 'Z')) &&
  547. p[1] == ':') {
  548. p += 2;
  549. slashonly = 0;
  550. }
  551. /* Remove leading "/../", "//", etc. */
  552. while (p[0] == '/' || p[0] == '\\') {
  553. if (p[1] == '.' && p[2] == '.' &&
  554. (p[3] == '/' || p[3] == '\\')) {
  555. p += 3; /* Remove "/..", leave "/"
  556. * for next pass. */
  557. slashonly = 0;
  558. } else
  559. p += 1; /* Remove "/". */
  560. }
  561. } while (rp != p);
  562. if (p != name && !bsdtar->warned_lead_slash &&
  563. !bsdtar->option_quiet) {
  564. /* Generate a warning the first time this happens. */
  565. if (slashonly)
  566. bsdtar_warnc(bsdtar, 0,
  567. "Removing leading '%c' from member names",
  568. name[0]);
  569. else
  570. bsdtar_warnc(bsdtar, 0,
  571. "Removing leading drive letter from "
  572. "member names");
  573. bsdtar->warned_lead_slash = 1;
  574. }
  575. /* Special case: Stripping everything yields ".". */
  576. if (*p == '\0')
  577. name = ".";
  578. else
  579. name = p;
  580. } else {
  581. /* Strip redundant leading '/' characters. */
  582. while (name[0] == '/' && name[1] == '/')
  583. name++;
  584. }
  585. /* Safely replace name in archive_entry. */
  586. if (name != archive_entry_pathname(entry)) {
  587. char *q = strdup(name);
  588. archive_entry_copy_pathname(entry, q);
  589. free(q);
  590. }
  591. return (0);
  592. }
  593. /*
  594. * Like strcmp(), but try to be a little more aware of the fact that
  595. * we're comparing two paths. Right now, it just handles leading
  596. * "./" and trailing '/' specially, so that "a/b/" == "./a/b"
  597. *
  598. * TODO: Make this better, so that "./a//b/./c/" == "a/b/c"
  599. * TODO: After this works, push it down into libarchive.
  600. * TODO: Publish the path normalization routines in libarchive so
  601. * that bsdtar can normalize paths and use fast strcmp() instead
  602. * of this.
  603. */
  604. int
  605. pathcmp(const char *a, const char *b)
  606. {
  607. /* Skip leading './' */
  608. if (a[0] == '.' && a[1] == '/' && a[2] != '\0')
  609. a += 2;
  610. if (b[0] == '.' && b[1] == '/' && b[2] != '\0')
  611. b += 2;
  612. /* Find the first difference, or return (0) if none. */
  613. while (*a == *b) {
  614. if (*a == '\0')
  615. return (0);
  616. a++;
  617. b++;
  618. }
  619. /*
  620. * If one ends in '/' and the other one doesn't,
  621. * they're the same.
  622. */
  623. if (a[0] == '/' && a[1] == '\0' && b[0] == '\0')
  624. return (0);
  625. if (a[0] == '\0' && b[0] == '/' && b[1] == '\0')
  626. return (0);
  627. /* They're really different, return the correct sign. */
  628. return (*(const unsigned char *)a - *(const unsigned char *)b);
  629. }
  630. /*
  631. * Display information about the current file.
  632. *
  633. * The format here roughly duplicates the output of 'ls -l'.
  634. * This is based on SUSv2, where 'tar tv' is documented as
  635. * listing additional information in an "unspecified format,"
  636. * and 'pax -l' is documented as using the same format as 'ls -l'.
  637. */
  638. void
  639. list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
  640. {
  641. const struct stat *st;
  642. char tmp[100];
  643. size_t w;
  644. const char *p;
  645. const char *fmt;
  646. time_t tim;
  647. static time_t now;
  648. st = archive_entry_stat(entry);
  649. /*
  650. * We avoid collecting the entire list in memory at once by
  651. * listing things as we see them. However, that also means we can't
  652. * just pre-compute the field widths. Instead, we start with guesses
  653. * and just widen them as necessary. These numbers are completely
  654. * arbitrary.
  655. */
  656. if (!bsdtar->u_width) {
  657. bsdtar->u_width = 6;
  658. bsdtar->gs_width = 13;
  659. }
  660. if (!now)
  661. time(&now);
  662. fprintf(out, "%s", archive_entry_strmode(entry));
  663. print_separator(out, " ", bsdtar->option_null_output, 2);
  664. fprintf(out, "%d", (int)(st->st_nlink));
  665. print_separator(out, " ", bsdtar->option_null_output, 2);
  666. /* Use uname if it's present, else uid. */
  667. p = archive_entry_uname(entry);
  668. if ((p == NULL) || (*p == '\0')) {
  669. sprintf(tmp, "%lu", (unsigned long)st->st_uid);
  670. p = tmp;
  671. }
  672. w = strlen(p);
  673. if (w > bsdtar->u_width)
  674. bsdtar->u_width = w;
  675. if (bsdtar->option_null_output)
  676. fprintf(out, "%s", p);
  677. else
  678. fprintf(out, "%-*s", (int)bsdtar->u_width, p);
  679. print_separator(out, " ", bsdtar->option_null_output, 2);
  680. /* Use gname if it's present, else gid. */
  681. p = archive_entry_gname(entry);
  682. if (p != NULL && p[0] != '\0') {
  683. fprintf(out, "%s", p);
  684. w = strlen(p);
  685. } else {
  686. sprintf(tmp, "%lu", (unsigned long)st->st_gid);
  687. w = strlen(tmp);
  688. fprintf(out, "%s", tmp);
  689. }
  690. /*
  691. * Print device number or file size, right-aligned so as to make
  692. * total width of group and devnum/filesize fields be gs_width.
  693. * If gs_width is too small, grow it.
  694. */
  695. if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
  696. sprintf(tmp, "%lu,%lu",
  697. (unsigned long)major(st->st_rdev),
  698. (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */
  699. } else {
  700. /*
  701. * Note the use of platform-dependent macros to format
  702. * the filesize here. We need the format string and the
  703. * corresponding type for the cast.
  704. */
  705. sprintf(tmp, BSDTAR_FILESIZE_PRINTF,
  706. (BSDTAR_FILESIZE_TYPE)st->st_size);
  707. }
  708. if (w + strlen(tmp) >= bsdtar->gs_width)
  709. bsdtar->gs_width = w+strlen(tmp)+1;
  710. if (bsdtar->option_null_output)
  711. fprintf(out, "%s", tmp);
  712. else
  713. fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp);
  714. /* Format the time. */
  715. tim = (time_t)st->st_mtime;
  716. if (bsdtar->option_iso_dates) {
  717. fmt = "%F %T";
  718. } else {
  719. /* Use the 'ls -l' convention. */
  720. #if defined(_WIN32) && !defined(__CYGWIN__)
  721. /* Windows' strftime function does not support %e format. */
  722. if (imaxabs(tim - now) > (365/2)*86400)
  723. fmt = bsdtar->day_first ? "%d %b %Y" : "%b %d %Y";
  724. else
  725. fmt = bsdtar->day_first ? "%d %b %H:%M" : "%b %d %H:%M";
  726. #else
  727. if (imaxabs(tim - now) > (365/2)*86400)
  728. fmt = bsdtar->day_first ? "%e %b %Y" : "%b %e %Y";
  729. else
  730. fmt = bsdtar->day_first ? "%e %b %H:%M" : "%b %e %H:%M";
  731. #endif
  732. }
  733. strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
  734. print_separator(out, " ", bsdtar->option_null_output, 2);
  735. fprintf(out, "%s", tmp);
  736. print_separator(out, " ", bsdtar->option_null_output, 2);
  737. safe_fprintf(out, "%s", archive_entry_pathname(entry));
  738. /* Extra information for links. */
  739. if (archive_entry_hardlink(entry)) { /* Hard link */
  740. print_separator(out, " ", bsdtar->option_null_output, 2);
  741. fprintf(out, "link to");
  742. print_separator(out, " ", bsdtar->option_null_output, 2);
  743. safe_fprintf(out, "%s", archive_entry_hardlink(entry));
  744. } else if (S_ISLNK(st->st_mode)) { /* Symbolic link */
  745. print_separator(out, " ", bsdtar->option_null_output, 2);
  746. fprintf(out, "->");
  747. print_separator(out, " ", bsdtar->option_null_output, 2);
  748. safe_fprintf(out, "%s", archive_entry_symlink(entry));
  749. }
  750. }