Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/archival/tar.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 815 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 3  Line 3 
3   * Mini tar implementation for busybox   * Mini tar implementation for busybox
4   *   *
5   * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg   * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg
6   *  Glenn McGrath <bug1@iinet.net.au>   *  by Glenn McGrath
7   *   *
8   * Note, that as of BusyBox-0.43, tar has been completely rewritten from the   * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
9   * ground up.  It still has remnants of the old code lying about, but it is   * ground up.  It still has remnants of the old code lying about, but it is
# Line 24  Line 24 
24   */   */
25    
26  #include <fnmatch.h>  #include <fnmatch.h>
27  #include <getopt.h>  #include "libbb.h"
 #include "busybox.h"  
28  #include "unarchive.h"  #include "unarchive.h"
29    
30    /* FIXME: Stop using this non-standard feature */
31    #ifndef FNM_LEADING_DIR
32    #define FNM_LEADING_DIR 0
33    #endif
34    
35    
36    #define block_buf bb_common_bufsiz1
37    
38    
39    #if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
40    /* Do not pass gzip flag to writeTarFile() */
41    #define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \
42     writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude)
43    #endif
44    
45    
46  #if ENABLE_FEATURE_TAR_CREATE  #if ENABLE_FEATURE_TAR_CREATE
47    
48  /* Tar file constants  */  /* Tar file constants  */
# Line 48  struct TarHeader {  /* byte offset */ Line 63  struct TarHeader {  /* byte offset */
63   char chksum[8];           /* 148-155 */   char chksum[8];           /* 148-155 */
64   char typeflag;            /* 156-156 */   char typeflag;            /* 156-156 */
65   char linkname[NAME_SIZE]; /* 157-256 */   char linkname[NAME_SIZE]; /* 157-256 */
66   char magic[6];            /* 257-262 */   /* POSIX:   "ustar" NUL "00" */
67   char version[2];          /* 263-264 */   /* GNU tar: "ustar  " NUL */
68     /* Normally it's defined as magic[6] followed by
69     * version[2], but we put them together to save code.
70     */
71     char magic[8];            /* 257-264 */
72   char uname[32];           /* 265-296 */   char uname[32];           /* 265-296 */
73   char gname[32];           /* 297-328 */   char gname[32];           /* 297-328 */
74   char devmajor[8];         /* 329-336 */   char devmajor[8];         /* 329-336 */
75   char devminor[8];         /* 337-344 */   char devminor[8];         /* 337-344 */
76   char prefix[155];         /* 345-499 */   char prefix[155];         /* 345-499 */
77   char padding[12];         /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */   char padding[12];         /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */
78  };  };
79    
80  /*  /*
# Line 65  struct TarHeader {  /* byte offset */ Line 84  struct TarHeader {  /* byte offset */
84  */  */
85  typedef struct HardLinkInfo HardLinkInfo;  typedef struct HardLinkInfo HardLinkInfo;
86  struct HardLinkInfo {  struct HardLinkInfo {
87   HardLinkInfo *next; /* Next entry in list */   HardLinkInfo *next;     /* Next entry in list */
88   dev_t dev; /* Device number */   dev_t dev;              /* Device number */
89   ino_t ino; /* Inode number */   ino_t ino;              /* Inode number */
90   short linkCount; /* (Hard) Link Count */   short linkCount;        /* (Hard) Link Count */
91   char name[1]; /* Start of filename (must be last) */   char name[1];           /* Start of filename (must be last) */
92  };  };
93    
94  /* Some info to be carried along when creating a new tarball */  /* Some info to be carried along when creating a new tarball */
95  typedef struct TarBallInfo TarBallInfo;  typedef struct TarBallInfo TarBallInfo;
96  struct TarBallInfo {  struct TarBallInfo {
97   int tarFd; /* Open-for-write file descriptor   int tarFd;                      /* Open-for-write file descriptor
98     for the tarball */                                   * for the tarball */
99   struct stat statBuf; /* Stat info for the tarball, letting   struct stat statBuf;            /* Stat info for the tarball, letting
100     us know the inode and device that the                                   * us know the inode and device that the
101     tarball lives, so we can avoid trying                                   * tarball lives, so we can avoid trying
102     to include the tarball into itself */                                   * to include the tarball into itself */
103   int verboseFlag; /* Whether to print extra stuff or not */   int verboseFlag;                /* Whether to print extra stuff or not */
104   const llist_t *excludeList; /* List of files to not include */   const llist_t *excludeList;     /* List of files to not include */
105   HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */   HardLinkInfo *hlInfoHead;       /* Hard Link Tracking Information */
106   HardLinkInfo *hlInfo; /* Hard Link Info for the current file */   HardLinkInfo *hlInfo;           /* Hard Link Info for the current file */
107  };  };
108    
109  /* A nice enum with all the possible tar file content types */  /* A nice enum with all the possible tar file content types */
# Line 104  enum TarFileType { Line 123  enum TarFileType {
123  typedef enum TarFileType TarFileType;  typedef enum TarFileType TarFileType;
124    
125  /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */  /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
126  static void addHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr,  static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
127   struct stat *statbuf,   struct stat *statbuf,
128   const char *fileName)   const char *fileName)
129  {  {
# Line 120  static void addHardLinkInfo(HardLinkInfo Line 139  static void addHardLinkInfo(HardLinkInfo
139   strcpy(hlInfo->name, fileName);   strcpy(hlInfo->name, fileName);
140  }  }
141    
142  static void freeHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr)  static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
143  {  {
144   HardLinkInfo *hlInfo;   HardLinkInfo *hlInfo;
145   HardLinkInfo *hlInfoNext;   HardLinkInfo *hlInfoNext;
# Line 134  static void freeHardLinkInfo(HardLinkInf Line 153  static void freeHardLinkInfo(HardLinkInf
153   }   }
154   *hlInfoHeadPtr = NULL;   *hlInfoHeadPtr = NULL;
155   }   }
  return;  
156  }  }
157    
158  /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */  /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
159  static HardLinkInfo *findHardLinkInfo(HardLinkInfo * hlInfo, struct stat *statbuf)  static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
160  {  {
161   while (hlInfo) {   while (hlInfo) {
162   if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev))   if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev))
# Line 173  static void putOctal(char *cp, int len, Line 191  static void putOctal(char *cp, int len,
191    
192  static void chksum_and_xwrite(int fd, struct TarHeader* hp)  static void chksum_and_xwrite(int fd, struct TarHeader* hp)
193  {  {
194     /* POSIX says that checksum is done on unsigned bytes
195     * (Sun and HP-UX gets it wrong... more details in
196     * GNU tar source) */
197   const unsigned char *cp;   const unsigned char *cp;
198   int chksum, size;   int chksum, size;
199    
# Line 273  static int writeTarHeader(struct TarBall Line 294  static int writeTarHeader(struct TarBall
294   tbInfo->hlInfo->name, 0);   tbInfo->hlInfo->name, 0);
295  #endif  #endif
296   } else if (S_ISLNK(statbuf->st_mode)) {   } else if (S_ISLNK(statbuf->st_mode)) {
297   char *lpath = xreadlink(fileName);   char *lpath = xmalloc_readlink_or_warn(fileName);
298   if (!lpath) /* Already printed err msg inside xreadlink() */   if (!lpath)
299   return FALSE;   return FALSE;
300   header.typeflag = SYMTYPE;   header.typeflag = SYMTYPE;
301   strncpy(header.linkname, lpath, sizeof(header.linkname));   strncpy(header.linkname, lpath, sizeof(header.linkname));
# Line 375  static int exclude_file(const llist_t *e Line 396  static int exclude_file(const llist_t *e
396  #define exclude_file(excluded_files, file) 0  #define exclude_file(excluded_files, file) 0
397  #endif  #endif
398    
399  static int writeFileToTarball(const char *fileName, struct stat *statbuf,  static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
400   void *userData, int depth ATTRIBUTE_UNUSED)   void *userData, int depth UNUSED_PARAM)
401  {  {
402   struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;   struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
403   const char *header_name;   const char *header_name;
404   int inputFileFd = -1;   int inputFileFd = -1;
405    
406     /* Strip leading '/' (must be before memorizing hardlink's name) */
407     header_name = fileName;
408     while (header_name[0] == '/') {
409     static smallint warned;
410    
411     if (!warned) {
412     bb_error_msg("removing leading '/' from member names");
413     warned = 1;
414     }
415     header_name++;
416     }
417    
418     if (header_name[0] == '\0')
419     return TRUE;
420    
421     /* It is against the rules to archive a socket */
422     if (S_ISSOCK(statbuf->st_mode)) {
423     bb_error_msg("%s: socket ignored", fileName);
424     return TRUE;
425     }
426    
427   /*   /*
428   * Check to see if we are dealing with a hard link.   * Check to see if we are dealing with a hard link.
429   * If so -   * If so -
# Line 393  static int writeFileToTarball(const char Line 435  static int writeFileToTarball(const char
435   if (statbuf->st_nlink > 1) {   if (statbuf->st_nlink > 1) {
436   tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);   tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
437   if (tbInfo->hlInfo == NULL)   if (tbInfo->hlInfo == NULL)
438   addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, fileName);   addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
  }  
   
  /* It is against the rules to archive a socket */  
  if (S_ISSOCK(statbuf->st_mode)) {  
  bb_error_msg("%s: socket ignored", fileName);  
  return TRUE;  
439   }   }
440    
441   /* It is a bad idea to store the archive we are in the process of creating,   /* It is a bad idea to store the archive we are in the process of creating,
442   * so check the device and inode to be sure that this particular file isn't   * so check the device and inode to be sure that this particular file isn't
443   * the new tarball */   * the new tarball */
444   if (tbInfo->statBuf.st_dev == statbuf->st_dev &&   if (tbInfo->statBuf.st_dev == statbuf->st_dev
445   tbInfo->statBuf.st_ino == statbuf->st_ino) {   && tbInfo->statBuf.st_ino == statbuf->st_ino
446     ) {
447   bb_error_msg("%s: file is the archive; skipping", fileName);   bb_error_msg("%s: file is the archive; skipping", fileName);
448   return TRUE;   return TRUE;
449   }   }
450    
451   header_name = fileName;   if (exclude_file(tbInfo->excludeList, header_name))
452   while (header_name[0] == '/') {   return SKIP;
  static int alreadyWarned = FALSE;  
   
  if (alreadyWarned == FALSE) {  
  bb_error_msg("removing leading '/' from member names");  
  alreadyWarned = TRUE;  
  }  
  header_name++;  
  }  
453    
454  #if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS  #if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
455   if (strlen(fileName) >= NAME_SIZE) {   if (strlen(header_name) >= NAME_SIZE) {
456   bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");   bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
457   return TRUE;   return TRUE;
458   }   }
459  #endif  #endif
460    
  if (header_name[0] == '\0')  
  return TRUE;  
   
  if (exclude_file(tbInfo->excludeList, header_name))  
  return SKIP;  
   
461   /* Is this a regular file? */   /* Is this a regular file? */
462   if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {   if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
463   /* open the file we want to archive, and make sure all is well */   /* open the file we want to archive, and make sure all is well */
464   inputFileFd = open(fileName, O_RDONLY);   inputFileFd = open_or_warn(fileName, O_RDONLY);
465   if (inputFileFd < 0) {   if (inputFileFd < 0) {
  bb_perror_msg("%s: cannot open", fileName);  
466   return FALSE;   return FALSE;
467   }   }
468   }   }
# Line 453  static int writeFileToTarball(const char Line 475  static int writeFileToTarball(const char
475   /* If it was a regular file, write out the body */   /* If it was a regular file, write out the body */
476   if (inputFileFd >= 0) {   if (inputFileFd >= 0) {
477   size_t readSize;   size_t readSize;
478   /* Wwrite the file to the archive. */   /* Write the file to the archive. */
479   /* We record size into header first, */   /* We record size into header first, */
480   /* and then write out file. If file shrinks in between, */   /* and then write out file. If file shrinks in between, */
481   /* tar will be corrupted. So we don't allow for that. */   /* tar will be corrupted. So we don't allow for that. */
# Line 474  static int writeFileToTarball(const char Line 496  static int writeFileToTarball(const char
496   /* Pad the file up to the tar block size */   /* Pad the file up to the tar block size */
497   /* (a few tricks here in the name of code size) */   /* (a few tricks here in the name of code size) */
498   readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);   readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
499   memset(bb_common_bufsiz1, 0, readSize);   memset(block_buf, 0, readSize);
500   xwrite(tbInfo->tarFd, bb_common_bufsiz1, readSize);   xwrite(tbInfo->tarFd, block_buf, readSize);
501   }   }
502    
503   return TRUE;   return TRUE;
504  }  }
505    
506  static int writeTarFile(const int tar_fd, const int verboseFlag,  #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
507   const unsigned long dereferenceFlag, const llist_t *include,  #if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
508   const llist_t *exclude, const int gzip)  #define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
509    #endif
510    /* Don't inline: vfork scares gcc and pessimizes code */
511    static void NOINLINE vfork_compressor(int tar_fd, int gzip)
512    {
513     pid_t gzipPid;
514    #if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
515     const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
516    #elif ENABLE_FEATURE_SEAMLESS_GZ
517     const char *zip_exec = "gzip";
518    #else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
519     const char *zip_exec = "bzip2";
520    #endif
521     // On Linux, vfork never unpauses parent early, although standard
522     // allows for that. Do we want to waste bytes checking for it?
523    #define WAIT_FOR_CHILD 0
524     volatile int vfork_exec_errno = 0;
525     struct fd_pair gzipDataPipe;
526    #if WAIT_FOR_CHILD
527     struct fd_pair gzipStatusPipe;
528     xpiped_pair(gzipStatusPipe);
529    #endif
530     xpiped_pair(gzipDataPipe);
531    
532     signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
533    
534    #if defined(__GNUC__) && __GNUC__
535     /* Avoid vfork clobbering */
536     (void) &zip_exec;
537    #endif
538    
539     gzipPid = vfork();
540     if (gzipPid < 0)
541     bb_perror_msg_and_die("vfork");
542    
543     if (gzipPid == 0) {
544     /* child */
545     /* NB: close _first_, then move fds! */
546     close(gzipDataPipe.wr);
547    #if WAIT_FOR_CHILD
548     close(gzipStatusPipe.rd);
549     /* gzipStatusPipe.wr will close only on exec -
550     * parent waits for this close to happen */
551     fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
552    #endif
553     xmove_fd(gzipDataPipe.rd, 0);
554     xmove_fd(tar_fd, 1);
555     /* exec gzip/bzip2 program/applet */
556     BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
557     vfork_exec_errno = errno;
558     _exit(EXIT_FAILURE);
559     }
560    
561     /* parent */
562     xmove_fd(gzipDataPipe.wr, tar_fd);
563     close(gzipDataPipe.rd);
564    #if WAIT_FOR_CHILD
565     close(gzipStatusPipe.wr);
566     while (1) {
567     char buf;
568     int n;
569    
570     /* Wait until child execs (or fails to) */
571     n = full_read(gzipStatusPipe.rd, &buf, 1);
572     if (n < 0 /* && errno == EAGAIN */)
573     continue; /* try it again */
574     }
575     close(gzipStatusPipe.rd);
576    #endif
577     if (vfork_exec_errno) {
578     errno = vfork_exec_errno;
579     bb_perror_msg_and_die("cannot exec %s", zip_exec);
580     }
581    }
582    #endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
583    
584    
585    /* gcc 4.2.1 inlines it, making code bigger */
586    static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
587     int dereferenceFlag, const llist_t *include,
588     const llist_t *exclude, int gzip)
589  {  {
  pid_t gzipPid = 0;  
590   int errorFlag = FALSE;   int errorFlag = FALSE;
591   struct TarBallInfo tbInfo;   struct TarBallInfo tbInfo;
592    
593   tbInfo.hlInfoHead = NULL;   tbInfo.hlInfoHead = NULL;
   
  fchmod(tar_fd, 0644);  
594   tbInfo.tarFd = tar_fd;   tbInfo.tarFd = tar_fd;
595   tbInfo.verboseFlag = verboseFlag;   tbInfo.verboseFlag = verboseFlag;
596    
# Line 500  static int writeTarFile(const int tar_fd Line 599  static int writeTarFile(const int tar_fd
599   if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)   if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
600   bb_perror_msg_and_die("cannot stat tar file");   bb_perror_msg_and_die("cannot stat tar file");
601    
602   if ((ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2) && gzip) {  #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
603   int gzipDataPipe[2] = { -1, -1 };   if (gzip)
604   int gzipStatusPipe[2] = { -1, -1 };   vfork_compressor(tbInfo.tarFd, gzip);
  volatile int vfork_exec_errno = 0;  
  char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";  
   
  if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0)  
  bb_perror_msg_and_die("pipe");  
   
  signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */  
   
 #if defined(__GNUC__) && __GNUC__  
  /* Avoid vfork clobbering */  
  (void) &include;  
  (void) &errorFlag;  
  (void) &zip_exec;  
605  #endif  #endif
606    
  gzipPid = vfork();  
   
  if (gzipPid == 0) {  
  dup2(gzipDataPipe[0], 0);  
  close(gzipDataPipe[1]);  
   
  dup2(tbInfo.tarFd, 1);  
   
  close(gzipStatusPipe[0]);  
  fcntl(gzipStatusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows success */  
   
  execlp(zip_exec, zip_exec, "-f", NULL);  
  vfork_exec_errno = errno;  
   
  close(gzipStatusPipe[1]);  
  exit(-1);  
  } else if (gzipPid > 0) {  
  close(gzipDataPipe[0]);  
  close(gzipStatusPipe[1]);  
   
  while (1) {  
  char buf;  
   
  int n = full_read(gzipStatusPipe[0], &buf, 1);  
   
  if (n == 0 && vfork_exec_errno != 0) {  
  errno = vfork_exec_errno;  
  bb_perror_msg_and_die("cannot exec %s", zip_exec);  
  } else if ((n < 0) && (errno == EAGAIN || errno == EINTR))  
  continue; /* try it again */  
  break;  
  }  
  close(gzipStatusPipe[0]);  
   
  tbInfo.tarFd = gzipDataPipe[1];  
  } else bb_perror_msg_and_die("vfork gzip");  
  }  
   
607   tbInfo.excludeList = exclude;   tbInfo.excludeList = exclude;
608    
609   /* Read the directory/files and iterate over them one at a time */   /* Read the directory/files and iterate over them one at a time */
610   while (include) {   while (include) {
611   if (!recursive_action(include->data, TRUE, dereferenceFlag,   if (!recursive_action(include->data, ACTION_RECURSE |
612   FALSE, writeFileToTarball, writeFileToTarball, &tbInfo, 0))   (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
613     writeFileToTarball, writeFileToTarball, &tbInfo, 0))
614   {   {
615   errorFlag = TRUE;   errorFlag = TRUE;
616   }   }
617   include = include->link;   include = include->link;
618   }   }
619   /* Write two empty blocks to the end of the archive */   /* Write two empty blocks to the end of the archive */
620   memset(bb_common_bufsiz1, 0, 2*TAR_BLOCK_SIZE);   memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
621   xwrite(tbInfo.tarFd, bb_common_bufsiz1, 2*TAR_BLOCK_SIZE);   xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
622    
623   /* To be pedantically correct, we would check if the tarball   /* To be pedantically correct, we would check if the tarball
624   * is smaller than 20 tar blocks, and pad it if it was smaller,   * is smaller than 20 tar blocks, and pad it if it was smaller,
# Line 586  static int writeTarFile(const int tar_fd Line 635  static int writeTarFile(const int tar_fd
635   if (errorFlag)   if (errorFlag)
636   bb_error_msg("error exit delayed from previous errors");   bb_error_msg("error exit delayed from previous errors");
637    
638   if (gzipPid) {  #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
639     if (gzip) {
640   int status;   int status;
641   if (waitpid(gzipPid, &status, 0) == -1)   if (safe_waitpid(-1, &status, 0) == -1)
642   bb_perror_msg("waitpid");   bb_perror_msg("waitpid");
643   else if (!WIFEXITED(status) || WEXITSTATUS(status))   else if (!WIFEXITED(status) || WEXITSTATUS(status))
644   /* gzip was killed or has exited with nonzero! */   /* gzip was killed or has exited with nonzero! */
645   errorFlag = TRUE;   errorFlag = TRUE;
646   }   }
647    #endif
648   return errorFlag;   return errorFlag;
649  }  }
650  #else  #else
651  int writeTarFile(const int tar_fd, const int verboseFlag,  int writeTarFile(int tar_fd, int verboseFlag,
652   const unsigned long dereferenceFlag, const llist_t *include,   int dereferenceFlag, const llist_t *include,
653   const llist_t *exclude, const int gzip);   const llist_t *exclude, int gzip);
654  #endif /* FEATURE_TAR_CREATE */  #endif /* FEATURE_TAR_CREATE */
655    
656  #if ENABLE_FEATURE_TAR_FROM  #if ENABLE_FEATURE_TAR_FROM
657  static llist_t *append_file_list_to_list(llist_t *list)  static llist_t *append_file_list_to_list(llist_t *list)
658  {  {
659   FILE *src_stream;   FILE *src_stream;
  llist_t *cur = list;  
  llist_t *tmp;  
660   char *line;   char *line;
661   llist_t *newlist = NULL;   llist_t *newlist = NULL;
662    
663   while (cur) {   while (list) {
664   src_stream = xfopen(cur->data, "r");   src_stream = xfopen_for_read(llist_pop(&list));
665   tmp = cur;   while ((line = xmalloc_fgetline(src_stream)) != NULL) {
  cur = cur->link;  
  free(tmp);  
  while ((line = xmalloc_getline(src_stream)) != NULL) {  
666   /* kill trailing '/' unless the string is just "/" */   /* kill trailing '/' unless the string is just "/" */
667   char *cp = last_char_is(line, '/');   char *cp = last_char_is(line, '/');
668   if (cp > line)   if (cp > line)
# Line 631  static llist_t *append_file_list_to_list Line 677  static llist_t *append_file_list_to_list
677  #define append_file_list_to_list(x) 0  #define append_file_list_to_list(x) 0
678  #endif  #endif
679    
680  #if ENABLE_FEATURE_TAR_COMPRESS  #if ENABLE_FEATURE_SEAMLESS_Z
681  static char get_header_tar_Z(archive_handle_t *archive_handle)  static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle)
682  {  {
683   /* Can't lseek over pipes */   /* Can't lseek over pipes */
684   archive_handle->seek = seek_by_read;   archive_handle->seek = seek_by_read;
# Line 644  static char get_header_tar_Z(archive_han Line 690  static char get_header_tar_Z(archive_han
690   bb_error_msg_and_die("invalid magic");   bb_error_msg_and_die("invalid magic");
691   }   }
692    
693   archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress);   open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress");
694   archive_handle->offset = 0;   archive_handle->offset = 0;
695   while (get_header_tar(archive_handle) == EXIT_SUCCESS)   while (get_header_tar(archive_handle) == EXIT_SUCCESS)
696   /* nothing */;   continue;
697    
698   /* Can only do one file at a time */   /* Can only do one file at a time */
699   return EXIT_FAILURE;   return EXIT_FAILURE;
# Line 666  static void handle_SIGCHLD(int status) Line 712  static void handle_SIGCHLD(int status)
712   /* Actually, 'status' is a signo. We reuse it for other needs */   /* Actually, 'status' is a signo. We reuse it for other needs */
713    
714   /* Wait for any child without blocking */   /* Wait for any child without blocking */
715   if (waitpid(-1, &status, WNOHANG) < 0)   if (wait_any_nohang(&status) < 0)
716   /* wait failed?! I'm confused... */   /* wait failed?! I'm confused... */
717   return;   return;
718    
# Line 674  static void handle_SIGCHLD(int status) Line 720  static void handle_SIGCHLD(int status)
720   /* child exited with 0 */   /* child exited with 0 */
721   return;   return;
722   /* Cannot happen?   /* Cannot happen?
723   if(!WIFSIGNALED(status) && !WIFEXITED(status)) return; */   if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
724   child_error = 1;   child_error = 1;
725  }  }
726  #endif  #endif
727    
728  enum {  enum {
729   OPTBIT_KEEP_OLD = 7,   OPTBIT_KEEP_OLD = 7,
730   USE_FEATURE_TAR_CREATE(  OPTBIT_CREATE      ,)   USE_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)
731   USE_FEATURE_TAR_CREATE(  OPTBIT_DEREFERENCE ,)   USE_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)
732   USE_FEATURE_TAR_BZIP2(   OPTBIT_BZIP2       ,)   USE_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)
733   USE_FEATURE_TAR_LZMA(    OPTBIT_LZMA        ,)   USE_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)
734   USE_FEATURE_TAR_FROM(    OPTBIT_INCLUDE_FROM,)   USE_FEATURE_TAR_FROM(     OPTBIT_INCLUDE_FROM,)
735   USE_FEATURE_TAR_FROM(    OPTBIT_EXCLUDE_FROM,)   USE_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)
736   USE_FEATURE_TAR_GZIP(    OPTBIT_GZIP        ,)   USE_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)
737   USE_FEATURE_TAR_COMPRESS(OPTBIT_COMPRESS    ,)   USE_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,)
738   OPTBIT_NOPRESERVE_OWN,   OPTBIT_NOPRESERVE_OWN,
739   OPTBIT_NOPRESERVE_PERM,   OPTBIT_NOPRESERVE_PERM,
740   OPT_TEST         = 1 << 0, // t   OPT_TEST         = 1 << 0, // t
# Line 699  enum { Line 745  enum {
745   OPT_P            = 1 << 5, // p   OPT_P            = 1 << 5, // p
746   OPT_VERBOSE      = 1 << 6, // v   OPT_VERBOSE      = 1 << 6, // v
747   OPT_KEEP_OLD     = 1 << 7, // k   OPT_KEEP_OLD     = 1 << 7, // k
748   OPT_CREATE       = USE_FEATURE_TAR_CREATE(  (1<<OPTBIT_CREATE      )) + 0, // c   OPT_CREATE       = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c
749   OPT_DEREFERENCE  = USE_FEATURE_TAR_CREATE(  (1<<OPTBIT_DEREFERENCE )) + 0, // h   OPT_DEREFERENCE  = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h
750   OPT_BZIP2        = USE_FEATURE_TAR_BZIP2(   (1<<OPTBIT_BZIP2       )) + 0, // j   OPT_BZIP2        = USE_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j
751   OPT_LZMA         = USE_FEATURE_TAR_LZMA(    (1<<OPTBIT_LZMA        )) + 0, // a   OPT_LZMA         = USE_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a
752   OPT_INCLUDE_FROM = USE_FEATURE_TAR_FROM(    (1<<OPTBIT_INCLUDE_FROM)) + 0, // T   OPT_INCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
753   OPT_EXCLUDE_FROM = USE_FEATURE_TAR_FROM(    (1<<OPTBIT_EXCLUDE_FROM)) + 0, // X   OPT_EXCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
754   OPT_GZIP         = USE_FEATURE_TAR_GZIP(    (1<<OPTBIT_GZIP        )) + 0, // z   OPT_GZIP         = USE_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z
755   OPT_COMPRESS     = USE_FEATURE_TAR_COMPRESS((1<<OPTBIT_COMPRESS    )) + 0, // Z   OPT_COMPRESS     = USE_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
756   OPT_NOPRESERVE_OWN  = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner   OPT_NOPRESERVE_OWN  = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner
757   OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions   OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions
758  };  };
759  #if ENABLE_FEATURE_TAR_LONG_OPTIONS  #if ENABLE_FEATURE_TAR_LONG_OPTIONS
760  static const struct option tar_long_options[] = {  static const char tar_longopts[] ALIGN1 =
761   { "list",               0,  NULL,   't' },   "list\0"                No_argument       "t"
762   { "extract",            0,  NULL,   'x' },   "extract\0"             No_argument       "x"
763   { "directory",          1,  NULL,   'C' },   "directory\0"           Required_argument "C"
764   { "file",               1,  NULL,   'f' },   "file\0"                Required_argument "f"
765   { "to-stdout",          0,  NULL,   'O' },   "to-stdout\0"           No_argument       "O"
766   { "same-permissions",   0,  NULL,   'p' },   "same-permissions\0"    No_argument       "p"
767   { "verbose",            0,  NULL,   'v' },   "verbose\0"             No_argument       "v"
768   { "keep-old",           0,  NULL,   'k' },   "keep-old\0"            No_argument       "k"
769  # if ENABLE_FEATURE_TAR_CREATE  # if ENABLE_FEATURE_TAR_CREATE
770   { "create",             0,  NULL,   'c' },   "create\0"              No_argument       "c"
771   { "dereference",        0,  NULL,   'h' },   "dereference\0"         No_argument       "h"
772  # endif  # endif
773  # if ENABLE_FEATURE_TAR_BZIP2  # if ENABLE_FEATURE_SEAMLESS_BZ2
774   { "bzip2",              0,  NULL,   'j' },   "bzip2\0"               No_argument       "j"
775  # endif  # endif
776  # if ENABLE_FEATURE_TAR_LZMA  # if ENABLE_FEATURE_SEAMLESS_LZMA
777   { "lzma",               0,  NULL,   'a' },   "lzma\0"                No_argument       "a"
778  # endif  # endif
779  # if ENABLE_FEATURE_TAR_FROM  # if ENABLE_FEATURE_TAR_FROM
780   { "files-from",         1,  NULL,   'T' },   "files-from\0"          Required_argument "T"
781   { "exclude-from",       1,  NULL,   'X' },   "exclude-from\0"        Required_argument "X"
782  # endif  # endif
783  # if ENABLE_FEATURE_TAR_GZIP  # if ENABLE_FEATURE_SEAMLESS_GZ
784   { "gzip",               0,  NULL,   'z' },   "gzip\0"                No_argument       "z"
785  # endif  # endif
786  # if ENABLE_FEATURE_TAR_COMPRESS  # if ENABLE_FEATURE_SEAMLESS_Z
787   { "compress",           0,  NULL,   'Z' },   "compress\0"            No_argument       "Z"
788  # endif  # endif
789   { "no-same-owner",      0,  NULL,   0xfd },   "no-same-owner\0"       No_argument       "\xfd"
790   { "no-same-permissions",0,  NULL,   0xfe },   "no-same-permissions\0" No_argument       "\xfe"
791   /* --exclude takes next bit position in option mask, */   /* --exclude takes next bit position in option mask, */
792   /* therefore we have to either put it _after_ --no-same-perm */   /* therefore we have to either put it _after_ --no-same-perm */
793   /* or add OPT[BIT]_EXCLUDE before OPT[BIT]_NOPRESERVE_OWN */   /* or add OPT[BIT]_EXCLUDE before OPT[BIT]_NOPRESERVE_OWN */
794  # if ENABLE_FEATURE_TAR_FROM  # if ENABLE_FEATURE_TAR_FROM
795   { "exclude",            1,  NULL,   0xff },   "exclude\0"             Required_argument "\xff"
796  # endif  # endif
797   { 0,                    0, 0, 0 }   ;
 };  
798  #endif  #endif
799    
800  int tar_main(int argc, char **argv)  int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
801    int tar_main(int argc UNUSED_PARAM, char **argv)
802  {  {
803   char (*get_header_ptr)(archive_handle_t *) = get_header_tar;   char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
804   archive_handle_t *tar_handle;   archive_handle_t *tar_handle;
805   char *base_dir = NULL;   char *base_dir = NULL;
806   const char *tar_filename = "-";   const char *tar_filename = "-";
# Line 766  int tar_main(int argc, char **argv) Line 812  int tar_main(int argc, char **argv)
812    
813   /* Initialise default values */   /* Initialise default values */
814   tar_handle = init_handle();   tar_handle = init_handle();
815   tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS   tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
816                    | ARCHIVE_PRESERVE_DATE                       | ARCHIVE_PRESERVE_DATE
817                    | ARCHIVE_EXTRACT_UNCONDITIONAL;                       | ARCHIVE_EXTRACT_UNCONDITIONAL;
818    
819     /* Apparently only root's tar preserves perms (see bug 3844) */
820     if (getuid() != 0)
821     tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;
822    
823   /* Prepend '-' to the first argument if required */   /* Prepend '-' to the first argument if required */
824   opt_complementary = "--:" // first arg is options   opt_complementary = "--:" // first arg is options
# Line 782  int tar_main(int argc, char **argv) Line 832  int tar_main(int argc, char **argv)
832   USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive   USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
833   SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive   SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
834  #if ENABLE_FEATURE_TAR_LONG_OPTIONS  #if ENABLE_FEATURE_TAR_LONG_OPTIONS
835   applet_long_options = tar_long_options;   applet_long_options = tar_longopts;
836  #endif  #endif
837   opt = getopt32(argc, argv,   opt = getopt32(argv,
838   "txC:f:Opvk"   "txC:f:Opvk"
839   USE_FEATURE_TAR_CREATE(  "ch"  )   USE_FEATURE_TAR_CREATE(   "ch"  )
840   USE_FEATURE_TAR_BZIP2(   "j"   )   USE_FEATURE_SEAMLESS_BZ2( "j"   )
841   USE_FEATURE_TAR_LZMA(    "a"   )   USE_FEATURE_SEAMLESS_LZMA("a"   )
842   USE_FEATURE_TAR_FROM(    "T:X:")   USE_FEATURE_TAR_FROM(     "T:X:")
843   USE_FEATURE_TAR_GZIP(    "z"   )   USE_FEATURE_SEAMLESS_GZ(  "z"   )
844   USE_FEATURE_TAR_COMPRESS("Z"   )   USE_FEATURE_SEAMLESS_Z(   "Z"   )
845   , &base_dir // -C dir   , &base_dir // -C dir
846   , &tar_filename // -f filename   , &tar_filename // -f filename
847   USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T   USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
# Line 802  int tar_main(int argc, char **argv) Line 852  int tar_main(int argc, char **argv)
852   , &verboseFlag // combined count for -t and -v   , &verboseFlag // combined count for -t and -v
853   , &verboseFlag // combined count for -t and -v   , &verboseFlag // combined count for -t and -v
854   );   );
855     argv += optind;
856    
857   if (verboseFlag) tar_handle->action_header = header_verbose_list;   if (verboseFlag) tar_handle->action_header = header_verbose_list;
858   if (verboseFlag == 1) tar_handle->action_header = header_list;   if (verboseFlag == 1) tar_handle->action_header = header_list;
# Line 813  int tar_main(int argc, char **argv) Line 864  int tar_main(int argc, char **argv)
864   tar_handle->action_data = data_extract_to_stdout;   tar_handle->action_data = data_extract_to_stdout;
865    
866   if (opt & OPT_KEEP_OLD)   if (opt & OPT_KEEP_OLD)
867   tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;   tar_handle->ah_flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;
868    
869   if (opt & OPT_NOPRESERVE_OWN)   if (opt & OPT_NOPRESERVE_OWN)
870   tar_handle->flags |= ARCHIVE_NOPRESERVE_OWN;   tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_OWN;
871    
872   if (opt & OPT_NOPRESERVE_PERM)   if (opt & OPT_NOPRESERVE_PERM)
873   tar_handle->flags |= ARCHIVE_NOPRESERVE_PERM;   tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;
874    
875   if (opt & OPT_GZIP)   if (opt & OPT_GZIP)
876   get_header_ptr = get_header_tar_gz;   get_header_ptr = get_header_tar_gz;
# Line 847  int tar_main(int argc, char **argv) Line 898  int tar_main(int argc, char **argv)
898   tar_handle->accept = append_file_list_to_list(tar_handle->accept);   tar_handle->accept = append_file_list_to_list(tar_handle->accept);
899  #endif  #endif
900    
  /* Check if we are reading from stdin */  
  if (argv[optind] && *argv[optind] == '-') {  
  /* Default is to read from stdin, so just skip to next arg */  
  optind++;  
  }  
   
901   /* Setup an array of filenames to work with */   /* Setup an array of filenames to work with */
902   /* TODO: This is the same as in ar, separate function ? */   /* TODO: This is the same as in ar, separate function ? */
903   while (optind < argc) {   while (*argv) {
904   /* kill trailing '/' unless the string is just "/" */   /* kill trailing '/' unless the string is just "/" */
905   char *cp = last_char_is(argv[optind], '/');   char *cp = last_char_is(*argv, '/');
906   if (cp > argv[optind])   if (cp > *argv)
907   *cp = '\0';   *cp = '\0';
908   llist_add_to(&tar_handle->accept, argv[optind]);   llist_add_to_end(&tar_handle->accept, *argv);
909   optind++;   argv++;
910   }   }
  tar_handle->accept = rev_llist(tar_handle->accept);  
911    
912   if (tar_handle->accept || tar_handle->reject)   if (tar_handle->accept || tar_handle->reject)
913   tar_handle->filter = filter_accept_reject_list;   tar_handle->filter = filter_accept_reject_list;
# Line 880  int tar_main(int argc, char **argv) Line 924  int tar_main(int argc, char **argv)
924    
925   tar_stream = stdout;   tar_stream = stdout;
926   /* Mimicking GNU tar 1.15.1: */   /* Mimicking GNU tar 1.15.1: */
927   flags = O_WRONLY|O_CREAT|O_TRUNC;   flags = O_WRONLY | O_CREAT | O_TRUNC;
  /* was doing unlink; open(O_WRONLY|O_CREAT|O_EXCL); why? */  
928   } else {   } else {
929   tar_stream = stdin;   tar_stream = stdin;
930   flags = O_RDONLY;   flags = O_RDONLY;
# Line 891  int tar_main(int argc, char **argv) Line 934  int tar_main(int argc, char **argv)
934   tar_handle->src_fd = fileno(tar_stream);   tar_handle->src_fd = fileno(tar_stream);
935   tar_handle->seek = seek_by_read;   tar_handle->seek = seek_by_read;
936   } else {   } else {
937   tar_handle->src_fd = xopen(tar_filename, flags);   if (ENABLE_FEATURE_TAR_AUTODETECT
938     && get_header_ptr == get_header_tar
939     && flags == O_RDONLY
940     ) {
941     tar_handle->src_fd = open_zipped(tar_filename);
942     if (tar_handle->src_fd < 0)
943     bb_perror_msg_and_die("can't open '%s'", tar_filename);
944     } else {
945     tar_handle->src_fd = xopen(tar_filename, flags);
946     }
947   }   }
948   }   }
949    
# Line 905  int tar_main(int argc, char **argv) Line 957  int tar_main(int argc, char **argv)
957    
958   /* create an archive */   /* create an archive */
959   if (opt & OPT_CREATE) {   if (opt & OPT_CREATE) {
960    #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
961   int zipMode = 0;   int zipMode = 0;
962   if (ENABLE_FEATURE_TAR_GZIP && get_header_ptr == get_header_tar_gz)   if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP))
963   zipMode = 1;   zipMode = 1;
964   if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2)   if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2))
965   zipMode = 2;   zipMode = 2;
966    #endif
967   /* NB: writeTarFile() closes tar_handle->src_fd */   /* NB: writeTarFile() closes tar_handle->src_fd */
968   return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,   return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
969   tar_handle->accept,   tar_handle->accept,
# Line 917  int tar_main(int argc, char **argv) Line 971  int tar_main(int argc, char **argv)
971   }   }
972    
973   while (get_header_ptr(tar_handle) == EXIT_SUCCESS)   while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
974   /* nothing */;   continue;
975    
976   /* Check that every file that should have been extracted was */   /* Check that every file that should have been extracted was */
977   while (tar_handle->accept) {   while (tar_handle->accept) {

Legend:
Removed from v.815  
changed lines
  Added in v.816