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#include <sys/queue.h> 68#include <copyfile.h> 69#include <fcntl.h> 70#include <libgen.h> 71 72#include <TargetConditionals.h> 73#if TARGET_OS_MAC && !TARGET_OS_IPHONE 74#define HAVE_QUARANTINE 1 75#endif /* TARGET_OS_MAC */ 76 77#ifdef HAVE_QUARANTINE 78#include <quarantine.h> 79#endif /* HAVE_QUARANTINE */ 80 81#include "bsdtar.h" 82#include "err.h" 83 84struct progress_data { 85 struct bsdtar *bsdtar; 86 struct archive *archive; 87 struct archive_entry *entry; 88}; 89 90struct copyfile_list_entry_t { 91 char *src; 92 char *dst; 93 char *tmp; 94 LIST_ENTRY(copyfile_list_entry_t) link; 95}; 96 97static void list_item_verbose(struct bsdtar *, FILE *, 98 struct archive_entry *); 99static void read_archive(struct bsdtar *bsdtar, char mode); 100 101void 102tar_mode_t(struct bsdtar *bsdtar) 103{ 104 read_archive(bsdtar, 't'); 105 if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0) 106 bsdtar->return_value = 1; 107} 108 109void 110tar_mode_x(struct bsdtar *bsdtar) 111{ 112 read_archive(bsdtar, 'x'); 113 114 if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0) 115 bsdtar->return_value = 1; 116} 117 118static void 119progress_func(void *cookie) 120{ 121 struct progress_data *progress_data = cookie; 122 struct bsdtar *bsdtar = progress_data->bsdtar; 123 struct archive *a = progress_data->archive; 124 struct archive_entry *entry = progress_data->entry; 125 uint64_t comp, uncomp; 126 127 if (!need_report()) 128 return; 129 130 if (bsdtar->verbose) 131 fprintf(stderr, "\n"); 132 if (a != NULL) { 133 comp = archive_position_compressed(a); 134 uncomp = archive_position_uncompressed(a); 135 fprintf(stderr, 136 "In: %s bytes, compression %d%%;", 137 tar_i64toa(comp), (int)((uncomp - comp) * 100 / uncomp)); 138 fprintf(stderr, " Out: %d files, %s bytes\n", 139 archive_file_count(a), tar_i64toa(uncomp)); 140 } 141 if (entry != NULL) { 142 safe_fprintf(stderr, "Current: %s", 143 archive_entry_pathname(entry)); 144 fprintf(stderr, " (%s bytes)\n", 145 tar_i64toa(archive_entry_size(entry))); 146 } 147} 148 149#ifdef HAVE_QUARANTINE 150void 151_qtnapply(struct bsdtar *bsdtar, qtn_file_t qf, char *path) 152{ 153 int stat_ok; 154 struct stat sb; 155 int qstatus; 156 157 if (qf == NULL) 158 return; 159 160 stat_ok = (stat(path, &sb) == 0); 161 162 if (stat_ok) chmod(path, sb.st_mode | S_IWUSR); 163 qstatus = qtn_file_apply_to_path(qf, path); 164 if (stat_ok) chmod(path, sb.st_mode); 165 166 if (qstatus) 167 lafe_warnc(0, "qtn_file_apply_to_path(%s): %s", path, qtn_error(qstatus)); 168} 169#endif /* HAVE_QUARANTINE */ 170 171/* 172 * Handle 'x' and 't' modes. 173 */ 174static void 175read_archive(struct bsdtar *bsdtar, char mode) 176{ 177 struct progress_data progress_data; 178 FILE *out; 179 struct archive *a; 180 struct archive_entry *entry; 181 const struct stat *st; 182 int r; 183#ifdef HAVE_QUARANTINE 184 qtn_file_t qf = NULL; 185#endif /* HAVE_QUARANTINE */ 186 LIST_HEAD(copyfile_list_t, copyfile_list_entry_t) copyfile_list; 187 struct copyfile_list_entry_t *cle; 188 189 LIST_INIT(©file_list); 190 191 while (*bsdtar->argv) { 192 lafe_include(&bsdtar->matching, *bsdtar->argv); 193 bsdtar->argv++; 194 } 195 196 if (bsdtar->names_from_file != NULL) 197 lafe_include_from_file(&bsdtar->matching, 198 bsdtar->names_from_file, bsdtar->option_null); 199 200 a = archive_read_new(); 201 if (bsdtar->compress_program != NULL) 202 archive_read_support_compression_program(a, bsdtar->compress_program); 203 else 204 archive_read_support_compression_all(a); 205 archive_read_support_format_all(a); 206 if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options)) 207 lafe_errc(1, 0, "%s", archive_error_string(a)); 208 if (archive_read_open_file(a, bsdtar->filename, 209 bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : 210 DEFAULT_BYTES_PER_BLOCK)) 211 lafe_errc(1, 0, "Error opening archive: %s", 212 archive_error_string(a)); 213 214 do_chdir(bsdtar); 215 216 if (mode == 'x') { 217 /* Set an extract callback so that we can handle SIGINFO. */ 218 progress_data.bsdtar = bsdtar; 219 progress_data.archive = a; 220 archive_read_extract_set_progress_callback(a, progress_func, 221 &progress_data); 222 } 223 224 if (mode == 'x' && bsdtar->option_chroot) { 225#if HAVE_CHROOT 226 if (chroot(".") != 0) 227 lafe_errc(1, errno, "Can't chroot to \".\""); 228#else 229 lafe_errc(1, 0, 230 "chroot isn't supported on this platform"); 231#endif 232 } 233 234#ifdef HAVE_QUARANTINE 235 if (mode == 'x' && bsdtar->filename != NULL && !bsdtar->option_stdout) { 236 if ((qf = qtn_file_alloc()) != NULL) { 237 int qstatus = qtn_file_init_with_path(qf, bsdtar->filename); 238 if (qstatus != 0) { 239 qtn_file_free(qf); 240 qf = NULL; 241 } 242 } 243 } 244#endif /* HAVE_QUARANTINE */ 245 246 for (;;) { 247 /* Support --fast-read option */ 248 if (bsdtar->option_fast_read && 249 lafe_unmatched_inclusions(bsdtar->matching) == 0) 250 break; 251 252 r = archive_read_next_header(a, &entry); 253 progress_data.entry = entry; 254 if (r == ARCHIVE_EOF) 255 break; 256 if (r < ARCHIVE_OK) 257 lafe_warnc(0, "%s", archive_error_string(a)); 258 if (r <= ARCHIVE_WARN) 259 bsdtar->return_value = 1; 260 if (r == ARCHIVE_RETRY) { 261 /* Retryable error: try again */ 262 lafe_warnc(0, "Retrying..."); 263 continue; 264 } 265 if (r == ARCHIVE_FATAL) 266 break; 267 268 if (bsdtar->option_numeric_owner) { 269 archive_entry_set_uname(entry, NULL); 270 archive_entry_set_gname(entry, NULL); 271 } 272 273 /* 274 * Exclude entries that are too old. 275 */ 276 st = archive_entry_stat(entry); 277 if (bsdtar->newer_ctime_sec > 0) { 278 if (st->st_ctime < bsdtar->newer_ctime_sec) 279 continue; /* Too old, skip it. */ 280 if (st->st_ctime == bsdtar->newer_ctime_sec 281 && ARCHIVE_STAT_CTIME_NANOS(st) 282 <= bsdtar->newer_ctime_nsec) 283 continue; /* Too old, skip it. */ 284 } 285 if (bsdtar->newer_mtime_sec > 0) { 286 if (st->st_mtime < bsdtar->newer_mtime_sec) 287 continue; /* Too old, skip it. */ 288 if (st->st_mtime == bsdtar->newer_mtime_sec 289 && ARCHIVE_STAT_MTIME_NANOS(st) 290 <= bsdtar->newer_mtime_nsec) 291 continue; /* Too old, skip it. */ 292 } 293 294 /* 295 * Note that pattern exclusions are checked before 296 * pathname rewrites are handled. This gives more 297 * control over exclusions, since rewrites always lose 298 * information. (For example, consider a rewrite 299 * s/foo[0-9]/foo/. If we check exclusions after the 300 * rewrite, there would be no way to exclude foo1/bar 301 * while allowing foo2/bar.) 302 */ 303 if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry))) 304 continue; /* Excluded by a pattern test. */ 305 306 if (mode == 't') { 307 /* Perversely, gtar uses -O to mean "send to stderr" 308 * when used with -t. */ 309 out = bsdtar->option_stdout ? stderr : stdout; 310 311 /* 312 * TODO: Provide some reasonable way to 313 * preview rewrites. gtar always displays 314 * the unedited path in -t output, which means 315 * you cannot easily preview rewrites. 316 */ 317 if (bsdtar->verbose < 2) 318 safe_fprintf(out, "%s", 319 archive_entry_pathname(entry)); 320 else 321 list_item_verbose(bsdtar, out, entry); 322 fflush(out); 323 r = archive_read_data_skip(a); 324 if (r == ARCHIVE_WARN) { 325 fprintf(out, "\n"); 326 lafe_warnc(0, "%s", 327 archive_error_string(a)); 328 } 329 if (r == ARCHIVE_RETRY) { 330 fprintf(out, "\n"); 331 lafe_warnc(0, "%s", 332 archive_error_string(a)); 333 } 334 if (r == ARCHIVE_FATAL) { 335 fprintf(out, "\n"); 336 lafe_warnc(0, "%s", 337 archive_error_string(a)); 338 bsdtar->return_value = 1; 339 break; 340 } 341 fprintf(out, "\n"); 342 } else { 343 /* Note: some rewrite failures prevent extraction. */ 344 if (edit_pathname(bsdtar, entry)) 345 continue; /* Excluded by a rewrite failure. */ 346 347 if (bsdtar->option_interactive && 348 !yes("extract '%s'", archive_entry_pathname(entry))) 349 continue; 350 351 /* 352 * Format here is from SUSv2, including the 353 * deferred '\n'. 354 */ 355 if (bsdtar->verbose) { 356 safe_fprintf(stderr, "x %s", 357 archive_entry_pathname(entry)); 358 fflush(stderr); 359 } 360 361 // TODO siginfo_printinfo(bsdtar, 0); 362 363 if (bsdtar->option_stdout) 364 r = archive_read_data_into_fd(a, 1); 365 else { 366 /* do this even if disable_copyfile is set, because it can get blown away by its associated real file */ 367 if (strncmp(basename((char *)archive_entry_pathname(entry)), "._", 2) == 0) { 368 cle = calloc(1, sizeof(struct copyfile_list_entry_t)); 369 cle->src = strdup(archive_entry_pathname(entry)); 370 asprintf(&cle->tmp, "%s.XXXXXX", cle->src); 371 mktemp(cle->tmp); 372 asprintf(&cle->dst, "%s/%s", dirname(cle->src), basename(cle->src) + 2); 373 LIST_INSERT_HEAD(©file_list, cle, link); 374 archive_entry_set_pathname(entry, cle->tmp); 375 } 376 r = archive_read_extract(a, entry, 377 bsdtar->extract_flags); 378#ifdef HAVE_QUARANTINE 379 if (r == ARCHIVE_OK) { 380 _qtnapply(bsdtar, qf, (char *)archive_entry_pathname(entry)); 381 } 382#endif /* HAVE_QUARANTINE */ 383 } 384 if (r != ARCHIVE_OK) { 385 if (!bsdtar->verbose) 386 safe_fprintf(stderr, "%s", 387 archive_entry_pathname(entry)); 388 safe_fprintf(stderr, ": %s", 389 archive_error_string(a)); 390 if (!bsdtar->verbose) 391 fprintf(stderr, "\n"); 392 bsdtar->return_value = 1; 393 } 394 if (bsdtar->verbose) 395 fprintf(stderr, "\n"); 396 if (r == ARCHIVE_FATAL) 397 break; 398 } 399 } 400 401 402 r = archive_read_close(a); 403 if (r != ARCHIVE_OK) 404 lafe_warnc(0, "%s", archive_error_string(a)); 405 if (r <= ARCHIVE_WARN) 406 bsdtar->return_value = 1; 407 408 LIST_FOREACH(cle, ©file_list, link) { 409 if (!bsdtar->disable_copyfile && copyfile(cle->tmp, cle->dst, 0, COPYFILE_UNPACK | COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR) == 0) { 410 unlink(cle->tmp); 411#ifdef HAVE_QUARANTINE 412 _qtnapply(bsdtar, qf, cle->dst); 413#endif /* HAVE_QUARANTINE */ 414 } else { 415 if (!bsdtar->disable_copyfile) 416 lafe_warnc(errno, "copyfile unpack (%s) failed", cle->dst); 417 rename(cle->tmp, cle->src); 418#ifdef HAVE_QUARANTINE 419 _qtnapply(bsdtar, qf, cle->src); 420#endif /* HAVE_QUARANTINE */ 421 } 422 } 423 424 if (bsdtar->verbose > 2) 425 fprintf(stdout, "Archive Format: %s, Compression: %s\n", 426 archive_format_name(a), archive_compression_name(a)); 427 428 archive_read_finish(a); 429 430#ifdef HAVE_QUARANTINE 431 if (qf != NULL) { 432 qtn_file_free(qf); 433 qf = NULL; 434 } 435#endif /* HAVE_QUARANTINE */ 436} 437 438 439/* 440 * Display information about the current file. 441 * 442 * The format here roughly duplicates the output of 'ls -l'. 443 * This is based on SUSv2, where 'tar tv' is documented as 444 * listing additional information in an "unspecified format," 445 * and 'pax -l' is documented as using the same format as 'ls -l'. 446 */ 447static void 448list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) 449{ 450 char tmp[100]; 451 size_t w; 452 const char *p; 453 const char *fmt; 454 time_t tim; 455 static time_t now; 456 457 /* 458 * We avoid collecting the entire list in memory at once by 459 * listing things as we see them. However, that also means we can't 460 * just pre-compute the field widths. Instead, we start with guesses 461 * and just widen them as necessary. These numbers are completely 462 * arbitrary. 463 */ 464 if (!bsdtar->u_width) { 465 bsdtar->u_width = 6; 466 bsdtar->gs_width = 13; 467 } 468 if (!now) 469 time(&now); 470 fprintf(out, "%s %d ", 471 archive_entry_strmode(entry), 472 archive_entry_nlink(entry)); 473 474 /* Use uname if it's present, else uid. */ 475 p = archive_entry_uname(entry); 476 if ((p == NULL) || (*p == '\0')) { 477 sprintf(tmp, "%lu ", 478 (unsigned long)archive_entry_uid(entry)); 479 p = tmp; 480 } 481 w = strlen(p); 482 if (w > bsdtar->u_width) 483 bsdtar->u_width = w; 484 fprintf(out, "%-*s ", (int)bsdtar->u_width, p); 485 486 /* Use gname if it's present, else gid. */ 487 p = archive_entry_gname(entry); 488 if (p != NULL && p[0] != '\0') { 489 fprintf(out, "%s", p); 490 w = strlen(p); 491 } else { 492 sprintf(tmp, "%lu", 493 (unsigned long)archive_entry_gid(entry)); 494 w = strlen(tmp); 495 fprintf(out, "%s", tmp); 496 } 497 498 /* 499 * Print device number or file size, right-aligned so as to make 500 * total width of group and devnum/filesize fields be gs_width. 501 * If gs_width is too small, grow it. 502 */ 503 if (archive_entry_filetype(entry) == AE_IFCHR 504 || archive_entry_filetype(entry) == AE_IFBLK) { 505 sprintf(tmp, "%lu,%lu", 506 (unsigned long)archive_entry_rdevmajor(entry), 507 (unsigned long)archive_entry_rdevminor(entry)); 508 } else { 509 strcpy(tmp, tar_i64toa(archive_entry_size(entry))); 510 } 511 if (w + strlen(tmp) >= bsdtar->gs_width) 512 bsdtar->gs_width = w+strlen(tmp)+1; 513 fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp); 514 515 /* Format the time using 'ls -l' conventions. */ 516 tim = archive_entry_mtime(entry); 517#define HALF_YEAR (time_t)365 * 86400 / 2 518#if defined(_WIN32) && !defined(__CYGWIN__) 519#define DAY_FMT "%d" /* Windows' strftime function does not support %e format. */ 520#else 521#define DAY_FMT "%e" /* Day number without leading zeros */ 522#endif 523 if (tim < now - HALF_YEAR || tim > now + HALF_YEAR) 524 fmt = bsdtar->day_first ? DAY_FMT " %b %Y" : "%b " DAY_FMT " %Y"; 525 else 526 fmt = bsdtar->day_first ? DAY_FMT " %b %H:%M" : "%b " DAY_FMT " %H:%M"; 527 strftime(tmp, sizeof(tmp), fmt, localtime(&tim)); 528 fprintf(out, " %s ", tmp); 529 safe_fprintf(out, "%s", archive_entry_pathname(entry)); 530 531 /* Extra information for links. */ 532 if (archive_entry_hardlink(entry)) /* Hard link */ 533 safe_fprintf(out, " link to %s", 534 archive_entry_hardlink(entry)); 535 else if (archive_entry_symlink(entry)) /* Symbolic link */ 536 safe_fprintf(out, " -> %s", archive_entry_symlink(entry)); 537} 538