Import libarchive-3.0.2.
[dragonfly.git] / contrib / libarchive / tar / read.c
1 /*-
2  * Copyright (c) 2003-2007 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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.
24  */
25
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 $");
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_SYS_PARAM_H
33 #include <sys/param.h>
34 #endif
35 #ifdef HAVE_SYS_STAT_H
36 #include <sys/stat.h>
37 #endif
38
39 #ifdef HAVE_ERRNO_H
40 #include <errno.h>
41 #endif
42 #ifdef HAVE_GRP_H
43 #include <grp.h>
44 #endif
45 #ifdef HAVE_LIMITS_H
46 #include <limits.h>
47 #endif
48 #ifdef HAVE_PWD_H
49 #include <pwd.h>
50 #endif
51 #ifdef HAVE_STDINT_H
52 #include <stdint.h>
53 #endif
54 #include <stdio.h>
55 #ifdef HAVE_STDLIB_H
56 #include <stdlib.h>
57 #endif
58 #ifdef HAVE_STRING_H
59 #include <string.h>
60 #endif
61 #ifdef HAVE_TIME_H
62 #include <time.h>
63 #endif
64 #ifdef HAVE_UNISTD_H
65 #include <unistd.h>
66 #endif
67
68 #include "bsdtar.h"
69 #include "err.h"
70
71 struct progress_data {
72         struct bsdtar *bsdtar;
73         struct archive *archive;
74         struct archive_entry *entry;
75 };
76
77 static void     list_item_verbose(struct bsdtar *, FILE *,
78                     struct archive_entry *);
79 static void     read_archive(struct bsdtar *bsdtar, char mode, struct archive *);
80
81 void
82 tar_mode_t(struct bsdtar *bsdtar)
83 {
84         read_archive(bsdtar, 't', NULL);
85         if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0)
86                 bsdtar->return_value = 1;
87 }
88
89 void
90 tar_mode_x(struct bsdtar *bsdtar)
91 {
92         struct archive *writer;
93
94         writer = archive_write_disk_new();
95         if (writer == NULL)
96                 lafe_errc(1, ENOMEM, "Cannot allocate disk writer object");
97         if (!bsdtar->option_numeric_owner)
98                 archive_write_disk_set_standard_lookup(writer);
99         archive_write_disk_set_options(writer, bsdtar->extract_flags);
100
101         read_archive(bsdtar, 'x', writer);
102
103         if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0)
104                 bsdtar->return_value = 1;
105         archive_write_free(writer);
106 }
107
108 static void
109 progress_func(void *cookie)
110 {
111         struct progress_data *progress_data = cookie;
112         struct bsdtar *bsdtar = progress_data->bsdtar;
113         struct archive *a = progress_data->archive;
114         struct archive_entry *entry = progress_data->entry;
115         uint64_t comp, uncomp;
116         int compression;
117
118         if (!need_report())
119                 return;
120
121         if (bsdtar->verbose)
122                 fprintf(stderr, "\n");
123         if (a != NULL) {
124                 comp = archive_position_compressed(a);
125                 uncomp = archive_position_uncompressed(a);
126                 if (comp > uncomp)
127                         compression = 0;
128                 else
129                         compression = (int)((uncomp - comp) * 100 / uncomp);
130                 fprintf(stderr,
131                     "In: %s bytes, compression %d%%;",
132                     tar_i64toa(comp), compression);
133                 fprintf(stderr, "  Out: %d files, %s bytes\n",
134                     archive_file_count(a), tar_i64toa(uncomp));
135         }
136         if (entry != NULL) {
137                 safe_fprintf(stderr, "Current: %s",
138                     archive_entry_pathname(entry));
139                 fprintf(stderr, " (%s bytes)\n",
140                     tar_i64toa(archive_entry_size(entry)));
141         }
142 }
143
144 /*
145  * Handle 'x' and 't' modes.
146  */
147 static void
148 read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer)
149 {
150         struct progress_data    progress_data;
151         FILE                     *out;
152         struct archive           *a;
153         struct archive_entry     *entry;
154         int                       r;
155         time_t                    sec;
156         long                      nsec;
157
158         while (*bsdtar->argv) {
159                 lafe_include(&bsdtar->matching, *bsdtar->argv);
160                 bsdtar->argv++;
161         }
162
163         if (bsdtar->names_from_file != NULL)
164                 lafe_include_from_file(&bsdtar->matching,
165                     bsdtar->names_from_file, bsdtar->option_null);
166
167         a = archive_read_new();
168         if (bsdtar->compress_program != NULL)
169                 archive_read_support_filter_program(a, bsdtar->compress_program);
170         else
171                 archive_read_support_filter_all(a);
172         archive_read_support_format_all(a);
173         if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options))
174                 lafe_errc(1, 0, "%s", archive_error_string(a));
175         if (archive_read_open_file(a, bsdtar->filename, bsdtar->bytes_per_block))
176                 lafe_errc(1, 0, "Error opening archive: %s",
177                     archive_error_string(a));
178
179         do_chdir(bsdtar);
180
181         if (mode == 'x') {
182                 /* Set an extract callback so that we can handle SIGINFO. */
183                 progress_data.bsdtar = bsdtar;
184                 progress_data.archive = a;
185                 archive_read_extract_set_progress_callback(a, progress_func,
186                     &progress_data);
187         }
188
189         if (mode == 'x' && bsdtar->option_chroot) {
190 #if HAVE_CHROOT
191                 if (chroot(".") != 0)
192                         lafe_errc(1, errno, "Can't chroot to \".\"");
193 #else
194                 lafe_errc(1, 0,
195                     "chroot isn't supported on this platform");
196 #endif
197         }
198
199         for (;;) {
200                 /* Support --fast-read option */
201                 if (bsdtar->option_fast_read &&
202                     lafe_unmatched_inclusions(bsdtar->matching) == 0)
203                         break;
204
205                 r = archive_read_next_header(a, &entry);
206                 progress_data.entry = entry;
207                 if (r == ARCHIVE_EOF)
208                         break;
209                 if (r < ARCHIVE_OK)
210                         lafe_warnc(0, "%s", archive_error_string(a));
211                 if (r <= ARCHIVE_WARN)
212                         bsdtar->return_value = 1;
213                 if (r == ARCHIVE_RETRY) {
214                         /* Retryable error: try again */
215                         lafe_warnc(0, "Retrying...");
216                         continue;
217                 }
218                 if (r == ARCHIVE_FATAL)
219                         break;
220
221                 if (bsdtar->uid >= 0) {
222                         archive_entry_set_uid(entry, bsdtar->uid);
223                         archive_entry_set_uname(entry, NULL);
224                 }
225                 if (bsdtar->gid >= 0) {
226                         archive_entry_set_gid(entry, bsdtar->gid);
227                         archive_entry_set_gname(entry, NULL);
228                 }
229                 if (bsdtar->uname)
230                         archive_entry_set_uname(entry, bsdtar->uname);
231                 if (bsdtar->gname)
232                         archive_entry_set_gname(entry, bsdtar->gname);
233
234                 /*
235                  * Exclude entries that are too old.
236                  */
237                 if (bsdtar->newer_ctime_filter) {
238                         /* Use ctime if format provides, else mtime. */
239                         if (archive_entry_ctime_is_set(entry)) {
240                                 sec = archive_entry_ctime(entry);
241                                 nsec = archive_entry_ctime_nsec(entry);
242                         } else if (archive_entry_mtime_is_set(entry)) {
243                                 sec = archive_entry_mtime(entry);
244                                 nsec = archive_entry_mtime_nsec(entry);
245                         } else {
246                                 sec = 0;
247                                 nsec = 0;
248                         }
249                         if (sec < bsdtar->newer_ctime_sec)
250                                 continue; /* Too old, skip it. */
251                         if (sec == bsdtar->newer_ctime_sec
252                             && nsec <= bsdtar->newer_ctime_nsec)
253                                 continue; /* Too old, skip it. */
254                 }
255                 if (bsdtar->newer_mtime_filter) {
256                         if (archive_entry_mtime_is_set(entry)) {
257                                 sec = archive_entry_mtime(entry);
258                                 nsec = archive_entry_mtime_nsec(entry);
259                         } else {
260                                 sec = 0;
261                                 nsec = 0;
262                         }
263                         if (sec < bsdtar->newer_mtime_sec)
264                                 continue; /* Too old, skip it. */
265                         if (sec == bsdtar->newer_mtime_sec
266                             && nsec <= bsdtar->newer_mtime_nsec)
267                                 continue; /* Too old, skip it. */
268                 }
269
270                 /*
271                  * Note that pattern exclusions are checked before
272                  * pathname rewrites are handled.  This gives more
273                  * control over exclusions, since rewrites always lose
274                  * information.  (For example, consider a rewrite
275                  * s/foo[0-9]/foo/.  If we check exclusions after the
276                  * rewrite, there would be no way to exclude foo1/bar
277                  * while allowing foo2/bar.)
278                  */
279                 if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry)))
280                         continue; /* Excluded by a pattern test. */
281
282                 if (mode == 't') {
283                         /* Perversely, gtar uses -O to mean "send to stderr"
284                          * when used with -t. */
285                         out = bsdtar->option_stdout ? stderr : stdout;
286
287                         /*
288                          * TODO: Provide some reasonable way to
289                          * preview rewrites.  gtar always displays
290                          * the unedited path in -t output, which means
291                          * you cannot easily preview rewrites.
292                          */
293                         if (bsdtar->verbose < 2)
294                                 safe_fprintf(out, "%s",
295                                     archive_entry_pathname(entry));
296                         else
297                                 list_item_verbose(bsdtar, out, entry);
298                         fflush(out);
299                         r = archive_read_data_skip(a);
300                         if (r == ARCHIVE_WARN) {
301                                 fprintf(out, "\n");
302                                 lafe_warnc(0, "%s",
303                                     archive_error_string(a));
304                         }
305                         if (r == ARCHIVE_RETRY) {
306                                 fprintf(out, "\n");
307                                 lafe_warnc(0, "%s",
308                                     archive_error_string(a));
309                         }
310                         if (r == ARCHIVE_FATAL) {
311                                 fprintf(out, "\n");
312                                 lafe_warnc(0, "%s",
313                                     archive_error_string(a));
314                                 bsdtar->return_value = 1;
315                                 break;
316                         }
317                         fprintf(out, "\n");
318                 } else {
319                         /* Note: some rewrite failures prevent extraction. */
320                         if (edit_pathname(bsdtar, entry))
321                                 continue; /* Excluded by a rewrite failure. */
322
323                         if (bsdtar->option_interactive &&
324                             !yes("extract '%s'", archive_entry_pathname(entry)))
325                                 continue;
326
327                         /*
328                          * Format here is from SUSv2, including the
329                          * deferred '\n'.
330                          */
331                         if (bsdtar->verbose) {
332                                 safe_fprintf(stderr, "x %s",
333                                     archive_entry_pathname(entry));
334                                 fflush(stderr);
335                         }
336
337                         /* TODO siginfo_printinfo(bsdtar, 0); */
338
339                         if (bsdtar->option_stdout)
340                                 r = archive_read_data_into_fd(a, 1);
341                         else
342                                 r = archive_read_extract2(a, entry, writer);
343                         if (r != ARCHIVE_OK) {
344                                 if (!bsdtar->verbose)
345                                         safe_fprintf(stderr, "%s",
346                                             archive_entry_pathname(entry));
347                                 safe_fprintf(stderr, ": %s",
348                                     archive_error_string(a));
349                                 if (!bsdtar->verbose)
350                                         fprintf(stderr, "\n");
351                                 bsdtar->return_value = 1;
352                         }
353                         if (bsdtar->verbose)
354                                 fprintf(stderr, "\n");
355                         if (r == ARCHIVE_FATAL)
356                                 break;
357                 }
358         }
359
360
361         r = archive_read_close(a);
362         if (r != ARCHIVE_OK)
363                 lafe_warnc(0, "%s", archive_error_string(a));
364         if (r <= ARCHIVE_WARN)
365                 bsdtar->return_value = 1;
366
367         if (bsdtar->verbose > 2)
368                 fprintf(stdout, "Archive Format: %s,  Compression: %s\n",
369                     archive_format_name(a), archive_compression_name(a));
370
371         archive_read_free(a);
372 }
373
374
375 /*
376  * Display information about the current file.
377  *
378  * The format here roughly duplicates the output of 'ls -l'.
379  * This is based on SUSv2, where 'tar tv' is documented as
380  * listing additional information in an "unspecified format,"
381  * and 'pax -l' is documented as using the same format as 'ls -l'.
382  */
383 static void
384 list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
385 {
386         char                     tmp[100];
387         size_t                   w;
388         const char              *p;
389         const char              *fmt;
390         time_t                   tim;
391         static time_t            now;
392
393         /*
394          * We avoid collecting the entire list in memory at once by
395          * listing things as we see them.  However, that also means we can't
396          * just pre-compute the field widths.  Instead, we start with guesses
397          * and just widen them as necessary.  These numbers are completely
398          * arbitrary.
399          */
400         if (!bsdtar->u_width) {
401                 bsdtar->u_width = 6;
402                 bsdtar->gs_width = 13;
403         }
404         if (!now)
405                 time(&now);
406         fprintf(out, "%s %d ",
407             archive_entry_strmode(entry),
408             archive_entry_nlink(entry));
409
410         /* Use uname if it's present, else uid. */
411         p = archive_entry_uname(entry);
412         if ((p == NULL) || (*p == '\0')) {
413                 sprintf(tmp, "%lu ",
414                     (unsigned long)archive_entry_uid(entry));
415                 p = tmp;
416         }
417         w = strlen(p);
418         if (w > bsdtar->u_width)
419                 bsdtar->u_width = w;
420         fprintf(out, "%-*s ", (int)bsdtar->u_width, p);
421
422         /* Use gname if it's present, else gid. */
423         p = archive_entry_gname(entry);
424         if (p != NULL && p[0] != '\0') {
425                 fprintf(out, "%s", p);
426                 w = strlen(p);
427         } else {
428                 sprintf(tmp, "%lu",
429                     (unsigned long)archive_entry_gid(entry));
430                 w = strlen(tmp);
431                 fprintf(out, "%s", tmp);
432         }
433
434         /*
435          * Print device number or file size, right-aligned so as to make
436          * total width of group and devnum/filesize fields be gs_width.
437          * If gs_width is too small, grow it.
438          */
439         if (archive_entry_filetype(entry) == AE_IFCHR
440             || archive_entry_filetype(entry) == AE_IFBLK) {
441                 sprintf(tmp, "%lu,%lu",
442                     (unsigned long)archive_entry_rdevmajor(entry),
443                     (unsigned long)archive_entry_rdevminor(entry));
444         } else {
445                 strcpy(tmp, tar_i64toa(archive_entry_size(entry)));
446         }
447         if (w + strlen(tmp) >= bsdtar->gs_width)
448                 bsdtar->gs_width = w+strlen(tmp)+1;
449         fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp);
450
451         /* Format the time using 'ls -l' conventions. */
452         tim = archive_entry_mtime(entry);
453 #define HALF_YEAR (time_t)365 * 86400 / 2
454 #if defined(_WIN32) && !defined(__CYGWIN__)
455 #define DAY_FMT  "%d"  /* Windows' strftime function does not support %e format. */
456 #else
457 #define DAY_FMT  "%e"  /* Day number without leading zeros */
458 #endif
459         if (tim < now - HALF_YEAR || tim > now + HALF_YEAR)
460                 fmt = bsdtar->day_first ? DAY_FMT " %b  %Y" : "%b " DAY_FMT "  %Y";
461         else
462                 fmt = bsdtar->day_first ? DAY_FMT " %b %H:%M" : "%b " DAY_FMT " %H:%M";
463         strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
464         fprintf(out, " %s ", tmp);
465         safe_fprintf(out, "%s", archive_entry_pathname(entry));
466
467         /* Extra information for links. */
468         if (archive_entry_hardlink(entry)) /* Hard link */
469                 safe_fprintf(out, " link to %s",
470                     archive_entry_hardlink(entry));
471         else if (archive_entry_symlink(entry)) /* Symbolic link */
472                 safe_fprintf(out, " -> %s", archive_entry_symlink(entry));
473 }