Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/archival/tar.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/archival/tar.c
r1765 r2725 4 4 * 5 5 * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg 6 * Glenn McGrath <bug1@iinet.net.au>6 * by Glenn McGrath 7 7 * 8 8 * Note, that as of BusyBox-0.43, tar has been completely rewritten from the … … 16 16 * Permission is granted to use, distribute, or modify this source, 17 17 * provided that this copyright notice remains intact. 18 * Permission to distribute sash derived code under theGPL has been granted.18 * Permission to distribute sash derived code under GPL has been granted. 19 19 * 20 20 * Based in part on the tar implementation from busybox-0.28 21 21 * Copyright (C) 1995 Bruce Perens 22 22 * 23 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.23 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 24 24 */ 25 25 26 26 #include <fnmatch.h> 27 #include <getopt.h>28 27 #include "libbb.h" 29 #include "unarchive.h" 28 #include "archive.h" 29 /* FIXME: Stop using this non-standard feature */ 30 #ifndef FNM_LEADING_DIR 31 # define FNM_LEADING_DIR 0 32 #endif 33 34 35 //#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) 36 #define DBG(...) ((void)0) 37 30 38 31 39 #define block_buf bb_common_bufsiz1 32 40 41 42 #if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2 43 /* Do not pass gzip flag to writeTarFile() */ 44 #define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \ 45 writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude) 46 #endif 47 48 33 49 #if ENABLE_FEATURE_TAR_CREATE 34 35 /* Tar file constants */36 37 #define TAR_BLOCK_SIZE 51238 39 /* POSIX tar Header Block, from POSIX 1003.1-1990 */40 #define NAME_SIZE 10041 #define NAME_SIZE_STR "100"42 typedef struct TarHeader TarHeader;43 struct TarHeader { /* byte offset */44 char name[NAME_SIZE]; /* 0-99 */45 char mode[8]; /* 100-107 */46 char uid[8]; /* 108-115 */47 char gid[8]; /* 116-123 */48 char size[12]; /* 124-135 */49 char mtime[12]; /* 136-147 */50 char chksum[8]; /* 148-155 */51 char typeflag; /* 156-156 */52 char linkname[NAME_SIZE]; /* 157-256 */53 char magic[6]; /* 257-262 */54 char version[2]; /* 263-264 */55 char uname[32]; /* 265-296 */56 char gname[32]; /* 297-328 */57 char devmajor[8]; /* 329-336 */58 char devminor[8]; /* 337-344 */59 char prefix[155]; /* 345-499 */60 char padding[12]; /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */61 };62 50 63 51 /* … … 66 54 ** Even these functions use the xxxHardLinkInfo() functions. 67 55 */ 68 typedef struct HardLinkInfo HardLinkInfo; 69 struct HardLinkInfo { 70 HardLinkInfo *next; /* Next entry in list */ 71 dev_t dev; /* Device number */ 72 ino_t ino; /* Inode number */ 73 short linkCount; /* (Hard) Link Count */ 74 char name[1]; /* Start of filename (must be last) */ 75 }; 56 typedef struct HardLinkInfo { 57 struct HardLinkInfo *next; /* Next entry in list */ 58 dev_t dev; /* Device number */ 59 ino_t ino; /* Inode number */ 60 // short linkCount; /* (Hard) Link Count */ 61 char name[1]; /* Start of filename (must be last) */ 62 } HardLinkInfo; 76 63 77 64 /* Some info to be carried along when creating a new tarball */ 78 typedef struct TarBallInfo TarBallInfo;79 struct TarBallInfo { 80 int tarFd; /* Open-for-write file descriptor81 for the tarball*/82 struct stat statBuf; /* Stat info for the tarball, letting83 us know the inode and device that the84 tarball lives, so we can avoid trying85 to include the tarball into itself */ 86 int verboseFlag; /* Whether to print extra stuff or not */87 const llist_t *excludeList; /* List of files to not include */88 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */89 HardLinkInfo *hlInfo; /* Hard Link Info for the current file*/90 } ;65 typedef struct TarBallInfo { 66 int tarFd; /* Open-for-write file descriptor 67 * for the tarball */ 68 int verboseFlag; /* Whether to print extra stuff or not */ 69 const llist_t *excludeList; /* List of files to not include */ 70 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ 71 HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ 72 //TODO: save only st_dev + st_ino 73 struct stat tarFileStatBuf; /* Stat info for the tarball, letting 74 * us know the inode and device that the 75 * tarball lives, so we can avoid trying 76 * to include the tarball into itself */ 77 } TarBallInfo; 91 78 92 79 /* A nice enum with all the possible tar file content types */ 93 enum TarFileType{80 enum { 94 81 REGTYPE = '0', /* regular file */ 95 82 REGTYPE0 = '\0', /* regular file (ancient bug compat) */ … … 104 91 GNULONGNAME = 'L', /* GNU long (>100 chars) file name */ 105 92 }; 106 typedef enum TarFileType TarFileType;107 93 108 94 /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ 109 static void addHardLinkInfo(HardLinkInfo ** 95 static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr, 110 96 struct stat *statbuf, 111 97 const char *fileName) … … 119 105 hlInfo->dev = statbuf->st_dev; 120 106 hlInfo->ino = statbuf->st_ino; 121 hlInfo->linkCount = statbuf->st_nlink;107 // hlInfo->linkCount = statbuf->st_nlink; 122 108 strcpy(hlInfo->name, fileName); 123 109 } 124 110 125 static void freeHardLinkInfo(HardLinkInfo ** 111 static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr) 126 112 { 127 113 HardLinkInfo *hlInfo; … … 139 125 } 140 126 141 /* Might be faster (and bigger) if the dev/ino were stored in numeric order ;) */142 static HardLinkInfo *findHardLinkInfo(HardLinkInfo * 127 /* Might be faster (and bigger) if the dev/ino were stored in numeric order ;) */ 128 static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf) 143 129 { 144 130 while (hlInfo) { 145 if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev)) 131 if (statbuf->st_ino == hlInfo->ino 132 && statbuf->st_dev == hlInfo->dev 133 ) { 134 DBG("found hardlink:'%s'", hlInfo->name); 146 135 break; 136 } 147 137 hlInfo = hlInfo->next; 148 138 } … … 155 145 static void putOctal(char *cp, int len, off_t value) 156 146 { 157 char tempBuffer[sizeof(off_t)*3 +1];147 char tempBuffer[sizeof(off_t)*3 + 1]; 158 148 char *tempString = tempBuffer; 159 149 int width; … … 173 163 #define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b)) 174 164 175 static void chksum_and_xwrite(int fd, struct TarHeader* hp)165 static void chksum_and_xwrite(int fd, struct tar_header_t* hp) 176 166 { 177 167 /* POSIX says that checksum is done on unsigned bytes … … 215 205 "00000000000", 216 206 }; 217 struct TarHeaderheader;207 struct tar_header_t header; 218 208 int size; 219 209 … … 242 232 243 233 /* Write out a tar header for the specified file/directory/whatever */ 244 void BUG_tar_header_size(void);245 234 static int writeTarHeader(struct TarBallInfo *tbInfo, 246 235 const char *header_name, const char *fileName, struct stat *statbuf) 247 236 { 248 struct TarHeader header; 249 250 if (sizeof(header) != 512) 251 BUG_tar_header_size(); 252 253 memset(&header, 0, sizeof(struct TarHeader)); 237 struct tar_header_t header; 238 239 memset(&header, 0, sizeof(header)); 254 240 255 241 strncpy(header.name, header_name, sizeof(header.name)); … … 315 301 && statbuf->st_size > (off_t)0777777777777LL 316 302 ) { 317 bb_error_msg_and_die("can not store file '%s' "318 "of size %"OFF_FMT" d, aborting",303 bb_error_msg_and_die("can't store file '%s' " 304 "of size %"OFF_FMT"u, aborting", 319 305 fileName, statbuf->st_size); 320 306 } … … 341 327 FILE *vbFd = stdout; 342 328 343 if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */ 329 /* If archive goes to stdout, verbose goes to stderr */ 330 if (tbInfo->tarFd == STDOUT_FILENO) 344 331 vbFd = stderr; 345 332 /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */ … … 359 346 if (excluded_files->data[0] == '/') { 360 347 if (fnmatch(excluded_files->data, file, 361 348 FNM_PATHNAME | FNM_LEADING_DIR) == 0) 362 349 return 1; 363 350 } else { … … 365 352 366 353 for (p = file; p[0] != '\0'; p++) { 367 if ((p == file || p[-1] == '/') && p[0] != '/' && 368 fnmatch(excluded_files->data, p, 369 FNM_PATHNAME | FNM_LEADING_DIR) == 0) 354 if ((p == file || p[-1] == '/') 355 && p[0] != '/' 356 && fnmatch(excluded_files->data, p, 357 FNM_PATHNAME | FNM_LEADING_DIR) == 0 358 ) { 370 359 return 1; 360 } 371 361 } 372 362 } … … 377 367 } 378 368 #else 379 # define exclude_file(excluded_files, file) 0380 #endif 381 382 static int writeFileToTarball(const char *fileName, struct stat *statbuf,383 void *userData, int depth ATTRIBUTE_UNUSED)369 # define exclude_file(excluded_files, file) 0 370 #endif 371 372 static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf, 373 void *userData, int depth UNUSED_PARAM) 384 374 { 385 375 struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData; 386 376 const char *header_name; 387 377 int inputFileFd = -1; 378 379 DBG("writeFileToTarball('%s')", fileName); 380 381 /* Strip leading '/' (must be before memorizing hardlink's name) */ 382 header_name = fileName; 383 while (header_name[0] == '/') { 384 static smallint warned; 385 386 if (!warned) { 387 bb_error_msg("removing leading '/' from member names"); 388 warned = 1; 389 } 390 header_name++; 391 } 392 393 if (header_name[0] == '\0') 394 return TRUE; 395 396 /* It is against the rules to archive a socket */ 397 if (S_ISSOCK(statbuf->st_mode)) { 398 bb_error_msg("%s: socket ignored", fileName); 399 return TRUE; 400 } 388 401 389 402 /* … … 395 408 */ 396 409 tbInfo->hlInfo = NULL; 397 if (statbuf->st_nlink > 1) { 410 if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) { 411 DBG("'%s': st_nlink > 1", header_name); 398 412 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf); 399 if (tbInfo->hlInfo == NULL) 400 addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, fileName); 401 } 402 403 /* It is against the rules to archive a socket */ 404 if (S_ISSOCK(statbuf->st_mode)) { 405 bb_error_msg("%s: socket ignored", fileName); 406 return TRUE; 413 if (tbInfo->hlInfo == NULL) { 414 DBG("'%s': addHardLinkInfo", header_name); 415 addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name); 416 } 407 417 } 408 418 … … 410 420 * so check the device and inode to be sure that this particular file isn't 411 421 * the new tarball */ 412 if (tbInfo->statBuf.st_dev == statbuf->st_dev && 413 tbInfo->statBuf.st_ino == statbuf->st_ino) { 422 if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev 423 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino 424 ) { 414 425 bb_error_msg("%s: file is the archive; skipping", fileName); 415 426 return TRUE; 416 427 } 417 428 418 header_name = fileName; 419 while (header_name[0] == '/') { 420 static smallint warned; 421 422 if (!warned) { 423 bb_error_msg("removing leading '/' from member names"); 424 warned = 1; 425 } 426 header_name++; 427 } 429 if (exclude_file(tbInfo->excludeList, header_name)) 430 return SKIP; 428 431 429 432 #if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS 430 if (strlen( fileName) >= NAME_SIZE) {433 if (strlen(header_name) >= NAME_SIZE) { 431 434 bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported"); 432 435 return TRUE; 433 436 } 434 437 #endif 435 436 if (header_name[0] == '\0')437 return TRUE;438 439 if (exclude_file(tbInfo->excludeList, header_name))440 return SKIP;441 438 442 439 /* Is this a regular file? */ … … 485 482 } 486 483 487 static int writeTarFile(const int tar_fd, const int verboseFlag, 488 const unsigned long dereferenceFlag, const llist_t *include, 489 const llist_t *exclude, const int gzip) 490 { 491 pid_t gzipPid = 0; 484 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 485 # if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2) 486 # define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd) 487 # endif 488 /* Don't inline: vfork scares gcc and pessimizes code */ 489 static void NOINLINE vfork_compressor(int tar_fd, int gzip) 490 { 491 pid_t gzipPid; 492 # if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2 493 const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; 494 # elif ENABLE_FEATURE_SEAMLESS_GZ 495 const char *zip_exec = "gzip"; 496 # else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */ 497 const char *zip_exec = "bzip2"; 498 # endif 499 // On Linux, vfork never unpauses parent early, although standard 500 // allows for that. Do we want to waste bytes checking for it? 501 # define WAIT_FOR_CHILD 0 502 volatile int vfork_exec_errno = 0; 503 struct fd_pair gzipDataPipe; 504 # if WAIT_FOR_CHILD 505 struct fd_pair gzipStatusPipe; 506 xpiped_pair(gzipStatusPipe); 507 # endif 508 xpiped_pair(gzipDataPipe); 509 510 signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ 511 512 # if defined(__GNUC__) && __GNUC__ 513 /* Avoid vfork clobbering */ 514 (void) &zip_exec; 515 # endif 516 517 gzipPid = xvfork(); 518 519 if (gzipPid == 0) { 520 /* child */ 521 /* NB: close _first_, then move fds! */ 522 close(gzipDataPipe.wr); 523 # if WAIT_FOR_CHILD 524 close(gzipStatusPipe.rd); 525 /* gzipStatusPipe.wr will close only on exec - 526 * parent waits for this close to happen */ 527 fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC); 528 # endif 529 xmove_fd(gzipDataPipe.rd, 0); 530 xmove_fd(tar_fd, 1); 531 /* exec gzip/bzip2 program/applet */ 532 BB_EXECLP(zip_exec, zip_exec, "-f", NULL); 533 vfork_exec_errno = errno; 534 _exit(EXIT_FAILURE); 535 } 536 537 /* parent */ 538 xmove_fd(gzipDataPipe.wr, tar_fd); 539 close(gzipDataPipe.rd); 540 # if WAIT_FOR_CHILD 541 close(gzipStatusPipe.wr); 542 while (1) { 543 char buf; 544 int n; 545 546 /* Wait until child execs (or fails to) */ 547 n = full_read(gzipStatusPipe.rd, &buf, 1); 548 if (n < 0 /* && errno == EAGAIN */) 549 continue; /* try it again */ 550 } 551 close(gzipStatusPipe.rd); 552 # endif 553 if (vfork_exec_errno) { 554 errno = vfork_exec_errno; 555 bb_perror_msg_and_die("can't execute '%s'", zip_exec); 556 } 557 } 558 #endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */ 559 560 561 /* gcc 4.2.1 inlines it, making code bigger */ 562 static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, 563 int dereferenceFlag, const llist_t *include, 564 const llist_t *exclude, int gzip) 565 { 492 566 int errorFlag = FALSE; 493 567 struct TarBallInfo tbInfo; 494 568 495 569 tbInfo.hlInfoHead = NULL; 496 497 fchmod(tar_fd, 0644);498 570 tbInfo.tarFd = tar_fd; 499 571 tbInfo.verboseFlag = verboseFlag; … … 501 573 /* Store the stat info for the tarball's file, so 502 574 * can avoid including the tarball into itself.... */ 503 if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) 504 bb_perror_msg_and_die("cannot stat tar file"); 505 506 if ((ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2) && gzip) { 507 int gzipDataPipe[2] = { -1, -1 }; 508 int gzipStatusPipe[2] = { -1, -1 }; 509 volatile int vfork_exec_errno = 0; 510 const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; 511 512 xpipe(gzipDataPipe); 513 xpipe(gzipStatusPipe); 514 515 signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ 516 517 #if defined(__GNUC__) && __GNUC__ 518 /* Avoid vfork clobbering */ 519 (void) &include; 520 (void) &errorFlag; 521 (void) &zip_exec; 522 #endif 523 524 gzipPid = vfork(); 525 526 if (gzipPid == 0) { 527 dup2(gzipDataPipe[0], 0); 528 close(gzipDataPipe[1]); 529 530 dup2(tbInfo.tarFd, 1); 531 532 close(gzipStatusPipe[0]); 533 fcntl(gzipStatusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows success */ 534 535 BB_EXECLP(zip_exec, zip_exec, "-f", NULL); 536 vfork_exec_errno = errno; 537 538 close(gzipStatusPipe[1]); 539 exit(-1); 540 } else if (gzipPid > 0) { 541 close(gzipDataPipe[0]); 542 close(gzipStatusPipe[1]); 543 544 while (1) { 545 char buf; 546 547 int n = full_read(gzipStatusPipe[0], &buf, 1); 548 549 if (n == 0 && vfork_exec_errno != 0) { 550 errno = vfork_exec_errno; 551 bb_perror_msg_and_die("cannot exec %s", zip_exec); 552 } else if ((n < 0) && (errno == EAGAIN || errno == EINTR)) 553 continue; /* try it again */ 554 break; 555 } 556 close(gzipStatusPipe[0]); 557 558 tbInfo.tarFd = gzipDataPipe[1]; 559 } else bb_perror_msg_and_die("vfork gzip"); 560 } 575 xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file"); 576 577 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 578 if (gzip) 579 vfork_compressor(tbInfo.tarFd, gzip); 580 #endif 561 581 562 582 tbInfo.excludeList = exclude; … … 566 586 if (!recursive_action(include->data, ACTION_RECURSE | 567 587 (dereferenceFlag ? ACTION_FOLLOWLINKS : 0), 568 writeFileToTarball, writeFileToTarball, &tbInfo, 0) )569 {588 writeFileToTarball, writeFileToTarball, &tbInfo, 0) 589 ) { 570 590 errorFlag = TRUE; 571 591 } … … 591 611 bb_error_msg("error exit delayed from previous errors"); 592 612 593 if (gzipPid) { 613 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 614 if (gzip) { 594 615 int status; 595 if ( waitpid(gzipPid, &status, 0) == -1)616 if (safe_waitpid(-1, &status, 0) == -1) 596 617 bb_perror_msg("waitpid"); 597 618 else if (!WIFEXITED(status) || WEXITSTATUS(status)) … … 599 620 errorFlag = TRUE; 600 621 } 622 #endif 601 623 return errorFlag; 602 624 } 603 625 #else 604 int writeTarFile( const int tar_fd, constint verboseFlag,605 const unsigned longdereferenceFlag, const llist_t *include,606 const llist_t *exclude, constint gzip);626 int writeTarFile(int tar_fd, int verboseFlag, 627 int dereferenceFlag, const llist_t *include, 628 const llist_t *exclude, int gzip); 607 629 #endif /* FEATURE_TAR_CREATE */ 608 630 … … 611 633 { 612 634 FILE *src_stream; 613 llist_t *cur = list;614 llist_t *tmp;615 635 char *line; 616 636 llist_t *newlist = NULL; 617 637 618 while (cur) { 619 src_stream = xfopen(cur->data, "r"); 620 tmp = cur; 621 cur = cur->link; 622 free(tmp); 623 while ((line = xmalloc_getline(src_stream)) != NULL) { 638 while (list) { 639 src_stream = xfopen_for_read(llist_pop(&list)); 640 while ((line = xmalloc_fgetline(src_stream)) != NULL) { 624 641 /* kill trailing '/' unless the string is just "/" */ 625 642 char *cp = last_char_is(line, '/'); … … 633 650 } 634 651 #else 635 # define append_file_list_to_list(x) 0636 #endif 637 638 #if ENABLE_FEATURE_ TAR_COMPRESS639 static char get_header_tar_Z(archive_handle_t *archive_handle)652 # define append_file_list_to_list(x) 0 653 #endif 654 655 #if ENABLE_FEATURE_SEAMLESS_Z 656 static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle) 640 657 { 641 658 /* Can't lseek over pipes */ … … 649 666 } 650 667 651 archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress, "uncompress", "uncompress", "-cf", "-", NULL);668 open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress"); 652 669 archive_handle->offset = 0; 653 670 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 654 /* nothing */;671 continue; 655 672 656 673 /* Can only do one file at a time */ … … 658 675 } 659 676 #else 660 # define get_header_tar_Z NULL677 # define get_header_tar_Z NULL 661 678 #endif 662 679 … … 671 688 672 689 /* Wait for any child without blocking */ 673 if (wait pid(-1, &status, WNOHANG) < 0)690 if (wait_any_nohang(&status) < 0) 674 691 /* wait failed?! I'm confused... */ 675 692 return; 676 693 677 if (WIFEXITED(status) && WEXITSTATUS(status) ==0)694 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 678 695 /* child exited with 0 */ 679 696 return; … … 684 701 #endif 685 702 703 //usage:#define tar_trivial_usage 704 //usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z") 705 //usage: IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a") 706 //usage: IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] " 707 //usage: IF_FEATURE_TAR_FROM("[-X FILE] ") 708 //usage: "[-f TARFILE] [-C DIR] [FILE]..." 709 //usage:#define tar_full_usage "\n\n" 710 //usage: IF_FEATURE_TAR_CREATE("Create, extract, ") 711 //usage: IF_NOT_FEATURE_TAR_CREATE("Extract ") 712 //usage: "or list files from a tar file\n" 713 //usage: "\nOperation:" 714 //usage: IF_FEATURE_TAR_CREATE( 715 //usage: "\n c Create" 716 //usage: ) 717 //usage: "\n x Extract" 718 //usage: "\n t List" 719 //usage: "\nOptions:" 720 //usage: "\n f Name of TARFILE ('-' for stdin/out)" 721 //usage: "\n C Change to DIR before operation" 722 //usage: "\n v Verbose" 723 //usage: IF_FEATURE_SEAMLESS_GZ( 724 //usage: "\n z (De)compress using gzip" 725 //usage: ) 726 //usage: IF_FEATURE_SEAMLESS_BZ2( 727 //usage: "\n j (De)compress using bzip2" 728 //usage: ) 729 //usage: IF_FEATURE_SEAMLESS_LZMA( 730 //usage: "\n a (De)compress using lzma" 731 //usage: ) 732 //usage: IF_FEATURE_SEAMLESS_Z( 733 //usage: "\n Z (De)compress using compress" 734 //usage: ) 735 //usage: "\n O Extract to stdout" 736 //usage: IF_FEATURE_TAR_CREATE( 737 //usage: "\n h Follow symlinks" 738 //usage: ) 739 //usage: IF_FEATURE_TAR_NOPRESERVE_TIME( 740 //usage: "\n m Don't restore mtime" 741 //usage: ) 742 //usage: IF_FEATURE_TAR_FROM( 743 //usage: IF_FEATURE_TAR_LONG_OPTIONS( 744 //usage: "\n exclude File to exclude" 745 //usage: ) 746 //usage: "\n X File with names to exclude" 747 //usage: "\n T File with names to include" 748 //usage: ) 749 //usage: 750 //usage:#define tar_example_usage 751 //usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" 752 //usage: "$ tar -cf /tmp/tarball.tar /usr/local\n" 753 754 // Supported but aren't in --help: 755 // o no-same-owner 756 // p same-permissions 757 // k keep-old 758 // numeric-owner 759 // no-same-permissions 760 // overwrite 761 //IF_FEATURE_TAR_TO_COMMAND( 762 // to-command 763 //) 764 686 765 enum { 687 OPTBIT_KEEP_OLD = 7, 688 USE_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) 689 USE_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,) 690 USE_FEATURE_TAR_BZIP2( OPTBIT_BZIP2 ,) 691 USE_FEATURE_TAR_LZMA( OPTBIT_LZMA ,) 692 USE_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,) 693 USE_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,) 694 USE_FEATURE_TAR_GZIP( OPTBIT_GZIP ,) 695 USE_FEATURE_TAR_COMPRESS(OPTBIT_COMPRESS ,) 696 OPTBIT_NOPRESERVE_OWN, 766 OPTBIT_KEEP_OLD = 8, 767 IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) 768 IF_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,) 769 IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2 ,) 770 IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA ,) 771 IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,) 772 IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,) 773 IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,) 774 IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) // 16th bit 775 IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,) 776 #if ENABLE_FEATURE_TAR_LONG_OPTIONS 777 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,) 778 OPTBIT_NUMERIC_OWNER, 697 779 OPTBIT_NOPRESERVE_PERM, 780 OPTBIT_OVERWRITE, 781 #endif 698 782 OPT_TEST = 1 << 0, // t 699 783 OPT_EXTRACT = 1 << 1, // x … … 701 785 OPT_TARNAME = 1 << 3, // f 702 786 OPT_2STDOUT = 1 << 4, // O 703 OPT_P = 1 << 5, // p 704 OPT_VERBOSE = 1 << 6, // v 705 OPT_KEEP_OLD = 1 << 7, // k 706 OPT_CREATE = USE_FEATURE_TAR_CREATE( (1<<OPTBIT_CREATE )) + 0, // c 707 OPT_DEREFERENCE = USE_FEATURE_TAR_CREATE( (1<<OPTBIT_DEREFERENCE )) + 0, // h 708 OPT_BZIP2 = USE_FEATURE_TAR_BZIP2( (1<<OPTBIT_BZIP2 )) + 0, // j 709 OPT_LZMA = USE_FEATURE_TAR_LZMA( (1<<OPTBIT_LZMA )) + 0, // a 710 OPT_INCLUDE_FROM = USE_FEATURE_TAR_FROM( (1<<OPTBIT_INCLUDE_FROM)) + 0, // T 711 OPT_EXCLUDE_FROM = USE_FEATURE_TAR_FROM( (1<<OPTBIT_EXCLUDE_FROM)) + 0, // X 712 OPT_GZIP = USE_FEATURE_TAR_GZIP( (1<<OPTBIT_GZIP )) + 0, // z 713 OPT_COMPRESS = USE_FEATURE_TAR_COMPRESS((1<<OPTBIT_COMPRESS )) + 0, // Z 714 OPT_NOPRESERVE_OWN = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner 715 OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions 787 OPT_NOPRESERVE_OWNER = 1 << 5, // o == no-same-owner 788 OPT_P = 1 << 6, // p 789 OPT_VERBOSE = 1 << 7, // v 790 OPT_KEEP_OLD = 1 << 8, // k 791 OPT_CREATE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE )) + 0, // c 792 OPT_DEREFERENCE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE )) + 0, // h 793 OPT_BZIP2 = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2 )) + 0, // j 794 OPT_LZMA = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA )) + 0, // a 795 OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0, // T 796 OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X 797 OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z 798 OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z 799 OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m 800 OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command 801 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner 802 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions 803 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite 716 804 }; 717 805 #if ENABLE_FEATURE_TAR_LONG_OPTIONS … … 722 810 "file\0" Required_argument "f" 723 811 "to-stdout\0" No_argument "O" 812 /* do not restore owner */ 813 /* Note: GNU tar handles 'o' as no-same-owner only on extract, 814 * on create, 'o' is --old-archive. We do not support --old-archive. */ 815 "no-same-owner\0" No_argument "o" 724 816 "same-permissions\0" No_argument "p" 725 817 "verbose\0" No_argument "v" … … 729 821 "dereference\0" No_argument "h" 730 822 # endif 731 # if ENABLE_FEATURE_ TAR_BZIP2823 # if ENABLE_FEATURE_SEAMLESS_BZ2 732 824 "bzip2\0" No_argument "j" 733 825 # endif 734 # if ENABLE_FEATURE_ TAR_LZMA826 # if ENABLE_FEATURE_SEAMLESS_LZMA 735 827 "lzma\0" No_argument "a" 736 828 # endif … … 739 831 "exclude-from\0" Required_argument "X" 740 832 # endif 741 # if ENABLE_FEATURE_ TAR_GZIP833 # if ENABLE_FEATURE_SEAMLESS_GZ 742 834 "gzip\0" No_argument "z" 743 835 # endif 744 # if ENABLE_FEATURE_ TAR_COMPRESS836 # if ENABLE_FEATURE_SEAMLESS_Z 745 837 "compress\0" No_argument "Z" 746 838 # endif 747 "no-same-owner\0" No_argument "\xfd" 748 "no-same-permissions\0" No_argument "\xfe" 839 # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME 840 "touch\0" No_argument "m" 841 # endif 842 # if ENABLE_FEATURE_TAR_TO_COMMAND 843 "to-command\0" Required_argument "\xfb" 844 # endif 845 /* use numeric uid/gid from tar header, not textual */ 846 "numeric-owner\0" No_argument "\xfc" 847 /* do not restore mode */ 848 "no-same-permissions\0" No_argument "\xfd" 849 /* on unpack, open with O_TRUNC and !O_EXCL */ 850 "overwrite\0" No_argument "\xfe" 749 851 /* --exclude takes next bit position in option mask, */ 750 /* therefore we have to either put it _after_ --no-same-perm */ 751 /* or add OPT[BIT]_EXCLUDE before OPT[BIT]_NOPRESERVE_OWN */ 852 /* therefore we have to put it _after_ --no-same-permissions */ 752 853 # if ENABLE_FEATURE_TAR_FROM 753 854 "exclude\0" Required_argument "\xff" … … 756 857 #endif 757 858 758 int tar_main(int argc, char **argv) ;759 int tar_main(int argc , char **argv)760 { 761 char (*get_header_ptr)(archive_handle_t *) = get_header_tar;859 int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 860 int tar_main(int argc UNUSED_PARAM, char **argv) 861 { 862 char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar; 762 863 archive_handle_t *tar_handle; 763 864 char *base_dir = NULL; … … 771 872 /* Initialise default values */ 772 873 tar_handle = init_handle(); 773 tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS 774 | ARCHIVE_PRESERVE_DATE 775 | ARCHIVE_EXTRACT_UNCONDITIONAL; 874 tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS 875 | ARCHIVE_RESTORE_DATE 876 | ARCHIVE_UNLINK_OLD; 877 878 /* Apparently only root's tar preserves perms (see bug 3844) */ 879 if (getuid() != 0) 880 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; 776 881 777 882 /* Prepend '-' to the first argument if required */ … … 783 888 "\xff::" // cumulative lists for --exclude 784 889 #endif 785 USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd786 USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive787 SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive890 IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd 891 IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive 892 IF_NOT_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive 788 893 #if ENABLE_FEATURE_TAR_LONG_OPTIONS 789 894 applet_long_options = tar_longopts; 790 895 #endif 896 #if ENABLE_DESKTOP 897 if (argv[1] && argv[1][0] != '-') { 898 /* Compat: 899 * 1st argument without dash handles options with parameters 900 * differently from dashed one: it takes *next argv[i]* 901 * as paramenter even if there are more chars in 1st argument: 902 * "tar fx TARFILE" - "x" is not taken as f's param 903 * but is interpreted as -x option 904 * "tar -xf TARFILE" - dashed equivalent of the above 905 * "tar -fx ..." - "x" is taken as f's param 906 * getopt32 wouldn't handle 1st command correctly. 907 * Unfortunately, people do use such commands. 908 * We massage argv[1] to work around it by moving 'f' 909 * to the end of the string. 910 * More contrived "tar fCx TARFILE DIR" still fails, 911 * but such commands are much less likely to be used. 912 */ 913 char *f = strchr(argv[1], 'f'); 914 if (f) { 915 while (f[1] != '\0') { 916 *f = f[1]; 917 f++; 918 } 919 *f = 'f'; 920 } 921 } 922 #endif 791 923 opt = getopt32(argv, 792 "txC:f:Opvk" 793 USE_FEATURE_TAR_CREATE( "ch" ) 794 USE_FEATURE_TAR_BZIP2( "j" ) 795 USE_FEATURE_TAR_LZMA( "a" ) 796 USE_FEATURE_TAR_FROM( "T:X:") 797 USE_FEATURE_TAR_GZIP( "z" ) 798 USE_FEATURE_TAR_COMPRESS("Z" ) 924 "txC:f:Oopvk" 925 IF_FEATURE_TAR_CREATE( "ch" ) 926 IF_FEATURE_SEAMLESS_BZ2( "j" ) 927 IF_FEATURE_SEAMLESS_LZMA("a" ) 928 IF_FEATURE_TAR_FROM( "T:X:") 929 IF_FEATURE_SEAMLESS_GZ( "z" ) 930 IF_FEATURE_SEAMLESS_Z( "Z" ) 931 IF_FEATURE_TAR_NOPRESERVE_TIME("m") 799 932 , &base_dir // -C dir 800 933 , &tar_filename // -f filename 801 USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T 802 USE_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X 934 IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T 935 IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X 936 IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command 803 937 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM 804 938 , &excludes // --exclude … … 807 941 , &verboseFlag // combined count for -t and -v 808 942 ); 943 //bb_error_msg("opt:%08x", opt); 944 argv += optind; 809 945 810 946 if (verboseFlag) tar_handle->action_header = header_verbose_list; … … 817 953 tar_handle->action_data = data_extract_to_stdout; 818 954 955 if (opt & OPT_2COMMAND) { 956 putenv((char*)"TAR_FILETYPE=f"); 957 signal(SIGPIPE, SIG_IGN); 958 tar_handle->action_data = data_extract_to_command; 959 } 960 819 961 if (opt & OPT_KEEP_OLD) 820 tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL; 821 822 if (opt & OPT_NOPRESERVE_OWN) 823 tar_handle->flags |= ARCHIVE_NOPRESERVE_OWN; 962 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD; 963 964 if (opt & OPT_NUMERIC_OWNER) 965 tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER; 966 967 if (opt & OPT_NOPRESERVE_OWNER) 968 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER; 824 969 825 970 if (opt & OPT_NOPRESERVE_PERM) 826 tar_handle->flags |= ARCHIVE_NOPRESERVE_PERM; 971 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; 972 973 if (opt & OPT_OVERWRITE) { 974 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD; 975 tar_handle->ah_flags |= ARCHIVE_O_TRUNC; 976 } 827 977 828 978 if (opt & OPT_GZIP) … … 838 988 get_header_ptr = get_header_tar_Z; 839 989 990 if (opt & OPT_NOPRESERVE_TIME) 991 tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE; 992 840 993 #if ENABLE_FEATURE_TAR_FROM 841 994 tar_handle->reject = append_file_list_to_list(tar_handle->reject); 842 # if ENABLE_FEATURE_TAR_LONG_OPTIONS995 # if ENABLE_FEATURE_TAR_LONG_OPTIONS 843 996 /* Append excludes to reject */ 844 997 while (excludes) { … … 848 1001 excludes = next; 849 1002 } 850 # endif1003 # endif 851 1004 tar_handle->accept = append_file_list_to_list(tar_handle->accept); 852 1005 #endif 853 1006 854 /* Check if we are reading from stdin */855 if (argv[optind] && *argv[optind] == '-') {856 /* Default is to read from stdin, so just skip to next arg */857 optind++;858 }859 860 1007 /* Setup an array of filenames to work with */ 861 /* TODO: This is the same as in ar, separate function? */862 while ( optind < argc) {1008 /* TODO: This is the same as in ar, make a separate function? */ 1009 while (*argv) { 863 1010 /* kill trailing '/' unless the string is just "/" */ 864 char *cp = last_char_is( argv[optind], '/');865 if (cp > argv[optind])1011 char *cp = last_char_is(*argv, '/'); 1012 if (cp > *argv) 866 1013 *cp = '\0'; 867 llist_add_to_end(&tar_handle->accept, argv[optind]);868 optind++;1014 llist_add_to_end(&tar_handle->accept, *argv); 1015 argv++; 869 1016 } 870 1017 … … 874 1021 /* Open the tar file */ 875 1022 { 876 FILE *tar_stream;877 int flags ;1023 int tar_fd = STDIN_FILENO; 1024 int flags = O_RDONLY; 878 1025 879 1026 if (opt & OPT_CREATE) { 880 /* Make sure there is at least one file to tar up .*/1027 /* Make sure there is at least one file to tar up */ 881 1028 if (tar_handle->accept == NULL) 882 1029 bb_error_msg_and_die("empty archive"); 883 1030 884 tar_ stream = stdout;1031 tar_fd = STDOUT_FILENO; 885 1032 /* Mimicking GNU tar 1.15.1: */ 886 flags = O_WRONLY|O_CREAT|O_TRUNC; 887 /* was doing unlink; open(O_WRONLY|O_CREAT|O_EXCL); why? */ 888 } else { 889 tar_stream = stdin; 890 flags = O_RDONLY; 1033 flags = O_WRONLY | O_CREAT | O_TRUNC; 891 1034 } 892 1035 893 1036 if (LONE_DASH(tar_filename)) { 894 tar_handle->src_fd = fileno(tar_stream);1037 tar_handle->src_fd = tar_fd; 895 1038 tar_handle->seek = seek_by_read; 896 1039 } else { 897 tar_handle->src_fd = xopen(tar_filename, flags); 1040 if (ENABLE_FEATURE_TAR_AUTODETECT 1041 && flags == O_RDONLY 1042 && get_header_ptr == get_header_tar 1043 ) { 1044 tar_handle->src_fd = open_zipped(tar_filename); 1045 if (tar_handle->src_fd < 0) 1046 bb_perror_msg_and_die("can't open '%s'", tar_filename); 1047 } else { 1048 tar_handle->src_fd = xopen(tar_filename, flags); 1049 } 898 1050 } 899 1051 } … … 907 1059 #endif 908 1060 909 /* create an archive */1061 /* Create an archive */ 910 1062 if (opt & OPT_CREATE) { 1063 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 911 1064 int zipMode = 0; 912 if (ENABLE_FEATURE_ TAR_GZIP && get_header_ptr == get_header_tar_gz)1065 if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP)) 913 1066 zipMode = 1; 914 if (ENABLE_FEATURE_ TAR_BZIP2 && get_header_ptr == get_header_tar_bz2)1067 if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2)) 915 1068 zipMode = 2; 1069 #endif 916 1070 /* NB: writeTarFile() closes tar_handle->src_fd */ 917 1071 return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE, … … 921 1075 922 1076 while (get_header_ptr(tar_handle) == EXIT_SUCCESS) 923 /* nothing */;1077 continue; 924 1078 925 1079 /* Check that every file that should have been extracted was */
Note:
See TracChangeset
for help on using the changeset viewer.