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