/[tar]/tar/src/create.c
ViewVC logotype

Contents of /tar/src/create.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.85 - (show annotations) (download)
Mon Apr 26 09:19:07 2004 UTC (20 years ago) by gray
Branch: MAIN
CVS Tags: release_1_14
Changes since 1.84: +13 -13 lines
File MIME type: text/plain
Produce an error, not warning, if the filename is too long.

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
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
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 *st)
341 {
342 return !(dev_null_output
343 || (st->archive_file_size == 0
344 && (st->stat.st_mode & MODE_R) == MODE_R));
345 }
346
347
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 ERROR ((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 ERROR ((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 ERROR ((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 ERROR ((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 char *p;
552
553 if (extended_header.buffer || extended_header.stk == NULL)
554 return old_header;
555
556 xheader_finish (&extended_header);
557 memcpy (hp.buffer, old_header, sizeof (hp));
558 p = xheader_xhdr_name (st);
559 xheader_write (XHDTYPE, p, &extended_header);
560 free (p);
561 header = find_next_block ();
562 memcpy (header, &hp.buffer, sizeof (hp.buffer));
563 return header;
564 }
565
566 static union block *
567 write_header_name (struct tar_stat_info *st)
568 {
569 if (archive_format == POSIX_FORMAT && !string_ascii_p (st->file_name))
570 {
571 xheader_store ("path", st, NULL);
572 return write_short_name (st);
573 }
574 else if (NAME_FIELD_SIZE < strlen (st->file_name))
575 return write_long_name (st);
576 else
577 return write_short_name (st);
578 }
579
580
581 /* Header handling. */
582
583 /* Make a header block for the file whose stat info is st,
584 and return its address. */
585
586 union block *
587 start_header (struct tar_stat_info *st)
588 {
589 union block *header;
590
591 header = write_header_name (st);
592 if (!header)
593 return NULL;
594
595 /* Override some stat fields, if requested to do so. */
596
597 if (owner_option != (uid_t) -1)
598 st->stat.st_uid = owner_option;
599 if (group_option != (gid_t) -1)
600 st->stat.st_gid = group_option;
601 if (mode_option)
602 st->stat.st_mode = ((st->stat.st_mode & ~MODE_ALL)
603 | mode_adjust (st->stat.st_mode, mode_option));
604
605 /* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a)
606 for a few tars and came up with the following interoperability
607 matrix:
608
609 WRITER
610 1 2 3 4 5 6 7 8 9 READER
611 . . . . . . . . . 1 = SunOS 4.2 tar
612 # . . # # . . # # 2 = NEC SVR4.0.2 tar
613 . . . # # . . # . 3 = Solaris 2.1 tar
614 . . . . . . . . . 4 = GNU tar 1.11.1
615 . . . . . . . . . 5 = HP-UX 8.07 tar
616 . . . . . . . . . 6 = Ultrix 4.1
617 . . . . . . . . . 7 = AIX 3.2
618 . . . . . . . . . 8 = Hitachi HI-UX 1.03
619 . . . . . . . . . 9 = Omron UNIOS-B 4.3BSD 1.60Beta
620
621 . = works
622 # = ``impossible file type''
623
624 The following mask for old archive removes the `#'s in column 4
625 above, thus making GNU tar both a universal donor and a universal
626 acceptor for Paul's test. */
627
628 if (archive_format == V7_FORMAT || archive_format == USTAR_FORMAT)
629 MODE_TO_CHARS (st->stat.st_mode & MODE_ALL, header->header.mode);
630 else
631 MODE_TO_CHARS (st->stat.st_mode, header->header.mode);
632
633 if (st->stat.st_uid > MAXOCTAL7 && archive_format == POSIX_FORMAT)
634 xheader_store ("uid", st, NULL);
635 else
636 UID_TO_CHARS (st->stat.st_uid, header->header.uid);
637
638 if (st->stat.st_gid > MAXOCTAL7 && archive_format == POSIX_FORMAT)
639 xheader_store ("gid", st, NULL);
640 else
641 GID_TO_CHARS (st->stat.st_gid, header->header.gid);
642
643 if (st->stat.st_size > MAXOCTAL11 && archive_format == POSIX_FORMAT)
644 xheader_store ("size", st, NULL);
645 else
646 OFF_TO_CHARS (st->stat.st_size, header->header.size);
647
648 TIME_TO_CHARS (st->stat.st_mtime, header->header.mtime);
649
650 /* FIXME */
651 if (S_ISCHR (st->stat.st_mode)
652 || S_ISBLK (st->stat.st_mode))
653 {
654 st->devmajor = major (st->stat.st_rdev);
655 st->devminor = minor (st->stat.st_rdev);
656
657 if (st->devmajor > MAXOCTAL7 && archive_format == POSIX_FORMAT)
658 xheader_store ("devmajor", st, NULL);
659 else
660 MAJOR_TO_CHARS (st->devmajor, header->header.devmajor);
661
662 if (st->devminor > MAXOCTAL7 && archive_format == POSIX_FORMAT)
663 xheader_store ("devminor", st, NULL);
664 else
665 MAJOR_TO_CHARS (st->devminor, header->header.devminor);
666 }
667 else
668 {
669 MAJOR_TO_CHARS (0, header->header.devmajor);
670 MINOR_TO_CHARS (0, header->header.devminor);
671 }
672
673 if (archive_format == POSIX_FORMAT)
674 {
675 xheader_store ("atime", st, NULL);
676 xheader_store ("ctime", st, NULL);
677 }
678 else if (incremental_option)
679 if (archive_format == OLDGNU_FORMAT || archive_format == GNU_FORMAT)
680 {
681 TIME_TO_CHARS (st->stat.st_atime, header->oldgnu_header.atime);
682 TIME_TO_CHARS (st->stat.st_ctime, header->oldgnu_header.ctime);
683 }
684
685 header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
686
687 switch (archive_format)
688 {
689 case V7_FORMAT:
690 break;
691
692 case OLDGNU_FORMAT:
693 case GNU_FORMAT: /*FIXME?*/
694 /* Overwrite header->header.magic and header.version in one blow. */
695 strcpy (header->header.magic, OLDGNU_MAGIC);
696 break;
697
698 case POSIX_FORMAT:
699 case USTAR_FORMAT:
700 strncpy (header->header.magic, TMAGIC, TMAGLEN);
701 strncpy (header->header.version, TVERSION, TVERSLEN);
702 break;
703
704 default:
705 abort ();
706 }
707
708 if (archive_format == V7_FORMAT || numeric_owner_option)
709 {
710 /* header->header.[ug]name are left as the empty string. */
711 }
712 else
713 {
714 uid_to_uname (st->stat.st_uid, &st->uname);
715 gid_to_gname (st->stat.st_gid, &st->gname);
716
717 if (archive_format == POSIX_FORMAT
718 && (strlen (st->uname) > UNAME_FIELD_SIZE
719 || !string_ascii_p (st->uname)))
720 xheader_store ("uname", st, NULL);
721 else
722 UNAME_TO_CHARS (st->uname, header->header.uname);
723
724 if (archive_format == POSIX_FORMAT
725 && (strlen (st->gname) > GNAME_FIELD_SIZE
726 || !string_ascii_p (st->gname)))
727 xheader_store ("gname", st, NULL);
728 else
729 GNAME_TO_CHARS (st->gname, header->header.gname);
730 }
731
732 return header;
733 }
734
735 void
736 simple_finish_header (union block *header)
737 {
738 size_t i;
739 int sum;
740 char *p;
741
742 memcpy (header->header.chksum, CHKBLANKS, sizeof header->header.chksum);
743
744 sum = 0;
745 p = header->buffer;
746 for (i = sizeof *header; i-- != 0; )
747 /* We can't use unsigned char here because of old compilers, e.g. V7. */
748 sum += 0xFF & *p++;
749
750 /* Fill in the checksum field. It's formatted differently from the
751 other fields: it has [6] digits, a null, then a space -- rather than
752 digits, then a null. We use to_chars.
753 The final space is already there, from
754 checksumming, and to_chars doesn't modify it.
755
756 This is a fast way to do:
757
758 sprintf(header->header.chksum, "%6o", sum); */
759
760 uintmax_to_chars ((uintmax_t) sum, header->header.chksum, 7);
761
762 set_next_block_after (header);
763 }
764
765 /* Finish off a filled-in header block and write it out. We also
766 print the file name and/or full info if verbose is on. If BLOCK_ORDINAL
767 is not negative, is the block ordinal of the first record for this
768 file, which may be a preceding long name or long link record. */
769 void
770 finish_header (struct tar_stat_info *st,
771 union block *header, off_t block_ordinal)
772 {
773 /* Note: It is important to do this before the call to write_extended(),
774 so that the actual ustar header is printed */
775 if (verbose_option
776 && header->header.typeflag != GNUTYPE_LONGLINK
777 && header->header.typeflag != GNUTYPE_LONGNAME
778 && header->header.typeflag != XHDTYPE
779 && header->header.typeflag != XGLTYPE)
780 {
781 /* These globals are parameters to print_header, sigh. */
782
783 current_header = header;
784 current_format = archive_format;
785 print_header (st, block_ordinal);
786 }
787
788 header = write_extended (st, header);
789 simple_finish_header (header);
790 }
791
792
793 void
794 pad_archive (off_t size_left)
795 {
796 union block *blk;
797 while (size_left > 0)
798 {
799 save_sizeleft = size_left;
800 blk = find_next_block ();
801 memset (blk->buffer, 0, BLOCKSIZE);
802 set_next_block_after (blk);
803 size_left -= BLOCKSIZE;
804 }
805 }
806
807 static enum dump_status
808 dump_regular_file (int fd, struct tar_stat_info *st)
809 {
810 off_t size_left = st->stat.st_size;
811 off_t block_ordinal;
812 union block *blk;
813
814 block_ordinal = current_block_ordinal ();
815 blk = start_header (st);
816 if (!blk)
817 return dump_status_fail;
818
819 /* Mark contiguous files, if we support them. */
820 if (archive_format != V7_FORMAT && S_ISCTG (st->stat.st_mode))
821 blk->header.typeflag = CONTTYPE;
822
823 finish_header (st, blk, block_ordinal);
824
825 while (size_left > 0)
826 {
827 size_t bufsize, count;
828
829 if (multi_volume_option)
830 {
831 assign_string (&save_name, st->file_name);
832 save_sizeleft = size_left;
833 save_totsize = st->stat.st_size;
834 }
835 blk = find_next_block ();
836
837 bufsize = available_space_after (blk);
838
839 if (size_left < bufsize)
840 {
841 /* Last read -- zero out area beyond. */
842 bufsize = size_left;
843 count = bufsize % BLOCKSIZE;
844 if (count)
845 memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
846 }
847
848 count = (fd < 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
849 if (count == SAFE_READ_ERROR)
850 {
851 read_diag_details (st->orig_file_name,
852 st->stat.st_size - size_left, bufsize);
853 pad_archive (size_left);
854 return dump_status_short;
855 }
856 size_left -= count;
857
858 set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
859
860 if (count != bufsize)
861 {
862 char buf[UINTMAX_STRSIZE_BOUND];
863 memset (blk->buffer + count, 0, bufsize - count);
864 WARN ((0, 0,
865 ngettext ("%s: File shrank by %s byte; padding with zeros",
866 "%s: File shrank by %s bytes; padding with zeros",
867 size_left),
868 quotearg_colon (st->orig_file_name),
869 STRINGIFY_BIGINT (size_left, buf)));
870 if (! ignore_failed_read_option)
871 exit_status = TAREXIT_FAILURE;
872 pad_archive (size_left);
873 return dump_status_short;
874 }
875 }
876 return dump_status_ok;
877 }
878
879 static void
880 dump_regular_finish (int fd, struct tar_stat_info *st, time_t original_ctime)
881 {
882 if (fd >= 0)
883 {
884 struct stat final_stat;
885 if (fstat (fd, &final_stat) != 0)
886 {
887 stat_diag (st->orig_file_name);
888 }
889 else if (final_stat.st_ctime != original_ctime)
890 {
891 WARN ((0, 0, _("%s: file changed as we read it"),
892 quotearg_colon (st->orig_file_name)));
893 }
894 if (close (fd) != 0)
895 {
896 close_diag (st->orig_file_name);
897 }
898 }
899 if (remove_files_option)
900 {
901 if (unlink (st->orig_file_name) == -1)
902 unlink_error (st->orig_file_name);
903 }
904 }
905
906 static void
907 dump_dir0 (char *directory,
908 struct tar_stat_info *st, int top_level, dev_t parent_device)
909 {
910 dev_t our_device = st->stat.st_dev;
911
912 if (!is_avoided_name (st->orig_file_name))
913 {
914 union block *blk = NULL;
915 off_t block_ordinal = current_block_ordinal ();
916 st->stat.st_size = 0; /* force 0 size on dir */
917
918 blk = start_header (st);
919 if (!blk)
920 return;
921
922 if (incremental_option)
923 blk->header.typeflag = GNUTYPE_DUMPDIR;
924 else /* if (standard_option) */
925 blk->header.typeflag = DIRTYPE;
926
927 /* If we're gnudumping, we aren't done yet so don't close it. */
928
929 if (!incremental_option)
930 finish_header (st, blk, block_ordinal);
931 else if (gnu_list_name->dir_contents)
932 {
933 off_t size_left;
934 off_t totsize;
935 size_t bufsize;
936 ssize_t count;
937 const char *buffer, *p_buffer;
938
939 block_ordinal = current_block_ordinal ();
940 buffer = gnu_list_name->dir_contents; /* FOO */
941 totsize = 0;
942 if (buffer)
943 for (p_buffer = buffer; *p_buffer; )
944 {
945 size_t size = strlen (p_buffer) + 1;
946 totsize += size;
947 p_buffer += size;
948 }
949 totsize++;
950 OFF_TO_CHARS (totsize, blk->header.size);
951 finish_header (st, blk, block_ordinal);
952 p_buffer = buffer;
953 size_left = totsize;
954 while (size_left > 0)
955 {
956 if (multi_volume_option)
957 {
958 assign_string (&save_name, st->orig_file_name);
959 save_sizeleft = size_left;
960 save_totsize = totsize;
961 }
962 blk = find_next_block ();
963 bufsize = available_space_after (blk);
964 if (size_left < bufsize)
965 {
966 bufsize = size_left;
967 count = bufsize % BLOCKSIZE;
968 if (count)
969 memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
970 }
971 memcpy (blk->buffer, p_buffer, bufsize);
972 size_left -= bufsize;
973 p_buffer += bufsize;
974 set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
975 }
976 if (multi_volume_option)
977 assign_string (&save_name, 0);
978 return;
979 }
980 }
981
982 if (!recursion_option)
983 return;
984
985 if (one_file_system_option
986 && !top_level
987 && parent_device != st->stat.st_dev)
988 {
989 if (verbose_option)
990 WARN ((0, 0,
991 _("%s: file is on a different filesystem; not dumped"),
992 quotearg_colon (st->orig_file_name)));
993 return;
994 }
995
996 {
997 char const *entry;
998 size_t entry_len;
999 char *name_buf = strdup (st->orig_file_name);
1000 size_t name_size = strlen (name_buf);
1001 size_t name_len = name_size;
1002
1003 /* Now output all the files in the directory. */
1004 /* FIXME: Should speed this up by cd-ing into the dir. */
1005
1006 for (entry = directory; (entry_len = strlen (entry)) != 0;
1007 entry += entry_len + 1)
1008 {
1009 if (name_size < name_len + entry_len)
1010 {
1011 name_size = name_len + entry_len;
1012 name_buf = xrealloc (name_buf, name_size + 1);
1013 }
1014 strcpy (name_buf + name_len, entry);
1015 if (!excluded_name (name_buf))
1016 dump_file (name_buf, 0, our_device);
1017 }
1018
1019 free (name_buf);
1020 }
1021 }
1022
1023 /* Ensure exactly one trailing slash. */
1024 static void
1025 ensure_slash (char **pstr)
1026 {
1027 size_t len = strlen (*pstr);
1028 while (len >= 1 && ISSLASH ((*pstr)[len - 1]))
1029 len--;
1030 if (!ISSLASH ((*pstr)[len]))
1031 *pstr = xrealloc (*pstr, len + 2);
1032 (*pstr)[len++] = '/';
1033 (*pstr)[len] = '\0';
1034 }
1035
1036 static bool
1037 dump_dir (struct tar_stat_info *st, int top_level, dev_t parent_device)
1038 {
1039 char *directory;
1040
1041 directory = savedir (st->orig_file_name);
1042 if (!directory)
1043 {
1044 savedir_diag (st->orig_file_name);
1045 return false;
1046 }
1047
1048 ensure_slash (&st->orig_file_name);
1049 ensure_slash (&st->file_name);
1050
1051 dump_dir0 (directory, st, top_level, parent_device);
1052
1053 free (directory);
1054 return true;
1055 }
1056
1057
1058 /* Main functions of this module. */
1059
1060 void
1061 create_archive (void)
1062 {
1063 char *p;
1064
1065 open_archive (ACCESS_WRITE);
1066 xheader_write_global ();
1067
1068 if (incremental_option)
1069 {
1070 size_t buffer_size = 1000;
1071 char *buffer = xmalloc (buffer_size);
1072 const char *q;
1073
1074 collect_and_sort_names ();
1075
1076 while ((p = name_from_list ()) != NULL)
1077 if (!excluded_name (p))
1078 dump_file (p, -1, (dev_t) 0);
1079
1080 blank_name_list ();
1081 while ((p = name_from_list ()) != NULL)
1082 if (!excluded_name (p))
1083 {
1084 size_t plen = strlen (p);
1085 if (buffer_size <= plen)
1086 {
1087 while ((buffer_size *= 2) <= plen)
1088 continue;
1089 buffer = xrealloc (buffer, buffer_size);
1090 }
1091 memcpy (buffer, p, plen);
1092 if (! ISSLASH (buffer[plen - 1]))
1093 buffer[plen++] = '/';
1094 q = gnu_list_name->dir_contents;
1095 if (q)
1096 while (*q)
1097 {
1098 size_t qlen = strlen (q);
1099 if (*q == 'Y')
1100 {
1101 if (buffer_size < plen + qlen)
1102 {
1103 while ((buffer_size *=2 ) < plen + qlen)
1104 continue;
1105 buffer = xrealloc (buffer, buffer_size);
1106 }
1107 strcpy (buffer + plen, q + 1);
1108 dump_file (buffer, -1, (dev_t) 0);
1109 }
1110 q += qlen + 1;
1111 }
1112 }
1113 free (buffer);
1114 }
1115 else
1116 {
1117 while ((p = name_next (1)) != NULL)
1118 if (!excluded_name (p))
1119 dump_file (p, 1, (dev_t) 0);
1120 }
1121
1122 write_eot ();
1123 close_archive ();
1124
1125 if (listed_incremental_option)
1126 write_directory_file ();
1127 }
1128
1129
1130 /* Calculate the hash of a link. */
1131 static unsigned
1132 hash_link (void const *entry, unsigned n_buckets)
1133 {
1134 struct link const *l = entry;
1135 uintmax_t num = l->dev ^ l->ino;
1136 return num % n_buckets;
1137 }
1138
1139 /* Compare two links for equality. */
1140 static bool
1141 compare_links (void const *entry1, void const *entry2)
1142 {
1143 struct link const *link1 = entry1;
1144 struct link const *link2 = entry2;
1145 return ((link1->dev ^ link2->dev) | (link1->ino ^ link2->ino)) == 0;
1146 }
1147
1148 static void
1149 unknown_file_error (char *p)
1150 {
1151 WARN ((0, 0, _("%s: Unknown file type; file ignored"),
1152 quotearg_colon (p)));
1153 if (!ignore_failed_read_option)
1154 exit_status = TAREXIT_FAILURE;
1155 }
1156
1157
1158 /* Handling of hard links */
1159
1160 /* Table of all non-directories that we've written so far. Any time
1161 we see another, we check the table and avoid dumping the data
1162 again if we've done it once already. */
1163 static Hash_table *link_table;
1164
1165 /* Try to dump stat as a hard link to another file in the archive. If
1166 succeeded returns true */
1167 static bool
1168 dump_hard_link (struct tar_stat_info *st)
1169 {
1170 if (link_table && st->stat.st_nlink > 1)
1171 {
1172 struct link lp;
1173 struct link *duplicate;
1174 off_t block_ordinal;
1175 union block *blk;
1176
1177 lp.ino = st->stat.st_ino;
1178 lp.dev = st->stat.st_dev;
1179
1180 if ((duplicate = hash_lookup (link_table, &lp)))
1181 {
1182 /* We found a link. */
1183 char const *link_name = safer_name_suffix (duplicate->name, true);
1184
1185 duplicate->nlink--;
1186
1187 block_ordinal = current_block_ordinal ();
1188 assign_string (&st->link_name, link_name);
1189 if (NAME_FIELD_SIZE < strlen (link_name))
1190 write_long_link (st);
1191
1192 st->stat.st_size = 0;
1193 blk = start_header (st);
1194 if (!blk)
1195 return true;
1196 tar_copy_str (blk->header.linkname, link_name, NAME_FIELD_SIZE);
1197
1198 blk->header.typeflag = LNKTYPE;
1199 finish_header (st, blk, block_ordinal);
1200
1201 if (remove_files_option && unlink (st->orig_file_name) != 0)
1202 unlink_error (st->orig_file_name);
1203
1204 return true;
1205 }
1206 }
1207 return false;
1208 }
1209
1210 static void
1211 file_count_links (struct tar_stat_info *st)
1212 {
1213 if (st->stat.st_nlink > 1)
1214 {
1215 struct link *duplicate;
1216 struct link *lp = xmalloc (offsetof (struct link, name)
1217 + strlen (st->orig_file_name) + 1);
1218 lp->ino = st->stat.st_ino;
1219 lp->dev = st->stat.st_dev;
1220 lp->nlink = st->stat.st_nlink;
1221 strcpy (lp->name, st->orig_file_name);
1222
1223 if (! ((link_table
1224 || (link_table = hash_initialize (0, 0, hash_link,
1225 compare_links, 0)))
1226 && (duplicate = hash_insert (link_table, lp))))
1227 xalloc_die ();
1228
1229 if (duplicate != lp)
1230 abort ();
1231 lp->nlink--;
1232 }
1233 }
1234
1235 /* For each dumped file, check if all its links were dumped. Emit
1236 warnings if it is not so. */
1237 void
1238 check_links (void)
1239 {
1240 struct link *lp;
1241
1242 if (!link_table)
1243 return;
1244
1245 for (lp = hash_get_first (link_table); lp;
1246 lp = hash_get_next (link_table, lp))
1247 {
1248 if (lp->nlink)
1249 {
1250 WARN ((0, 0, _("Missing links to '%s'.\n"), lp->name));
1251 }
1252 }
1253 }
1254
1255
1256 /* Dump a single file, recursing on directories. P is the file name
1257 to dump. TOP_LEVEL tells whether this is a top-level call; zero
1258 means no, positive means yes, and negative means the top level
1259 of an incremental dump. PARENT_DEVICE is the device of P's
1260 parent directory; it is examined only if TOP_LEVEL is zero. */
1261
1262 /* FIXME: One should make sure that for *every* path leading to setting
1263 exit_status to failure, a clear diagnostic has been issued. */
1264
1265 static void
1266 dump_file0 (struct tar_stat_info *st, char *p,
1267 int top_level, dev_t parent_device)
1268 {
1269 union block *header;
1270 char type;
1271 time_t original_ctime;
1272 struct utimbuf restore_times;
1273 off_t block_ordinal = -1;
1274
1275 if (interactive_option && !confirm ("add", p))
1276 return;
1277
1278 assign_string (&st->orig_file_name, p);
1279 assign_string (&st->file_name, safer_name_suffix (p, false));
1280
1281 if (deref_stat (dereference_option, p, &st->stat) != 0)
1282 {
1283 stat_diag (p);
1284 return;
1285 }
1286 st->archive_file_size = st->stat.st_size;
1287 sys_stat_nanoseconds (st);
1288 original_ctime = st->stat.st_ctime;
1289 restore_times.actime = st->stat.st_atime;
1290 restore_times.modtime = st->stat.st_mtime;
1291
1292 #ifdef S_ISHIDDEN
1293 if (S_ISHIDDEN (st->stat.st_mode))
1294 {
1295 char *new = (char *) alloca (strlen (p) + 2);
1296 if (new)
1297 {
1298 strcpy (new, p);
1299 strcat (new, "@");
1300 p = new;
1301 }
1302 }
1303 #endif
1304
1305 /* See if we want only new files, and check if this one is too old to
1306 put in the archive. */
1307
1308 if (!S_ISDIR (st->stat.st_mode)
1309 && OLDER_STAT_TIME (st->stat, m)
1310 && (!after_date_option || OLDER_STAT_TIME (st->stat, c)))
1311 {
1312 if (0 < top_level) /* equivalent to !incremental_option */
1313 WARN ((0, 0, _("%s: file is unchanged; not dumped"),
1314 quotearg_colon (p)));
1315 /* FIXME: recheck this return. */
1316 return;
1317 }
1318
1319 /* See if we are trying to dump the archive. */
1320 if (sys_file_is_archive (st))
1321 {
1322 WARN ((0, 0, _("%s: file is the archive; not dumped"),
1323 quotearg_colon (p)));
1324 return;
1325 }
1326
1327 if (S_ISDIR (st->stat.st_mode))
1328 {
1329 dump_dir (st, top_level, parent_device);
1330 if (atime_preserve_option)
1331 utime (p, &restore_times);
1332 return;
1333 }
1334 else if (is_avoided_name (p))
1335 return;
1336 else
1337 {
1338 /* Check for multiple links. */
1339 if (dump_hard_link (st))
1340 return;
1341
1342 /* This is not a link to a previously dumped file, so dump it. */
1343
1344 if (S_ISREG (st->stat.st_mode)
1345 || S_ISCTG (st->stat.st_mode))
1346 {
1347 int fd;
1348 enum dump_status status;
1349
1350 if (file_dumpable_p (st))
1351 {
1352 fd = open (st->orig_file_name,
1353 O_RDONLY | O_BINARY);
1354 if (fd < 0)
1355 {
1356 if (!top_level && errno == ENOENT)
1357 WARN ((0, 0, _("%s: File removed before we read it"),
1358 quotearg_colon (st->orig_file_name)));
1359 else
1360 open_diag (st->orig_file_name);
1361 return;
1362 }
1363 }
1364 else
1365 fd = -1;
1366
1367 if (sparse_option && sparse_file_p (st))
1368 {
1369 status = sparse_dump_file (fd, st);
1370 if (status == dump_status_not_implemented)
1371 status = dump_regular_file (fd, st);
1372 }
1373 else
1374 status = dump_regular_file (fd, st);
1375
1376 switch (status)
1377 {
1378 case dump_status_ok:
1379 if (multi_volume_option)
1380 assign_string (&save_name, 0);
1381 dump_regular_finish (fd, st, original_ctime);
1382 break;
1383
1384 case dump_status_short:
1385 if (multi_volume_option)
1386 assign_string (&save_name, 0);
1387 close (fd);
1388 break;
1389
1390 case dump_status_fail:
1391 close (fd);
1392 return;
1393
1394 case dump_status_not_implemented:
1395 abort ();
1396 }
1397
1398 if (atime_preserve_option)
1399 utime (st->orig_file_name, &restore_times);
1400 file_count_links (st);
1401 return;
1402 }
1403 #ifdef HAVE_READLINK
1404 else if (S_ISLNK (st->stat.st_mode))
1405 {
1406 char *buffer;
1407 int size;
1408 size_t linklen = st->stat.st_size;
1409 if (linklen != st->stat.st_size || linklen + 1 == 0)
1410 xalloc_die ();
1411 buffer = (char *) alloca (linklen + 1);
1412 size = readlink (p, buffer, linklen + 1);
1413 if (size < 0)
1414 {
1415 readlink_diag (p);
1416 return;
1417 }
1418 buffer[size] = '\0';
1419 assign_string (&st->link_name, buffer);
1420 if (size > NAME_FIELD_SIZE)
1421 write_long_link (st);
1422
1423 block_ordinal = current_block_ordinal ();
1424 st->stat.st_size = 0; /* force 0 size on symlink */
1425 header = start_header (st);
1426 if (!header)
1427 return;
1428 tar_copy_str (header->header.linkname, buffer, NAME_FIELD_SIZE);
1429 header->header.typeflag = SYMTYPE;
1430 finish_header (st, header, block_ordinal);
1431 /* nothing more to do to it */
1432
1433 if (remove_files_option)
1434 {
1435 if (unlink (p) == -1)
1436 unlink_error (p);
1437 }
1438 file_count_links (st);
1439 return;
1440 }
1441 #endif
1442 else if (S_ISCHR (st->stat.st_mode))
1443 type = CHRTYPE;
1444 else if (S_ISBLK (st->stat.st_mode))
1445 type = BLKTYPE;
1446 else if (S_ISFIFO (st->stat.st_mode))
1447 type = FIFOTYPE;
1448 else if (S_ISSOCK (st->stat.st_mode))
1449 {
1450 WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
1451 return;
1452 }
1453 else if (S_ISDOOR (st->stat.st_mode))
1454 {
1455 WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
1456 return;
1457 }
1458 else
1459 {
1460 unknown_file_error (p);
1461 return;
1462 }
1463 }
1464
1465 if (archive_format == V7_FORMAT)
1466 {
1467 unknown_file_error (p);
1468 return;
1469 }
1470
1471 block_ordinal = current_block_ordinal ();
1472 st->stat.st_size = 0; /* force 0 size */
1473 header = start_header (st);
1474 if (!header)
1475 return;
1476 header->header.typeflag = type;
1477
1478 if (type != FIFOTYPE)
1479 {
1480 MAJOR_TO_CHARS (major (st->stat.st_rdev),
1481 header->header.devmajor);
1482 MINOR_TO_CHARS (minor (st->stat.st_rdev),
1483 header->header.devminor);
1484 }
1485
1486 finish_header (st, header, block_ordinal);
1487 if (remove_files_option)
1488 {
1489 if (unlink (p) == -1)
1490 unlink_error (p);
1491 }
1492 }
1493
1494 void
1495 dump_file (char *p, int top_level, dev_t parent_device)
1496 {
1497 struct tar_stat_info st;
1498 tar_stat_init (&st);
1499 dump_file0 (&st, p, top_level, parent_device);
1500 tar_stat_destroy (&st);
1501 }

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26