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