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