Added tar -cz support (creating gzipped tar files without a gzip pipe)
authorRobert Griebl <griebl@gmx.de>
Tue, 23 Jul 2002 22:05:47 +0000 (22:05 -0000)
committerRobert Griebl <griebl@gmx.de>
Tue, 23 Jul 2002 22:05:47 +0000 (22:05 -0000)
archival/config.in
archival/tar.c

index 5a064dc89d147a354e6fcb0b318b44b0170bd6c9..ac90ec0a91b8fb7deb17300429ca93e961e62e37 100644 (file)
@@ -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
index b18f1f87f2d6a36c04c9dcd3c8908ca26f9cb7c6..2aa5f07888e70267b6794477b6c2f87ec6d45344 100644 (file)
@@ -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);