Magellan Linux

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

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

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 26  Line 26 
26  #include <fnmatch.h>  #include <fnmatch.h>
27  #include "libbb.h"  #include "libbb.h"
28  #include "unarchive.h"  #include "unarchive.h"
   
29  /* FIXME: Stop using this non-standard feature */  /* FIXME: Stop using this non-standard feature */
30  #ifndef FNM_LEADING_DIR  #ifndef FNM_LEADING_DIR
31  #define FNM_LEADING_DIR 0  # define FNM_LEADING_DIR 0
32  #endif  #endif
33    
34    
35    //#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
36    #define DBG(...) ((void)0)
37    
38    
39  #define block_buf bb_common_bufsiz1  #define block_buf bb_common_bufsiz1
40    
41    
# Line 52  Line 55 
55  /* POSIX tar Header Block, from POSIX 1003.1-1990  */  /* POSIX tar Header Block, from POSIX 1003.1-1990  */
56  #define NAME_SIZE      100  #define NAME_SIZE      100
57  #define NAME_SIZE_STR "100"  #define NAME_SIZE_STR "100"
58  typedef struct TarHeader TarHeader;  typedef struct TarHeader {       /* byte offset */
 struct TarHeader {  /* byte offset */  
59   char name[NAME_SIZE];     /*   0-99 */   char name[NAME_SIZE];     /*   0-99 */
60   char mode[8];             /* 100-107 */   char mode[8];             /* 100-107 */
61   char uid[8];              /* 108-115 */   char uid[8];              /* 108-115 */
# Line 75  struct TarHeader {  /* byte offset */ Line 77  struct TarHeader {  /* byte offset */
77   char devminor[8];         /* 337-344 */   char devminor[8];         /* 337-344 */
78   char prefix[155];         /* 345-499 */   char prefix[155];         /* 345-499 */
79   char padding[12];         /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */   char padding[12];         /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */
80  };  } TarHeader;
81    
82  /*  /*
83  ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are  ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
84  ** the only functions that deal with the HardLinkInfo structure.  ** the only functions that deal with the HardLinkInfo structure.
85  ** Even these functions use the xxxHardLinkInfo() functions.  ** Even these functions use the xxxHardLinkInfo() functions.
86  */  */
87  typedef struct HardLinkInfo HardLinkInfo;  typedef struct HardLinkInfo {
88  struct HardLinkInfo {   struct HardLinkInfo *next; /* Next entry in list */
89   HardLinkInfo *next;     /* Next entry in list */   dev_t dev;                 /* Device number */
90   dev_t dev;              /* Device number */   ino_t ino;                 /* Inode number */
91   ino_t ino;              /* Inode number */  // short linkCount;           /* (Hard) Link Count */
92   short linkCount;        /* (Hard) Link Count */   char name[1];              /* Start of filename (must be last) */
93   char name[1];           /* Start of filename (must be last) */  } HardLinkInfo;
 };  
94    
95  /* Some info to be carried along when creating a new tarball */  /* Some info to be carried along when creating a new tarball */
96  typedef struct TarBallInfo TarBallInfo;  typedef 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 */
  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 */  
99   int verboseFlag;                /* Whether to print extra stuff or not */   int verboseFlag;                /* Whether to print extra stuff or not */
100   const llist_t *excludeList;     /* List of files to not include */   const llist_t *excludeList;     /* List of files to not include */
101   HardLinkInfo *hlInfoHead;       /* Hard Link Tracking Information */   HardLinkInfo *hlInfoHead;       /* Hard Link Tracking Information */
102   HardLinkInfo *hlInfo;           /* Hard Link Info for the current file */   HardLinkInfo *hlInfo;           /* Hard Link Info for the current file */
103  };  //TODO: save only st_dev + st_ino
104     struct stat tarFileStatBuf;     /* Stat info for the tarball, letting
105                                     * us know the inode and device that the
106                                     * tarball lives, so we can avoid trying
107                                     * to include the tarball into itself */
108    } TarBallInfo;
109    
110  /* A nice enum with all the possible tar file content types */  /* A nice enum with all the possible tar file content types */
111  enum TarFileType {  enum {
112   REGTYPE = '0', /* regular file */   REGTYPE = '0', /* regular file */
113   REGTYPE0 = '\0', /* regular file (ancient bug compat) */   REGTYPE0 = '\0', /* regular file (ancient bug compat) */
114   LNKTYPE = '1', /* hard link */   LNKTYPE = '1', /* hard link */
# Line 120  enum TarFileType { Line 121  enum TarFileType {
121   GNULONGLINK = 'K', /* GNU long (>100 chars) link name */   GNULONGLINK = 'K', /* GNU long (>100 chars) link name */
122   GNULONGNAME = 'L', /* GNU long (>100 chars) file name */   GNULONGNAME = 'L', /* GNU long (>100 chars) file name */
123  };  };
 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,
# Line 135  static void addHardLinkInfo(HardLinkInfo Line 135  static void addHardLinkInfo(HardLinkInfo
135   *hlInfoHeadPtr = hlInfo;   *hlInfoHeadPtr = hlInfo;
136   hlInfo->dev = statbuf->st_dev;   hlInfo->dev = statbuf->st_dev;
137   hlInfo->ino = statbuf->st_ino;   hlInfo->ino = statbuf->st_ino;
138   hlInfo->linkCount = statbuf->st_nlink;  // hlInfo->linkCount = statbuf->st_nlink;
139   strcpy(hlInfo->name, fileName);   strcpy(hlInfo->name, fileName);
140  }  }
141    
# Line 155  static void freeHardLinkInfo(HardLinkInf Line 155  static void freeHardLinkInfo(HardLinkInf
155   }   }
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
163     && statbuf->st_dev == hlInfo->dev
164     ) {
165     DBG("found hardlink:'%s'", hlInfo->name);
166   break;   break;
167     }
168   hlInfo = hlInfo->next;   hlInfo = hlInfo->next;
169   }   }
170   return hlInfo;   return hlInfo;
# Line 171  static HardLinkInfo *findHardLinkInfo(Ha Line 175  static HardLinkInfo *findHardLinkInfo(Ha
175   * Stores low-order bits only if whole value does not fit. */   * Stores low-order bits only if whole value does not fit. */
176  static void putOctal(char *cp, int len, off_t value)  static void putOctal(char *cp, int len, off_t value)
177  {  {
178   char tempBuffer[sizeof(off_t)*3+1];   char tempBuffer[sizeof(off_t)*3 + 1];
179   char *tempString = tempBuffer;   char *tempString = tempBuffer;
180   int width;   int width;
181    
# Line 331  static int writeTarHeader(struct TarBall Line 335  static int writeTarHeader(struct TarBall
335   if (sizeof(statbuf->st_size) > 4   if (sizeof(statbuf->st_size) > 4
336   && statbuf->st_size > (off_t)0777777777777LL   && statbuf->st_size > (off_t)0777777777777LL
337   ) {   ) {
338   bb_error_msg_and_die("cannot store file '%s' "   bb_error_msg_and_die("can't store file '%s' "
339   "of size %"OFF_FMT"d, aborting",   "of size %"OFF_FMT"u, aborting",
340   fileName, statbuf->st_size);   fileName, statbuf->st_size);
341   }   }
342   header.typeflag = REGTYPE;   header.typeflag = REGTYPE;
# Line 357  static int writeTarHeader(struct TarBall Line 361  static int writeTarHeader(struct TarBall
361   if (tbInfo->verboseFlag) {   if (tbInfo->verboseFlag) {
362   FILE *vbFd = stdout;   FILE *vbFd = stdout;
363    
364   if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */   /* If archive goes to stdout, verbose goes to stderr */
365     if (tbInfo->tarFd == STDOUT_FILENO)
366   vbFd = stderr;   vbFd = stderr;
367   /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */   /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
368   /* We don't have such excesses here: for us "v" == "vv" */   /* We don't have such excesses here: for us "v" == "vv" */
# Line 375  static int exclude_file(const llist_t *e Line 380  static int exclude_file(const llist_t *e
380   while (excluded_files) {   while (excluded_files) {
381   if (excluded_files->data[0] == '/') {   if (excluded_files->data[0] == '/') {
382   if (fnmatch(excluded_files->data, file,   if (fnmatch(excluded_files->data, file,
383   FNM_PATHNAME | FNM_LEADING_DIR) == 0)   FNM_PATHNAME | FNM_LEADING_DIR) == 0)
384   return 1;   return 1;
385   } else {   } else {
386   const char *p;   const char *p;
387    
388   for (p = file; p[0] != '\0'; p++) {   for (p = file; p[0] != '\0'; p++) {
389   if ((p == file || p[-1] == '/') && p[0] != '/' &&   if ((p == file || p[-1] == '/')
390   fnmatch(excluded_files->data, p,   && p[0] != '/'
391   FNM_PATHNAME | FNM_LEADING_DIR) == 0)   && fnmatch(excluded_files->data, p,
392     FNM_PATHNAME | FNM_LEADING_DIR) == 0
393     ) {
394   return 1;   return 1;
395     }
396   }   }
397   }   }
398   excluded_files = excluded_files->link;   excluded_files = excluded_files->link;
# Line 393  static int exclude_file(const llist_t *e Line 401  static int exclude_file(const llist_t *e
401   return 0;   return 0;
402  }  }
403  #else  #else
404  #define exclude_file(excluded_files, file) 0  # define exclude_file(excluded_files, file) 0
405  #endif  #endif
406    
407  static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,  static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
# Line 403  static int FAST_FUNC writeFileToTarball( Line 411  static int FAST_FUNC writeFileToTarball(
411   const char *header_name;   const char *header_name;
412   int inputFileFd = -1;   int inputFileFd = -1;
413    
414     DBG("writeFileToTarball('%s')", fileName);
415    
416   /* Strip leading '/' (must be before memorizing hardlink's name) */   /* Strip leading '/' (must be before memorizing hardlink's name) */
417   header_name = fileName;   header_name = fileName;
418   while (header_name[0] == '/') {   while (header_name[0] == '/') {
# Line 432  static int FAST_FUNC writeFileToTarball( Line 442  static int FAST_FUNC writeFileToTarball(
442   * by adding the file information to the HardLinkInfo linked list.   * by adding the file information to the HardLinkInfo linked list.
443   */   */
444   tbInfo->hlInfo = NULL;   tbInfo->hlInfo = NULL;
445   if (statbuf->st_nlink > 1) {   if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) {
446     DBG("'%s': st_nlink > 1", header_name);
447   tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);   tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
448   if (tbInfo->hlInfo == NULL)   if (tbInfo->hlInfo == NULL) {
449     DBG("'%s': addHardLinkInfo", header_name);
450   addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);   addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
451     }
452   }   }
453    
454   /* 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,
455   * 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
456   * the new tarball */   * the new tarball */
457   if (tbInfo->statBuf.st_dev == statbuf->st_dev   if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
458   && tbInfo->statBuf.st_ino == statbuf->st_ino   && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
459   ) {   ) {
460   bb_error_msg("%s: file is the archive; skipping", fileName);   bb_error_msg("%s: file is the archive; skipping", fileName);
461   return TRUE;   return TRUE;
# Line 504  static int FAST_FUNC writeFileToTarball( Line 517  static int FAST_FUNC writeFileToTarball(
517  }  }
518    
519  #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2  #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
520  #if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)  # if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
521  #define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)  #  define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
522  #endif  # endif
523  /* Don't inline: vfork scares gcc and pessimizes code */  /* Don't inline: vfork scares gcc and pessimizes code */
524  static void NOINLINE vfork_compressor(int tar_fd, int gzip)  static void NOINLINE vfork_compressor(int tar_fd, int gzip)
525  {  {
526   pid_t gzipPid;   pid_t gzipPid;
527  #if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2  # if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
528   const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";   const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
529  #elif ENABLE_FEATURE_SEAMLESS_GZ  # elif ENABLE_FEATURE_SEAMLESS_GZ
530   const char *zip_exec = "gzip";   const char *zip_exec = "gzip";
531  #else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */  # else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
532   const char *zip_exec = "bzip2";   const char *zip_exec = "bzip2";
533  #endif  # endif
534   // On Linux, vfork never unpauses parent early, although standard   // On Linux, vfork never unpauses parent early, although standard
535   // allows for that. Do we want to waste bytes checking for it?   // allows for that. Do we want to waste bytes checking for it?
536  #define WAIT_FOR_CHILD 0  # define WAIT_FOR_CHILD 0
537   volatile int vfork_exec_errno = 0;   volatile int vfork_exec_errno = 0;
538   struct fd_pair gzipDataPipe;   struct fd_pair gzipDataPipe;
539  #if WAIT_FOR_CHILD  # if WAIT_FOR_CHILD
540   struct fd_pair gzipStatusPipe;   struct fd_pair gzipStatusPipe;
541   xpiped_pair(gzipStatusPipe);   xpiped_pair(gzipStatusPipe);
542  #endif  # endif
543   xpiped_pair(gzipDataPipe);   xpiped_pair(gzipDataPipe);
544    
545   signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */   signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
546    
547  #if defined(__GNUC__) && __GNUC__  # if defined(__GNUC__) && __GNUC__
548   /* Avoid vfork clobbering */   /* Avoid vfork clobbering */
549   (void) &zip_exec;   (void) &zip_exec;
550  #endif  # endif
551    
552   gzipPid = vfork();   gzipPid = vfork();
553   if (gzipPid < 0)   if (gzipPid < 0)
# Line 544  static void NOINLINE vfork_compressor(in Line 557  static void NOINLINE vfork_compressor(in
557   /* child */   /* child */
558   /* NB: close _first_, then move fds! */   /* NB: close _first_, then move fds! */
559   close(gzipDataPipe.wr);   close(gzipDataPipe.wr);
560  #if WAIT_FOR_CHILD  # if WAIT_FOR_CHILD
561   close(gzipStatusPipe.rd);   close(gzipStatusPipe.rd);
562   /* gzipStatusPipe.wr will close only on exec -   /* gzipStatusPipe.wr will close only on exec -
563   * parent waits for this close to happen */   * parent waits for this close to happen */
564   fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);   fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
565  #endif  # endif
566   xmove_fd(gzipDataPipe.rd, 0);   xmove_fd(gzipDataPipe.rd, 0);
567   xmove_fd(tar_fd, 1);   xmove_fd(tar_fd, 1);
568   /* exec gzip/bzip2 program/applet */   /* exec gzip/bzip2 program/applet */
# Line 561  static void NOINLINE vfork_compressor(in Line 574  static void NOINLINE vfork_compressor(in
574   /* parent */   /* parent */
575   xmove_fd(gzipDataPipe.wr, tar_fd);   xmove_fd(gzipDataPipe.wr, tar_fd);
576   close(gzipDataPipe.rd);   close(gzipDataPipe.rd);
577  #if WAIT_FOR_CHILD  # if WAIT_FOR_CHILD
578   close(gzipStatusPipe.wr);   close(gzipStatusPipe.wr);
579   while (1) {   while (1) {
580   char buf;   char buf;
# Line 573  static void NOINLINE vfork_compressor(in Line 586  static void NOINLINE vfork_compressor(in
586   continue; /* try it again */   continue; /* try it again */
587   }   }
588   close(gzipStatusPipe.rd);   close(gzipStatusPipe.rd);
589  #endif  # endif
590   if (vfork_exec_errno) {   if (vfork_exec_errno) {
591   errno = vfork_exec_errno;   errno = vfork_exec_errno;
592   bb_perror_msg_and_die("cannot exec %s", zip_exec);   bb_perror_msg_and_die("can't execute '%s'", zip_exec);
593   }   }
594  }  }
595  #endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */  #endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
# Line 596  static NOINLINE int writeTarFile(int tar Line 609  static NOINLINE int writeTarFile(int tar
609    
610   /* Store the stat info for the tarball's file, so   /* Store the stat info for the tarball's file, so
611   * can avoid including the tarball into itself....  */   * can avoid including the tarball into itself....  */
612   if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)   if (fstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf) < 0)
613   bb_perror_msg_and_die("cannot stat tar file");   bb_perror_msg_and_die("can't stat tar file");
614    
615  #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2  #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
616   if (gzip)   if (gzip)
# Line 610  static NOINLINE int writeTarFile(int tar Line 623  static NOINLINE int writeTarFile(int tar
623   while (include) {   while (include) {
624   if (!recursive_action(include->data, ACTION_RECURSE |   if (!recursive_action(include->data, ACTION_RECURSE |
625   (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),   (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
626   writeFileToTarball, writeFileToTarball, &tbInfo, 0))   writeFileToTarball, writeFileToTarball, &tbInfo, 0)
627   {   ) {
628   errorFlag = TRUE;   errorFlag = TRUE;
629   }   }
630   include = include->link;   include = include->link;
# Line 674  static llist_t *append_file_list_to_list Line 687  static llist_t *append_file_list_to_list
687   return newlist;   return newlist;
688  }  }
689  #else  #else
690  #define append_file_list_to_list(x) 0  # define append_file_list_to_list(x) 0
691  #endif  #endif
692    
693  #if ENABLE_FEATURE_SEAMLESS_Z  #if ENABLE_FEATURE_SEAMLESS_Z
# Line 699  static char FAST_FUNC get_header_tar_Z(a Line 712  static char FAST_FUNC get_header_tar_Z(a
712   return EXIT_FAILURE;   return EXIT_FAILURE;
713  }  }
714  #else  #else
715  #define get_header_tar_Z NULL  # define get_header_tar_Z NULL
716  #endif  #endif
717    
718  #ifdef CHECK_FOR_CHILD_EXITCODE  #ifdef CHECK_FOR_CHILD_EXITCODE
# Line 716  static void handle_SIGCHLD(int status) Line 729  static void handle_SIGCHLD(int status)
729   /* wait failed?! I'm confused... */   /* wait failed?! I'm confused... */
730   return;   return;
731    
732   if (WIFEXITED(status) && WEXITSTATUS(status)==0)   if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
733   /* child exited with 0 */   /* child exited with 0 */
734   return;   return;
735   /* Cannot happen?   /* Cannot happen?
# Line 726  static void handle_SIGCHLD(int status) Line 739  static void handle_SIGCHLD(int status)
739  #endif  #endif
740    
741  enum {  enum {
742   OPTBIT_KEEP_OLD = 7,   OPTBIT_KEEP_OLD = 8,
743   USE_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)   IF_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)
744   USE_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)   IF_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)
745   USE_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)   IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)
746   USE_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)   IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)
747   USE_FEATURE_TAR_FROM(     OPTBIT_INCLUDE_FROM,)   IF_FEATURE_TAR_FROM(     OPTBIT_INCLUDE_FROM,)
748   USE_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)   IF_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)
749   USE_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)   IF_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)
750   USE_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,)   IF_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,) // 16th bit
751   OPTBIT_NOPRESERVE_OWN,   IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
752    #if ENABLE_FEATURE_TAR_LONG_OPTIONS
753     OPTBIT_NUMERIC_OWNER,
754   OPTBIT_NOPRESERVE_PERM,   OPTBIT_NOPRESERVE_PERM,
755     OPTBIT_OVERWRITE,
756    #endif
757   OPT_TEST         = 1 << 0, // t   OPT_TEST         = 1 << 0, // t
758   OPT_EXTRACT      = 1 << 1, // x   OPT_EXTRACT      = 1 << 1, // x
759   OPT_BASEDIR      = 1 << 2, // C   OPT_BASEDIR      = 1 << 2, // C
760   OPT_TARNAME      = 1 << 3, // f   OPT_TARNAME      = 1 << 3, // f
761   OPT_2STDOUT      = 1 << 4, // O   OPT_2STDOUT      = 1 << 4, // O
762   OPT_P            = 1 << 5, // p   OPT_NOPRESERVE_OWNER = 1 << 5, // o == no-same-owner
763   OPT_VERBOSE      = 1 << 6, // v   OPT_P            = 1 << 6, // p
764   OPT_KEEP_OLD     = 1 << 7, // k   OPT_VERBOSE      = 1 << 7, // v
765   OPT_CREATE       = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c   OPT_KEEP_OLD     = 1 << 8, // k
766   OPT_DEREFERENCE  = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h   OPT_CREATE       = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c
767   OPT_BZIP2        = USE_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j   OPT_DEREFERENCE  = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h
768   OPT_LZMA         = USE_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a   OPT_BZIP2        = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j
769   OPT_INCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_INCLUDE_FROM)) + 0, // T   OPT_LZMA         = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a
770   OPT_EXCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X   OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM(     (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
771   OPT_GZIP         = USE_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z   OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
772   OPT_COMPRESS     = USE_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z   OPT_GZIP         = IF_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z
773   OPT_NOPRESERVE_OWN  = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner   OPT_COMPRESS     = IF_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
774   OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions   OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m
775     OPT_NUMERIC_OWNER   = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER  )) + 0, // numeric-owner
776     OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
777     OPT_OVERWRITE       = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE      )) + 0, // overwrite
778  };  };
779  #if ENABLE_FEATURE_TAR_LONG_OPTIONS  #if ENABLE_FEATURE_TAR_LONG_OPTIONS
780  static const char tar_longopts[] ALIGN1 =  static const char tar_longopts[] ALIGN1 =
# Line 763  static const char tar_longopts[] ALIGN1 Line 783  static const char tar_longopts[] ALIGN1
783   "directory\0"           Required_argument "C"   "directory\0"           Required_argument "C"
784   "file\0"                Required_argument "f"   "file\0"                Required_argument "f"
785   "to-stdout\0"           No_argument       "O"   "to-stdout\0"           No_argument       "O"
786     /* do not restore owner */
787     /* Note: GNU tar handles 'o' as no-same-owner only on extract,
788     * on create, 'o' is --old-archive. We do not support --old-archive. */
789     "no-same-owner\0"       No_argument       "o"
790   "same-permissions\0"    No_argument       "p"   "same-permissions\0"    No_argument       "p"
791   "verbose\0"             No_argument       "v"   "verbose\0"             No_argument       "v"
792   "keep-old\0"            No_argument       "k"   "keep-old\0"            No_argument       "k"
# Line 786  static const char tar_longopts[] ALIGN1 Line 810  static const char tar_longopts[] ALIGN1
810  # if ENABLE_FEATURE_SEAMLESS_Z  # if ENABLE_FEATURE_SEAMLESS_Z
811   "compress\0"            No_argument       "Z"   "compress\0"            No_argument       "Z"
812  # endif  # endif
813   "no-same-owner\0"       No_argument       "\xfd"  # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
814   "no-same-permissions\0" No_argument       "\xfe"   "touch\0"               No_argument       "m"
815    # endif
816     /* use numeric uid/gid from tar header, not textual */
817     "numeric-owner\0"       No_argument       "\xfc"
818     /* do not restore mode */
819     "no-same-permissions\0" No_argument       "\xfd"
820     /* on unpack, open with O_TRUNC and !O_EXCL */
821     "overwrite\0"           No_argument       "\xfe"
822   /* --exclude takes next bit position in option mask, */   /* --exclude takes next bit position in option mask, */
823   /* therefore we have to either put it _after_ --no-same-perm */   /* therefore we have to put it _after_ --no-same-permissions */
  /* or add OPT[BIT]_EXCLUDE before OPT[BIT]_NOPRESERVE_OWN */  
824  # if ENABLE_FEATURE_TAR_FROM  # if ENABLE_FEATURE_TAR_FROM
825   "exclude\0"             Required_argument "\xff"   "exclude\0"             Required_argument "\xff"
826  # endif  # endif
# Line 813  int tar_main(int argc UNUSED_PARAM, char Line 843  int tar_main(int argc UNUSED_PARAM, char
843   /* Initialise default values */   /* Initialise default values */
844   tar_handle = init_handle();   tar_handle = init_handle();
845   tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS   tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
846                       | ARCHIVE_PRESERVE_DATE                       | ARCHIVE_RESTORE_DATE
847                       | ARCHIVE_EXTRACT_UNCONDITIONAL;                       | ARCHIVE_UNLINK_OLD;
848    
849   /* Apparently only root's tar preserves perms (see bug 3844) */   /* Apparently only root's tar preserves perms (see bug 3844) */
850   if (getuid() != 0)   if (getuid() != 0)
851   tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;   tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
852    
853   /* Prepend '-' to the first argument if required */   /* Prepend '-' to the first argument if required */
854   opt_complementary = "--:" // first arg is options   opt_complementary = "--:" // first arg is options
# Line 828  int tar_main(int argc UNUSED_PARAM, char Line 858  int tar_main(int argc UNUSED_PARAM, char
858  #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM  #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
859   "\xff::" // cumulative lists for --exclude   "\xff::" // cumulative lists for --exclude
860  #endif  #endif
861   USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd   IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
862   USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive   IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
863   SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive   IF_NOT_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
864  #if ENABLE_FEATURE_TAR_LONG_OPTIONS  #if ENABLE_FEATURE_TAR_LONG_OPTIONS
865   applet_long_options = tar_longopts;   applet_long_options = tar_longopts;
866  #endif  #endif
867    #if ENABLE_DESKTOP
868     if (argv[1] && argv[1][0] != '-') {
869     /* Compat:
870     * 1st argument without dash handles options with parameters
871     * differently from dashed one: it takes *next argv[i]*
872     * as paramenter even if there are more chars in 1st argument:
873     *  "tar fx TARFILE" - "x" is not taken as f's param
874     *  but is interpreted as -x option
875     *  "tar -xf TARFILE" - dashed equivalent of the above
876     *  "tar -fx ..." - "x" is taken as f's param
877     * getopt32 wouldn't handle 1st command correctly.
878     * Unfortunately, people do use such commands.
879     * We massage argv[1] to work around it by moving 'f'
880     * to the end of the string.
881     * More contrived "tar fCx TARFILE DIR" still fails,
882     * but such commands are much less likely to be used.
883     */
884     char *f = strchr(argv[1], 'f');
885     if (f) {
886     while (f[1] != '\0') {
887     *f = f[1];
888     f++;
889     }
890     *f = 'f';
891     }
892     }
893    #endif
894   opt = getopt32(argv,   opt = getopt32(argv,
895   "txC:f:Opvk"   "txC:f:Oopvk"
896   USE_FEATURE_TAR_CREATE(   "ch"  )   IF_FEATURE_TAR_CREATE(   "ch"  )
897   USE_FEATURE_SEAMLESS_BZ2( "j"   )   IF_FEATURE_SEAMLESS_BZ2( "j"   )
898   USE_FEATURE_SEAMLESS_LZMA("a"   )   IF_FEATURE_SEAMLESS_LZMA("a"   )
899   USE_FEATURE_TAR_FROM(     "T:X:")   IF_FEATURE_TAR_FROM(     "T:X:")
900   USE_FEATURE_SEAMLESS_GZ(  "z"   )   IF_FEATURE_SEAMLESS_GZ(  "z"   )
901   USE_FEATURE_SEAMLESS_Z(   "Z"   )   IF_FEATURE_SEAMLESS_Z(   "Z"   )
902     IF_FEATURE_TAR_NOPRESERVE_TIME("m")
903   , &base_dir // -C dir   , &base_dir // -C dir
904   , &tar_filename // -f filename   , &tar_filename // -f filename
905   USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T   IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
906   USE_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X   IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
907  #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM  #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
908   , &excludes // --exclude   , &excludes // --exclude
909  #endif  #endif
910   , &verboseFlag // combined count for -t and -v   , &verboseFlag // combined count for -t and -v
911   , &verboseFlag // combined count for -t and -v   , &verboseFlag // combined count for -t and -v
912   );   );
913     //bb_error_msg("opt:%08x", opt);
914   argv += optind;   argv += optind;
915    
916   if (verboseFlag) tar_handle->action_header = header_verbose_list;   if (verboseFlag) tar_handle->action_header = header_verbose_list;
# Line 864  int tar_main(int argc UNUSED_PARAM, char Line 923  int tar_main(int argc UNUSED_PARAM, char
923   tar_handle->action_data = data_extract_to_stdout;   tar_handle->action_data = data_extract_to_stdout;
924    
925   if (opt & OPT_KEEP_OLD)   if (opt & OPT_KEEP_OLD)
926   tar_handle->ah_flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;   tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
927    
928   if (opt & OPT_NOPRESERVE_OWN)   if (opt & OPT_NUMERIC_OWNER)
929   tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_OWN;   tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
930    
931     if (opt & OPT_NOPRESERVE_OWNER)
932     tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER;
933    
934   if (opt & OPT_NOPRESERVE_PERM)   if (opt & OPT_NOPRESERVE_PERM)
935   tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;   tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
936    
937     if (opt & OPT_OVERWRITE) {
938     tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
939     tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
940     }
941    
942   if (opt & OPT_GZIP)   if (opt & OPT_GZIP)
943   get_header_ptr = get_header_tar_gz;   get_header_ptr = get_header_tar_gz;
# Line 884  int tar_main(int argc UNUSED_PARAM, char Line 951  int tar_main(int argc UNUSED_PARAM, char
951   if (opt & OPT_COMPRESS)   if (opt & OPT_COMPRESS)
952   get_header_ptr = get_header_tar_Z;   get_header_ptr = get_header_tar_Z;
953    
954     if (opt & OPT_NOPRESERVE_TIME)
955     tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
956    
957  #if ENABLE_FEATURE_TAR_FROM  #if ENABLE_FEATURE_TAR_FROM
958   tar_handle->reject = append_file_list_to_list(tar_handle->reject);   tar_handle->reject = append_file_list_to_list(tar_handle->reject);
959  #if ENABLE_FEATURE_TAR_LONG_OPTIONS  # if ENABLE_FEATURE_TAR_LONG_OPTIONS
960   /* Append excludes to reject */   /* Append excludes to reject */
961   while (excludes) {   while (excludes) {
962   llist_t *next = excludes->link;   llist_t *next = excludes->link;
# Line 894  int tar_main(int argc UNUSED_PARAM, char Line 964  int tar_main(int argc UNUSED_PARAM, char
964   tar_handle->reject = excludes;   tar_handle->reject = excludes;
965   excludes = next;   excludes = next;
966   }   }
967  #endif  # endif
968   tar_handle->accept = append_file_list_to_list(tar_handle->accept);   tar_handle->accept = append_file_list_to_list(tar_handle->accept);
969  #endif  #endif
970    
971   /* Setup an array of filenames to work with */   /* Setup an array of filenames to work with */
972   /* TODO: This is the same as in ar, separate function ? */   /* TODO: This is the same as in ar, make a separate function? */
973   while (*argv) {   while (*argv) {
974   /* kill trailing '/' unless the string is just "/" */   /* kill trailing '/' unless the string is just "/" */
975   char *cp = last_char_is(*argv, '/');   char *cp = last_char_is(*argv, '/');
# Line 914  int tar_main(int argc UNUSED_PARAM, char Line 984  int tar_main(int argc UNUSED_PARAM, char
984    
985   /* Open the tar file */   /* Open the tar file */
986   {   {
987   FILE *tar_stream;   int tar_fd = STDIN_FILENO;
988   int flags;   int flags = O_RDONLY;
989    
990   if (opt & OPT_CREATE) {   if (opt & OPT_CREATE) {
991   /* Make sure there is at least one file to tar up.  */   /* Make sure there is at least one file to tar up */
992   if (tar_handle->accept == NULL)   if (tar_handle->accept == NULL)
993   bb_error_msg_and_die("empty archive");   bb_error_msg_and_die("empty archive");
994    
995   tar_stream = stdout;   tar_fd = STDOUT_FILENO;
996   /* Mimicking GNU tar 1.15.1: */   /* Mimicking GNU tar 1.15.1: */
997   flags = O_WRONLY | O_CREAT | O_TRUNC;   flags = O_WRONLY | O_CREAT | O_TRUNC;
  } else {  
  tar_stream = stdin;  
  flags = O_RDONLY;  
998   }   }
999    
1000   if (LONE_DASH(tar_filename)) {   if (LONE_DASH(tar_filename)) {
1001   tar_handle->src_fd = fileno(tar_stream);   tar_handle->src_fd = tar_fd;
1002   tar_handle->seek = seek_by_read;   tar_handle->seek = seek_by_read;
1003   } else {   } else {
1004   if (ENABLE_FEATURE_TAR_AUTODETECT   if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY) {
1005   && get_header_ptr == get_header_tar   get_header_ptr = get_header_tar;
  && flags == O_RDONLY  
  ) {  
1006   tar_handle->src_fd = open_zipped(tar_filename);   tar_handle->src_fd = open_zipped(tar_filename);
1007   if (tar_handle->src_fd < 0)   if (tar_handle->src_fd < 0)
1008   bb_perror_msg_and_die("can't open '%s'", tar_filename);   bb_perror_msg_and_die("can't open '%s'", tar_filename);
# Line 955  int tar_main(int argc UNUSED_PARAM, char Line 1020  int tar_main(int argc UNUSED_PARAM, char
1020   signal(SIGCHLD, handle_SIGCHLD);   signal(SIGCHLD, handle_SIGCHLD);
1021  #endif  #endif
1022    
1023   /* create an archive */   /* Create an archive */
1024   if (opt & OPT_CREATE) {   if (opt & OPT_CREATE) {
1025  #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2  #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
1026   int zipMode = 0;   int zipMode = 0;

Legend:
Removed from v.983  
changed lines
  Added in v.984