xheader.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. /* POSIX extended headers for tar.
  2. Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU General Public License as published by the
  5. Free Software Foundation; either version 2, or (at your option) any later
  6. version.
  7. This program is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
  10. Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with this program; if not, write to the Free Software Foundation, Inc.,
  13. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  14. #include <system.h>
  15. #include <fnmatch.h>
  16. #include <hash.h>
  17. #include <quotearg.h>
  18. #include <stpcpy.h>
  19. #include <xstrtol.h>
  20. #include "common.h"
  21. #include <fnmatch.h>
  22. static bool xheader_protected_pattern_p (char const *pattern);
  23. static bool xheader_protected_keyword_p (char const *keyword);
  24. static void xheader_set_single_keyword (char *) __attribute__ ((noreturn));
  25. /* Used by xheader_finish() */
  26. static void code_string (char const *string, char const *keyword,
  27. struct xheader *xhdr);
  28. static void extended_header_init (void);
  29. /* Number of global headers written so far. */
  30. static size_t global_header_count;
  31. /* FIXME: Possibly it should be reset after changing the volume.
  32. POSIX %n specification says that it is expanded to the sequence
  33. number of current global header in *the* archive. However, for
  34. multi-volume archives this will yield duplicate header names
  35. in different volumes, which I'd like to avoid. The best way
  36. to solve this would be to use per-archive header count as required
  37. by POSIX *and* set globexthdr.name to, say,
  38. $TMPDIR/GlobalHead.%p.$NUMVOLUME.%n.
  39. However it should wait until buffer.c is finally rewritten */
  40. /* Keyword options */
  41. struct keyword_list
  42. {
  43. struct keyword_list *next;
  44. char *pattern;
  45. char *value;
  46. };
  47. /* List of keyword patterns set by delete= option */
  48. static struct keyword_list *keyword_pattern_list;
  49. /* List of keyword/value pairs set by `keyword=value' option */
  50. static struct keyword_list *keyword_global_override_list;
  51. /* List of keyword/value pairs set by `keyword:=value' option */
  52. static struct keyword_list *keyword_override_list;
  53. /* List of keyword/value pairs decoded from the last 'g' type header */
  54. static struct keyword_list *global_header_override_list;
  55. /* Template for the name field of an 'x' type header */
  56. static char *exthdr_name;
  57. /* Template for the name field of a 'g' type header */
  58. static char *globexthdr_name;
  59. static bool
  60. xheader_keyword_deleted_p (const char *kw)
  61. {
  62. struct keyword_list *kp;
  63. for (kp = keyword_pattern_list; kp; kp = kp->next)
  64. if (fnmatch (kp->pattern, kw, 0) == 0)
  65. return true;
  66. return false;
  67. }
  68. static bool
  69. xheader_keyword_override_p (const char *keyword)
  70. {
  71. struct keyword_list *kp;
  72. for (kp = keyword_override_list; kp; kp = kp->next)
  73. if (strcmp (kp->pattern, keyword) == 0)
  74. return true;
  75. return false;
  76. }
  77. static void
  78. xheader_list_append (struct keyword_list **root, char const *kw,
  79. char const *value)
  80. {
  81. struct keyword_list *kp = xmalloc (sizeof *kp);
  82. kp->pattern = xstrdup (kw);
  83. kp->value = value ? xstrdup (value) : NULL;
  84. kp->next = *root;
  85. *root = kp;
  86. }
  87. static void
  88. xheader_list_destroy (struct keyword_list **root)
  89. {
  90. if (root)
  91. {
  92. struct keyword_list *kw = *root;
  93. while (kw)
  94. {
  95. struct keyword_list *next = kw->next;
  96. free (kw->pattern);
  97. free (kw->value);
  98. free (kw);
  99. kw = next;
  100. }
  101. *root = NULL;
  102. }
  103. }
  104. static void
  105. xheader_set_single_keyword (char *kw)
  106. {
  107. USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet imlemented"), kw));
  108. }
  109. static void
  110. xheader_set_keyword_equal (char *kw, char *eq)
  111. {
  112. bool global = true;
  113. char *p = eq;
  114. if (eq[-1] == ':')
  115. {
  116. p--;
  117. global = false;
  118. }
  119. while (p > kw && isspace (*p))
  120. p--;
  121. *p = 0;
  122. for (p = eq + 1; *p && isspace (*p); p++)
  123. ;
  124. if (strcmp (kw, "delete") == 0)
  125. {
  126. if (xheader_protected_pattern_p (p))
  127. USAGE_ERROR ((0, 0, _("Pattern %s cannot be used"), quote (p)));
  128. xheader_list_append (&keyword_pattern_list, p, NULL);
  129. }
  130. else if (strcmp (kw, "exthdr.name") == 0)
  131. assign_string (&exthdr_name, p);
  132. else if (strcmp (kw, "globexthdr.name") == 0)
  133. assign_string (&globexthdr_name, p);
  134. else
  135. {
  136. if (xheader_protected_keyword_p (kw))
  137. USAGE_ERROR ((0, 0, _("Keyword %s cannot be overridden"), kw));
  138. if (global)
  139. xheader_list_append (&keyword_global_override_list, kw, p);
  140. else
  141. xheader_list_append (&keyword_override_list, kw, p);
  142. }
  143. }
  144. void
  145. xheader_set_option (char *string)
  146. {
  147. char *token;
  148. for (token = strtok (string, ","); token; token = strtok (NULL, ","))
  149. {
  150. char *p = strchr (token, '=');
  151. if (!p)
  152. xheader_set_single_keyword (token);
  153. else
  154. xheader_set_keyword_equal (token, p);
  155. }
  156. }
  157. static void
  158. to_decimal (uintmax_t value, char *where, size_t size)
  159. {
  160. size_t i = 0, j;
  161. where[i++] = 0;
  162. do
  163. {
  164. where[i++] = '0' + value % 10;
  165. value /= 10;
  166. }
  167. while (i < size && value);
  168. for (j = 0, i--; j < i; j++, i--)
  169. {
  170. char c = where[j];
  171. where[j] = where[i];
  172. where[i] = c;
  173. }
  174. }
  175. /*
  176. string Includes: Replaced By:
  177. %d The directory name of the file,
  178. equivalent to the result of the
  179. dirname utility on the translated
  180. file name.
  181. %f The filename of the file, equivalent
  182. to the result of the basename
  183. utility on the translated file name.
  184. %p The process ID of the pax process.
  185. %% A '%' character. */
  186. static char *
  187. xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n)
  188. {
  189. char *buf;
  190. size_t len = strlen (fmt);
  191. char *q;
  192. const char *p;
  193. char *dir = NULL;
  194. char *base = NULL;
  195. char pidbuf[64];
  196. char nbuf[64];
  197. for (p = fmt; *p && (p = strchr (p, '%')); )
  198. {
  199. switch (p[1])
  200. {
  201. case '%':
  202. len--;
  203. break;
  204. case 'd':
  205. if (st)
  206. {
  207. dir = safer_name_suffix (dir_name (st->orig_file_name), false);
  208. len += strlen (dir) - 1;
  209. }
  210. break;
  211. case 'f':
  212. if (st)
  213. {
  214. base = base_name (st->orig_file_name);
  215. len += strlen (base) - 1;
  216. }
  217. break;
  218. case 'p':
  219. to_decimal (getpid (), pidbuf, sizeof pidbuf);
  220. len += strlen (pidbuf) - 1;
  221. break;
  222. case 'n':
  223. if (allow_n)
  224. {
  225. to_decimal (global_header_count + 1, pidbuf, sizeof pidbuf);
  226. len += strlen (nbuf) - 1;
  227. }
  228. break;
  229. }
  230. p++;
  231. }
  232. buf = xmalloc (len + 1);
  233. for (q = buf, p = fmt; *p; )
  234. {
  235. if (*p == '%')
  236. {
  237. switch (p[1])
  238. {
  239. case '%':
  240. *q++ = *p++;
  241. p++;
  242. break;
  243. case 'd':
  244. if (dir)
  245. q = stpcpy (q, dir);
  246. p += 2;
  247. break;
  248. case 'f':
  249. if (base)
  250. q = stpcpy (q, base);
  251. p += 2;
  252. break;
  253. case 'p':
  254. q = stpcpy (q, pidbuf);
  255. p += 2;
  256. break;
  257. case 'n':
  258. if (allow_n)
  259. {
  260. q = stpcpy (q, nbuf);
  261. p += 2;
  262. }
  263. /* else fall through */
  264. default:
  265. *q++ = *p++;
  266. if (*p)
  267. *q++ = *p++;
  268. }
  269. }
  270. else
  271. *q++ = *p++;
  272. }
  273. /* Do not allow it to end in a slash */
  274. while (q > buf && ISSLASH (q[-1]))
  275. q--;
  276. *q = 0;
  277. return buf;
  278. }
  279. char *
  280. xheader_xhdr_name (struct tar_stat_info *st)
  281. {
  282. if (!exthdr_name)
  283. assign_string (&exthdr_name, "%d/PaxHeaders.%p/%f");
  284. return xheader_format_name (st, exthdr_name, false);
  285. }
  286. #define GLOBAL_HEADER_TEMPLATE "/GlobalHead.%p.%n"
  287. char *
  288. xheader_ghdr_name (void)
  289. {
  290. if (!globexthdr_name)
  291. {
  292. size_t len;
  293. const char *tmp = getenv ("TMPDIR");
  294. if (!tmp)
  295. tmp = "/tmp";
  296. len = strlen (tmp) + sizeof (GLOBAL_HEADER_TEMPLATE); /* Includes nul */
  297. globexthdr_name = xmalloc (len);
  298. strcpy(globexthdr_name, tmp);
  299. strcat(globexthdr_name, GLOBAL_HEADER_TEMPLATE);
  300. }
  301. return xheader_format_name (NULL, globexthdr_name, true);
  302. }
  303. void
  304. xheader_write (char type, char *name, struct xheader *xhdr)
  305. {
  306. union block *header;
  307. size_t size;
  308. char *p;
  309. size = xhdr->size;
  310. header = start_private_header (name, size);
  311. header->header.typeflag = type;
  312. simple_finish_header (header);
  313. p = xhdr->buffer;
  314. do
  315. {
  316. size_t len;
  317. header = find_next_block ();
  318. len = BLOCKSIZE;
  319. if (len > size)
  320. len = size;
  321. memcpy (header->buffer, p, len);
  322. if (len < BLOCKSIZE)
  323. memset (header->buffer + len, 0, BLOCKSIZE - len);
  324. p += len;
  325. size -= len;
  326. set_next_block_after (header);
  327. }
  328. while (size > 0);
  329. xheader_destroy (xhdr);
  330. }
  331. void
  332. xheader_write_global (void)
  333. {
  334. char *name;
  335. struct keyword_list *kp;
  336. if (!keyword_global_override_list)
  337. return;
  338. extended_header_init ();
  339. for (kp = keyword_global_override_list; kp; kp = kp->next)
  340. code_string (kp->value, kp->pattern, &extended_header);
  341. xheader_finish (&extended_header);
  342. xheader_write (XGLTYPE, name = xheader_ghdr_name (),
  343. &extended_header);
  344. free (name);
  345. global_header_count++;
  346. }
  347. /* General Interface */
  348. struct xhdr_tab
  349. {
  350. char const *keyword;
  351. void (*coder) (struct tar_stat_info const *, char const *,
  352. struct xheader *, void *data);
  353. void (*decoder) (struct tar_stat_info *, char const *);
  354. bool protect;
  355. };
  356. /* This declaration must be extern, because ISO C99 section 6.9.2
  357. prohibits a tentative definition that has both internal linkage and
  358. incomplete type. If we made it static, we'd have to declare its
  359. size which would be a maintenance pain; if we put its initializer
  360. here, we'd need a boatload of forward declarations, which would be
  361. even more of a pain. */
  362. extern struct xhdr_tab const xhdr_tab[];
  363. static struct xhdr_tab const *
  364. locate_handler (char const *keyword)
  365. {
  366. struct xhdr_tab const *p;
  367. for (p = xhdr_tab; p->keyword; p++)
  368. if (strcmp (p->keyword, keyword) == 0)
  369. return p;
  370. return NULL;
  371. }
  372. static bool
  373. xheader_protected_pattern_p (const char *pattern)
  374. {
  375. struct xhdr_tab const *p;
  376. for (p = xhdr_tab; p->keyword; p++)
  377. if (p->protect && fnmatch (pattern, p->keyword, 0) == 0)
  378. return true;
  379. return false;
  380. }
  381. static bool
  382. xheader_protected_keyword_p (const char *keyword)
  383. {
  384. struct xhdr_tab const *p;
  385. for (p = xhdr_tab; p->keyword; p++)
  386. if (p->protect && strcmp (p->keyword, keyword) == 0)
  387. return true;
  388. return false;
  389. }
  390. /* Decode a single extended header record, advancing *PTR to the next record.
  391. Return true on success, false otherwise. */
  392. static bool
  393. decode_record (char **ptr,
  394. void (*handler) (void *, char const *, char const *),
  395. void *data)
  396. {
  397. char *start = *ptr;
  398. char *p = start;
  399. unsigned long int len;
  400. char *len_lim;
  401. char const *keyword;
  402. char *nextp;
  403. size_t len_max = extended_header.buffer + extended_header.size - start;
  404. while (*p == ' ' || *p == '\t')
  405. p++;
  406. if (! ISDIGIT (*p))
  407. {
  408. if (*p)
  409. ERROR ((0, 0, _("Malformed extended header: missing length")));
  410. return false;
  411. }
  412. errno = 0;
  413. len = strtoul (p, &len_lim, 10);
  414. if (len_max < len || (len == ULONG_MAX && errno == ERANGE))
  415. {
  416. ERROR ((0, 0, _("Malformed extended header: length out of range")));
  417. return false;
  418. }
  419. nextp = start + len;
  420. for (p = len_lim; *p == ' ' || *p == '\t'; p++)
  421. continue;
  422. if (p == len_lim)
  423. {
  424. ERROR ((0, 0,
  425. _("Malformed extended header: missing blank after length")));
  426. return false;
  427. }
  428. keyword = p;
  429. p = strchr (p, '=');
  430. if (! (p && p < nextp))
  431. {
  432. ERROR ((0, 0, _("Malformed extended header: missing equal sign")));
  433. return false;
  434. }
  435. if (nextp[-1] != '\n')
  436. {
  437. ERROR ((0, 0, _("Malformed extended header: missing newline")));
  438. return false;
  439. }
  440. *p = nextp[-1] = '\0';
  441. handler (data, keyword, p + 1);
  442. *p = '=';
  443. nextp[-1] = '\n';
  444. *ptr = nextp;
  445. return true;
  446. }
  447. static void
  448. run_override_list (struct keyword_list *kp, struct tar_stat_info *st)
  449. {
  450. for (; kp; kp = kp->next)
  451. {
  452. struct xhdr_tab const *t = locate_handler (kp->pattern);
  453. if (t)
  454. t->decoder (st, kp->value);
  455. }
  456. }
  457. static void
  458. decx (void *data, char const *keyword, char const *value)
  459. {
  460. struct xhdr_tab const *t;
  461. struct tar_stat_info *st = data;
  462. if (xheader_keyword_deleted_p (keyword)
  463. || xheader_keyword_override_p (keyword))
  464. return;
  465. t = locate_handler (keyword);
  466. if (t)
  467. t->decoder (st, value);
  468. }
  469. void
  470. xheader_decode (struct tar_stat_info *st)
  471. {
  472. run_override_list (keyword_global_override_list, st);
  473. run_override_list (global_header_override_list, st);
  474. if (extended_header.size)
  475. {
  476. char *p = extended_header.buffer + BLOCKSIZE;
  477. while (decode_record (&p, decx, st))
  478. continue;
  479. }
  480. run_override_list (keyword_override_list, st);
  481. }
  482. static void
  483. decg (void *data, char const *keyword, char const *value)
  484. {
  485. struct keyword_list **kwl = data;
  486. xheader_list_append (kwl, keyword, value);
  487. }
  488. void
  489. xheader_decode_global (void)
  490. {
  491. if (extended_header.size)
  492. {
  493. char *p = extended_header.buffer + BLOCKSIZE;
  494. xheader_list_destroy (&global_header_override_list);
  495. while (decode_record (&p, decg, &global_header_override_list))
  496. continue;
  497. }
  498. }
  499. static void
  500. extended_header_init (void)
  501. {
  502. if (!extended_header.stk)
  503. {
  504. extended_header.stk = xmalloc (sizeof *extended_header.stk);
  505. obstack_init (extended_header.stk);
  506. }
  507. }
  508. void
  509. xheader_store (char const *keyword, struct tar_stat_info const *st, void *data)
  510. {
  511. struct xhdr_tab const *t;
  512. if (extended_header.buffer)
  513. return;
  514. t = locate_handler (keyword);
  515. if (!t)
  516. return;
  517. if (xheader_keyword_deleted_p (keyword)
  518. || xheader_keyword_override_p (keyword))
  519. return;
  520. extended_header_init ();
  521. t->coder (st, keyword, &extended_header, data);
  522. }
  523. void
  524. xheader_read (union block *p, size_t size)
  525. {
  526. size_t j = 0;
  527. size_t nblocks;
  528. free (extended_header.buffer);
  529. size += BLOCKSIZE;
  530. extended_header.size = size;
  531. nblocks = (size + BLOCKSIZE - 1) / BLOCKSIZE;
  532. extended_header.buffer = xmalloc (size + 1);
  533. extended_header.buffer[size] = '\0';
  534. do
  535. {
  536. size_t len = size;
  537. if (len > BLOCKSIZE)
  538. len = BLOCKSIZE;
  539. memcpy (&extended_header.buffer[j], p->buffer, len);
  540. set_next_block_after (p);
  541. p = find_next_block ();
  542. j += len;
  543. size -= len;
  544. }
  545. while (size > 0);
  546. }
  547. static size_t
  548. format_uintmax (uintmax_t val, char *buf, size_t s)
  549. {
  550. if (!buf)
  551. {
  552. s = 0;
  553. do
  554. s++;
  555. while ((val /= 10) != 0);
  556. }
  557. else
  558. {
  559. char *p = buf + s - 1;
  560. do
  561. {
  562. *p-- = val % 10 + '0';
  563. }
  564. while ((val /= 10) != 0);
  565. while (p >= buf)
  566. *p-- = '0';
  567. }
  568. return s;
  569. }
  570. static void
  571. xheader_print (struct xheader *xhdr, char const *keyword, char const *value)
  572. {
  573. size_t len = strlen (keyword) + strlen (value) + 3; /* ' ' + '=' + '\n' */
  574. size_t p, n = 0;
  575. char nbuf[100];
  576. do
  577. {
  578. p = n;
  579. n = format_uintmax (len + p, NULL, 0);
  580. }
  581. while (n != p);
  582. format_uintmax (len + n, nbuf, n);
  583. obstack_grow (xhdr->stk, nbuf, n);
  584. obstack_1grow (xhdr->stk, ' ');
  585. obstack_grow (xhdr->stk, keyword, strlen (keyword));
  586. obstack_1grow (xhdr->stk, '=');
  587. obstack_grow (xhdr->stk, value, strlen (value));
  588. obstack_1grow (xhdr->stk, '\n');
  589. }
  590. void
  591. xheader_finish (struct xheader *xhdr)
  592. {
  593. struct keyword_list *kp;
  594. for (kp = keyword_override_list; kp; kp = kp->next)
  595. code_string (kp->value, kp->pattern, xhdr);
  596. obstack_1grow (xhdr->stk, 0);
  597. xhdr->buffer = obstack_finish (xhdr->stk);
  598. xhdr->size = strlen (xhdr->buffer);
  599. }
  600. void
  601. xheader_destroy (struct xheader *xhdr)
  602. {
  603. if (xhdr->stk)
  604. {
  605. obstack_free (xhdr->stk, NULL);
  606. free (xhdr->stk);
  607. xhdr->stk = NULL;
  608. }
  609. else
  610. free (xhdr->buffer);
  611. xhdr->buffer = 0;
  612. xhdr->size = 0;
  613. }
  614. /* Implementations */
  615. static void
  616. code_string (char const *string, char const *keyword, struct xheader *xhdr)
  617. {
  618. char *outstr;
  619. if (!utf8_convert (true, string, &outstr))
  620. {
  621. /* FIXME: report error */
  622. outstr = xstrdup (string);
  623. }
  624. xheader_print (xhdr, keyword, outstr);
  625. free (outstr);
  626. }
  627. static void
  628. decode_string (char **string, char const *arg)
  629. {
  630. if (*string)
  631. {
  632. free (*string);
  633. *string = NULL;
  634. }
  635. if (!utf8_convert (false, arg, string))
  636. {
  637. /* FIXME: report error and act accordingly to --pax invalid=UTF-8 */
  638. assign_string (string, arg);
  639. }
  640. }
  641. static void
  642. code_time (time_t t, unsigned long nano,
  643. char const *keyword, struct xheader *xhdr)
  644. {
  645. char sbuf[200];
  646. size_t s = format_uintmax (t, NULL, 0);
  647. if (s + 11 >= sizeof sbuf)
  648. return;
  649. format_uintmax (t, sbuf, s);
  650. sbuf[s++] = '.';
  651. s += format_uintmax (nano, sbuf + s, 9);
  652. sbuf[s] = 0;
  653. xheader_print (xhdr, keyword, sbuf);
  654. }
  655. static void
  656. decode_time (char const *arg, time_t *secs, unsigned long *nsecs)
  657. {
  658. uintmax_t u;
  659. char *p;
  660. if (xstrtoumax (arg, &p, 10, &u, "") == LONGINT_OK)
  661. {
  662. *secs = u;
  663. if (*p == '.' && xstrtoumax (p+1, NULL, 10, &u, "") == LONGINT_OK)
  664. *nsecs = u;
  665. }
  666. }
  667. static void
  668. code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
  669. {
  670. char sbuf[100];
  671. size_t s = format_uintmax (value, NULL, 0);
  672. format_uintmax (value, sbuf, s);
  673. sbuf[s] = 0;
  674. xheader_print (xhdr, keyword, sbuf);
  675. }
  676. static void
  677. dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)),
  678. char const *keyword __attribute__ ((unused)),
  679. struct xheader *xhdr __attribute__ ((unused)),
  680. void *data __attribute__ ((unused)))
  681. {
  682. }
  683. static void
  684. dummy_decoder (struct tar_stat_info *st __attribute__ ((unused)),
  685. char const *arg __attribute__ ((unused)))
  686. {
  687. }
  688. static void
  689. atime_coder (struct tar_stat_info const *st, char const *keyword,
  690. struct xheader *xhdr, void *data __attribute__ ((unused)))
  691. {
  692. code_time (st->stat.st_atime, st->atime_nsec, keyword, xhdr);
  693. }
  694. static void
  695. atime_decoder (struct tar_stat_info *st, char const *arg)
  696. {
  697. decode_time (arg, &st->stat.st_atime, &st->atime_nsec);
  698. }
  699. static void
  700. gid_coder (struct tar_stat_info const *st, char const *keyword,
  701. struct xheader *xhdr, void *data __attribute__ ((unused)))
  702. {
  703. code_num (st->stat.st_gid, keyword, xhdr);
  704. }
  705. static void
  706. gid_decoder (struct tar_stat_info *st, char const *arg)
  707. {
  708. uintmax_t u;
  709. if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
  710. st->stat.st_gid = u;
  711. }
  712. static void
  713. gname_coder (struct tar_stat_info const *st, char const *keyword,
  714. struct xheader *xhdr, void *data __attribute__ ((unused)))
  715. {
  716. code_string (st->gname, keyword, xhdr);
  717. }
  718. static void
  719. gname_decoder (struct tar_stat_info *st, char const *arg)
  720. {
  721. decode_string (&st->gname, arg);
  722. }
  723. static void
  724. linkpath_coder (struct tar_stat_info const *st, char const *keyword,
  725. struct xheader *xhdr, void *data __attribute__ ((unused)))
  726. {
  727. code_string (st->link_name, keyword, xhdr);
  728. }
  729. static void
  730. linkpath_decoder (struct tar_stat_info *st, char const *arg)
  731. {
  732. decode_string (&st->link_name, arg);
  733. }
  734. static void
  735. ctime_coder (struct tar_stat_info const *st, char const *keyword,
  736. struct xheader *xhdr, void *data __attribute__ ((unused)))
  737. {
  738. code_time (st->stat.st_ctime, st->ctime_nsec, keyword, xhdr);
  739. }
  740. static void
  741. ctime_decoder (struct tar_stat_info *st, char const *arg)
  742. {
  743. decode_time (arg, &st->stat.st_ctime, &st->ctime_nsec);
  744. }
  745. static void
  746. mtime_coder (struct tar_stat_info const *st, char const *keyword,
  747. struct xheader *xhdr, void *data __attribute__ ((unused)))
  748. {
  749. code_time (st->stat.st_mtime, st->mtime_nsec, keyword, xhdr);
  750. }
  751. static void
  752. mtime_decoder (struct tar_stat_info *st, char const *arg)
  753. {
  754. decode_time (arg, &st->stat.st_mtime, &st->mtime_nsec);
  755. }
  756. static void
  757. path_coder (struct tar_stat_info const *st, char const *keyword,
  758. struct xheader *xhdr, void *data __attribute__ ((unused)))
  759. {
  760. code_string (st->file_name, keyword, xhdr);
  761. }
  762. static void
  763. path_decoder (struct tar_stat_info *st, char const *arg)
  764. {
  765. decode_string (&st->orig_file_name, arg);
  766. decode_string (&st->file_name, arg);
  767. st->had_trailing_slash = strip_trailing_slashes (st->file_name);
  768. }
  769. static void
  770. size_coder (struct tar_stat_info const *st, char const *keyword,
  771. struct xheader *xhdr, void *data __attribute__ ((unused)))
  772. {
  773. code_num (st->stat.st_size, keyword, xhdr);
  774. }
  775. static void
  776. size_decoder (struct tar_stat_info *st, char const *arg)
  777. {
  778. uintmax_t u;
  779. if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
  780. st->archive_file_size = st->stat.st_size = u;
  781. }
  782. static void
  783. uid_coder (struct tar_stat_info const *st, char const *keyword,
  784. struct xheader *xhdr, void *data __attribute__ ((unused)))
  785. {
  786. code_num (st->stat.st_uid, keyword, xhdr);
  787. }
  788. static void
  789. uid_decoder (struct tar_stat_info *st, char const *arg)
  790. {
  791. uintmax_t u;
  792. if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
  793. st->stat.st_uid = u;
  794. }
  795. static void
  796. uname_coder (struct tar_stat_info const *st, char const *keyword,
  797. struct xheader *xhdr, void *data __attribute__ ((unused)))
  798. {
  799. code_string (st->uname, keyword, xhdr);
  800. }
  801. static void
  802. uname_decoder (struct tar_stat_info *st, char const *arg)
  803. {
  804. decode_string (&st->uname, arg);
  805. }
  806. static void
  807. sparse_size_coder (struct tar_stat_info const *st, char const *keyword,
  808. struct xheader *xhdr, void *data)
  809. {
  810. size_coder (st, keyword, xhdr, data);
  811. }
  812. static void
  813. sparse_size_decoder (struct tar_stat_info *st, char const *arg)
  814. {
  815. uintmax_t u;
  816. if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
  817. st->stat.st_size = u;
  818. }
  819. static void
  820. sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword,
  821. struct xheader *xhdr,
  822. void *data __attribute__ ((unused)))
  823. {
  824. code_num (st->sparse_map_avail, keyword, xhdr);
  825. }
  826. static void
  827. sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg)
  828. {
  829. uintmax_t u;
  830. if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
  831. {
  832. st->sparse_map_size = u;
  833. st->sparse_map = calloc(st->sparse_map_size, sizeof(st->sparse_map[0]));
  834. st->sparse_map_avail = 0;
  835. }
  836. }
  837. static void
  838. sparse_offset_coder (struct tar_stat_info const *st, char const *keyword,
  839. struct xheader *xhdr, void *data)
  840. {
  841. size_t i = *(size_t*)data;
  842. code_num (st->sparse_map[i].offset, keyword, xhdr);
  843. }
  844. static void
  845. sparse_offset_decoder (struct tar_stat_info *st, char const *arg)
  846. {
  847. uintmax_t u;
  848. if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
  849. st->sparse_map[st->sparse_map_avail].offset = u;
  850. }
  851. static void
  852. sparse_numbytes_coder (struct tar_stat_info const *st, char const *keyword,
  853. struct xheader *xhdr, void *data)
  854. {
  855. size_t i = *(size_t*)data;
  856. code_num (st->sparse_map[i].numbytes, keyword, xhdr);
  857. }
  858. static void
  859. sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg)
  860. {
  861. uintmax_t u;
  862. if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
  863. {
  864. if (st->sparse_map_avail == st->sparse_map_size)
  865. {
  866. st->sparse_map_size *= 2;
  867. st->sparse_map = xrealloc (st->sparse_map,
  868. st->sparse_map_size
  869. * sizeof st->sparse_map[0]);
  870. }
  871. st->sparse_map[st->sparse_map_avail++].numbytes = u;
  872. }
  873. }
  874. struct xhdr_tab const xhdr_tab[] = {
  875. { "atime", atime_coder, atime_decoder, false },
  876. { "comment", dummy_coder, dummy_decoder, false },
  877. { "charset", dummy_coder, dummy_decoder, false },
  878. { "ctime", ctime_coder, ctime_decoder, false },
  879. { "gid", gid_coder, gid_decoder, false },
  880. { "gname", gname_coder, gname_decoder, false },
  881. { "linkpath", linkpath_coder, linkpath_decoder, false },
  882. { "mtime", mtime_coder, mtime_decoder, false },
  883. { "path", path_coder, path_decoder, false },
  884. { "size", size_coder, size_decoder, false },
  885. { "uid", uid_coder, uid_decoder, false },
  886. { "uname", uname_coder, uname_decoder, false },
  887. /* Sparse file handling */
  888. { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true },
  889. { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder,
  890. true },
  891. { "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder,
  892. true },
  893. { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
  894. true },
  895. #if 0 /* GNU private keywords (not yet implemented) */
  896. /* The next directory entry actually contains the names of files
  897. that were in the directory at the time the dump was made.
  898. Supersedes GNUTYPE_DUMPDIR header type. */
  899. { "GNU.dump.name", dump_name_coder, dump_name_decoder, false },
  900. { "GNU.dump.status", dump_status_coder, dump_status_decoder, false },
  901. /* Keeps the tape/volume header. May be present only in the global headers.
  902. Equivalent to GNUTYPE_VOLHDR. */
  903. { "GNU.volume.header", volume_header_coder, volume_header_decoder, false },
  904. /* These may be present in a first global header of the archive.
  905. They provide the same functionality as GNUTYPE_MULTIVOL header.
  906. The GNU.volume.size keeps the real_s_sizeleft value, which is
  907. otherwise kept in the size field of a multivolume header. The
  908. GNU.volume.offset keeps the offset of the start of this volume,
  909. otherwise kept in oldgnu_header.offset. */
  910. { "GNU.volume.size", volume_size_coder, volume_size_decoder, false },
  911. { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, false },
  912. #endif
  913. { NULL, NULL, NULL, false }
  914. };