]> Dogcows Code - chaz/tar/blob - src/list.c
474651c5c1cbb4273ad9c30a85f4fca8723e8e2b
[chaz/tar] / src / list.c
1 /* List a tar archive, with support routines for reading a tar archive.
2 Copyright 1988,92,93,94,96,97,98,1999 Free Software Foundation, Inc.
3 Written by John Gilmore, on 1985-08-26.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any later
8 version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18
19 /* Define to non-zero for forcing old ctime() instead of isotime(). */
20 #undef USE_OLD_CTIME
21
22 #include "system.h"
23 #include <quotearg.h>
24
25 #include <time.h>
26
27 #include "common.h"
28
29 #define max(a, b) ((a) < (b) ? (b) : (a))
30
31 union block *current_header; /* points to current archive header */
32 struct stat current_stat; /* stat struct corresponding */
33 enum archive_format current_format; /* recognized format */
34
35 static uintmax_t from_chars PARAMS ((const char *, size_t, const char *,
36 uintmax_t, uintmax_t));
37
38 /* Table of base 64 digit values indexed by unsigned chars.
39 The value is 64 for unsigned chars that are not base 64 digits. */
40 static char base64_map[1 + (unsigned char) -1];
41
42 static void
43 base64_init (void)
44 {
45 int i;
46 memset (base64_map, 64, sizeof base64_map);
47 for (i = 0; i < 64; i++)
48 base64_map[(int) base_64_digits[i]] = i;
49 }
50
51 /*-----------------------------------.
52 | Main loop for reading an archive. |
53 `-----------------------------------*/
54
55 void
56 read_and (void (*do_something) ())
57 {
58 enum read_header status = HEADER_STILL_UNREAD;
59 enum read_header prev_status;
60
61 base64_init ();
62 name_gather ();
63 open_archive (ACCESS_READ);
64
65 while (1)
66 {
67 prev_status = status;
68 status = read_header ();
69 switch (status)
70 {
71 case HEADER_STILL_UNREAD:
72 abort ();
73
74 case HEADER_SUCCESS:
75
76 /* Valid header. We should decode next field (mode) first.
77 Ensure incoming names are null terminated. */
78
79 /* FIXME: This is a quick kludge before 1.12 goes out. */
80 current_stat.st_mtime
81 = TIME_FROM_CHARS (current_header->header.mtime);
82
83 if (!name_match (current_file_name)
84 || current_stat.st_mtime < newer_mtime_option
85 || excluded_name (current_file_name))
86 {
87 char save_typeflag;
88
89 if (current_header->header.typeflag == GNUTYPE_VOLHDR
90 || current_header->header.typeflag == GNUTYPE_MULTIVOL
91 || current_header->header.typeflag == GNUTYPE_NAMES)
92 {
93 (*do_something) ();
94 continue;
95 }
96 if (show_omitted_dirs_option
97 && current_header->header.typeflag == DIRTYPE)
98 WARN ((0, 0, _("Omitting %s"), current_file_name));
99
100 /* Skip past it in the archive. */
101
102 save_typeflag = current_header->header.typeflag;
103 set_next_block_after (current_header);
104 if (current_header->oldgnu_header.isextended)
105 skip_extended_headers ();
106
107 /* Skip to the next header on the archive. */
108
109 if (save_typeflag != DIRTYPE)
110 skip_file (current_stat.st_size);
111 continue;
112 }
113
114 (*do_something) ();
115 continue;
116
117 case HEADER_ZERO_BLOCK:
118 if (block_number_option)
119 {
120 char buf[UINTMAX_STRSIZE_BOUND];
121 fprintf (stdlis, _("block %s: ** Block of NULs **\n"),
122 STRINGIFY_BIGINT (current_block_ordinal (), buf));
123 }
124
125 set_next_block_after (current_header);
126 status = prev_status;
127 if (ignore_zeros_option)
128 continue;
129 break;
130
131 case HEADER_END_OF_FILE:
132 if (block_number_option)
133 {
134 char buf[UINTMAX_STRSIZE_BOUND];
135 fprintf (stdlis, _("block %s: ** End of File **\n"),
136 STRINGIFY_BIGINT (current_block_ordinal (), buf));
137 }
138 break;
139
140 case HEADER_FAILURE:
141 /* If the previous header was good, tell them that we are
142 skipping bad ones. */
143 set_next_block_after (current_header);
144 switch (prev_status)
145 {
146 case HEADER_STILL_UNREAD:
147 WARN ((0, 0, _("Hmm, this doesn't look like a tar archive")));
148 /* Fall through. */
149
150 case HEADER_ZERO_BLOCK:
151 case HEADER_SUCCESS:
152 WARN ((0, 0, _("Skipping to next file header")));
153 break;
154
155 case HEADER_END_OF_FILE:
156 case HEADER_FAILURE:
157 /* We are in the middle of a cascade of errors. */
158 break;
159 }
160 continue;
161 }
162 break;
163 }
164
165 apply_delayed_set_stat ();
166 close_archive ();
167 names_notfound (); /* print names not found */
168 }
169
170 /*---------------------------------------------.
171 | Print a header block, based on tar options. |
172 `---------------------------------------------*/
173
174 void
175 list_archive (void)
176 {
177 /* Print the header block. */
178
179 if (verbose_option)
180 {
181 if (verbose_option > 1)
182 decode_header (current_header, &current_stat, &current_format, 0);
183 print_header ();
184 }
185
186 if (incremental_option && current_header->header.typeflag == GNUTYPE_DUMPDIR)
187 {
188 off_t size;
189 size_t written, check;
190 union block *data_block;
191
192 set_next_block_after (current_header);
193 if (multi_volume_option)
194 {
195 assign_string (&save_name, current_file_name);
196 save_totsize = current_stat.st_size;
197 }
198 for (size = current_stat.st_size; size > 0; size -= written)
199 {
200 if (multi_volume_option)
201 save_sizeleft = size;
202 data_block = find_next_block ();
203 if (!data_block)
204 {
205 ERROR ((0, 0, _("EOF in archive file")));
206 break; /* FIXME: What happens, then? */
207 }
208 written = available_space_after (data_block);
209 if (written > size)
210 written = size;
211 errno = 0; /* FIXME: errno should be read-only */
212 check = fwrite (data_block->buffer, sizeof (char), written, stdlis);
213 set_next_block_after ((union block *)
214 (data_block->buffer + written - 1));
215 if (check != written)
216 {
217 ERROR ((0, errno, _("Only wrote %lu of %lu bytes to file %s"),
218 (unsigned long) check,
219 (unsigned long) written, current_file_name));
220 skip_file (size - written);
221 break;
222 }
223 }
224 if (multi_volume_option)
225 assign_string (&save_name, NULL);
226 fputc ('\n', stdlis);
227 fflush (stdlis);
228 return;
229
230 }
231
232 /* Skip past the header in the archive, and past any extended headers. */
233
234 set_next_block_after (current_header);
235 if (current_header->oldgnu_header.isextended)
236 skip_extended_headers ();
237
238 if (multi_volume_option)
239 assign_string (&save_name, current_file_name);
240
241 /* Skip to the next header on the archive. */
242
243 skip_file (current_stat.st_size);
244
245 if (multi_volume_option)
246 assign_string (&save_name, NULL);
247 }
248
249 /*-----------------------------------------------------------------------.
250 | Read a block that's supposed to be a header block. Return its address |
251 | in "current_header", and if it is good, the file's size in |
252 | current_stat.st_size. |
253 | |
254 | Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a |
255 | block full of zeros (EOF marker). |
256 | |
257 | You must always set_next_block_after(current_header) to skip past the |
258 | header which this routine reads. |
259 `-----------------------------------------------------------------------*/
260
261 /* The standard BSD tar sources create the checksum by adding up the
262 bytes in the header as type char. I think the type char was unsigned
263 on the PDP-11, but it's signed on the Next and Sun. It looks like the
264 sources to BSD tar were never changed to compute the checksum
265 currectly, so both the Sun and Next add the bytes of the header as
266 signed chars. This doesn't cause a problem until you get a file with
267 a name containing characters with the high bit set. So read_header
268 computes two checksums -- signed and unsigned. */
269
270 enum read_header
271 read_header (void)
272 {
273 size_t i;
274 int unsigned_sum; /* the POSIX one :-) */
275 int signed_sum; /* the Sun one :-( */
276 int recorded_sum;
277 uintmax_t parsed_sum;
278 char *p;
279 union block *header;
280 char **longp;
281 char *bp;
282 union block *data_block;
283 size_t size, written;
284 static char *next_long_name, *next_long_link;
285
286 while (1)
287 {
288 header = find_next_block ();
289 current_header = header;
290 if (!header)
291 return HEADER_END_OF_FILE;
292
293 unsigned_sum = 0;
294 signed_sum = 0;
295 p = header->buffer;
296 for (i = sizeof (*header); i-- != 0;)
297 {
298 unsigned_sum += (unsigned char) *p;
299 signed_sum += signed_char (*p++);
300 }
301
302 if (unsigned_sum == 0)
303 return HEADER_ZERO_BLOCK;
304
305 /* Adjust checksum to count the "chksum" field as blanks. */
306
307 for (i = sizeof (header->header.chksum); i-- != 0;)
308 {
309 unsigned_sum -= (unsigned char) header->header.chksum[i];
310 signed_sum -= signed_char (header->header.chksum[i]);
311 }
312 unsigned_sum += ' ' * sizeof header->header.chksum;
313 signed_sum += ' ' * sizeof header->header.chksum;
314
315 parsed_sum = from_chars (header->header.chksum,
316 sizeof header->header.chksum,
317 (char *) 0, (uintmax_t) 0,
318 (uintmax_t) TYPE_MAXIMUM (int));
319 if (parsed_sum == (uintmax_t) -1)
320 return HEADER_FAILURE;
321
322 recorded_sum = parsed_sum;
323
324 if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
325 return HEADER_FAILURE;
326
327 /* Good block. Decode file size and return. */
328
329 if (header->header.typeflag == LNKTYPE)
330 current_stat.st_size = 0; /* links 0 size on tape */
331 else
332 current_stat.st_size = OFF_FROM_CHARS (header->header.size);
333
334 if (header->header.typeflag == GNUTYPE_LONGNAME
335 || header->header.typeflag == GNUTYPE_LONGLINK)
336 {
337 longp = ((header->header.typeflag == GNUTYPE_LONGNAME)
338 ? &next_long_name
339 : &next_long_link);
340
341 set_next_block_after (header);
342 if (*longp)
343 free (*longp);
344 size = current_stat.st_size;
345 if (size != current_stat.st_size)
346 FATAL_ERROR ((0, 0, _("Memory exhausted")));
347 bp = *longp = (char *) xmalloc (size);
348
349 for (; size > 0; size -= written)
350 {
351 data_block = find_next_block ();
352 if (data_block == NULL)
353 {
354 ERROR ((0, 0, _("Unexpected EOF on archive file")));
355 break;
356 }
357 written = available_space_after (data_block);
358 if (written > size)
359 written = size;
360
361 memcpy (bp, data_block->buffer, written);
362 bp += written;
363 set_next_block_after ((union block *)
364 (data_block->buffer + written - 1));
365 }
366
367 /* Loop! */
368
369 }
370 else
371 {
372 char *name;
373 struct posix_header *h = &current_header->header;
374 char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
375
376 name = next_long_name;
377 if (! name)
378 {
379 /* Accept file names as specified by POSIX.1-1996
380 section 10.1.1. */
381 int posix_header = strcmp (h->magic, TMAGIC) == 0;
382 char *np = namebuf;
383
384 if (posix_header && h->prefix[0])
385 {
386 memcpy (np, h->prefix, sizeof h->prefix);
387 np[sizeof h->prefix] = '\0';
388 np += strlen (np);
389 *np++ = '/';
390 }
391 memcpy (np, h->name, sizeof h->name);
392 np[sizeof h->name] = '\0';
393 name = namebuf;
394 }
395 assign_string (&current_file_name, name);
396 if (next_long_name)
397 {
398 free (next_long_name);
399 next_long_name = 0;
400 }
401
402 name = next_long_link;
403 if (! name)
404 {
405 memcpy (namebuf, h->linkname, sizeof h->linkname);
406 namebuf[sizeof h->linkname] = '\0';
407 name = namebuf;
408 }
409 assign_string (&current_link_name, name);
410 if (next_long_link)
411 {
412 free (next_long_link);
413 next_long_link = 0;
414 }
415
416 return HEADER_SUCCESS;
417 }
418 }
419 }
420
421 /*-------------------------------------------------------------------------.
422 | Decode things from a file HEADER block into STAT_INFO, also setting |
423 | *FORMAT_POINTER depending on the header block format. If DO_USER_GROUP, |
424 | decode the user/group information (this is useful for extraction, but |
425 | waste time when merely listing). |
426 | |
427 | read_header() has already decoded the checksum and length, so we don't. |
428 | |
429 | This routine should *not* be called twice for the same block, since the |
430 | two calls might use different DO_USER_GROUP values and thus might end up |
431 | with different uid/gid for the two calls. If anybody wants the uid/gid |
432 | they should decode it first, and other callers should decode it without |
433 | uid/gid before calling a routine, e.g. print_header, that assumes |
434 | decoded data. |
435 `-------------------------------------------------------------------------*/
436
437 void
438 decode_header (union block *header, struct stat *stat_info,
439 enum archive_format *format_pointer, int do_user_group)
440 {
441 enum archive_format format;
442
443 if (strcmp (header->header.magic, TMAGIC) == 0)
444 format = POSIX_FORMAT;
445 else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
446 format = OLDGNU_FORMAT;
447 else
448 format = V7_FORMAT;
449 *format_pointer = format;
450
451 stat_info->st_mode = MODE_FROM_CHARS (header->header.mode);
452 stat_info->st_mtime = TIME_FROM_CHARS (header->header.mtime);
453
454 if (format == OLDGNU_FORMAT && incremental_option)
455 {
456 stat_info->st_atime = TIME_FROM_CHARS (header->oldgnu_header.atime);
457 stat_info->st_ctime = TIME_FROM_CHARS (header->oldgnu_header.ctime);
458 }
459
460 if (format == V7_FORMAT)
461 {
462 stat_info->st_uid = UID_FROM_CHARS (header->header.uid);
463 stat_info->st_gid = GID_FROM_CHARS (header->header.gid);
464 stat_info->st_rdev = 0;
465 }
466 else
467 {
468 if (do_user_group)
469 {
470 /* FIXME: Decide if this should somewhat depend on -p. */
471
472 if (numeric_owner_option
473 || !*header->header.uname
474 || !uname_to_uid (header->header.uname, &stat_info->st_uid))
475 stat_info->st_uid = UID_FROM_CHARS (header->header.uid);
476
477 if (numeric_owner_option
478 || !*header->header.gname
479 || !gname_to_gid (header->header.gname, &stat_info->st_gid))
480 stat_info->st_gid = GID_FROM_CHARS (header->header.gid);
481 }
482 switch (header->header.typeflag)
483 {
484 case BLKTYPE:
485 stat_info->st_rdev
486 = makedev (MAJOR_FROM_CHARS (header->header.devmajor),
487 MINOR_FROM_CHARS (header->header.devminor));
488 break;
489
490 case CHRTYPE:
491 stat_info->st_rdev
492 = makedev (MAJOR_FROM_CHARS (header->header.devmajor),
493 MINOR_FROM_CHARS (header->header.devminor));
494 break;
495
496 default:
497 stat_info->st_rdev = 0;
498 }
499 }
500 }
501
502 /*------------------------------------------------------------------------.
503 | Convert buffer at WHERE0 of size DIGS from external format to uintmax_t.|
504 | The data is of type TYPE. The buffer must represent a value in the |
505 | range -MINUS_MINVAL through MAXVAL. |
506 `------------------------------------------------------------------------*/
507
508 static uintmax_t
509 from_chars (char const *where0, size_t digs, char const *type,
510 uintmax_t minus_minval, uintmax_t maxval)
511 {
512 uintmax_t value;
513 char const *where = where0;
514 char const *lim = where + digs;
515 int negative = 0;
516
517 /* Accommodate buggy tar of unknown vintage, which outputs leading
518 NUL if the previous field overflows. */
519 where += !*where;
520
521 /* Accommodate older tars, which output leading spaces. */
522 for (;;)
523 {
524 if (where == lim)
525 {
526 if (type)
527 ERROR ((0, 0,
528 _("Blanks in header where numeric %s value expected"),
529 type));
530 return -1;
531 }
532 if (!ISSPACE ((unsigned char) *where))
533 break;
534 where++;
535 }
536
537 value = 0;
538 if (ISODIGIT (*where))
539 {
540 do
541 {
542 if (value << LG_8 >> LG_8 != value)
543 goto out_of_range;
544 value = (value << LG_8) | (*where++ - '0');
545 }
546 while (where != lim && ISODIGIT (*where));
547
548 /* Parse the output of older tars, which output negative values
549 in two's complement octal. This method works only if the
550 type has the same number of bits as it did on the host that
551 created the tar file, but that's the best we can do. */
552 if (maxval < value && value - maxval <= minus_minval)
553 {
554 value = minus_minval - (value - maxval);
555 negative = 1;
556 }
557 }
558 else if (*where == '-' || *where == '+')
559 {
560 int dig;
561 negative = *where++ == '-';
562 while (where != lim
563 && (dig = base64_map[(unsigned char) *where]) < 64)
564 {
565 if (value << LG_64 >> LG_64 != value)
566 goto out_of_range;
567 value = (value << LG_64) | dig;
568 where++;
569 }
570 }
571
572 if (where != lim && *where && !ISSPACE ((unsigned char) *where))
573 {
574 if (type)
575 {
576 char buf[1000]; /* Big enough to represent any header. */
577 static struct quoting_options *o;
578
579 if (!o)
580 {
581 o = clone_quoting_options ((struct quoting_options *) 0);
582 set_quoting_style (o, c_quoting_style);
583 }
584
585 while (where0 != lim && ! lim[-1])
586 lim--;
587 quotearg_buffer (buf, sizeof buf, where0, lim - where, o);
588 ERROR ((0, 0,
589 _("Header contains `%.*s' where numeric %s value expected"),
590 (int) sizeof buf, buf, type));
591 }
592
593 return -1;
594 }
595
596 if (value <= (negative ? minus_minval : maxval))
597 return negative ? -value : value;
598
599 out_of_range:
600 if (type)
601 ERROR ((0, 0, _("Numeric value `%.*s' is out of range for %s"),
602 (int) digs, where0, type));
603 return -1;
604 }
605
606 gid_t
607 gid_from_chars (const char *p, size_t s)
608 {
609 return from_chars (p, s, "gid_t",
610 - (uintmax_t) TYPE_MINIMUM (gid_t),
611 (uintmax_t) TYPE_MAXIMUM (gid_t));
612 }
613
614 major_t
615 major_from_chars (const char *p, size_t s)
616 {
617 return from_chars (p, s, "major_t",
618 - (uintmax_t) TYPE_MINIMUM (major_t),
619 (uintmax_t) TYPE_MAXIMUM (major_t));
620 }
621
622 minor_t
623 minor_from_chars (const char *p, size_t s)
624 {
625 return from_chars (p, s, "minor_t",
626 - (uintmax_t) TYPE_MINIMUM (minor_t),
627 (uintmax_t) TYPE_MAXIMUM (minor_t));
628 }
629
630 mode_t
631 mode_from_chars (const char *p, size_t s)
632 {
633 /* Do not complain about unrecognized mode bits. */
634 unsigned u = from_chars (p, s, "mode_t",
635 - (uintmax_t) TYPE_MINIMUM (mode_t),
636 TYPE_MAXIMUM (uintmax_t));
637 return ((u & TSUID ? S_ISUID : 0)
638 | (u & TSGID ? S_ISGID : 0)
639 | (u & TSVTX ? S_ISVTX : 0)
640 | (u & TUREAD ? S_IRUSR : 0)
641 | (u & TUWRITE ? S_IWUSR : 0)
642 | (u & TUEXEC ? S_IXUSR : 0)
643 | (u & TGREAD ? S_IRGRP : 0)
644 | (u & TGWRITE ? S_IWGRP : 0)
645 | (u & TGEXEC ? S_IXGRP : 0)
646 | (u & TOREAD ? S_IROTH : 0)
647 | (u & TOWRITE ? S_IWOTH : 0)
648 | (u & TOEXEC ? S_IXOTH : 0));
649 }
650
651 off_t
652 off_from_chars (const char *p, size_t s)
653 {
654 return from_chars (p, s, "off_t",
655 - (uintmax_t) TYPE_MINIMUM (off_t),
656 (uintmax_t) TYPE_MAXIMUM (off_t));
657 }
658
659 size_t
660 size_from_chars (const char *p, size_t s)
661 {
662 return from_chars (p, s, "size_t", (uintmax_t) 0,
663 (uintmax_t) TYPE_MAXIMUM (size_t));
664 }
665
666 time_t
667 time_from_chars (const char *p, size_t s)
668 {
669 return from_chars (p, s, "time_t",
670 - (uintmax_t) TYPE_MINIMUM (time_t),
671 (uintmax_t) TYPE_MAXIMUM (time_t));
672 }
673
674 uid_t
675 uid_from_chars (const char *p, size_t s)
676 {
677 return from_chars (p, s, "uid_t", (uintmax_t) 0,
678 (uintmax_t) TYPE_MAXIMUM (uid_t));
679 }
680
681 uintmax_t
682 uintmax_from_chars (const char *p, size_t s)
683 {
684 return from_chars (p, s, "uintmax_t", (uintmax_t) 0,
685 TYPE_MAXIMUM (uintmax_t));
686 }
687
688
689 /*----------------------------------------------------------------------.
690 | Format O as a null-terminated decimal string into BUF _backwards_; |
691 | return pointer to start of result. |
692 `----------------------------------------------------------------------*/
693 char *
694 stringify_uintmax_t_backwards (uintmax_t o, char *buf)
695 {
696 *--buf = '\0';
697 do
698 *--buf = '0' + (int) (o % 10);
699 while ((o /= 10) != 0);
700 return buf;
701 }
702
703 #if !USE_OLD_CTIME
704
705 /*-------------------------------------------.
706 | Return the time formatted along ISO 8601. |
707 `-------------------------------------------*/
708
709 /* Also, see http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html. */
710
711 static char const *
712 isotime (time_t time)
713 {
714 static char buffer[max (UINTMAX_STRSIZE_BOUND + 1,
715 INT_STRLEN_BOUND (int) + 16)];
716 struct tm *tm = localtime (&time);
717 if (tm)
718 {
719 sprintf (buffer, "%04d-%02d-%02d %02d:%02d:%02d",
720 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
721 tm->tm_hour, tm->tm_min, tm->tm_sec);
722 return buffer;
723 }
724 else
725 {
726 /* The timestamp cannot be broken down, most likely because it
727 is a huge timestamp. Convert it as an integer,
728 right-adjusted in a field with the same width as the usual
729 19-byte 4-year ISO time format. */
730 uintmax_t abstime = time < 0 ? - (uintmax_t) time : time;
731 char *p = stringify_uintmax_t_backwards (abstime,
732 buffer + sizeof buffer);
733 if (time < 0)
734 *--p = '-';
735 while (buffer + sizeof buffer - 19 - 1 < p)
736 *--p = ' ';
737 return p;
738 }
739 }
740
741 #endif /* not USE_OLD_CTIME */
742
743 /*-------------------------------------------------------------------------.
744 | Decode MODE from its binary form in a stat structure, and encode it into |
745 | a 9 characters string STRING, terminated with a NUL. |
746 `-------------------------------------------------------------------------*/
747
748 static void
749 decode_mode (mode_t mode, char *string)
750 {
751 *string++ = mode & S_IRUSR ? 'r' : '-';
752 *string++ = mode & S_IWUSR ? 'w' : '-';
753 *string++ = (mode & S_ISUID
754 ? (mode & S_IXUSR ? 's' : 'S')
755 : (mode & S_IXUSR ? 'x' : '-'));
756 *string++ = mode & S_IRGRP ? 'r' : '-';
757 *string++ = mode & S_IWGRP ? 'w' : '-';
758 *string++ = (mode & S_ISGID
759 ? (mode & S_IXGRP ? 's' : 'S')
760 : (mode & S_IXGRP ? 'x' : '-'));
761 *string++ = mode & S_IROTH ? 'r' : '-';
762 *string++ = mode & S_IWOTH ? 'w' : '-';
763 *string++ = (mode & S_ISVTX
764 ? (mode & S_IXOTH ? 't' : 'T')
765 : (mode & S_IXOTH ? 'x' : '-'));
766 *string = '\0';
767 }
768
769 /*-------------------------------------------------------------------------.
770 | Actually print it. |
771 | |
772 | Plain and fancy file header block logging. Non-verbose just prints the |
773 | name, e.g. for "tar t" or "tar x". This should just contain file names, |
774 | so it can be fed back into tar with xargs or the "-T" option. The |
775 | verbose option can give a bunch of info, one line per file. I doubt |
776 | anybody tries to parse its format, or if they do, they shouldn't. Unix |
777 | tar is pretty random here anyway. |
778 `-------------------------------------------------------------------------*/
779
780 /* FIXME: Note that print_header uses the globals HEAD, HSTAT, and
781 HEAD_STANDARD, which must be set up in advance. Not very clean... */
782
783 /* UGSWIDTH starts with 18, so with user and group names <= 8 chars, the
784 columns never shift during the listing. */
785 #define UGSWIDTH 18
786 static int ugswidth = UGSWIDTH; /* maximum width encountered so far */
787
788 /* DATEWIDTH is the number of columns taken by the date and time fields. */
789 #if USE_OLD_CDATE
790 # define DATEWIDTH 19
791 #else
792 # define DATEWIDTH 18
793 #endif
794
795 void
796 print_header (void)
797 {
798 char modes[11];
799 char const *timestamp;
800 /* These hold formatted ints. */
801 char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND];
802 char *user, *group;
803 char size[2 * UINTMAX_STRSIZE_BOUND];
804 /* holds formatted size or major,minor */
805 char uintbuf[UINTMAX_STRSIZE_BOUND];
806 time_t longie; /* to make ctime() call portable */
807 int pad;
808 char *name;
809
810 if (block_number_option)
811 {
812 char buf[UINTMAX_STRSIZE_BOUND];
813 fprintf (stdlis, _("block %s: "),
814 STRINGIFY_BIGINT (current_block_ordinal (), buf));
815 }
816
817 if (verbose_option <= 1)
818 {
819 /* Just the fax, mam. */
820
821 char *quoted_name = quote_copy_string (current_file_name);
822
823 if (quoted_name)
824 {
825 fprintf (stdlis, "%s\n", quoted_name);
826 free (quoted_name);
827 }
828 else
829 fprintf (stdlis, "%s\n", current_file_name);
830 }
831 else
832 {
833 /* File type and modes. */
834
835 modes[0] = '?';
836 switch (current_header->header.typeflag)
837 {
838 case GNUTYPE_VOLHDR:
839 modes[0] = 'V';
840 break;
841
842 case GNUTYPE_MULTIVOL:
843 modes[0] = 'M';
844 break;
845
846 case GNUTYPE_NAMES:
847 modes[0] = 'N';
848 break;
849
850 case GNUTYPE_LONGNAME:
851 case GNUTYPE_LONGLINK:
852 ERROR ((0, 0, _("Visible longname error")));
853 break;
854
855 case GNUTYPE_SPARSE:
856 case REGTYPE:
857 case AREGTYPE:
858 case LNKTYPE:
859 modes[0] = '-';
860 if (current_file_name[strlen (current_file_name) - 1] == '/')
861 modes[0] = 'd';
862 break;
863 case GNUTYPE_DUMPDIR:
864 modes[0] = 'd';
865 break;
866 case DIRTYPE:
867 modes[0] = 'd';
868 break;
869 case SYMTYPE:
870 modes[0] = 'l';
871 break;
872 case BLKTYPE:
873 modes[0] = 'b';
874 break;
875 case CHRTYPE:
876 modes[0] = 'c';
877 break;
878 case FIFOTYPE:
879 modes[0] = 'p';
880 break;
881 case CONTTYPE:
882 modes[0] = 'C';
883 break;
884 }
885
886 decode_mode (current_stat.st_mode, modes + 1);
887
888 /* Timestamp. */
889
890 longie = current_stat.st_mtime;
891 #if USE_OLD_CTIME
892 {
893 char *ct = ctime (&longie);
894 if (ct)
895 {
896 timestamp = ct + 4;
897 for (ct += 16; ct[4] != '\n'; ct++)
898 ct[0] = ct[4];
899 ct[0] = '\0';
900 }
901 else
902 timestamp = "??? ?? ??:?? ????";
903 }
904 #else
905 timestamp = isotime (longie);
906 #endif
907
908 /* User and group names. */
909
910 if (*current_header->header.uname && current_format != V7_FORMAT
911 && !numeric_owner_option)
912 user = current_header->header.uname;
913 else
914 user = STRINGIFY_BIGINT (UINTMAX_FROM_CHARS
915 (current_header->header.uid),
916 uform);
917
918 if (*current_header->header.gname && current_format != V7_FORMAT
919 && !numeric_owner_option)
920 group = current_header->header.gname;
921 else
922 group = STRINGIFY_BIGINT (UINTMAX_FROM_CHARS
923 (current_header->header.gid),
924 gform);
925
926 /* Format the file size or major/minor device numbers. */
927
928 switch (current_header->header.typeflag)
929 {
930 case CHRTYPE:
931 case BLKTYPE:
932 strcpy (size,
933 STRINGIFY_BIGINT (major (current_stat.st_rdev), uintbuf));
934 strcat (size, ",");
935 strcat (size,
936 STRINGIFY_BIGINT (minor (current_stat.st_rdev), uintbuf));
937 break;
938 case GNUTYPE_SPARSE:
939 strcpy (size,
940 STRINGIFY_BIGINT
941 (UINTMAX_FROM_CHARS (current_header->oldgnu_header.realsize),
942 uintbuf));
943 break;
944 default:
945 strcpy (size, STRINGIFY_BIGINT (current_stat.st_size, uintbuf));
946 break;
947 }
948
949 /* Figure out padding and print the whole line. */
950
951 pad = strlen (user) + strlen (group) + strlen (size) + 1;
952 if (pad > ugswidth)
953 ugswidth = pad;
954
955 fprintf (stdlis, "%s %s/%s %*s%s %s",
956 modes, user, group, ugswidth - pad, "", size, timestamp);
957
958 name = quote_copy_string (current_file_name);
959 if (name)
960 {
961 fprintf (stdlis, " %s", name);
962 free (name);
963 }
964 else
965 fprintf (stdlis, " %s", current_file_name);
966
967 switch (current_header->header.typeflag)
968 {
969 case SYMTYPE:
970 name = quote_copy_string (current_link_name);
971 if (name)
972 {
973 fprintf (stdlis, " -> %s\n", name);
974 free (name);
975 }
976 else
977 fprintf (stdlis, " -> %s\n", current_link_name);
978 break;
979
980 case LNKTYPE:
981 name = quote_copy_string (current_link_name);
982 if (name)
983 {
984 fprintf (stdlis, _(" link to %s\n"), name);
985 free (name);
986 }
987 else
988 fprintf (stdlis, _(" link to %s\n"), current_link_name);
989 break;
990
991 default:
992 fprintf (stdlis, _(" unknown file type `%c'\n"),
993 current_header->header.typeflag);
994 break;
995
996 case AREGTYPE:
997 case REGTYPE:
998 case GNUTYPE_SPARSE:
999 case CHRTYPE:
1000 case BLKTYPE:
1001 case DIRTYPE:
1002 case FIFOTYPE:
1003 case CONTTYPE:
1004 case GNUTYPE_DUMPDIR:
1005 putc ('\n', stdlis);
1006 break;
1007
1008 case GNUTYPE_VOLHDR:
1009 fprintf (stdlis, _("--Volume Header--\n"));
1010 break;
1011
1012 case GNUTYPE_MULTIVOL:
1013 strcpy (size,
1014 STRINGIFY_BIGINT
1015 (UINTMAX_FROM_CHARS (current_header->oldgnu_header.offset),
1016 uintbuf));
1017 fprintf (stdlis, _("--Continued at byte %s--\n"), size);
1018 break;
1019
1020 case GNUTYPE_NAMES:
1021 fprintf (stdlis, _("--Mangled file names--\n"));
1022 break;
1023 }
1024 }
1025 fflush (stdlis);
1026 }
1027
1028 /*--------------------------------------------------------------.
1029 | Print a similar line when we make a directory automatically. |
1030 `--------------------------------------------------------------*/
1031
1032 void
1033 print_for_mkdir (char *pathname, int length, mode_t mode)
1034 {
1035 char modes[11];
1036 char *name;
1037
1038 if (verbose_option > 1)
1039 {
1040 /* File type and modes. */
1041
1042 modes[0] = 'd';
1043 decode_mode (mode, modes + 1);
1044
1045 if (block_number_option)
1046 {
1047 char buf[UINTMAX_STRSIZE_BOUND];
1048 fprintf (stdlis, _("block %s: "),
1049 STRINGIFY_BIGINT (current_block_ordinal (), buf));
1050 }
1051 name = quote_copy_string (pathname);
1052 if (name)
1053 {
1054 fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
1055 _("Creating directory:"), length, name);
1056 free (name);
1057 }
1058 else
1059 fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
1060 _("Creating directory:"), length, pathname);
1061 }
1062 }
1063
1064 /*--------------------------------------------------------.
1065 | Skip over SIZE bytes of data in blocks in the archive. |
1066 `--------------------------------------------------------*/
1067
1068 void
1069 skip_file (off_t size)
1070 {
1071 union block *x;
1072
1073 if (multi_volume_option)
1074 {
1075 save_totsize = size;
1076 save_sizeleft = size;
1077 }
1078
1079 while (size > 0)
1080 {
1081 x = find_next_block ();
1082 if (x == NULL)
1083 FATAL_ERROR ((0, 0, _("Unexpected EOF on archive file")));
1084
1085 set_next_block_after (x);
1086 size -= BLOCKSIZE;
1087 if (multi_volume_option)
1088 save_sizeleft -= BLOCKSIZE;
1089 }
1090 }
1091
1092 /*---.
1093 | ? |
1094 `---*/
1095
1096 void
1097 skip_extended_headers (void)
1098 {
1099 union block *exhdr;
1100
1101 do
1102 {
1103 exhdr = find_next_block ();
1104 if (!exhdr)
1105 FATAL_ERROR ((0, 0, _("Unexpected EOF on archive file")));
1106 set_next_block_after (exhdr);
1107 }
1108 while (exhdr->sparse_header.isextended);
1109 }
This page took 0.086821 seconds and 3 git commands to generate.