read.c revision 228763
1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "bsdtar_platform.h" 27228763Smm__FBSDID("$FreeBSD: head/contrib/libarchive/tar/read.c 228763 2011-12-21 11:13:29Z mm $"); 28228753Smm 29228753Smm#ifdef HAVE_SYS_TYPES_H 30228753Smm#include <sys/types.h> 31228753Smm#endif 32228753Smm#ifdef HAVE_SYS_PARAM_H 33228753Smm#include <sys/param.h> 34228753Smm#endif 35228753Smm#ifdef HAVE_SYS_STAT_H 36228753Smm#include <sys/stat.h> 37228753Smm#endif 38228753Smm 39228753Smm#ifdef HAVE_ERRNO_H 40228753Smm#include <errno.h> 41228753Smm#endif 42228753Smm#ifdef HAVE_GRP_H 43228753Smm#include <grp.h> 44228753Smm#endif 45228753Smm#ifdef HAVE_LIMITS_H 46228753Smm#include <limits.h> 47228753Smm#endif 48228753Smm#ifdef HAVE_PWD_H 49228753Smm#include <pwd.h> 50228753Smm#endif 51228753Smm#ifdef HAVE_STDINT_H 52228753Smm#include <stdint.h> 53228753Smm#endif 54228753Smm#include <stdio.h> 55228753Smm#ifdef HAVE_STDLIB_H 56228753Smm#include <stdlib.h> 57228753Smm#endif 58228753Smm#ifdef HAVE_STRING_H 59228753Smm#include <string.h> 60228753Smm#endif 61228753Smm#ifdef HAVE_TIME_H 62228753Smm#include <time.h> 63228753Smm#endif 64228753Smm#ifdef HAVE_UNISTD_H 65228753Smm#include <unistd.h> 66228753Smm#endif 67228753Smm 68228753Smm#include "bsdtar.h" 69228753Smm#include "err.h" 70228753Smm 71228753Smmstruct progress_data { 72228753Smm struct bsdtar *bsdtar; 73228753Smm struct archive *archive; 74228753Smm struct archive_entry *entry; 75228753Smm}; 76228753Smm 77228753Smmstatic void list_item_verbose(struct bsdtar *, FILE *, 78228753Smm struct archive_entry *); 79228753Smmstatic void read_archive(struct bsdtar *bsdtar, char mode); 80228753Smm 81228753Smmvoid 82228753Smmtar_mode_t(struct bsdtar *bsdtar) 83228753Smm{ 84228753Smm read_archive(bsdtar, 't'); 85228753Smm if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0) 86228753Smm bsdtar->return_value = 1; 87228753Smm} 88228753Smm 89228753Smmvoid 90228753Smmtar_mode_x(struct bsdtar *bsdtar) 91228753Smm{ 92228753Smm read_archive(bsdtar, 'x'); 93228753Smm 94228753Smm if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0) 95228753Smm bsdtar->return_value = 1; 96228753Smm} 97228753Smm 98228753Smmstatic void 99228753Smmprogress_func(void *cookie) 100228753Smm{ 101228753Smm struct progress_data *progress_data = cookie; 102228753Smm struct bsdtar *bsdtar = progress_data->bsdtar; 103228753Smm struct archive *a = progress_data->archive; 104228753Smm struct archive_entry *entry = progress_data->entry; 105228753Smm uint64_t comp, uncomp; 106228753Smm 107228753Smm if (!need_report()) 108228753Smm return; 109228753Smm 110228753Smm if (bsdtar->verbose) 111228753Smm fprintf(stderr, "\n"); 112228753Smm if (a != NULL) { 113228753Smm comp = archive_position_compressed(a); 114228753Smm uncomp = archive_position_uncompressed(a); 115228753Smm fprintf(stderr, 116228753Smm "In: %s bytes, compression %d%%;", 117228753Smm tar_i64toa(comp), (int)((uncomp - comp) * 100 / uncomp)); 118228753Smm fprintf(stderr, " Out: %d files, %s bytes\n", 119228753Smm archive_file_count(a), tar_i64toa(uncomp)); 120228753Smm } 121228753Smm if (entry != NULL) { 122228753Smm safe_fprintf(stderr, "Current: %s", 123228753Smm archive_entry_pathname(entry)); 124228753Smm fprintf(stderr, " (%s bytes)\n", 125228753Smm tar_i64toa(archive_entry_size(entry))); 126228753Smm } 127228753Smm} 128228753Smm 129228753Smm/* 130228753Smm * Handle 'x' and 't' modes. 131228753Smm */ 132228753Smmstatic void 133228753Smmread_archive(struct bsdtar *bsdtar, char mode) 134228753Smm{ 135228753Smm struct progress_data progress_data; 136228753Smm FILE *out; 137228753Smm struct archive *a; 138228753Smm struct archive_entry *entry; 139228753Smm const struct stat *st; 140228753Smm int r; 141228753Smm 142228753Smm while (*bsdtar->argv) { 143228753Smm lafe_include(&bsdtar->matching, *bsdtar->argv); 144228753Smm bsdtar->argv++; 145228753Smm } 146228753Smm 147228753Smm if (bsdtar->names_from_file != NULL) 148228753Smm lafe_include_from_file(&bsdtar->matching, 149228753Smm bsdtar->names_from_file, bsdtar->option_null); 150228753Smm 151228753Smm a = archive_read_new(); 152228753Smm if (bsdtar->compress_program != NULL) 153228753Smm archive_read_support_compression_program(a, bsdtar->compress_program); 154228753Smm else 155228753Smm archive_read_support_compression_all(a); 156228753Smm archive_read_support_format_all(a); 157228753Smm if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options)) 158228753Smm lafe_errc(1, 0, "%s", archive_error_string(a)); 159228753Smm if (archive_read_open_file(a, bsdtar->filename, 160228753Smm bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : 161228753Smm DEFAULT_BYTES_PER_BLOCK)) 162228753Smm lafe_errc(1, 0, "Error opening archive: %s", 163228753Smm archive_error_string(a)); 164228753Smm 165228753Smm do_chdir(bsdtar); 166228753Smm 167228753Smm if (mode == 'x') { 168228753Smm /* Set an extract callback so that we can handle SIGINFO. */ 169228753Smm progress_data.bsdtar = bsdtar; 170228753Smm progress_data.archive = a; 171228753Smm archive_read_extract_set_progress_callback(a, progress_func, 172228753Smm &progress_data); 173228753Smm } 174228753Smm 175228753Smm if (mode == 'x' && bsdtar->option_chroot) { 176228753Smm#if HAVE_CHROOT 177228753Smm if (chroot(".") != 0) 178228753Smm lafe_errc(1, errno, "Can't chroot to \".\""); 179228753Smm#else 180228753Smm lafe_errc(1, 0, 181228753Smm "chroot isn't supported on this platform"); 182228753Smm#endif 183228753Smm } 184228753Smm 185228753Smm for (;;) { 186228753Smm /* Support --fast-read option */ 187228753Smm if (bsdtar->option_fast_read && 188228753Smm lafe_unmatched_inclusions(bsdtar->matching) == 0) 189228753Smm break; 190228753Smm 191228753Smm r = archive_read_next_header(a, &entry); 192228753Smm progress_data.entry = entry; 193228753Smm if (r == ARCHIVE_EOF) 194228753Smm break; 195228753Smm if (r < ARCHIVE_OK) 196228753Smm lafe_warnc(0, "%s", archive_error_string(a)); 197228753Smm if (r <= ARCHIVE_WARN) 198228753Smm bsdtar->return_value = 1; 199228753Smm if (r == ARCHIVE_RETRY) { 200228753Smm /* Retryable error: try again */ 201228753Smm lafe_warnc(0, "Retrying..."); 202228753Smm continue; 203228753Smm } 204228753Smm if (r == ARCHIVE_FATAL) 205228753Smm break; 206228753Smm 207228753Smm if (bsdtar->uid >= 0) { 208228753Smm archive_entry_set_uid(entry, bsdtar->uid); 209228753Smm archive_entry_set_uname(entry, NULL); 210228753Smm } 211228753Smm if (bsdtar->gid >= 0) { 212228753Smm archive_entry_set_gid(entry, bsdtar->gid); 213228753Smm archive_entry_set_gname(entry, NULL); 214228753Smm } 215228753Smm if (bsdtar->uname) 216228753Smm archive_entry_set_uname(entry, bsdtar->uname); 217228753Smm if (bsdtar->gname >= 0) 218228753Smm archive_entry_set_gname(entry, bsdtar->gname); 219228753Smm 220228753Smm /* 221228753Smm * Exclude entries that are too old. 222228753Smm */ 223228753Smm st = archive_entry_stat(entry); 224228753Smm if (bsdtar->newer_ctime_sec > 0) { 225228753Smm if (st->st_ctime < bsdtar->newer_ctime_sec) 226228753Smm continue; /* Too old, skip it. */ 227228753Smm if (st->st_ctime == bsdtar->newer_ctime_sec 228228753Smm && ARCHIVE_STAT_CTIME_NANOS(st) 229228753Smm <= bsdtar->newer_ctime_nsec) 230228753Smm continue; /* Too old, skip it. */ 231228753Smm } 232228753Smm if (bsdtar->newer_mtime_sec > 0) { 233228753Smm if (st->st_mtime < bsdtar->newer_mtime_sec) 234228753Smm continue; /* Too old, skip it. */ 235228753Smm if (st->st_mtime == bsdtar->newer_mtime_sec 236228753Smm && ARCHIVE_STAT_MTIME_NANOS(st) 237228753Smm <= bsdtar->newer_mtime_nsec) 238228753Smm continue; /* Too old, skip it. */ 239228753Smm } 240228753Smm 241228753Smm /* 242228753Smm * Note that pattern exclusions are checked before 243228753Smm * pathname rewrites are handled. This gives more 244228753Smm * control over exclusions, since rewrites always lose 245228753Smm * information. (For example, consider a rewrite 246228753Smm * s/foo[0-9]/foo/. If we check exclusions after the 247228753Smm * rewrite, there would be no way to exclude foo1/bar 248228753Smm * while allowing foo2/bar.) 249228753Smm */ 250228753Smm if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry))) 251228753Smm continue; /* Excluded by a pattern test. */ 252228753Smm 253228753Smm if (mode == 't') { 254228753Smm /* Perversely, gtar uses -O to mean "send to stderr" 255228753Smm * when used with -t. */ 256228753Smm out = bsdtar->option_stdout ? stderr : stdout; 257228753Smm 258228753Smm /* 259228753Smm * TODO: Provide some reasonable way to 260228753Smm * preview rewrites. gtar always displays 261228753Smm * the unedited path in -t output, which means 262228753Smm * you cannot easily preview rewrites. 263228753Smm */ 264228753Smm if (bsdtar->verbose < 2) 265228753Smm safe_fprintf(out, "%s", 266228753Smm archive_entry_pathname(entry)); 267228753Smm else 268228753Smm list_item_verbose(bsdtar, out, entry); 269228753Smm fflush(out); 270228753Smm r = archive_read_data_skip(a); 271228753Smm if (r == ARCHIVE_WARN) { 272228753Smm fprintf(out, "\n"); 273228753Smm lafe_warnc(0, "%s", 274228753Smm archive_error_string(a)); 275228753Smm } 276228753Smm if (r == ARCHIVE_RETRY) { 277228753Smm fprintf(out, "\n"); 278228753Smm lafe_warnc(0, "%s", 279228753Smm archive_error_string(a)); 280228753Smm } 281228753Smm if (r == ARCHIVE_FATAL) { 282228753Smm fprintf(out, "\n"); 283228753Smm lafe_warnc(0, "%s", 284228753Smm archive_error_string(a)); 285228753Smm bsdtar->return_value = 1; 286228753Smm break; 287228753Smm } 288228753Smm fprintf(out, "\n"); 289228753Smm } else { 290228753Smm /* Note: some rewrite failures prevent extraction. */ 291228753Smm if (edit_pathname(bsdtar, entry)) 292228753Smm continue; /* Excluded by a rewrite failure. */ 293228753Smm 294228753Smm if (bsdtar->option_interactive && 295228753Smm !yes("extract '%s'", archive_entry_pathname(entry))) 296228753Smm continue; 297228753Smm 298228753Smm /* 299228753Smm * Format here is from SUSv2, including the 300228753Smm * deferred '\n'. 301228753Smm */ 302228753Smm if (bsdtar->verbose) { 303228753Smm safe_fprintf(stderr, "x %s", 304228753Smm archive_entry_pathname(entry)); 305228753Smm fflush(stderr); 306228753Smm } 307228753Smm 308228753Smm // TODO siginfo_printinfo(bsdtar, 0); 309228753Smm 310228753Smm if (bsdtar->option_stdout) 311228753Smm r = archive_read_data_into_fd(a, 1); 312228753Smm else 313228753Smm r = archive_read_extract(a, entry, 314228753Smm bsdtar->extract_flags); 315228753Smm if (r != ARCHIVE_OK) { 316228753Smm if (!bsdtar->verbose) 317228753Smm safe_fprintf(stderr, "%s", 318228753Smm archive_entry_pathname(entry)); 319228753Smm safe_fprintf(stderr, ": %s", 320228753Smm archive_error_string(a)); 321228753Smm if (!bsdtar->verbose) 322228753Smm fprintf(stderr, "\n"); 323228753Smm bsdtar->return_value = 1; 324228753Smm } 325228753Smm if (bsdtar->verbose) 326228753Smm fprintf(stderr, "\n"); 327228753Smm if (r == ARCHIVE_FATAL) 328228753Smm break; 329228753Smm } 330228753Smm } 331228753Smm 332228753Smm 333228753Smm r = archive_read_close(a); 334228753Smm if (r != ARCHIVE_OK) 335228753Smm lafe_warnc(0, "%s", archive_error_string(a)); 336228753Smm if (r <= ARCHIVE_WARN) 337228753Smm bsdtar->return_value = 1; 338228753Smm 339228753Smm if (bsdtar->verbose > 2) 340228753Smm fprintf(stdout, "Archive Format: %s, Compression: %s\n", 341228753Smm archive_format_name(a), archive_compression_name(a)); 342228753Smm 343228753Smm archive_read_finish(a); 344228753Smm} 345228753Smm 346228753Smm 347228753Smm/* 348228753Smm * Display information about the current file. 349228753Smm * 350228753Smm * The format here roughly duplicates the output of 'ls -l'. 351228753Smm * This is based on SUSv2, where 'tar tv' is documented as 352228753Smm * listing additional information in an "unspecified format," 353228753Smm * and 'pax -l' is documented as using the same format as 'ls -l'. 354228753Smm */ 355228753Smmstatic void 356228753Smmlist_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) 357228753Smm{ 358228753Smm char tmp[100]; 359228753Smm size_t w; 360228753Smm const char *p; 361228753Smm const char *fmt; 362228753Smm time_t tim; 363228753Smm static time_t now; 364228753Smm 365228753Smm /* 366228753Smm * We avoid collecting the entire list in memory at once by 367228753Smm * listing things as we see them. However, that also means we can't 368228753Smm * just pre-compute the field widths. Instead, we start with guesses 369228753Smm * and just widen them as necessary. These numbers are completely 370228753Smm * arbitrary. 371228753Smm */ 372228753Smm if (!bsdtar->u_width) { 373228753Smm bsdtar->u_width = 6; 374228753Smm bsdtar->gs_width = 13; 375228753Smm } 376228753Smm if (!now) 377228753Smm time(&now); 378228753Smm fprintf(out, "%s %d ", 379228753Smm archive_entry_strmode(entry), 380228753Smm archive_entry_nlink(entry)); 381228753Smm 382228753Smm /* Use uname if it's present, else uid. */ 383228753Smm p = archive_entry_uname(entry); 384228753Smm if ((p == NULL) || (*p == '\0')) { 385228753Smm sprintf(tmp, "%lu ", 386228753Smm (unsigned long)archive_entry_uid(entry)); 387228753Smm p = tmp; 388228753Smm } 389228753Smm w = strlen(p); 390228753Smm if (w > bsdtar->u_width) 391228753Smm bsdtar->u_width = w; 392228753Smm fprintf(out, "%-*s ", (int)bsdtar->u_width, p); 393228753Smm 394228753Smm /* Use gname if it's present, else gid. */ 395228753Smm p = archive_entry_gname(entry); 396228753Smm if (p != NULL && p[0] != '\0') { 397228753Smm fprintf(out, "%s", p); 398228753Smm w = strlen(p); 399228753Smm } else { 400228753Smm sprintf(tmp, "%lu", 401228753Smm (unsigned long)archive_entry_gid(entry)); 402228753Smm w = strlen(tmp); 403228753Smm fprintf(out, "%s", tmp); 404228753Smm } 405228753Smm 406228753Smm /* 407228753Smm * Print device number or file size, right-aligned so as to make 408228753Smm * total width of group and devnum/filesize fields be gs_width. 409228753Smm * If gs_width is too small, grow it. 410228753Smm */ 411228753Smm if (archive_entry_filetype(entry) == AE_IFCHR 412228753Smm || archive_entry_filetype(entry) == AE_IFBLK) { 413228753Smm sprintf(tmp, "%lu,%lu", 414228753Smm (unsigned long)archive_entry_rdevmajor(entry), 415228753Smm (unsigned long)archive_entry_rdevminor(entry)); 416228753Smm } else { 417228753Smm strcpy(tmp, tar_i64toa(archive_entry_size(entry))); 418228753Smm } 419228753Smm if (w + strlen(tmp) >= bsdtar->gs_width) 420228753Smm bsdtar->gs_width = w+strlen(tmp)+1; 421228753Smm fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp); 422228753Smm 423228753Smm /* Format the time using 'ls -l' conventions. */ 424228753Smm tim = archive_entry_mtime(entry); 425228753Smm#define HALF_YEAR (time_t)365 * 86400 / 2 426228753Smm#if defined(_WIN32) && !defined(__CYGWIN__) 427228753Smm#define DAY_FMT "%d" /* Windows' strftime function does not support %e format. */ 428228753Smm#else 429228753Smm#define DAY_FMT "%e" /* Day number without leading zeros */ 430228753Smm#endif 431228753Smm if (tim < now - HALF_YEAR || tim > now + HALF_YEAR) 432228753Smm fmt = bsdtar->day_first ? DAY_FMT " %b %Y" : "%b " DAY_FMT " %Y"; 433228753Smm else 434228753Smm fmt = bsdtar->day_first ? DAY_FMT " %b %H:%M" : "%b " DAY_FMT " %H:%M"; 435228753Smm strftime(tmp, sizeof(tmp), fmt, localtime(&tim)); 436228753Smm fprintf(out, " %s ", tmp); 437228753Smm safe_fprintf(out, "%s", archive_entry_pathname(entry)); 438228753Smm 439228753Smm /* Extra information for links. */ 440228753Smm if (archive_entry_hardlink(entry)) /* Hard link */ 441228753Smm safe_fprintf(out, " link to %s", 442228753Smm archive_entry_hardlink(entry)); 443228753Smm else if (archive_entry_symlink(entry)) /* Symbolic link */ 444228753Smm safe_fprintf(out, " -> %s", archive_entry_symlink(entry)); 445228753Smm} 446