diff options
Diffstat (limited to 'archival')
-rw-r--r-- | archival/tar.c | 80 |
1 files changed, 42 insertions, 38 deletions
diff --git a/archival/tar.c b/archival/tar.c index e1af27401..9a171ceea 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -601,35 +601,46 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb | |||
601 | /* Don't inline: vfork scares gcc and pessimizes code */ | 601 | /* Don't inline: vfork scares gcc and pessimizes code */ |
602 | static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) | 602 | static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) |
603 | { | 603 | { |
604 | pid_t gzipPid; | ||
605 | |||
606 | // On Linux, vfork never unpauses parent early, although standard | 604 | // On Linux, vfork never unpauses parent early, although standard |
607 | // allows for that. Do we want to waste bytes checking for it? | 605 | // allows for that. Do we want to waste bytes checking for it? |
608 | # define WAIT_FOR_CHILD 0 | 606 | # define WAIT_FOR_CHILD 0 |
609 | volatile int vfork_exec_errno = 0; | 607 | volatile int vfork_exec_errno = 0; |
610 | struct fd_pair gzipDataPipe; | 608 | struct fd_pair data; |
611 | # if WAIT_FOR_CHILD | 609 | # if WAIT_FOR_CHILD |
612 | struct fd_pair gzipStatusPipe; | 610 | struct fd_pair status; |
613 | xpiped_pair(gzipStatusPipe); | 611 | xpiped_pair(status); |
614 | # endif | 612 | # endif |
615 | xpiped_pair(gzipDataPipe); | 613 | xpiped_pair(data); |
616 | 614 | ||
617 | signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ | 615 | signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ |
618 | 616 | ||
619 | gzipPid = xvfork(); | 617 | if (xvfork() == 0) { |
620 | |||
621 | if (gzipPid == 0) { | ||
622 | /* child */ | 618 | /* child */ |
619 | int tfd; | ||
623 | /* NB: close _first_, then move fds! */ | 620 | /* NB: close _first_, then move fds! */ |
624 | close(gzipDataPipe.wr); | 621 | close(data.wr); |
625 | # if WAIT_FOR_CHILD | 622 | # if WAIT_FOR_CHILD |
626 | close(gzipStatusPipe.rd); | 623 | close(status.rd); |
627 | /* gzipStatusPipe.wr will close only on exec - | 624 | /* status.wr will close only on exec - |
628 | * parent waits for this close to happen */ | 625 | * parent waits for this close to happen */ |
629 | fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC); | 626 | fcntl(status.wr, F_SETFD, FD_CLOEXEC); |
630 | # endif | 627 | # endif |
631 | xmove_fd(gzipDataPipe.rd, 0); | 628 | /* copy it: parent's tar_fd variable must not change */ |
632 | xmove_fd(tar_fd, 1); | 629 | tfd = tar_fd; |
630 | if (tfd == 0) { | ||
631 | /* Output tar fd may be zero. | ||
632 | * xmove_fd(data.rd, 0) would destroy it. | ||
633 | * Reproducer: | ||
634 | * exec 0>&- | ||
635 | * exec 1>&- | ||
636 | * tar czf Z.tar.gz FILE | ||
637 | * Swapping move_fd's order wouldn't work: | ||
638 | * data.rd is 1 and _it_ would be destroyed. | ||
639 | */ | ||
640 | tfd = dup(tfd); | ||
641 | } | ||
642 | xmove_fd(data.rd, 0); | ||
643 | xmove_fd(tfd, 1); | ||
633 | /* exec gzip/bzip2 program/applet */ | 644 | /* exec gzip/bzip2 program/applet */ |
634 | BB_EXECLP(gzip, gzip, "-f", (char *)0); | 645 | BB_EXECLP(gzip, gzip, "-f", (char *)0); |
635 | vfork_exec_errno = errno; | 646 | vfork_exec_errno = errno; |
@@ -637,20 +648,18 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) | |||
637 | } | 648 | } |
638 | 649 | ||
639 | /* parent */ | 650 | /* parent */ |
640 | xmove_fd(gzipDataPipe.wr, tar_fd); | 651 | xmove_fd(data.wr, tar_fd); |
641 | close(gzipDataPipe.rd); | 652 | close(data.rd); |
642 | # if WAIT_FOR_CHILD | 653 | # if WAIT_FOR_CHILD |
643 | close(gzipStatusPipe.wr); | 654 | close(status.wr); |
644 | while (1) { | 655 | while (1) { |
645 | char buf; | ||
646 | int n; | ||
647 | |||
648 | /* Wait until child execs (or fails to) */ | 656 | /* Wait until child execs (or fails to) */ |
649 | n = full_read(gzipStatusPipe.rd, &buf, 1); | 657 | char buf; |
658 | int n = full_read(status.rd, &buf, 1); | ||
650 | if (n < 0 /* && errno == EAGAIN */) | 659 | if (n < 0 /* && errno == EAGAIN */) |
651 | continue; /* try it again */ | 660 | continue; /* try it again */ |
652 | } | 661 | } |
653 | close(gzipStatusPipe.rd); | 662 | close(status.rd); |
654 | # endif | 663 | # endif |
655 | if (vfork_exec_errno) { | 664 | if (vfork_exec_errno) { |
656 | errno = vfork_exec_errno; | 665 | errno = vfork_exec_errno; |
@@ -754,11 +763,7 @@ static NOINLINE int writeTarFile( | |||
754 | return errorFlag; | 763 | return errorFlag; |
755 | } | 764 | } |
756 | 765 | ||
757 | #else /* !FEATURE_TAR_CREATE */ | 766 | #endif /* FEATURE_TAR_CREATE */ |
758 | |||
759 | # define writeTarFile(...) 0 | ||
760 | |||
761 | #endif | ||
762 | 767 | ||
763 | #if ENABLE_FEATURE_TAR_FROM | 768 | #if ENABLE_FEATURE_TAR_FROM |
764 | static llist_t *append_file_list_to_list(llist_t *list) | 769 | static llist_t *append_file_list_to_list(llist_t *list) |
@@ -1190,17 +1195,16 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1190 | if (LONE_DASH(tar_filename)) { | 1195 | if (LONE_DASH(tar_filename)) { |
1191 | tar_handle->src_fd = tar_fd; | 1196 | tar_handle->src_fd = tar_fd; |
1192 | tar_handle->seek = seek_by_read; | 1197 | tar_handle->seek = seek_by_read; |
1198 | } else | ||
1199 | if (ENABLE_FEATURE_TAR_AUTODETECT | ||
1200 | && flags == O_RDONLY | ||
1201 | && !(opt & OPT_ANY_COMPRESS) | ||
1202 | ) { | ||
1203 | tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); | ||
1204 | if (tar_handle->src_fd < 0) | ||
1205 | bb_perror_msg_and_die("can't open '%s'", tar_filename); | ||
1193 | } else { | 1206 | } else { |
1194 | if (ENABLE_FEATURE_TAR_AUTODETECT | 1207 | tar_handle->src_fd = xopen(tar_filename, flags); |
1195 | && flags == O_RDONLY | ||
1196 | && !(opt & OPT_ANY_COMPRESS) | ||
1197 | ) { | ||
1198 | tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); | ||
1199 | if (tar_handle->src_fd < 0) | ||
1200 | bb_perror_msg_and_die("can't open '%s'", tar_filename); | ||
1201 | } else { | ||
1202 | tar_handle->src_fd = xopen(tar_filename, flags); | ||
1203 | } | ||
1204 | } | 1208 | } |
1205 | } | 1209 | } |
1206 | 1210 | ||