xheader.c 25 KB

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