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