aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archival/config.in2
-rw-r--r--archival/tar.c119
2 files changed, 95 insertions, 26 deletions
diff --git a/archival/config.in b/archival/config.in
index 5a064dc89..ac90ec0a9 100644
--- a/archival/config.in
+++ b/archival/config.in
@@ -18,7 +18,7 @@ bool 'tar' CONFIG_TAR
if [ "$CONFIG_TAR" = "y" ] ; then
bool ' Enable archive creation' CONFIG_FEATURE_TAR_CREATE
bool ' Enable -X and --exclude options (exclude files)' CONFIG_FEATURE_TAR_EXCLUDE
- bool ' Enable -z option (currently only for extracting)' CONFIG_FEATURE_TAR_GZIP
+ bool ' Enable -z option' CONFIG_FEATURE_TAR_GZIP
fi
if [ "$CONFIG_CPIO" = "y" -o "$CONFIG_TAR" = "y" ] ; then
bool ' Enable tape drive support' CONFIG_FEATURE_UNARCHIVE_TAPE
diff --git a/archival/tar.c b/archival/tar.c
index b18f1f87f..2aa5f0788 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -47,6 +47,9 @@
#include <fnmatch.h>
#include <string.h>
#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
#include "unarchive.h"
#include "busybox.h"
@@ -305,9 +308,10 @@ writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name,
write(tbInfo->tarFd, "\0", 1);
}
/* Now do the verbose thing (or not) */
- if (tbInfo->verboseFlag==TRUE) {
+
+ if (tbInfo->verboseFlag) {
FILE *vbFd = stdout;
- if (tbInfo->tarFd == fileno(stdout)) // If the archive goes to stdout, verbose to stderr
+ if (tbInfo->verboseFlag == 2) // If the archive goes to stdout, verbose to stderr
vbFd = stderr;
fprintf(vbFd, "%s\n", header.name);
}
@@ -445,13 +449,17 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
}
static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
- char** excludeList)
+ char** excludeList, int gzip)
{
- int tarFd=-1;
+#ifdef CONFIG_FEATURE_TAR_GZIP
+ int gzipDataPipe [2] = { -1, -1 };
+ int gzipStatusPipe [2] = { -1, -1 };
+ pid_t gzipPid = 0;
+#endif
+
int errorFlag=FALSE;
ssize_t size;
struct TarBallInfo tbInfo;
- tbInfo.verboseFlag = verboseFlag;
tbInfo.hlInfoHead = NULL;
/* Make sure there is at least one file to tar up. */
@@ -459,21 +467,78 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
error_msg_and_die("Cowardly refusing to create an empty archive");
/* Open the tar file for writing. */
- if (tarName == NULL)
+ if (tarName == NULL) {
tbInfo.tarFd = fileno(stdout);
- else
+ tbInfo.verboseFlag = verboseFlag ? 2 : 0;
+ }
+ else {
tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ tbInfo.verboseFlag = verboseFlag ? 1 : 0;
+ }
+
if (tbInfo.tarFd < 0) {
perror_msg( "Error opening '%s'", tarName);
freeHardLinkInfo(&tbInfo.hlInfoHead);
return ( FALSE);
}
- tbInfo.excludeList=excludeList;
+
/* Store the stat info for the tarball's file, so
* can avoid including the tarball into itself.... */
if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
error_msg_and_die(io_error, tarName, strerror(errno));
+#ifdef CONFIG_FEATURE_TAR_GZIP
+ if ( gzip ) {
+ if ( socketpair ( AF_UNIX, SOCK_STREAM, 0, gzipDataPipe ) < 0 || pipe ( gzipStatusPipe ) < 0 )
+ perror_msg_and_die ( "Failed to create gzip pipe" );
+
+ signal ( SIGPIPE, SIG_IGN ); // we only want EPIPE on errors
+
+ gzipPid = fork ( );
+
+ if ( gzipPid == 0 ) {
+ dup2 ( gzipDataPipe [0], 0 );
+ close ( gzipDataPipe [1] );
+
+ if ( tbInfo. tarFd != 1 );
+ dup2 ( tbInfo. tarFd, 1 );
+
+ close ( gzipStatusPipe [0] );
+ fcntl( gzipStatusPipe [1], F_SETFD, FD_CLOEXEC ); // close on exec shows sucess
+
+ execl ( "/bin/gzip", "gzip", "-f", 0 );
+
+ write ( gzipStatusPipe [1], "", 1 );
+ close ( gzipStatusPipe [1] );
+
+ exit ( -1 );
+ }
+ else if ( gzipPid > 0 ) {
+ close ( gzipDataPipe [0] );
+ close ( gzipStatusPipe [1] );
+
+ while ( 1 ) {
+ char buf;
+
+ int n = read ( gzipStatusPipe [0], &buf, 1 );
+ if ( n == 1 )
+ error_msg_and_die ( "Could not exec gzip process" ); // socket was not closed => error
+ else if (( n < 0 ) && ( errno==EAGAIN || errno==EINTR ))
+ continue; // try it again
+ break;
+ }
+ close ( gzipStatusPipe [0] );
+
+ tbInfo. tarFd = gzipDataPipe [1];
+ }
+ else {
+ perror_msg_and_die ( "Failed to fork gzip process" );
+ }
+ }
+#endif
+
+ tbInfo.excludeList=excludeList;
+
/* Read the directory/files and iterate over them one at a time */
while (*argv != NULL) {
if (! recursive_action(*argv++, TRUE, FALSE, FALSE,
@@ -493,14 +558,20 @@ static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
* so is considered a waste of space */
/* Hang up the tools, close up shop, head home */
- close(tarFd);
- if (errorFlag) {
+ close(tbInfo.tarFd);
+ if (errorFlag)
error_msg("Error exit delayed from previous errors");
- freeHardLinkInfo(&tbInfo.hlInfoHead);
- return(FALSE);
- }
+
freeHardLinkInfo(&tbInfo.hlInfoHead);
- return( TRUE);
+
+#ifdef CONFIG_FEATURE_TAR_GZIP
+ if ( gzip && gzipPid ) {
+ if ( waitpid ( gzipPid, NULL, 0 ) == -1 )
+ printf ( "Couldnt wait ?" );
+ }
+#endif
+
+ return !errorFlag;
}
#endif //tar_create
@@ -653,10 +724,7 @@ int tar_main(int argc, char **argv)
case 'p':
break;
case 'v':
- if (extract_function & extract_list) {
- extract_function |= extract_verbose_list;
- }
- extract_function |= extract_list;
+ extract_function |= extract_verbose_list;
break;
#ifdef CONFIG_FEATURE_TAR_GZIP
case 'z':
@@ -711,22 +779,23 @@ int tar_main(int argc, char **argv)
/* create an archive */
else if (untar_funct & untar_create) {
int verboseFlag = FALSE;
+ int gzipFlag = FALSE;
#ifdef CONFIG_FEATURE_TAR_GZIP
- if (untar_funct & untar_unzip) {
- error_msg_and_die("Creation of compressed tarfile not internally support by tar, pipe to busybox gunzip");
- }
+ if (untar_funct & untar_unzip)
+ gzipFlag = TRUE;
+
#endif // CONFIG_FEATURE_TAR_GZIP
- if (extract_function & extract_verbose_list) {
+ if (extract_function & extract_verbose_list)
verboseFlag = TRUE;
- }
- writeTarFile(src_filename, verboseFlag, include_list, exclude_list);
+
+ writeTarFile(src_filename, verboseFlag, include_list, exclude_list, gzipFlag);
}
#endif // CONFIG_FEATURE_TAR_CREATE
/* Cleanups */
#ifdef CONFIG_FEATURE_TAR_GZIP
- if (untar_funct & untar_unzip) {
+ if ( !( untar_funct & untar_create ) && ( untar_funct & untar_unzip )) {
fclose(src_stream);
close(gz_fd);
gz_close(gunzip_pid);