Disable debugging
[oweals/busybox.git] / archival / tar.c
index 5f3f567840939d16d0cab1a9921129b35ac2bc4d..2aa5f07888e70267b6794477b6c2f87ec6d45344 100644 (file)
@@ -10,7 +10,7 @@
  * very different now (i.e., cleaner, less global variables, etc.)
  *
  * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
- * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
  *
  * Based in part in the tar implementation in sash
  *  Copyright (c) 1999 by David I. Bell
@@ -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,26 +467,83 @@ 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 (!strcmp(tarName, "-"))
+       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,
+               if (recursive_action(*argv++, TRUE, FALSE, FALSE,
                                        writeFileToTarball, writeFileToTarball, 
-                                       (void*) &tbInfo) == FALSE) {
+                                       (void*) &tbInfo)) {
                        errorFlag = TRUE;
                }
        }
@@ -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 == TRUE) {
+       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
 
@@ -516,14 +587,10 @@ void append_file_list_to_list(char *filename, char ***name_list, int *num_of_ent
 {
        FILE *src_stream;
        char *line;
-       char *line_ptr;
        
        src_stream = xfopen(filename, "r");
        while ((line = get_line_from_file(src_stream)) != NULL) {
-               line_ptr = last_char_is(line, '\n');
-               if (line_ptr) {
-                       *line_ptr = '\0';
-               }
+               chomp (line);
                append_file_to_list(line, name_list, num_of_entries);
                free(line);
        }
@@ -556,7 +623,7 @@ char **list_and_not_list(char **include_list, char **exclude_list)
                        exclude_count++;
                }
 
-               if (found == FALSE) {
+               if (! found) {
                        new_include_list = realloc(new_include_list, sizeof(char *) * (include_count + 2));
                        new_include_list[new_include_count] = include_list[include_count];
                        new_include_count++;
@@ -573,14 +640,12 @@ char **list_and_not_list(char **include_list, char **exclude_list)
 int tar_main(int argc, char **argv)
 {
        enum untar_funct_e {
-               /* These are optional */
-               untar_from_file = 1,
-               untar_from_stdin = 2,
-               untar_unzip = 4,
+               /* This is optional */
+               untar_unzip = 1,
                /* Require one and only one of these */
-               untar_list = 8,
-               untar_create = 16,
-               untar_extract = 32
+               untar_list = 2,
+               untar_create = 4,
+               untar_extract = 8
        };
 
        FILE *src_stream = NULL;
@@ -589,7 +654,6 @@ int tar_main(int argc, char **argv)
        char **exclude_list = NULL;
        char *src_filename = NULL;
        char *dst_prefix = NULL;
-       char *file_list_name = NULL;
        int opt;
        unsigned short untar_funct = 0;
        unsigned short untar_funct_required = 0;
@@ -649,10 +713,8 @@ int tar_main(int argc, char **argv)
                        break;
                case 'f':       // archive filename
                        if (strcmp(optarg, "-") == 0) {
-                               // Untar from stdin to stdout
-                               untar_funct |= untar_from_stdin;
+                               src_filename = NULL;
                        } else {
-                               untar_funct |= untar_from_file;
                                src_filename = xstrdup(optarg);
                        }
                        break;
@@ -662,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':
@@ -693,14 +752,13 @@ int tar_main(int argc, char **argv)
                append_file_to_list(argv[optind], &include_list, &include_list_count);
                optind++;
        }
-
        if (extract_function & (extract_list | extract_all_to_fs)) {
                if (dst_prefix == NULL) {
                        dst_prefix = xstrdup("./");
                }
 
                /* Setup the source of the tar data */
-               if (untar_funct & untar_from_file) {
+               if (src_filename != NULL) {
                        src_stream = xfopen(src_filename, "r");
                } else {
                        src_stream = stdin;
@@ -721,32 +779,32 @@ 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, &argv[argc - 1], include_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);
        }
 #endif // CONFIG_FEATURE_TAR_GZIP
+#ifdef CONFIG_FEATURE_CLEAN_UP
        if (src_filename) {
                free(src_filename);
        }
-       if (file_list_name) {
-               free(file_list_name);
-       }
+#endif
        return(EXIT_SUCCESS);
 }