2 * Copyright (c) 2003-2007 Tim Kientzle
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "bsdtar_platform.h"
27 __FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.40 2008/08/21 06:41:14 kientzle Exp $");
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
32 #ifdef HAVE_SYS_PARAM_H
33 #include <sys/param.h>
35 #ifdef HAVE_SYS_STAT_H
71 struct progress_data
{
72 struct bsdtar
*bsdtar
;
73 struct archive
*archive
;
74 struct archive_entry
*entry
;
77 static void list_item_verbose(struct bsdtar
*, FILE *,
78 struct archive_entry
*);
79 static void read_archive(struct bsdtar
*bsdtar
, char mode
);
82 tar_mode_t(struct bsdtar
*bsdtar
)
84 read_archive(bsdtar
, 't');
85 if (lafe_unmatched_inclusions_warn(bsdtar
->matching
, "Not found in archive") != 0)
86 bsdtar
->return_value
= 1;
90 tar_mode_x(struct bsdtar
*bsdtar
)
92 read_archive(bsdtar
, 'x');
94 if (lafe_unmatched_inclusions_warn(bsdtar
->matching
, "Not found in archive") != 0)
95 bsdtar
->return_value
= 1;
99 progress_func(void *cookie
)
101 struct progress_data
*progress_data
= cookie
;
102 struct bsdtar
*bsdtar
= progress_data
->bsdtar
;
103 struct archive
*a
= progress_data
->archive
;
104 struct archive_entry
*entry
= progress_data
->entry
;
105 uint64_t comp
, uncomp
;
111 fprintf(stderr
, "\n");
113 comp
= archive_position_compressed(a
);
114 uncomp
= archive_position_uncompressed(a
);
116 "In: %s bytes, compression %d%%;",
117 tar_i64toa(comp
), (int)((uncomp
- comp
) * 100 / uncomp
));
118 fprintf(stderr
, " Out: %d files, %s bytes\n",
119 archive_file_count(a
), tar_i64toa(uncomp
));
122 safe_fprintf(stderr
, "Current: %s",
123 archive_entry_pathname(entry
));
124 fprintf(stderr
, " (%s bytes)\n",
125 tar_i64toa(archive_entry_size(entry
)));
130 * Handle 'x' and 't' modes.
133 read_archive(struct bsdtar
*bsdtar
, char mode
)
135 struct progress_data progress_data
;
138 struct archive_entry
*entry
;
139 const struct stat
*st
;
142 while (*bsdtar
->argv
) {
143 lafe_include(&bsdtar
->matching
, *bsdtar
->argv
);
147 if (bsdtar
->names_from_file
!= NULL
)
148 lafe_include_from_file(&bsdtar
->matching
,
149 bsdtar
->names_from_file
, bsdtar
->option_null
);
151 a
= archive_read_new();
152 if (bsdtar
->compress_program
!= NULL
)
153 archive_read_support_compression_program(a
, bsdtar
->compress_program
);
155 archive_read_support_compression_all(a
);
156 archive_read_support_format_all(a
);
157 if (ARCHIVE_OK
!= archive_read_set_options(a
, bsdtar
->option_options
))
158 lafe_errc(1, 0, "%s", archive_error_string(a
));
159 if (archive_read_open_file(a
, bsdtar
->filename
,
160 bsdtar
->bytes_per_block
!= 0 ? bsdtar
->bytes_per_block
:
161 DEFAULT_BYTES_PER_BLOCK
))
162 lafe_errc(1, 0, "Error opening archive: %s",
163 archive_error_string(a
));
168 /* Set an extract callback so that we can handle SIGINFO. */
169 progress_data
.bsdtar
= bsdtar
;
170 progress_data
.archive
= a
;
171 archive_read_extract_set_progress_callback(a
, progress_func
,
175 if (mode
== 'x' && bsdtar
->option_chroot
) {
177 if (chroot(".") != 0)
178 lafe_errc(1, errno
, "Can't chroot to \".\"");
181 "chroot isn't supported on this platform");
186 /* Support --fast-read option */
187 if (bsdtar
->option_fast_read
&&
188 lafe_unmatched_inclusions(bsdtar
->matching
) == 0)
191 r
= archive_read_next_header(a
, &entry
);
192 progress_data
.entry
= entry
;
193 if (r
== ARCHIVE_EOF
)
196 lafe_warnc(0, "%s", archive_error_string(a
));
197 if (r
<= ARCHIVE_WARN
)
198 bsdtar
->return_value
= 1;
199 if (r
== ARCHIVE_RETRY
) {
200 /* Retryable error: try again */
201 lafe_warnc(0, "Retrying...");
204 if (r
== ARCHIVE_FATAL
)
207 if (bsdtar
->option_numeric_owner
) {
208 archive_entry_set_uname(entry
, NULL
);
209 archive_entry_set_gname(entry
, NULL
);
213 * Exclude entries that are too old.
215 st
= archive_entry_stat(entry
);
216 if (bsdtar
->newer_ctime_sec
> 0) {
217 if (st
->st_ctime
< bsdtar
->newer_ctime_sec
)
218 continue; /* Too old, skip it. */
219 if (st
->st_ctime
== bsdtar
->newer_ctime_sec
220 && ARCHIVE_STAT_CTIME_NANOS(st
)
221 <= bsdtar
->newer_ctime_nsec
)
222 continue; /* Too old, skip it. */
224 if (bsdtar
->newer_mtime_sec
> 0) {
225 if (st
->st_mtime
< bsdtar
->newer_mtime_sec
)
226 continue; /* Too old, skip it. */
227 if (st
->st_mtime
== bsdtar
->newer_mtime_sec
228 && ARCHIVE_STAT_MTIME_NANOS(st
)
229 <= bsdtar
->newer_mtime_nsec
)
230 continue; /* Too old, skip it. */
234 * Note that pattern exclusions are checked before
235 * pathname rewrites are handled. This gives more
236 * control over exclusions, since rewrites always lose
237 * information. (For example, consider a rewrite
238 * s/foo[0-9]/foo/. If we check exclusions after the
239 * rewrite, there would be no way to exclude foo1/bar
240 * while allowing foo2/bar.)
242 if (lafe_excluded(bsdtar
->matching
, archive_entry_pathname(entry
)))
243 continue; /* Excluded by a pattern test. */
246 /* Perversely, gtar uses -O to mean "send to stderr"
247 * when used with -t. */
248 out
= bsdtar
->option_stdout
? stderr
: stdout
;
251 * TODO: Provide some reasonable way to
252 * preview rewrites. gtar always displays
253 * the unedited path in -t output, which means
254 * you cannot easily preview rewrites.
256 if (bsdtar
->verbose
< 2)
257 safe_fprintf(out
, "%s",
258 archive_entry_pathname(entry
));
260 list_item_verbose(bsdtar
, out
, entry
);
262 r
= archive_read_data_skip(a
);
263 if (r
== ARCHIVE_WARN
) {
266 archive_error_string(a
));
268 if (r
== ARCHIVE_RETRY
) {
271 archive_error_string(a
));
273 if (r
== ARCHIVE_FATAL
) {
276 archive_error_string(a
));
277 bsdtar
->return_value
= 1;
282 /* Note: some rewrite failures prevent extraction. */
283 if (edit_pathname(bsdtar
, entry
))
284 continue; /* Excluded by a rewrite failure. */
286 if (bsdtar
->option_interactive
&&
287 !yes("extract '%s'", archive_entry_pathname(entry
)))
291 * Format here is from SUSv2, including the
294 if (bsdtar
->verbose
) {
295 safe_fprintf(stderr
, "x %s",
296 archive_entry_pathname(entry
));
300 // TODO siginfo_printinfo(bsdtar, 0);
302 if (bsdtar
->option_stdout
)
303 r
= archive_read_data_into_fd(a
, 1);
305 r
= archive_read_extract(a
, entry
,
306 bsdtar
->extract_flags
);
307 if (r
!= ARCHIVE_OK
) {
308 if (!bsdtar
->verbose
)
309 safe_fprintf(stderr
, "%s",
310 archive_entry_pathname(entry
));
311 safe_fprintf(stderr
, ": %s",
312 archive_error_string(a
));
313 if (!bsdtar
->verbose
)
314 fprintf(stderr
, "\n");
315 bsdtar
->return_value
= 1;
318 fprintf(stderr
, "\n");
319 if (r
== ARCHIVE_FATAL
)
325 r
= archive_read_close(a
);
327 lafe_warnc(0, "%s", archive_error_string(a
));
328 if (r
<= ARCHIVE_WARN
)
329 bsdtar
->return_value
= 1;
331 if (bsdtar
->verbose
> 2)
332 fprintf(stdout
, "Archive Format: %s, Compression: %s\n",
333 archive_format_name(a
), archive_compression_name(a
));
335 archive_read_finish(a
);
340 * Display information about the current file.
342 * The format here roughly duplicates the output of 'ls -l'.
343 * This is based on SUSv2, where 'tar tv' is documented as
344 * listing additional information in an "unspecified format,"
345 * and 'pax -l' is documented as using the same format as 'ls -l'.
348 list_item_verbose(struct bsdtar
*bsdtar
, FILE *out
, struct archive_entry
*entry
)
358 * We avoid collecting the entire list in memory at once by
359 * listing things as we see them. However, that also means we can't
360 * just pre-compute the field widths. Instead, we start with guesses
361 * and just widen them as necessary. These numbers are completely
364 if (!bsdtar
->u_width
) {
366 bsdtar
->gs_width
= 13;
370 fprintf(out
, "%s %d ",
371 archive_entry_strmode(entry
),
372 archive_entry_nlink(entry
));
374 /* Use uname if it's present, else uid. */
375 p
= archive_entry_uname(entry
);
376 if ((p
== NULL
) || (*p
== '\0')) {
378 (unsigned long)archive_entry_uid(entry
));
382 if (w
> bsdtar
->u_width
)
384 fprintf(out
, "%-*s ", (int)bsdtar
->u_width
, p
);
386 /* Use gname if it's present, else gid. */
387 p
= archive_entry_gname(entry
);
388 if (p
!= NULL
&& p
[0] != '\0') {
389 fprintf(out
, "%s", p
);
393 (unsigned long)archive_entry_gid(entry
));
395 fprintf(out
, "%s", tmp
);
399 * Print device number or file size, right-aligned so as to make
400 * total width of group and devnum/filesize fields be gs_width.
401 * If gs_width is too small, grow it.
403 if (archive_entry_filetype(entry
) == AE_IFCHR
404 || archive_entry_filetype(entry
) == AE_IFBLK
) {
405 sprintf(tmp
, "%lu,%lu",
406 (unsigned long)archive_entry_rdevmajor(entry
),
407 (unsigned long)archive_entry_rdevminor(entry
));
409 strcpy(tmp
, tar_i64toa(archive_entry_size(entry
)));
411 if (w
+ strlen(tmp
) >= bsdtar
->gs_width
)
412 bsdtar
->gs_width
= w
+strlen(tmp
)+1;
413 fprintf(out
, "%*s", (int)(bsdtar
->gs_width
- w
), tmp
);
415 /* Format the time using 'ls -l' conventions. */
416 tim
= archive_entry_mtime(entry
);
417 #define HALF_YEAR (time_t)365 * 86400 / 2
418 #if defined(_WIN32) && !defined(__CYGWIN__)
419 #define DAY_FMT "%d" /* Windows' strftime function does not support %e format. */
421 #define DAY_FMT "%e" /* Day number without leading zeros */
423 if (tim
< now
- HALF_YEAR
|| tim
> now
+ HALF_YEAR
)
424 fmt
= bsdtar
->day_first
? DAY_FMT
" %b %Y" : "%b " DAY_FMT
" %Y";
426 fmt
= bsdtar
->day_first
? DAY_FMT
" %b %H:%M" : "%b " DAY_FMT
" %H:%M";
427 strftime(tmp
, sizeof(tmp
), fmt
, localtime(&tim
));
428 fprintf(out
, " %s ", tmp
);
429 safe_fprintf(out
, "%s", archive_entry_pathname(entry
));
431 /* Extra information for links. */
432 if (archive_entry_hardlink(entry
)) /* Hard link */
433 safe_fprintf(out
, " link to %s",
434 archive_entry_hardlink(entry
));
435 else if (archive_entry_symlink(entry
)) /* Symbolic link */
436 safe_fprintf(out
, " -> %s", archive_entry_symlink(entry
));