aboutsummaryrefslogtreecommitdiff
path: root/archival
diff options
context:
space:
mode:
Diffstat (limited to 'archival')
-rw-r--r--archival/tar.c80
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 */
602static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) 602static 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
764static llist_t *append_file_list_to_list(llist_t *list) 769static 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