]> Dogcows Code - chaz/tar/blob - src/create.c
Added a comment
[chaz/tar] / src / create.c
1 /* Create a tar archive.
2
3 Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
4 2003 Free Software Foundation, Inc.
5
6 Written by John Gilmore, on 1985-08-25.
7
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16 Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22 #include "system.h"
23
24 #if HAVE_UTIME_H
25 # include <utime.h>
26 #else
27 struct utimbuf
28 {
29 long actime;
30 long modtime;
31 };
32 #endif
33
34 #include <quotearg.h>
35
36 #include "common.h"
37 #include <hash.h>
38
39 struct link
40 {
41 dev_t dev;
42 ino_t ino;
43 size_t nlink;
44 char name[1];
45 };
46 \f
47 /* The maximum uintmax_t value that can be represented with DIGITS digits,
48 assuming that each digit is BITS_PER_DIGIT wide. */
49 #define MAX_VAL_WITH_DIGITS(digits, bits_per_digit) \
50 ((digits) * (bits_per_digit) < sizeof (uintmax_t) * CHAR_BIT \
51 ? ((uintmax_t) 1 << ((digits) * (bits_per_digit))) - 1 \
52 : (uintmax_t) -1)
53
54 /* Convert VALUE to an octal representation suitable for tar headers.
55 Output to buffer WHERE with size SIZE.
56 The result is undefined if SIZE is 0 or if VALUE is too large to fit. */
57
58 static void
59 to_octal (uintmax_t value, char *where, size_t size)
60 {
61 uintmax_t v = value;
62 size_t i = size;
63
64 do
65 {
66 where[--i] = '0' + (v & ((1 << LG_8) - 1));
67 v >>= LG_8;
68 }
69 while (i);
70 }
71
72 /* Convert NEGATIVE VALUE to a base-256 representation suitable for
73 tar headers. NEGATIVE is 1 if VALUE was negative before being cast
74 to uintmax_t, 0 otherwise. Output to buffer WHERE with size SIZE.
75 The result is undefined if SIZE is 0 or if VALUE is too large to
76 fit. */
77
78 static void
79 to_base256 (int negative, uintmax_t value, char *where, size_t size)
80 {
81 uintmax_t v = value;
82 uintmax_t propagated_sign_bits =
83 ((uintmax_t) - negative << (CHAR_BIT * sizeof v - LG_256));
84 size_t i = size;
85
86 do
87 {
88 where[--i] = v & ((1 << LG_256) - 1);
89 v = propagated_sign_bits | (v >> LG_256);
90 }
91 while (i);
92 }
93
94 /* Convert NEGATIVE VALUE (which was originally of size VALSIZE) to
95 external form, using SUBSTITUTE (...) if VALUE won't fit. Output
96 to buffer WHERE with size SIZE. NEGATIVE is 1 iff VALUE was
97 negative before being cast to uintmax_t; its original bitpattern
98 can be deduced from VALSIZE, its original size before casting.
99 TYPE is the kind of value being output (useful for diagnostics).
100 Prefer the POSIX format of SIZE - 1 octal digits (with leading zero
101 digits), followed by '\0'. If this won't work, and if GNU or
102 OLDGNU format is allowed, use '\200' followed by base-256, or (if
103 NEGATIVE is nonzero) '\377' followed by two's complement base-256.
104 If neither format works, use SUBSTITUTE (...) instead. Pass to
105 SUBSTITUTE the address of an 0-or-1 flag recording whether the
106 substitute value is negative. */
107
108 static void
109 to_chars (int negative, uintmax_t value, size_t valsize,
110 uintmax_t (*substitute) (int *),
111 char *where, size_t size, const char *type)
112 {
113 int base256_allowed = (archive_format == GNU_FORMAT
114 || archive_format == OLDGNU_FORMAT);
115
116 /* Generate the POSIX octal representation if the number fits. */
117 if (! negative && value <= MAX_VAL_WITH_DIGITS (size - 1, LG_8))
118 {
119 where[size - 1] = '\0';
120 to_octal (value, where, size - 1);
121 }
122
123 /* Otherwise, generate the base-256 representation if we are
124 generating an old or new GNU format and if the number fits. */
125 else if (((negative ? -1 - value : value)
126 <= MAX_VAL_WITH_DIGITS (size - 1, LG_256))
127 && base256_allowed)
128 {
129 where[0] = negative ? -1 : 1 << (LG_256 - 1);
130 to_base256 (negative, value, where + 1, size - 1);
131 }
132
133 /* Otherwise, if the number is negative, and if it would not cause
134 ambiguity on this host by confusing positive with negative
135 values, then generate the POSIX octal representation of the value
136 modulo 2**(field bits). The resulting tar file is
137 machine-dependent, since it depends on the host word size. Yuck!
138 But this is the traditional behavior. */
139 else if (negative && valsize * CHAR_BIT <= (size - 1) * LG_8)
140 {
141 static int warned_once;
142 if (! warned_once)
143 {
144 warned_once = 1;
145 WARN ((0, 0, _("Generating negative octal headers")));
146 }
147 where[size - 1] = '\0';
148 to_octal (value & MAX_VAL_WITH_DIGITS (valsize * CHAR_BIT, 1),
149 where, size - 1);
150 }
151
152 /* Otherwise, output a substitute value if possible (with a
153 warning), and an error message if not. */
154 else
155 {
156 uintmax_t maxval = (base256_allowed
157 ? MAX_VAL_WITH_DIGITS (size - 1, LG_256)
158 : MAX_VAL_WITH_DIGITS (size - 1, LG_8));
159 char valbuf[UINTMAX_STRSIZE_BOUND + 1];
160 char maxbuf[UINTMAX_STRSIZE_BOUND];
161 char minbuf[UINTMAX_STRSIZE_BOUND + 1];
162 char const *minval_string;
163 char const *maxval_string = STRINGIFY_BIGINT (maxval, maxbuf);
164 char const *value_string;
165
166 if (base256_allowed)
167 {
168 uintmax_t m = maxval + 1 ? maxval + 1 : maxval / 2 + 1;
169 char *p = STRINGIFY_BIGINT (m, minbuf + 1);
170 *--p = '-';
171 minval_string = p;
172 }
173 else
174 minval_string = "0";
175
176 if (negative)
177 {
178 char *p = STRINGIFY_BIGINT (- value, valbuf + 1);
179 *--p = '-';
180 value_string = p;
181 }
182 else
183 value_string = STRINGIFY_BIGINT (value, valbuf);
184
185 if (substitute)
186 {
187 int negsub;
188 uintmax_t sub = substitute (&negsub) & maxval;
189 /* FIXME: This is the only place where GNU_FORMAT differs from
190 OLDGNU_FORMAT. Apart from this they are completely identical. */
191 uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? - sub : sub;
192 char subbuf[UINTMAX_STRSIZE_BOUND + 1];
193 char *sub_string = STRINGIFY_BIGINT (s, subbuf + 1);
194 if (negsub)
195 *--sub_string = '-';
196 WARN ((0, 0, _("value %s out of %s range %s..%s; substituting %s"),
197 value_string, type, minval_string, maxval_string,
198 sub_string));
199 to_chars (negsub, s, valsize, 0, where, size, type);
200 }
201 else
202 ERROR ((0, 0, _("value %s out of %s range %s..%s"),
203 value_string, type, minval_string, maxval_string));
204 }
205 }
206
207 static uintmax_t
208 gid_substitute (int *negative)
209 {
210 gid_t r;
211 #ifdef GID_NOBODY
212 r = GID_NOBODY;
213 #else
214 static gid_t gid_nobody;
215 if (!gid_nobody && !gname_to_gid ("nobody", &gid_nobody))
216 gid_nobody = -2;
217 r = gid_nobody;
218 #endif
219 *negative = r < 0;
220 return r;
221 }
222
223 void
224 gid_to_chars (gid_t v, char *p, size_t s)
225 {
226 to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t");
227 }
228
229 void
230 major_to_chars (major_t v, char *p, size_t s)
231 {
232 to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "major_t");
233 }
234
235 void
236 minor_to_chars (minor_t v, char *p, size_t s)
237 {
238 to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "minor_t");
239 }
240
241 void
242 mode_to_chars (mode_t v, char *p, size_t s)
243 {
244 /* In the common case where the internal and external mode bits are the same,
245 and we are not using POSIX or GNU format,
246 propagate all unknown bits to the external mode.
247 This matches historical practice.
248 Otherwise, just copy the bits we know about. */
249 int negative;
250 uintmax_t u;
251 if (S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX
252 && S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC
253 && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC
254 && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
255 && archive_format != POSIX_FORMAT
256 && archive_format != USTAR_FORMAT
257 && archive_format != GNU_FORMAT)
258 {
259 negative = v < 0;
260 u = v;
261 }
262 else
263 {
264 negative = 0;
265 u = ((v & S_ISUID ? TSUID : 0)
266 | (v & S_ISGID ? TSGID : 0)
267 | (v & S_ISVTX ? TSVTX : 0)
268 | (v & S_IRUSR ? TUREAD : 0)
269 | (v & S_IWUSR ? TUWRITE : 0)
270 | (v & S_IXUSR ? TUEXEC : 0)
271 | (v & S_IRGRP ? TGREAD : 0)
272 | (v & S_IWGRP ? TGWRITE : 0)
273 | (v & S_IXGRP ? TGEXEC : 0)
274 | (v & S_IROTH ? TOREAD : 0)
275 | (v & S_IWOTH ? TOWRITE : 0)
276 | (v & S_IXOTH ? TOEXEC : 0));
277 }
278 to_chars (negative, u, sizeof v, 0, p, s, "mode_t");
279 }
280
281 void
282 off_to_chars (off_t v, char *p, size_t s)
283 {
284 to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "off_t");
285 }
286
287 void
288 size_to_chars (size_t v, char *p, size_t s)
289 {
290 to_chars (0, (uintmax_t) v, sizeof v, 0, p, s, "size_t");
291 }
292
293 void
294 time_to_chars (time_t v, char *p, size_t s)
295 {
296 to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "time_t");
297 }
298
299 static uintmax_t
300 uid_substitute (int *negative)
301 {
302 uid_t r;
303 #ifdef UID_NOBODY
304 r = UID_NOBODY;
305 #else
306 static uid_t uid_nobody;
307 if (!uid_nobody && !uname_to_uid ("nobody", &uid_nobody))
308 uid_nobody = -2;
309 r = uid_nobody;
310 #endif
311 *negative = r < 0;
312 return r;
313 }
314
315 void
316 uid_to_chars (uid_t v, char *p, size_t s)
317 {
318 to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
319 }
320
321 void
322 uintmax_to_chars (uintmax_t v, char *p, size_t s)
323 {
324 to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
325 }
326
327 void
328 string_to_chars (char *str, char *p, size_t s)
329 {
330 strncpy (p, str, s);
331 p[s-1] = 0;
332 }
333
334 \f
335 /* A file is not dumpable if
336 a) it is empty *and* world-readable, or
337 b) current archive is /dev/null */
338
339 bool
340 file_dumpable_p (struct tar_stat_info *stat)
341 {
342 return !(dev_null_output
343 || (stat->archive_file_size == 0
344 && (stat->stat.st_mode & MODE_R) == MODE_R));
345 }
346
347 \f
348 /* Writing routines. */
349
350 /* Write the EOT block(s). Zero at least two blocks, through the end
351 of the record. Old tar, as previous versions of GNU tar, writes
352 garbage after two zeroed blocks. */
353 void
354 write_eot (void)
355 {
356 union block *pointer = find_next_block ();
357 memset (pointer->buffer, 0, BLOCKSIZE);
358 set_next_block_after (pointer);
359 pointer = find_next_block ();
360 memset (pointer->buffer, 0, available_space_after (pointer));
361 set_next_block_after (pointer);
362 }
363
364 /* Copy at most LEN bytes from SRC to DST. Terminate with NUL unless
365 SRC is LEN characters long */
366 static void
367 tar_copy_str (char *dst, const char *src, size_t len)
368 {
369 dst[len-1] = 0;
370 strncpy (dst, src, len);
371 }
372
373 /* Write a "private" header */
374 static union block *
375 start_private_header (const char *name, size_t size)
376 {
377 time_t t;
378 union block *header = find_next_block ();
379
380 memset (header->buffer, 0, sizeof (union block));
381
382 tar_copy_str (header->header.name, name, NAME_FIELD_SIZE);
383 OFF_TO_CHARS (size, header->header.size);
384
385 time (&t);
386 TIME_TO_CHARS (t, header->header.mtime);
387 MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode);
388 UID_TO_CHARS (getuid (), header->header.uid);
389 GID_TO_CHARS (getgid (), header->header.gid);
390 MAJOR_TO_CHARS (0, header->header.devmajor);
391 MAJOR_TO_CHARS (0, header->header.devminor);
392 strncpy (header->header.magic, TMAGIC, TMAGLEN);
393 strncpy (header->header.version, TVERSION, TVERSLEN);
394 return header;
395 }
396
397 /* Create a new header and store there at most NAME_FIELD_SIZE bytes of
398 the file name */
399
400 static union block *
401 write_short_name (struct tar_stat_info *st)
402 {
403 union block *header = find_next_block ();
404 memset (header->buffer, 0, sizeof (union block));
405 tar_copy_str (header->header.name, st->file_name, NAME_FIELD_SIZE);
406 return header;
407 }
408
409 /* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */
410 static void
411 write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
412 {
413 size_t size = strlen (p) + 1;
414 size_t bufsize;
415 union block *header;
416
417 header = start_private_header ("././@LongLink", size);
418 strcpy (header->header.magic, OLDGNU_MAGIC);
419 header->header.typeflag = type;
420 finish_header (st, header, -1);
421
422 header = find_next_block ();
423
424 bufsize = available_space_after (header);
425
426 while (bufsize < size)
427 {
428 memcpy (header->buffer, p, bufsize);
429 p += bufsize;
430 size -= bufsize;
431 set_next_block_after (header + (bufsize - 1) / BLOCKSIZE);
432 header = find_next_block ();
433 bufsize = available_space_after (header);
434 }
435 memcpy (header->buffer, p, size);
436 memset (header->buffer + size, 0, bufsize - size);
437 set_next_block_after (header + (size - 1) / BLOCKSIZE);
438 }
439
440 static size_t
441 split_long_name (const char *name, size_t length)
442 {
443 size_t i;
444
445 if (length > PREFIX_FIELD_SIZE)
446 length = PREFIX_FIELD_SIZE+2;
447 for (i = length - 1; i > 0; i--)
448 if (ISSLASH (name[i]))
449 break;
450 return i;
451 }
452
453 static union block *
454 write_ustar_long_name (const char *name)
455 {
456 size_t length = strlen (name);
457 size_t i;
458 union block *header;
459
460 if (length > PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1)
461 {
462 WARN ((0, 0, _("%s: file name is too long (max %d); not dumped"),
463 quotearg_colon (name),
464 PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1));
465 return NULL;
466 }
467
468 i = split_long_name (name, length);
469 if (i == 0 || length - i - 1 > NAME_FIELD_SIZE)
470 {
471 WARN ((0, 0,
472 _("%s: file name is too long (cannot be split); not dumped"),
473 quotearg_colon (name)));
474 return NULL;
475 }
476
477 header = find_next_block ();
478 memset (header->buffer, 0, sizeof (header->buffer));
479 memcpy (header->header.prefix, name, i);
480 memcpy (header->header.name, name + i + 1, length - i - 1);
481
482 return header;
483 }
484
485 /* Write a long link name, depending on the current archive format */
486 static void
487 write_long_link (struct tar_stat_info *st)
488 {
489 switch (archive_format)
490 {
491 case POSIX_FORMAT:
492 xheader_store ("linkpath", st, NULL);
493 break;
494
495 case V7_FORMAT: /* old V7 tar format */
496 case USTAR_FORMAT:
497 case STAR_FORMAT:
498 WARN ((0, 0,
499 _("%s: link name is too long; not dumped"),
500 quotearg_colon (st->link_name)));
501 break;
502
503 case OLDGNU_FORMAT:
504 case GNU_FORMAT:
505 write_gnu_long_link (st, st->link_name, GNUTYPE_LONGLINK);
506 break;
507
508 default:
509 abort(); /*FIXME*/
510 }
511 }
512
513 static union block *
514 write_long_name (struct tar_stat_info *st)
515 {
516 switch (archive_format)
517 {
518 case POSIX_FORMAT:
519 xheader_store ("path", st, NULL);
520 break;
521
522 case V7_FORMAT:
523 case USTAR_FORMAT:
524 case STAR_FORMAT:
525 return write_ustar_long_name (st->file_name);
526
527 case OLDGNU_FORMAT:
528 case GNU_FORMAT:
529 write_gnu_long_link (st, st->file_name, GNUTYPE_LONGNAME);
530 break;
531
532 default:
533 abort(); /*FIXME*/
534 }
535 return write_short_name (st);
536 }
537
538 static union block *
539 write_extended (struct tar_stat_info *st, union block *old_header, char type)
540 {
541 union block *header, hp;
542 size_t size;
543 char *p;
544
545 if (extended_header.buffer || extended_header.stk == NULL)
546 return old_header;
547
548 xheader_finish (&extended_header);
549 size = extended_header.size;
550
551 memcpy (hp.buffer, old_header, sizeof (hp));
552
553 header = start_private_header (p = xheader_xhdr_name (st), size);
554 free (p);
555 header->header.typeflag = type;
556
557 finish_header (st, header, -1);
558
559 p = extended_header.buffer;
560
561 do
562 {
563 size_t len;
564
565 header = find_next_block ();
566 len = BLOCKSIZE;
567 if (len > size)
568 len = size;
569 memcpy (header->buffer, p, len);
570 if (len < BLOCKSIZE)
571 memset (header->buffer + len, 0, BLOCKSIZE - len);
572 p += len;
573 size -= len;
574 set_next_block_after (header);
575 }
576 while (size > 0);
577
578 xheader_destroy (&extended_header);
579 header = find_next_block ();
580 memcpy (header, &hp.buffer, sizeof (hp.buffer));
581 return header;
582 }
583
584 static union block *
585 write_header_name (struct tar_stat_info *st)
586 {
587 if (NAME_FIELD_SIZE < strlen (st->file_name))
588 return write_long_name (st);
589 else
590 return write_short_name (st);
591 }
592
593 \f
594 /* Header handling. */
595
596 /* Make a header block for the file whose stat info is st,
597 and return its address. */
598
599 union block *
600 start_header (struct tar_stat_info *st)
601 {
602 union block *header;
603
604 header = write_header_name (st);
605 if (!header)
606 return NULL;
607
608 /* Override some stat fields, if requested to do so. */
609
610 if (owner_option != (uid_t) -1)
611 st->stat.st_uid = owner_option;
612 if (group_option != (gid_t) -1)
613 st->stat.st_gid = group_option;
614 if (mode_option)
615 st->stat.st_mode = ((st->stat.st_mode & ~MODE_ALL)
616 | mode_adjust (st->stat.st_mode, mode_option));
617
618 /* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a)
619 for a few tars and came up with the following interoperability
620 matrix:
621
622 WRITER
623 1 2 3 4 5 6 7 8 9 READER
624 . . . . . . . . . 1 = SunOS 4.2 tar
625 # . . # # . . # # 2 = NEC SVR4.0.2 tar
626 . . . # # . . # . 3 = Solaris 2.1 tar
627 . . . . . . . . . 4 = GNU tar 1.11.1
628 . . . . . . . . . 5 = HP-UX 8.07 tar
629 . . . . . . . . . 6 = Ultrix 4.1
630 . . . . . . . . . 7 = AIX 3.2
631 . . . . . . . . . 8 = Hitachi HI-UX 1.03
632 . . . . . . . . . 9 = Omron UNIOS-B 4.3BSD 1.60Beta
633
634 . = works
635 # = ``impossible file type''
636
637 The following mask for old archive removes the `#'s in column 4
638 above, thus making GNU tar both a universal donor and a universal
639 acceptor for Paul's test. */
640
641 if (archive_format == V7_FORMAT || archive_format == USTAR_FORMAT)
642 MODE_TO_CHARS (st->stat.st_mode & MODE_ALL, header->header.mode);
643 else
644 MODE_TO_CHARS (st->stat.st_mode, header->header.mode);
645
646 if (st->stat.st_uid > MAXOCTAL7 && archive_format == POSIX_FORMAT)
647 xheader_store ("uid", st, NULL);
648 else
649 UID_TO_CHARS (st->stat.st_uid, header->header.uid);
650
651 if (st->stat.st_gid > MAXOCTAL7 && archive_format == POSIX_FORMAT)
652 xheader_store ("gid", st, NULL);
653 else
654 GID_TO_CHARS (st->stat.st_gid, header->header.gid);
655
656 if (st->stat.st_size > MAXOCTAL11 && archive_format == POSIX_FORMAT)
657 xheader_store ("size", st, NULL);
658 else
659 OFF_TO_CHARS (st->stat.st_size, header->header.size);
660
661 TIME_TO_CHARS (st->stat.st_mtime, header->header.mtime);
662
663 /* FIXME */
664 if (S_ISCHR (st->stat.st_mode)
665 || S_ISBLK (st->stat.st_mode))
666 {
667 st->devmajor = major (st->stat.st_rdev);
668 st->devminor = minor (st->stat.st_rdev);
669
670 if (st->devmajor > MAXOCTAL7 && archive_format == POSIX_FORMAT)
671 xheader_store ("devmajor", st, NULL);
672 else
673 MAJOR_TO_CHARS (st->devmajor, header->header.devmajor);
674
675 if (st->devminor > MAXOCTAL7 && archive_format == POSIX_FORMAT)
676 xheader_store ("devminor", st, NULL);
677 else
678 MAJOR_TO_CHARS (st->devminor, header->header.devminor);
679 }
680 else
681 {
682 MAJOR_TO_CHARS (0, header->header.devmajor);
683 MINOR_TO_CHARS (0, header->header.devminor);
684 }
685
686 if (archive_format == POSIX_FORMAT)
687 {
688 xheader_store ("atime", st, NULL);
689 xheader_store ("ctime", st, NULL);
690 }
691 else if (incremental_option)
692 if (archive_format == OLDGNU_FORMAT)
693 {
694 TIME_TO_CHARS (st->stat.st_atime, header->oldgnu_header.atime);
695 TIME_TO_CHARS (st->stat.st_ctime, header->oldgnu_header.ctime);
696 }
697
698 header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
699
700 switch (archive_format)
701 {
702 case V7_FORMAT:
703 break;
704
705 case OLDGNU_FORMAT:
706 case GNU_FORMAT: /*FIXME?*/
707 /* Overwrite header->header.magic and header.version in one blow. */
708 strcpy (header->header.magic, OLDGNU_MAGIC);
709 break;
710
711 case POSIX_FORMAT:
712 case USTAR_FORMAT:
713 strncpy (header->header.magic, TMAGIC, TMAGLEN);
714 strncpy (header->header.version, TVERSION, TVERSLEN);
715 break;
716
717 default:
718 abort ();
719 }
720
721 if (archive_format == V7_FORMAT || numeric_owner_option)
722 {
723 /* header->header.[ug]name are left as the empty string. */
724 }
725 else
726 {
727 uid_to_uname (st->stat.st_uid, &st->uname);
728 gid_to_gname (st->stat.st_gid, &st->gname);
729
730 if (archive_format == POSIX_FORMAT
731 && strlen (st->uname) > UNAME_FIELD_SIZE)
732 xheader_store ("uname", st, NULL);
733 else
734 UNAME_TO_CHARS (st->uname, header->header.uname);
735
736 if (archive_format == POSIX_FORMAT
737 && strlen (st->gname) > GNAME_FIELD_SIZE)
738 xheader_store ("gname", st, NULL);
739 else
740 GNAME_TO_CHARS (st->gname, header->header.gname);
741 }
742
743 return header;
744 }
745
746 /* Finish off a filled-in header block and write it out. We also
747 print the file name and/or full info if verbose is on. If BLOCK_ORDINAL
748 is not negative, is the block ordinal of the first record for this
749 file, which may be a preceding long name or long link record. */
750 void
751 finish_header (struct tar_stat_info *st,
752 union block *header, off_t block_ordinal)
753 {
754 size_t i;
755 int sum;
756 char *p;
757
758 /* Note: It is important to do this before the call to write_extended(),
759 so that the actual ustar header is printed */
760 if (verbose_option
761 && header->header.typeflag != GNUTYPE_LONGLINK
762 && header->header.typeflag != GNUTYPE_LONGNAME
763 && header->header.typeflag != XHDTYPE
764 && header->header.typeflag != XGLTYPE)
765 {
766 /* These globals are parameters to print_header, sigh. */
767
768 current_header = header;
769 current_format = archive_format;
770 print_header (st, block_ordinal);
771 }
772
773 header = write_extended (st, header, XHDTYPE);
774
775 memcpy (header->header.chksum, CHKBLANKS, sizeof header->header.chksum);
776
777 sum = 0;
778 p = header->buffer;
779 for (i = sizeof *header; i-- != 0; )
780 /* We can't use unsigned char here because of old compilers, e.g. V7. */
781 sum += 0xFF & *p++;
782
783 /* Fill in the checksum field. It's formatted differently from the
784 other fields: it has [6] digits, a null, then a space -- rather than
785 digits, then a null. We use to_chars.
786 The final space is already there, from
787 checksumming, and to_chars doesn't modify it.
788
789 This is a fast way to do:
790
791 sprintf(header->header.chksum, "%6o", sum); */
792
793 uintmax_to_chars ((uintmax_t) sum, header->header.chksum, 7);
794
795 set_next_block_after (header);
796 }
797 \f
798
799 void
800 pad_archive (off_t size_left)
801 {
802 union block *blk;
803 while (size_left > 0)
804 {
805 save_sizeleft = size_left;
806 blk = find_next_block ();
807 memset (blk->buffer, 0, BLOCKSIZE);
808 set_next_block_after (blk);
809 size_left -= BLOCKSIZE;
810 }
811 }
812
813 static enum dump_status
814 dump_regular_file (int fd, struct tar_stat_info *stat)
815 {
816 off_t size_left = stat->stat.st_size;
817 off_t block_ordinal;
818 union block *blk;
819
820 block_ordinal = current_block_ordinal ();
821 blk = start_header (stat);
822 if (!blk)
823 return dump_status_fail;
824
825 /* Mark contiguous files, if we support them. */
826 if (archive_format != V7_FORMAT && S_ISCTG (stat->stat.st_mode))
827 blk->header.typeflag = CONTTYPE;
828
829 finish_header (stat, blk, block_ordinal);
830
831 while (size_left > 0)
832 {
833 size_t bufsize, count;
834
835 if (multi_volume_option)
836 {
837 assign_string (&save_name, stat->file_name);
838 save_sizeleft = size_left;
839 save_totsize = stat->stat.st_size;
840 }
841 blk = find_next_block ();
842
843 bufsize = available_space_after (blk);
844
845 if (size_left < bufsize)
846 {
847 /* Last read -- zero out area beyond. */
848 bufsize = size_left;
849 count = bufsize % BLOCKSIZE;
850 if (count)
851 memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
852 }
853
854 count = (fd < 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
855 if (count < 0)
856 {
857 read_diag_details (stat->orig_file_name,
858 stat->stat.st_size - size_left, bufsize);
859 pad_archive (size_left);
860 return dump_status_short;
861 }
862 size_left -= count;
863
864 set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
865
866 if (count != bufsize)
867 {
868 char buf[UINTMAX_STRSIZE_BOUND];
869 memset (blk->buffer + count, 0, bufsize - count);
870 WARN ((0, 0,
871 ngettext ("%s: File shrank by %s byte; padding with zeros",
872 "%s: File shrank by %s bytes; padding with zeros",
873 size_left),
874 quotearg_colon (stat->orig_file_name),
875 STRINGIFY_BIGINT (size_left, buf)));
876 if (! ignore_failed_read_option)
877 exit_status = TAREXIT_FAILURE;
878 pad_archive (size_left);
879 return dump_status_short;
880 }
881 }
882 return dump_status_ok;
883 }
884
885 void
886 dump_regular_finish (int fd, struct tar_stat_info *st, time_t original_ctime)
887 {
888 if (fd >= 0)
889 {
890 struct stat final_stat;
891 if (fstat (fd, &final_stat) != 0)
892 {
893 stat_diag (st->orig_file_name);
894 }
895 else if (final_stat.st_ctime != original_ctime)
896 {
897 WARN ((0, 0, _("%s: file changed as we read it"),
898 quotearg_colon (st->orig_file_name)));
899 }
900 if (close (fd) != 0)
901 {
902 close_diag (st->orig_file_name);
903 }
904 }
905 if (remove_files_option)
906 {
907 if (unlink (st->orig_file_name) == -1)
908 unlink_error (st->orig_file_name);
909 }
910 }
911
912 void
913 dump_dir0 (char *directory,
914 struct tar_stat_info *stat, int top_level, dev_t parent_device)
915 {
916 dev_t our_device = stat->stat.st_dev;
917
918 if (!is_avoided_name (stat->orig_file_name))
919 {
920 union block *blk = NULL;
921 off_t block_ordinal = current_block_ordinal ();
922 stat->stat.st_size = 0; /* force 0 size on dir */
923
924 blk = start_header (stat);
925 if (!blk)
926 return;
927
928 if (incremental_option)
929 blk->header.typeflag = GNUTYPE_DUMPDIR;
930 else /* if (standard_option) */
931 blk->header.typeflag = DIRTYPE;
932
933 /* If we're gnudumping, we aren't done yet so don't close it. */
934
935 if (!incremental_option)
936 finish_header (stat, blk, block_ordinal);
937 else if (gnu_list_name->dir_contents)
938 {
939 off_t size_left;
940 off_t totsize;
941 size_t bufsize;
942 ssize_t count;
943 const char *buffer, *p_buffer;
944 off_t block_ordinal = current_block_ordinal ();
945
946 buffer = gnu_list_name->dir_contents; /* FOO */
947 totsize = 0;
948 if (buffer)
949 for (p_buffer = buffer; *p_buffer; )
950 {
951 size_t size = strlen (p_buffer) + 1;
952 totsize += size;
953 p_buffer += size;
954 }
955 totsize++;
956 OFF_TO_CHARS (totsize, blk->header.size);
957 finish_header (stat, blk, block_ordinal);
958 p_buffer = buffer;
959 size_left = totsize;
960 while (size_left > 0)
961 {
962 if (multi_volume_option)
963 {
964 assign_string (&save_name, stat->orig_file_name);
965 save_sizeleft = size_left;
966 save_totsize = totsize;
967 }
968 blk = find_next_block ();
969 bufsize = available_space_after (blk);
970 if (size_left < bufsize)
971 {
972 bufsize = size_left;
973 count = bufsize % BLOCKSIZE;
974 if (count)
975 memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
976 }
977 memcpy (blk->buffer, p_buffer, bufsize);
978 size_left -= bufsize;
979 p_buffer += bufsize;
980 set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
981 }
982 if (multi_volume_option)
983 assign_string (&save_name, 0);
984 return;
985 }
986 }
987
988 if (!recursion_option)
989 return;
990
991 if (one_file_system_option
992 && !top_level
993 && parent_device != stat->stat.st_dev)
994 {
995 if (verbose_option)
996 WARN ((0, 0,
997 _("%s: file is on a different filesystem; not dumped"),
998 quotearg_colon (stat->orig_file_name)));
999 return;
1000 }
1001
1002 {
1003 char const *entry;
1004 size_t entry_len;
1005 char *name_buf = strdup (stat->orig_file_name);
1006 size_t name_size = strlen (name_buf);
1007 size_t name_len = name_size;
1008
1009 /* Now output all the files in the directory. */
1010 /* FIXME: Should speed this up by cd-ing into the dir. */
1011
1012 for (entry = directory; (entry_len = strlen (entry)) != 0;
1013 entry += entry_len + 1)
1014 {
1015 if (name_size < name_len + entry_len)
1016 {
1017 name_size = name_len + entry_len;
1018 name_buf = xrealloc (name_buf, name_size + 1);
1019 }
1020 strcpy (name_buf + name_len, entry);
1021 if (!excluded_name (name_buf))
1022 dump_file (name_buf, 0, our_device);
1023 }
1024
1025 free (name_buf);
1026 }
1027 }
1028
1029 /* Ensure exactly one trailing slash. */
1030 static void
1031 ensure_slash (char **pstr)
1032 {
1033 size_t len = strlen (*pstr);
1034 while (len >= 1 && ISSLASH ((*pstr)[len - 1]))
1035 len--;
1036 if (!ISSLASH ((*pstr)[len]))
1037 *pstr = xrealloc (*pstr, len + 2);
1038 (*pstr)[len++] = '/';
1039 (*pstr)[len] = '\0';
1040 }
1041
1042 bool
1043 dump_dir (struct tar_stat_info *stat, int top_level, dev_t parent_device)
1044 {
1045 char *directory;
1046
1047 directory = savedir (stat->orig_file_name);
1048 if (!directory)
1049 {
1050 savedir_diag (stat->orig_file_name);
1051 return false;
1052 }
1053
1054 ensure_slash (&stat->orig_file_name);
1055 ensure_slash (&stat->file_name);
1056
1057 dump_dir0 (directory, stat, top_level, parent_device);
1058
1059 free (directory);
1060 return true;
1061 }
1062
1063 \f
1064 /* Main functions of this module. */
1065
1066 void
1067 create_archive (void)
1068 {
1069 char *p;
1070
1071 open_archive (ACCESS_WRITE);
1072
1073 if (incremental_option)
1074 {
1075 size_t buffer_size = 1000;
1076 char *buffer = xmalloc (buffer_size);
1077 const char *q;
1078
1079 collect_and_sort_names ();
1080
1081 while ((p = name_from_list ()) != NULL)
1082 if (!excluded_name (p))
1083 dump_file (p, -1, (dev_t) 0);
1084
1085 blank_name_list ();
1086 while ((p = name_from_list ()) != NULL)
1087 if (!excluded_name (p))
1088 {
1089 size_t plen = strlen (p);
1090 if (buffer_size <= plen)
1091 {
1092 while ((buffer_size *= 2) <= plen)
1093 continue;
1094 buffer = xrealloc (buffer, buffer_size);
1095 }
1096 memcpy (buffer, p, plen);
1097 if (! ISSLASH (buffer[plen - 1]))
1098 buffer[plen++] = '/';
1099 q = gnu_list_name->dir_contents;
1100 if (q)
1101 while (*q)
1102 {
1103 size_t qlen = strlen (q);
1104 if (*q == 'Y')
1105 {
1106 if (buffer_size < plen + qlen)
1107 {
1108 while ((buffer_size *=2 ) < plen + qlen)
1109 continue;
1110 buffer = xrealloc (buffer, buffer_size);
1111 }
1112 strcpy (buffer + plen, q + 1);
1113 dump_file (buffer, -1, (dev_t) 0);
1114 }
1115 q += qlen + 1;
1116 }
1117 }
1118 free (buffer);
1119 }
1120 else
1121 {
1122 while ((p = name_next (1)) != NULL)
1123 if (!excluded_name (p))
1124 dump_file (p, 1, (dev_t) 0);
1125 }
1126
1127 write_eot ();
1128 close_archive ();
1129
1130 if (listed_incremental_option)
1131 write_directory_file ();
1132 }
1133
1134
1135 /* Calculate the hash of a link. */
1136 static unsigned
1137 hash_link (void const *entry, unsigned n_buckets)
1138 {
1139 struct link const *link = entry;
1140 return (uintmax_t) (link->dev ^ link->ino) % n_buckets;
1141 }
1142
1143 /* Compare two links for equality. */
1144 static bool
1145 compare_links (void const *entry1, void const *entry2)
1146 {
1147 struct link const *link1 = entry1;
1148 struct link const *link2 = entry2;
1149 return ((link1->dev ^ link2->dev) | (link1->ino ^ link2->ino)) == 0;
1150 }
1151
1152 static void
1153 unknown_file_error (char *p)
1154 {
1155 WARN ((0, 0, _("%s: Unknown file type; file ignored"),
1156 quotearg_colon (p)));
1157 if (!ignore_failed_read_option)
1158 exit_status = TAREXIT_FAILURE;
1159 }
1160
1161 \f
1162 /* Handling of hard links */
1163
1164 /* Table of all non-directories that we've written so far. Any time
1165 we see another, we check the table and avoid dumping the data
1166 again if we've done it once already. */
1167 static Hash_table *link_table;
1168
1169 /* Try to dump stat as a hard link to another file in the archive. If
1170 succeeded returns true */
1171 static bool
1172 dump_hard_link (struct tar_stat_info *stat)
1173 {
1174 if (link_table && stat->stat.st_nlink > 1)
1175 {
1176 struct link lp;
1177 struct link *dup;
1178 off_t block_ordinal;
1179 union block *blk;
1180
1181 lp.ino = stat->stat.st_ino;
1182 lp.dev = stat->stat.st_dev;
1183
1184 if ((dup = hash_lookup (link_table, &lp)))
1185 {
1186 /* We found a link. */
1187 char const *link_name = safer_name_suffix (dup->name, true);
1188
1189 dup->nlink--;
1190
1191 block_ordinal = current_block_ordinal ();
1192 assign_string (&stat->link_name, link_name);
1193 if (NAME_FIELD_SIZE < strlen (link_name))
1194 write_long_link (stat);
1195
1196 stat->stat.st_size = 0;
1197 blk = start_header (stat);
1198 if (!blk)
1199 return true;
1200 tar_copy_str (blk->header.linkname, link_name, NAME_FIELD_SIZE);
1201
1202 blk->header.typeflag = LNKTYPE;
1203 finish_header (stat, blk, block_ordinal);
1204
1205 if (remove_files_option && unlink (stat->orig_file_name) != 0)
1206 unlink_error (stat->orig_file_name);
1207
1208 return true;
1209 }
1210 }
1211 return false;
1212 }
1213
1214 static void
1215 file_count_links (struct tar_stat_info *stat)
1216 {
1217 if (stat->stat.st_nlink > 1)
1218 {
1219 struct link *dup;
1220 struct link *lp = xmalloc (offsetof (struct link, name)
1221 + strlen (stat->orig_file_name) + 1);
1222 lp->ino = stat->stat.st_ino;
1223 lp->dev = stat->stat.st_dev;
1224 lp->nlink = stat->stat.st_nlink;
1225 strcpy (lp->name, stat->orig_file_name);
1226
1227 if (! ((link_table
1228 || (link_table = hash_initialize (0, 0, hash_link,
1229 compare_links, 0)))
1230 && (dup = hash_insert (link_table, lp))))
1231 xalloc_die ();
1232
1233 if (dup != lp)
1234 abort ();
1235 lp->nlink--;
1236 }
1237 }
1238
1239 /* For each dumped file, check if all its links were dumped. Emit
1240 warnings if it is not so. */
1241 void
1242 check_links ()
1243 {
1244 struct link *lp;
1245
1246 if (!link_table)
1247 return;
1248
1249 for (lp = hash_get_first (link_table); lp;
1250 lp = hash_get_next (link_table, lp))
1251 {
1252 if (lp->nlink)
1253 {
1254 WARN ((0, 0, _("Missing links to '%s'.\n"), lp->name));
1255 }
1256 }
1257 }
1258
1259
1260 /* Dump a single file, recursing on directories. P is the file name
1261 to dump. TOP_LEVEL tells whether this is a top-level call; zero
1262 means no, positive means yes, and negative means the top level
1263 of an incremental dump. PARENT_DEVICE is the device of P's
1264 parent directory; it is examined only if TOP_LEVEL is zero. */
1265
1266 /* FIXME: One should make sure that for *every* path leading to setting
1267 exit_status to failure, a clear diagnostic has been issued. */
1268
1269 void
1270 dump_file0 (struct tar_stat_info *stat, char *p,
1271 int top_level, dev_t parent_device)
1272 {
1273 union block *header;
1274 char type;
1275 time_t original_ctime;
1276 struct utimbuf restore_times;
1277 off_t block_ordinal = -1;
1278
1279 if (interactive_option && !confirm ("add", p))
1280 return;
1281
1282 assign_string (&stat->orig_file_name, p);
1283 assign_string (&stat->file_name, safer_name_suffix (p, false));
1284
1285 if (deref_stat (dereference_option, p, &stat->stat) != 0)
1286 {
1287 stat_diag (p);
1288 return;
1289 }
1290 stat->archive_file_size = stat->stat.st_size;
1291 sys_stat_nanoseconds(stat);
1292 original_ctime = stat->stat.st_ctime;
1293 restore_times.actime = stat->stat.st_atime;
1294 restore_times.modtime = stat->stat.st_mtime;
1295
1296 #ifdef S_ISHIDDEN
1297 if (S_ISHIDDEN (stat->stat.st_mode))
1298 {
1299 char *new = (char *) alloca (strlen (p) + 2);
1300 if (new)
1301 {
1302 strcpy (new, p);
1303 strcat (new, "@");
1304 p = new;
1305 }
1306 }
1307 #endif
1308
1309 /* See if we want only new files, and check if this one is too old to
1310 put in the archive. */
1311
1312 if ((0 < top_level || !incremental_option)
1313 && !S_ISDIR (stat->stat.st_mode)
1314 && stat->stat.st_mtime < newer_mtime_option
1315 && (!after_date_option || stat->stat.st_ctime < newer_ctime_option))
1316 {
1317 if (0 < top_level)
1318 WARN ((0, 0, _("%s: file is unchanged; not dumped"),
1319 quotearg_colon (p)));
1320 /* FIXME: recheck this return. */
1321 return;
1322 }
1323
1324 /* See if we are trying to dump the archive. */
1325 if (sys_file_is_archive (stat))
1326 {
1327 WARN ((0, 0, _("%s: file is the archive; not dumped"),
1328 quotearg_colon (p)));
1329 return;
1330 }
1331
1332 if (S_ISDIR (stat->stat.st_mode))
1333 {
1334 dump_dir (stat, top_level, parent_device);
1335 if (atime_preserve_option)
1336 utime (p, &restore_times);
1337 return;
1338 }
1339 else if (is_avoided_name (p))
1340 return;
1341 else
1342 {
1343 /* Check for multiple links. */
1344 if (dump_hard_link (stat))
1345 return;
1346
1347 /* This is not a link to a previously dumped file, so dump it. */
1348
1349 if (S_ISREG (stat->stat.st_mode)
1350 || S_ISCTG (stat->stat.st_mode))
1351 {
1352 int fd;
1353 enum dump_status status;
1354
1355 if (file_dumpable_p (stat))
1356 {
1357 fd = open (stat->orig_file_name,
1358 O_RDONLY | O_BINARY);
1359 if (fd < 0)
1360 {
1361 if (!top_level && errno == ENOENT)
1362 WARN ((0, 0, _("%s: File removed before we read it"),
1363 quotearg_colon (stat->orig_file_name)));
1364 else
1365 open_diag (stat->orig_file_name);
1366 return;
1367 }
1368 }
1369 else
1370 fd = -1;
1371
1372 if (sparse_option && sparse_file_p (stat))
1373 {
1374 status = sparse_dump_file (fd, stat);
1375 if (status == dump_status_not_implemented)
1376 status = dump_regular_file (fd, stat);
1377 }
1378 else
1379 status = dump_regular_file (fd, stat);
1380
1381 switch (status)
1382 {
1383 case dump_status_ok:
1384 if (multi_volume_option)
1385 assign_string (&save_name, 0);
1386 dump_regular_finish (fd, stat, original_ctime);
1387 break;
1388
1389 case dump_status_short:
1390 if (multi_volume_option)
1391 assign_string (&save_name, 0);
1392 close (fd);
1393 break;
1394
1395 case dump_status_fail:
1396 close (fd);
1397 return;
1398
1399 case dump_status_not_implemented:
1400 abort ();
1401 }
1402
1403 if (atime_preserve_option)
1404 utime (stat->orig_file_name, &restore_times);
1405 file_count_links (stat);
1406 return;
1407 }
1408 #ifdef HAVE_READLINK
1409 else if (S_ISLNK (stat->stat.st_mode))
1410 {
1411 char *buffer;
1412 int size;
1413 size_t linklen = stat->stat.st_size;
1414 if (linklen != stat->stat.st_size || linklen + 1 == 0)
1415 xalloc_die ();
1416 buffer = (char *) alloca (linklen + 1);
1417 size = readlink (p, buffer, linklen + 1);
1418 if (size < 0)
1419 {
1420 readlink_diag (p);
1421 return;
1422 }
1423 buffer[size] = '\0';
1424 assign_string (&stat->link_name, buffer);
1425 if (size > NAME_FIELD_SIZE)
1426 write_long_link (stat);
1427
1428 block_ordinal = current_block_ordinal ();
1429 stat->stat.st_size = 0; /* force 0 size on symlink */
1430 header = start_header (stat);
1431 if (!header)
1432 return;
1433 tar_copy_str (header->header.linkname, buffer, NAME_FIELD_SIZE);
1434 header->header.typeflag = SYMTYPE;
1435 finish_header (stat, header, block_ordinal);
1436 /* nothing more to do to it */
1437
1438 if (remove_files_option)
1439 {
1440 if (unlink (p) == -1)
1441 unlink_error (p);
1442 }
1443 file_count_links (stat);
1444 return;
1445 }
1446 #endif
1447 else if (S_ISCHR (stat->stat.st_mode))
1448 type = CHRTYPE;
1449 else if (S_ISBLK (stat->stat.st_mode))
1450 type = BLKTYPE;
1451 else if (S_ISFIFO (stat->stat.st_mode))
1452 type = FIFOTYPE;
1453 else if (S_ISSOCK (stat->stat.st_mode))
1454 {
1455 WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
1456 return;
1457 }
1458 else if (S_ISDOOR (stat->stat.st_mode))
1459 {
1460 WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
1461 return;
1462 }
1463 else
1464 {
1465 unknown_file_error (p);
1466 return;
1467 }
1468 }
1469
1470 if (archive_format == V7_FORMAT)
1471 {
1472 unknown_file_error (p);
1473 return;
1474 }
1475
1476 block_ordinal = current_block_ordinal ();
1477 stat->stat.st_size = 0; /* force 0 size */
1478 header = start_header (stat);
1479 if (!header)
1480 return;
1481 header->header.typeflag = type;
1482
1483 if (type != FIFOTYPE)
1484 {
1485 MAJOR_TO_CHARS (major (stat->stat.st_rdev),
1486 header->header.devmajor);
1487 MINOR_TO_CHARS (minor (stat->stat.st_rdev),
1488 header->header.devminor);
1489 }
1490
1491 finish_header (stat, header, block_ordinal);
1492 if (remove_files_option)
1493 {
1494 if (unlink (p) == -1)
1495 unlink_error (p);
1496 }
1497 }
1498
1499 void
1500 dump_file (char *p, int top_level, dev_t parent_device)
1501 {
1502 struct tar_stat_info stat;
1503 tar_stat_init (&stat);
1504 dump_file0 (&stat, p, top_level, parent_device);
1505 tar_stat_destroy (&stat);
1506 }
This page took 0.096068 seconds and 5 git commands to generate.