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