]> Dogcows Code - chaz/tar/blob - src/create.c
(write_long_name): Do not allow more than
[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, 2004 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 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 if (strlen (st->file_name) > NAME_FIELD_SIZE-1)
524 {
525 WARN ((0, 0, _("%s: file name is too long (max %d); not dumped"),
526 quotearg_colon (st->file_name),
527 NAME_FIELD_SIZE - 1));
528 return NULL;
529 }
530 break;
531
532 case USTAR_FORMAT:
533 case STAR_FORMAT:
534 return write_ustar_long_name (st->file_name);
535
536 case OLDGNU_FORMAT:
537 case GNU_FORMAT:
538 write_gnu_long_link (st, st->file_name, GNUTYPE_LONGNAME);
539 break;
540
541 default:
542 abort(); /*FIXME*/
543 }
544 return write_short_name (st);
545 }
546
547 static union block *
548 write_extended (struct tar_stat_info *st, union block *old_header)
549 {
550 union block *header, hp;
551 size_t size;
552 char *p;
553
554 if (extended_header.buffer || extended_header.stk == NULL)
555 return old_header;
556
557 xheader_finish (&extended_header);
558 memcpy (hp.buffer, old_header, sizeof (hp));
559 p = xheader_xhdr_name (st);
560 xheader_write (XHDTYPE, p, &extended_header);
561 free (p);
562 header = find_next_block ();
563 memcpy (header, &hp.buffer, sizeof (hp.buffer));
564 return header;
565 }
566
567 static union block *
568 write_header_name (struct tar_stat_info *st)
569 {
570 if (archive_format == POSIX_FORMAT && !string_ascii_p (st->file_name))
571 {
572 xheader_store ("path", st, NULL);
573 return write_short_name (st);
574 }
575 else if (NAME_FIELD_SIZE < strlen (st->file_name))
576 return write_long_name (st);
577 else
578 return write_short_name (st);
579 }
580
581 \f
582 /* Header handling. */
583
584 /* Make a header block for the file whose stat info is st,
585 and return its address. */
586
587 union block *
588 start_header (struct tar_stat_info *st)
589 {
590 union block *header;
591
592 header = write_header_name (st);
593 if (!header)
594 return NULL;
595
596 /* Override some stat fields, if requested to do so. */
597
598 if (owner_option != (uid_t) -1)
599 st->stat.st_uid = owner_option;
600 if (group_option != (gid_t) -1)
601 st->stat.st_gid = group_option;
602 if (mode_option)
603 st->stat.st_mode = ((st->stat.st_mode & ~MODE_ALL)
604 | mode_adjust (st->stat.st_mode, mode_option));
605
606 /* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a)
607 for a few tars and came up with the following interoperability
608 matrix:
609
610 WRITER
611 1 2 3 4 5 6 7 8 9 READER
612 . . . . . . . . . 1 = SunOS 4.2 tar
613 # . . # # . . # # 2 = NEC SVR4.0.2 tar
614 . . . # # . . # . 3 = Solaris 2.1 tar
615 . . . . . . . . . 4 = GNU tar 1.11.1
616 . . . . . . . . . 5 = HP-UX 8.07 tar
617 . . . . . . . . . 6 = Ultrix 4.1
618 . . . . . . . . . 7 = AIX 3.2
619 . . . . . . . . . 8 = Hitachi HI-UX 1.03
620 . . . . . . . . . 9 = Omron UNIOS-B 4.3BSD 1.60Beta
621
622 . = works
623 # = ``impossible file type''
624
625 The following mask for old archive removes the `#'s in column 4
626 above, thus making GNU tar both a universal donor and a universal
627 acceptor for Paul's test. */
628
629 if (archive_format == V7_FORMAT || archive_format == USTAR_FORMAT)
630 MODE_TO_CHARS (st->stat.st_mode & MODE_ALL, header->header.mode);
631 else
632 MODE_TO_CHARS (st->stat.st_mode, header->header.mode);
633
634 if (st->stat.st_uid > MAXOCTAL7 && archive_format == POSIX_FORMAT)
635 xheader_store ("uid", st, NULL);
636 else
637 UID_TO_CHARS (st->stat.st_uid, header->header.uid);
638
639 if (st->stat.st_gid > MAXOCTAL7 && archive_format == POSIX_FORMAT)
640 xheader_store ("gid", st, NULL);
641 else
642 GID_TO_CHARS (st->stat.st_gid, header->header.gid);
643
644 if (st->stat.st_size > MAXOCTAL11 && archive_format == POSIX_FORMAT)
645 xheader_store ("size", st, NULL);
646 else
647 OFF_TO_CHARS (st->stat.st_size, header->header.size);
648
649 TIME_TO_CHARS (st->stat.st_mtime, header->header.mtime);
650
651 /* FIXME */
652 if (S_ISCHR (st->stat.st_mode)
653 || S_ISBLK (st->stat.st_mode))
654 {
655 st->devmajor = major (st->stat.st_rdev);
656 st->devminor = minor (st->stat.st_rdev);
657
658 if (st->devmajor > MAXOCTAL7 && archive_format == POSIX_FORMAT)
659 xheader_store ("devmajor", st, NULL);
660 else
661 MAJOR_TO_CHARS (st->devmajor, header->header.devmajor);
662
663 if (st->devminor > MAXOCTAL7 && archive_format == POSIX_FORMAT)
664 xheader_store ("devminor", st, NULL);
665 else
666 MAJOR_TO_CHARS (st->devminor, header->header.devminor);
667 }
668 else
669 {
670 MAJOR_TO_CHARS (0, header->header.devmajor);
671 MINOR_TO_CHARS (0, header->header.devminor);
672 }
673
674 if (archive_format == POSIX_FORMAT)
675 {
676 xheader_store ("atime", st, NULL);
677 xheader_store ("ctime", st, NULL);
678 }
679 else if (incremental_option)
680 if (archive_format == OLDGNU_FORMAT || archive_format == GNU_FORMAT)
681 {
682 TIME_TO_CHARS (st->stat.st_atime, header->oldgnu_header.atime);
683 TIME_TO_CHARS (st->stat.st_ctime, header->oldgnu_header.ctime);
684 }
685
686 header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
687
688 switch (archive_format)
689 {
690 case V7_FORMAT:
691 break;
692
693 case OLDGNU_FORMAT:
694 case GNU_FORMAT: /*FIXME?*/
695 /* Overwrite header->header.magic and header.version in one blow. */
696 strcpy (header->header.magic, OLDGNU_MAGIC);
697 break;
698
699 case POSIX_FORMAT:
700 case USTAR_FORMAT:
701 strncpy (header->header.magic, TMAGIC, TMAGLEN);
702 strncpy (header->header.version, TVERSION, TVERSLEN);
703 break;
704
705 default:
706 abort ();
707 }
708
709 if (archive_format == V7_FORMAT || numeric_owner_option)
710 {
711 /* header->header.[ug]name are left as the empty string. */
712 }
713 else
714 {
715 uid_to_uname (st->stat.st_uid, &st->uname);
716 gid_to_gname (st->stat.st_gid, &st->gname);
717
718 if (archive_format == POSIX_FORMAT
719 && (strlen (st->uname) > UNAME_FIELD_SIZE
720 || !string_ascii_p (st->uname)))
721 xheader_store ("uname", st, NULL);
722 else
723 UNAME_TO_CHARS (st->uname, header->header.uname);
724
725 if (archive_format == POSIX_FORMAT
726 && (strlen (st->gname) > GNAME_FIELD_SIZE
727 || !string_ascii_p (st->gname)))
728 xheader_store ("gname", st, NULL);
729 else
730 GNAME_TO_CHARS (st->gname, header->header.gname);
731 }
732
733 return header;
734 }
735
736 void
737 simple_finish_header (union block *header)
738 {
739 size_t i;
740 int sum;
741 char *p;
742
743 memcpy (header->header.chksum, CHKBLANKS, sizeof header->header.chksum);
744
745 sum = 0;
746 p = header->buffer;
747 for (i = sizeof *header; i-- != 0; )
748 /* We can't use unsigned char here because of old compilers, e.g. V7. */
749 sum += 0xFF & *p++;
750
751 /* Fill in the checksum field. It's formatted differently from the
752 other fields: it has [6] digits, a null, then a space -- rather than
753 digits, then a null. We use to_chars.
754 The final space is already there, from
755 checksumming, and to_chars doesn't modify it.
756
757 This is a fast way to do:
758
759 sprintf(header->header.chksum, "%6o", sum); */
760
761 uintmax_to_chars ((uintmax_t) sum, header->header.chksum, 7);
762
763 set_next_block_after (header);
764 }
765
766 /* Finish off a filled-in header block and write it out. We also
767 print the file name and/or full info if verbose is on. If BLOCK_ORDINAL
768 is not negative, is the block ordinal of the first record for this
769 file, which may be a preceding long name or long link record. */
770 void
771 finish_header (struct tar_stat_info *st,
772 union block *header, off_t block_ordinal)
773 {
774 size_t i;
775 int sum;
776 char *p;
777
778 /* Note: It is important to do this before the call to write_extended(),
779 so that the actual ustar header is printed */
780 if (verbose_option
781 && header->header.typeflag != GNUTYPE_LONGLINK
782 && header->header.typeflag != GNUTYPE_LONGNAME
783 && header->header.typeflag != XHDTYPE
784 && header->header.typeflag != XGLTYPE)
785 {
786 /* These globals are parameters to print_header, sigh. */
787
788 current_header = header;
789 current_format = archive_format;
790 print_header (st, block_ordinal);
791 }
792
793 header = write_extended (st, header);
794 simple_finish_header (header);
795 }
796 \f
797
798 void
799 pad_archive (off_t size_left)
800 {
801 union block *blk;
802 while (size_left > 0)
803 {
804 save_sizeleft = size_left;
805 blk = find_next_block ();
806 memset (blk->buffer, 0, BLOCKSIZE);
807 set_next_block_after (blk);
808 size_left -= BLOCKSIZE;
809 }
810 }
811
812 static enum dump_status
813 dump_regular_file (int fd, struct tar_stat_info *stat)
814 {
815 off_t size_left = stat->stat.st_size;
816 off_t block_ordinal;
817 union block *blk;
818
819 block_ordinal = current_block_ordinal ();
820 blk = start_header (stat);
821 if (!blk)
822 return dump_status_fail;
823
824 /* Mark contiguous files, if we support them. */
825 if (archive_format != V7_FORMAT && S_ISCTG (stat->stat.st_mode))
826 blk->header.typeflag = CONTTYPE;
827
828 finish_header (stat, blk, block_ordinal);
829
830 while (size_left > 0)
831 {
832 size_t bufsize, count;
833
834 if (multi_volume_option)
835 {
836 assign_string (&save_name, stat->file_name);
837 save_sizeleft = size_left;
838 save_totsize = stat->stat.st_size;
839 }
840 blk = find_next_block ();
841
842 bufsize = available_space_after (blk);
843
844 if (size_left < bufsize)
845 {
846 /* Last read -- zero out area beyond. */
847 bufsize = size_left;
848 count = bufsize % BLOCKSIZE;
849 if (count)
850 memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
851 }
852
853 count = (fd < 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
854 if (count < 0)
855 {
856 read_diag_details (stat->orig_file_name,
857 stat->stat.st_size - size_left, bufsize);
858 pad_archive (size_left);
859 return dump_status_short;
860 }
861 size_left -= count;
862
863 set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
864
865 if (count != bufsize)
866 {
867 char buf[UINTMAX_STRSIZE_BOUND];
868 memset (blk->buffer + count, 0, bufsize - count);
869 WARN ((0, 0,
870 ngettext ("%s: File shrank by %s byte; padding with zeros",
871 "%s: File shrank by %s bytes; padding with zeros",
872 size_left),
873 quotearg_colon (stat->orig_file_name),
874 STRINGIFY_BIGINT (size_left, buf)));
875 if (! ignore_failed_read_option)
876 exit_status = TAREXIT_FAILURE;
877 pad_archive (size_left);
878 return dump_status_short;
879 }
880 }
881 return dump_status_ok;
882 }
883
884 void
885 dump_regular_finish (int fd, struct tar_stat_info *st, time_t original_ctime)
886 {
887 if (fd >= 0)
888 {
889 struct stat final_stat;
890 if (fstat (fd, &final_stat) != 0)
891 {
892 stat_diag (st->orig_file_name);
893 }
894 else if (final_stat.st_ctime != original_ctime)
895 {
896 WARN ((0, 0, _("%s: file changed as we read it"),
897 quotearg_colon (st->orig_file_name)));
898 }
899 if (close (fd) != 0)
900 {
901 close_diag (st->orig_file_name);
902 }
903 }
904 if (remove_files_option)
905 {
906 if (unlink (st->orig_file_name) == -1)
907 unlink_error (st->orig_file_name);
908 }
909 }
910
911 void
912 dump_dir0 (char *directory,
913 struct tar_stat_info *stat, int top_level, dev_t parent_device)
914 {
915 dev_t our_device = stat->stat.st_dev;
916
917 if (!is_avoided_name (stat->orig_file_name))
918 {
919 union block *blk = NULL;
920 off_t block_ordinal = current_block_ordinal ();
921 stat->stat.st_size = 0; /* force 0 size on dir */
922
923 blk = start_header (stat);
924 if (!blk)
925 return;
926
927 if (incremental_option)
928 blk->header.typeflag = GNUTYPE_DUMPDIR;
929 else /* if (standard_option) */
930 blk->header.typeflag = DIRTYPE;
931
932 /* If we're gnudumping, we aren't done yet so don't close it. */
933
934 if (!incremental_option)
935 finish_header (stat, blk, block_ordinal);
936 else if (gnu_list_name->dir_contents)
937 {
938 off_t size_left;
939 off_t totsize;
940 size_t bufsize;
941 ssize_t count;
942 const char *buffer, *p_buffer;
943 off_t block_ordinal = current_block_ordinal ();
944
945 buffer = gnu_list_name->dir_contents; /* FOO */
946 totsize = 0;
947 if (buffer)
948 for (p_buffer = buffer; *p_buffer; )
949 {
950 size_t size = strlen (p_buffer) + 1;
951 totsize += size;
952 p_buffer += size;
953 }
954 totsize++;
955 OFF_TO_CHARS (totsize, blk->header.size);
956 finish_header (stat, blk, block_ordinal);
957 p_buffer = buffer;
958 size_left = totsize;
959 while (size_left > 0)
960 {
961 if (multi_volume_option)
962 {
963 assign_string (&save_name, stat->orig_file_name);
964 save_sizeleft = size_left;
965 save_totsize = totsize;
966 }
967 blk = find_next_block ();
968 bufsize = available_space_after (blk);
969 if (size_left < bufsize)
970 {
971 bufsize = size_left;
972 count = bufsize % BLOCKSIZE;
973 if (count)
974 memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
975 }
976 memcpy (blk->buffer, p_buffer, bufsize);
977 size_left -= bufsize;
978 p_buffer += bufsize;
979 set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
980 }
981 if (multi_volume_option)
982 assign_string (&save_name, 0);
983 return;
984 }
985 }
986
987 if (!recursion_option)
988 return;
989
990 if (one_file_system_option
991 && !top_level
992 && parent_device != stat->stat.st_dev)
993 {
994 if (verbose_option)
995 WARN ((0, 0,
996 _("%s: file is on a different filesystem; not dumped"),
997 quotearg_colon (stat->orig_file_name)));
998 return;
999 }
1000
1001 {
1002 char const *entry;
1003 size_t entry_len;
1004 char *name_buf = strdup (stat->orig_file_name);
1005 size_t name_size = strlen (name_buf);
1006 size_t name_len = name_size;
1007
1008 /* Now output all the files in the directory. */
1009 /* FIXME: Should speed this up by cd-ing into the dir. */
1010
1011 for (entry = directory; (entry_len = strlen (entry)) != 0;
1012 entry += entry_len + 1)
1013 {
1014 if (name_size < name_len + entry_len)
1015 {
1016 name_size = name_len + entry_len;
1017 name_buf = xrealloc (name_buf, name_size + 1);
1018 }
1019 strcpy (name_buf + name_len, entry);
1020 if (!excluded_name (name_buf))
1021 dump_file (name_buf, 0, our_device);
1022 }
1023
1024 free (name_buf);
1025 }
1026 }
1027
1028 /* Ensure exactly one trailing slash. */
1029 static void
1030 ensure_slash (char **pstr)
1031 {
1032 size_t len = strlen (*pstr);
1033 while (len >= 1 && ISSLASH ((*pstr)[len - 1]))
1034 len--;
1035 if (!ISSLASH ((*pstr)[len]))
1036 *pstr = xrealloc (*pstr, len + 2);
1037 (*pstr)[len++] = '/';
1038 (*pstr)[len] = '\0';
1039 }
1040
1041 bool
1042 dump_dir (struct tar_stat_info *stat, int top_level, dev_t parent_device)
1043 {
1044 char *directory;
1045
1046 directory = savedir (stat->orig_file_name);
1047 if (!directory)
1048 {
1049 savedir_diag (stat->orig_file_name);
1050 return false;
1051 }
1052
1053 ensure_slash (&stat->orig_file_name);
1054 ensure_slash (&stat->file_name);
1055
1056 dump_dir0 (directory, stat, top_level, parent_device);
1057
1058 free (directory);
1059 return true;
1060 }
1061
1062 \f
1063 /* Main functions of this module. */
1064
1065 void
1066 create_archive (void)
1067 {
1068 char *p;
1069
1070 open_archive (ACCESS_WRITE);
1071 xheader_write_global ();
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 (!S_ISDIR (stat->stat.st_mode)
1313 && stat->stat.st_mtime < newer_mtime_option
1314 && (!after_date_option || stat->stat.st_ctime < newer_ctime_option))
1315 {
1316 if (0 < top_level) /* equivalent to !incremental_option */
1317 WARN ((0, 0, _("%s: file is unchanged; not dumped"),
1318 quotearg_colon (p)));
1319 /* FIXME: recheck this return. */
1320 return;
1321 }
1322
1323 /* See if we are trying to dump the archive. */
1324 if (sys_file_is_archive (stat))
1325 {
1326 WARN ((0, 0, _("%s: file is the archive; not dumped"),
1327 quotearg_colon (p)));
1328 return;
1329 }
1330
1331 if (S_ISDIR (stat->stat.st_mode))
1332 {
1333 dump_dir (stat, top_level, parent_device);
1334 if (atime_preserve_option)
1335 utime (p, &restore_times);
1336 return;
1337 }
1338 else if (is_avoided_name (p))
1339 return;
1340 else
1341 {
1342 /* Check for multiple links. */
1343 if (dump_hard_link (stat))
1344 return;
1345
1346 /* This is not a link to a previously dumped file, so dump it. */
1347
1348 if (S_ISREG (stat->stat.st_mode)
1349 || S_ISCTG (stat->stat.st_mode))
1350 {
1351 int fd;
1352 enum dump_status status;
1353
1354 if (file_dumpable_p (stat))
1355 {
1356 fd = open (stat->orig_file_name,
1357 O_RDONLY | O_BINARY);
1358 if (fd < 0)
1359 {
1360 if (!top_level && errno == ENOENT)
1361 WARN ((0, 0, _("%s: File removed before we read it"),
1362 quotearg_colon (stat->orig_file_name)));
1363 else
1364 open_diag (stat->orig_file_name);
1365 return;
1366 }
1367 }
1368 else
1369 fd = -1;
1370
1371 if (sparse_option && sparse_file_p (stat))
1372 {
1373 status = sparse_dump_file (fd, stat);
1374 if (status == dump_status_not_implemented)
1375 status = dump_regular_file (fd, stat);
1376 }
1377 else
1378 status = dump_regular_file (fd, stat);
1379
1380 switch (status)
1381 {
1382 case dump_status_ok:
1383 if (multi_volume_option)
1384 assign_string (&save_name, 0);
1385 dump_regular_finish (fd, stat, original_ctime);
1386 break;
1387
1388 case dump_status_short:
1389 if (multi_volume_option)
1390 assign_string (&save_name, 0);
1391 close (fd);
1392 break;
1393
1394 case dump_status_fail:
1395 close (fd);
1396 return;
1397
1398 case dump_status_not_implemented:
1399 abort ();
1400 }
1401
1402 if (atime_preserve_option)
1403 utime (stat->orig_file_name, &restore_times);
1404 file_count_links (stat);
1405 return;
1406 }
1407 #ifdef HAVE_READLINK
1408 else if (S_ISLNK (stat->stat.st_mode))
1409 {
1410 char *buffer;
1411 int size;
1412 size_t linklen = stat->stat.st_size;
1413 if (linklen != stat->stat.st_size || linklen + 1 == 0)
1414 xalloc_die ();
1415 buffer = (char *) alloca (linklen + 1);
1416 size = readlink (p, buffer, linklen + 1);
1417 if (size < 0)
1418 {
1419 readlink_diag (p);
1420 return;
1421 }
1422 buffer[size] = '\0';
1423 assign_string (&stat->link_name, buffer);
1424 if (size > NAME_FIELD_SIZE)
1425 write_long_link (stat);
1426
1427 block_ordinal = current_block_ordinal ();
1428 stat->stat.st_size = 0; /* force 0 size on symlink */
1429 header = start_header (stat);
1430 if (!header)
1431 return;
1432 tar_copy_str (header->header.linkname, buffer, NAME_FIELD_SIZE);
1433 header->header.typeflag = SYMTYPE;
1434 finish_header (stat, header, block_ordinal);
1435 /* nothing more to do to it */
1436
1437 if (remove_files_option)
1438 {
1439 if (unlink (p) == -1)
1440 unlink_error (p);
1441 }
1442 file_count_links (stat);
1443 return;
1444 }
1445 #endif
1446 else if (S_ISCHR (stat->stat.st_mode))
1447 type = CHRTYPE;
1448 else if (S_ISBLK (stat->stat.st_mode))
1449 type = BLKTYPE;
1450 else if (S_ISFIFO (stat->stat.st_mode))
1451 type = FIFOTYPE;
1452 else if (S_ISSOCK (stat->stat.st_mode))
1453 {
1454 WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
1455 return;
1456 }
1457 else if (S_ISDOOR (stat->stat.st_mode))
1458 {
1459 WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
1460 return;
1461 }
1462 else
1463 {
1464 unknown_file_error (p);
1465 return;
1466 }
1467 }
1468
1469 if (archive_format == V7_FORMAT)
1470 {
1471 unknown_file_error (p);
1472 return;
1473 }
1474
1475 block_ordinal = current_block_ordinal ();
1476 stat->stat.st_size = 0; /* force 0 size */
1477 header = start_header (stat);
1478 if (!header)
1479 return;
1480 header->header.typeflag = type;
1481
1482 if (type != FIFOTYPE)
1483 {
1484 MAJOR_TO_CHARS (major (stat->stat.st_rdev),
1485 header->header.devmajor);
1486 MINOR_TO_CHARS (minor (stat->stat.st_rdev),
1487 header->header.devminor);
1488 }
1489
1490 finish_header (stat, header, block_ordinal);
1491 if (remove_files_option)
1492 {
1493 if (unlink (p) == -1)
1494 unlink_error (p);
1495 }
1496 }
1497
1498 void
1499 dump_file (char *p, int top_level, dev_t parent_device)
1500 {
1501 struct tar_stat_info stat;
1502 tar_stat_init (&stat);
1503 dump_file0 (&stat, p, top_level, parent_device);
1504 tar_stat_destroy (&stat);
1505 }
This page took 0.102805 seconds and 5 git commands to generate.