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