diff options
Diffstat (limited to 'archival/tar.c')
-rw-r--r-- | archival/tar.c | 190 |
1 files changed, 98 insertions, 92 deletions
diff --git a/archival/tar.c b/archival/tar.c index 0c90ac07e..0aa216c39 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -84,26 +84,26 @@ struct TarHeader { /* byte offset */ */ typedef struct HardLinkInfo HardLinkInfo; struct HardLinkInfo { - HardLinkInfo *next; /* Next entry in list */ - dev_t dev; /* Device number */ - ino_t ino; /* Inode number */ - short linkCount; /* (Hard) Link Count */ - char name[1]; /* Start of filename (must be last) */ + HardLinkInfo *next; /* Next entry in list */ + dev_t dev; /* Device number */ + ino_t ino; /* Inode number */ + short linkCount; /* (Hard) Link Count */ + char name[1]; /* Start of filename (must be last) */ }; /* Some info to be carried along when creating a new tarball */ typedef struct TarBallInfo TarBallInfo; struct TarBallInfo { - int tarFd; /* Open-for-write file descriptor - for the tarball */ - struct stat statBuf; /* Stat info for the tarball, letting - us know the inode and device that the - tarball lives, so we can avoid trying - to include the tarball into itself */ - int verboseFlag; /* Whether to print extra stuff or not */ - const llist_t *excludeList; /* List of files to not include */ - HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ - HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ + int tarFd; /* Open-for-write file descriptor + * for the tarball */ + struct stat statBuf; /* Stat info for the tarball, letting + * us know the inode and device that the + * tarball lives, so we can avoid trying + * to include the tarball into itself */ + int verboseFlag; /* Whether to print extra stuff or not */ + const llist_t *excludeList; /* List of files to not include */ + HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ + HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ }; /* A nice enum with all the possible tar file content types */ @@ -503,100 +503,104 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, return TRUE; } -static int writeTarFile(const int tar_fd, const int verboseFlag, - const unsigned long dereferenceFlag, const llist_t *include, - const llist_t *exclude, const int gzip) -{ - pid_t gzipPid = 0; - int errorFlag = FALSE; - struct TarBallInfo tbInfo; - - tbInfo.hlInfoHead = NULL; - - fchmod(tar_fd, 0644); - tbInfo.tarFd = tar_fd; - tbInfo.verboseFlag = verboseFlag; - - /* Store the stat info for the tarball's file, so - * can avoid including the tarball into itself.... */ - if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) - bb_perror_msg_and_die("cannot stat tar file"); - #if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2 - if (gzip) { +/* Don't inline: vfork scares gcc and pessimizes code */ +static void NOINLINE vfork_compressor(int tar_fd, int gzip) +{ + pid_t gzipPid; #if ENABLE_FEATURE_TAR_GZIP && ENABLE_FEATURE_TAR_BZIP2 - const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; + const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; #elif ENABLE_FEATURE_TAR_GZIP - const char *zip_exec = "gzip"; + const char *zip_exec = "gzip"; #else /* only ENABLE_FEATURE_TAR_BZIP2 */ - const char *zip_exec = "bzip2"; + const char *zip_exec = "bzip2"; #endif // On Linux, vfork never unpauses parent early, although standard // allows for that. Do we want to waste bytes checking for it? #define WAIT_FOR_CHILD 0 - volatile int vfork_exec_errno = 0; -#if WAIT_FOR_CHILD - struct fd_pair gzipStatusPipe; -#endif - struct fd_pair gzipDataPipe; - xpiped_pair(gzipDataPipe); + volatile int vfork_exec_errno = 0; + struct fd_pair gzipDataPipe; #if WAIT_FOR_CHILD - xpiped_pair(gzipStatusPipe); + struct fd_pair gzipStatusPipe; + xpiped_pair(gzipStatusPipe); #endif + xpiped_pair(gzipDataPipe); - signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ + signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ #if defined(__GNUC__) && __GNUC__ - /* Avoid vfork clobbering */ - (void) &include; - (void) &errorFlag; - (void) &zip_exec; + /* Avoid vfork clobbering */ + (void) &zip_exec; #endif - gzipPid = vfork(); - if (gzipPid < 0) - bb_perror_msg_and_die("vfork gzip"); + gzipPid = vfork(); + if (gzipPid < 0) + bb_perror_msg_and_die("can't vfork"); - if (gzipPid == 0) { - /* child */ - /* NB: close _first_, then move fds! */ - close(gzipDataPipe.wr); + if (gzipPid == 0) { + /* child */ + /* NB: close _first_, then move fds! */ + close(gzipDataPipe.wr); #if WAIT_FOR_CHILD - close(gzipStatusPipe.rd); - /* gzipStatusPipe.wr will close only on exec - - * parent waits for this close to happen */ - fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC); + close(gzipStatusPipe.rd); + /* gzipStatusPipe.wr will close only on exec - + * parent waits for this close to happen */ + fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC); #endif - xmove_fd(gzipDataPipe.rd, 0); - xmove_fd(tbInfo.tarFd, 1); - /* exec gzip/bzip2 program/applet */ - BB_EXECLP(zip_exec, zip_exec, "-f", NULL); - vfork_exec_errno = errno; - _exit(1); - } + xmove_fd(gzipDataPipe.rd, 0); + xmove_fd(tar_fd, 1); + /* exec gzip/bzip2 program/applet */ + BB_EXECLP(zip_exec, zip_exec, "-f", NULL); + vfork_exec_errno = errno; + _exit(1); + } - /* parent */ - xmove_fd(gzipDataPipe.wr, tbInfo.tarFd); - close(gzipDataPipe.rd); + /* parent */ + xmove_fd(gzipDataPipe.wr, tar_fd); + close(gzipDataPipe.rd); #if WAIT_FOR_CHILD - close(gzipStatusPipe.wr); - while (1) { - char buf; - int n; - - /* Wait until child execs (or fails to) */ - n = full_read(gzipStatusPipe.rd, &buf, 1); - if (n < 0 /* && errno == EAGAIN */) - continue; /* try it again */ - - } - close(gzipStatusPipe.rd); + close(gzipStatusPipe.wr); + while (1) { + char buf; + int n; + + /* Wait until child execs (or fails to) */ + n = full_read(gzipStatusPipe.rd, &buf, 1); + if (n < 0 /* && errno == EAGAIN */) + continue; /* try it again */ + } + close(gzipStatusPipe.rd); #endif - if (vfork_exec_errno) { - errno = vfork_exec_errno; - bb_perror_msg_and_die("cannot exec %s", zip_exec); - } + if (vfork_exec_errno) { + errno = vfork_exec_errno; + bb_perror_msg_and_die("cannot exec %s", zip_exec); } +} +#endif /* ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2 */ + + +/* gcc 4.2.1 inlines it, making code bigger */ +static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, + int dereferenceFlag, const llist_t *include, + const llist_t *exclude, int gzip) +{ + int errorFlag = FALSE; + struct TarBallInfo tbInfo; + + tbInfo.hlInfoHead = NULL; + + fchmod(tar_fd, 0644); + tbInfo.tarFd = tar_fd; + tbInfo.verboseFlag = verboseFlag; + + /* Store the stat info for the tarball's file, so + * can avoid including the tarball into itself.... */ + if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) + bb_perror_msg_and_die("cannot stat tar file"); + +#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2 + if (gzip) + vfork_compressor(tbInfo.tarFd, gzip); #endif tbInfo.excludeList = exclude; @@ -630,20 +634,22 @@ static int writeTarFile(const int tar_fd, const int verboseFlag, if (errorFlag) bb_error_msg("error exit delayed from previous errors"); - if (gzipPid) { +#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2 + if (gzip) { int status; - if (safe_waitpid(gzipPid, &status, 0) == -1) + if (safe_waitpid(-1, &status, 0) == -1) bb_perror_msg("waitpid"); else if (!WIFEXITED(status) || WEXITSTATUS(status)) /* gzip was killed or has exited with nonzero! */ errorFlag = TRUE; } +#endif return errorFlag; } #else -int writeTarFile(const int tar_fd, const int verboseFlag, - const unsigned long dereferenceFlag, const llist_t *include, - const llist_t *exclude, const int gzip); +int writeTarFile(int tar_fd, int verboseFlag, + int dereferenceFlag, const llist_t *include, + const llist_t *exclude, int gzip); #endif /* FEATURE_TAR_CREATE */ #if ENABLE_FEATURE_TAR_FROM |