aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-02-19 11:26:28 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-02-19 11:26:28 +0000
commit431a7c9c53b69a7416091721da673bcff7c91a02 (patch)
tree03cbe0e15af01d82b05138f0db41d44179262a3f
parenta37e7134f76b7661b86bb9cc926f28f81b1e1109 (diff)
downloadbusybox-w32-431a7c9c53b69a7416091721da673bcff7c91a02.tar.gz
busybox-w32-431a7c9c53b69a7416091721da673bcff7c91a02.tar.bz2
busybox-w32-431a7c9c53b69a7416091721da673bcff7c91a02.zip
tar: optional autodetection of gz/bz2 compressed tarballs.
+130 bytes. Closes bug 992.
-rw-r--r--archival/Config.in36
-rw-r--r--archival/libunarchive/get_header_tar.c52
-rw-r--r--archival/tar.c35
3 files changed, 92 insertions, 31 deletions
diff --git a/archival/Config.in b/archival/Config.in
index 160c54d64..6f803f4fe 100644
--- a/archival/Config.in
+++ b/archival/Config.in
@@ -166,6 +166,14 @@ config FEATURE_TAR_CREATE
166 If you enable this option you'll be able to create 166 If you enable this option you'll be able to create
167 tar archives using the `-c' option. 167 tar archives using the `-c' option.
168 168
169config FEATURE_TAR_GZIP
170 bool "Enable -z option"
171 default y
172 depends on TAR
173 help
174 If you enable this option tar will be able to call gzip,
175 when creating or extracting tar gziped archives.
176
169config FEATURE_TAR_BZIP2 177config FEATURE_TAR_BZIP2
170 bool "Enable -j option to handle .tar.bz2 files" 178 bool "Enable -j option to handle .tar.bz2 files"
171 default n 179 default n
@@ -182,29 +190,29 @@ config FEATURE_TAR_LZMA
182 If you enable this option you'll be able to extract 190 If you enable this option you'll be able to extract
183 archives compressed with lzma. 191 archives compressed with lzma.
184 192
185config FEATURE_TAR_FROM 193config FEATURE_TAR_COMPRESS
186 bool "Enable -X (exclude from) and -T (include from) options)" 194 bool "Enable -Z option"
187 default n 195 default n
188 depends on TAR 196 depends on TAR
189 help 197 help
190 If you enable this option you'll be able to specify 198 If you enable this option tar will be able to call uncompress,
191 a list of files to include or exclude from an archive. 199 when extracting .tar.Z archives.
192 200
193config FEATURE_TAR_GZIP 201config FEATURE_TAR_AUTODETECT
194 bool "Enable -z option" 202 bool "Let tar autodetect gz/bz2 compresses tarballs"
195 default y 203 default n
196 depends on TAR 204 depends on FEATURE_TAR_GZIP || FEATURE_TAR_BZIP2
197 help 205 help
198 If you enable this option tar will be able to call gzip, 206 With this option tar can automatically detect gzip/bzip2 compressed
199 when creating or extracting tar gziped archives. 207 tarballs. Currently it works only on seekable streams.
200 208
201config FEATURE_TAR_COMPRESS 209config FEATURE_TAR_FROM
202 bool "Enable -Z option" 210 bool "Enable -X (exclude from) and -T (include from) options)"
203 default n 211 default n
204 depends on TAR 212 depends on TAR
205 help 213 help
206 If you enable this option tar will be able to call uncompress, 214 If you enable this option you'll be able to specify
207 when extracting .tar.Z archives. 215 a list of files to include or exclude from an archive.
208 216
209config FEATURE_TAR_OLDGNU_COMPATIBILITY 217config FEATURE_TAR_OLDGNU_COMPATIBILITY
210 bool "Enable support for old tar header format" 218 bool "Enable support for old tar header format"
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c
index 893cd5b79..54c8f7665 100644
--- a/archival/libunarchive/get_header_tar.c
+++ b/archival/libunarchive/get_header_tar.c
@@ -46,6 +46,9 @@ void BUG_tar_header_size(void);
46char get_header_tar(archive_handle_t *archive_handle) 46char get_header_tar(archive_handle_t *archive_handle)
47{ 47{
48 static smallint end; 48 static smallint end;
49#if ENABLE_FEATURE_TAR_AUTODETECT
50 static smallint not_first;
51#endif
49 52
50 file_header_t *file_header = archive_handle->file_header; 53 file_header_t *file_header = archive_handle->file_header;
51 struct { 54 struct {
@@ -115,7 +118,7 @@ char get_header_tar(archive_handle_t *archive_handle)
115 * Read until the end to empty the pipe from gz or bz2 118 * Read until the end to empty the pipe from gz or bz2
116 */ 119 */
117 while (full_read(archive_handle->src_fd, &tar, 512) == 512) 120 while (full_read(archive_handle->src_fd, &tar, 512) == 512)
118 /* repeat */; 121 continue;
119 return EXIT_FAILURE; 122 return EXIT_FAILURE;
120 } 123 }
121 end = 1; 124 end = 1;
@@ -123,16 +126,49 @@ char get_header_tar(archive_handle_t *archive_handle)
123 } 126 }
124 end = 0; 127 end = 0;
125 128
126 /* Check header has valid magic, "ustar" is for the proper tar 129 /* Check header has valid magic, "ustar" is for the proper tar,
127 * 0's are for the old tar format 130 * five NULs are for the old tar format */
128 */ 131 if (strncmp(tar.magic, "ustar", 5) != 0
129 if (strncmp(tar.magic, "ustar", 5) != 0) { 132 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
130#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY 133 || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
131 if (memcmp(tar.magic, "\0\0\0\0", 5) != 0) 134 ) {
135#if ENABLE_FEATURE_TAR_AUTODETECT
136 char (*get_header_ptr)(archive_handle_t *);
137
138 /* tar gz/bz autodetect: check for gz/bz2 magic.
139 * If it is the very first block, and we see the magic,
140 * we can switch to get_header_tar_gz/bz2/lzma().
141 * Needs seekable fd. I wish recv(MSG_PEEK) would work
142 * on any fd... */
143 if (not_first)
144 goto err;
145#if ENABLE_FEATURE_TAR_GZIP
146 if (tar.name[0] == 0x1f && tar.name[1] == 0x8b) { /* gzip */
147 get_header_ptr = get_header_tar_gz;
148 } else
132#endif 149#endif
133 bb_error_msg_and_die("invalid tar magic"); 150#if ENABLE_FEATURE_TAR_BZIP2
151 if (tar.name[0] == 'B' && tar.name[1] == 'Z'
152 && tar.name[2] == 'h' && isdigit(tar.name[3])
153 ) { /* bzip2 */
154 get_header_ptr = get_header_tar_bz2;
155 } else
156#endif
157 goto err;
158 if (lseek(archive_handle->src_fd, -512, SEEK_CUR) != 0)
159 goto err;
160 while (get_header_ptr(archive_handle) == EXIT_SUCCESS)
161 continue;
162 return EXIT_FAILURE;
163 err:
164#endif /* FEATURE_TAR_AUTODETECT */
165 bb_error_msg_and_die("invalid tar magic");
134 } 166 }
135 167
168#if ENABLE_FEATURE_TAR_AUTODETECT
169 not_first = 1;
170#endif
171
136 /* Do checksum on headers. 172 /* Do checksum on headers.
137 * POSIX says that checksum is done on unsigned bytes, but 173 * POSIX says that checksum is done on unsigned bytes, but
138 * Sun and HP-UX gets it wrong... more details in 174 * Sun and HP-UX gets it wrong... more details in
diff --git a/archival/tar.c b/archival/tar.c
index 4ec454b88..e790f28ea 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -33,8 +33,17 @@
33#define FNM_LEADING_DIR 0 33#define FNM_LEADING_DIR 0
34#endif 34#endif
35 35
36
36#define block_buf bb_common_bufsiz1 37#define block_buf bb_common_bufsiz1
37 38
39
40#if !ENABLE_FEATURE_TAR_GZIP && !ENABLE_FEATURE_TAR_BZIP2
41/* Do not pass gzip flag to writeTarFile() */
42#define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \
43 writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude)
44#endif
45
46
38#if ENABLE_FEATURE_TAR_CREATE 47#if ENABLE_FEATURE_TAR_CREATE
39 48
40/* Tar file constants */ 49/* Tar file constants */
@@ -514,18 +523,23 @@ static int writeTarFile(const int tar_fd, const int verboseFlag,
514 if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) 523 if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
515 bb_perror_msg_and_die("cannot stat tar file"); 524 bb_perror_msg_and_die("cannot stat tar file");
516 525
517 if ((ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2) && gzip) { 526#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2
518// On Linux, vfork never unpauses parent early, although standard 527 if (gzip) {
519// allows for that. Do we want to waste bytes checking for it? 528#if ENABLE_FEATURE_TAR_GZIP && ENABLE_FEATURE_TAR_BZIP2
529 const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
530#elif ENABLE_FEATURE_TAR_GZIP
531 const char *zip_exec = "gzip";
532#else /* only ENABLE_FEATURE_TAR_BZIP2 */
533 const char *zip_exec = "bzip2";
534#endif
535 // On Linux, vfork never unpauses parent early, although standard
536 // allows for that. Do we want to waste bytes checking for it?
520#define WAIT_FOR_CHILD 0 537#define WAIT_FOR_CHILD 0
521
522 volatile int vfork_exec_errno = 0; 538 volatile int vfork_exec_errno = 0;
523#if WAIT_FOR_CHILD 539#if WAIT_FOR_CHILD
524 struct fd_pair gzipStatusPipe; 540 struct fd_pair gzipStatusPipe;
525#endif 541#endif
526 struct fd_pair gzipDataPipe; 542 struct fd_pair gzipDataPipe;
527 const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
528
529 xpiped_pair(gzipDataPipe); 543 xpiped_pair(gzipDataPipe);
530#if WAIT_FOR_CHILD 544#if WAIT_FOR_CHILD
531 xpiped_pair(gzipStatusPipe); 545 xpiped_pair(gzipStatusPipe);
@@ -584,6 +598,7 @@ static int writeTarFile(const int tar_fd, const int verboseFlag,
584 bb_perror_msg_and_die("cannot exec %s", zip_exec); 598 bb_perror_msg_and_die("cannot exec %s", zip_exec);
585 } 599 }
586 } 600 }
601#endif
587 602
588 tbInfo.excludeList = exclude; 603 tbInfo.excludeList = exclude;
589 604
@@ -934,11 +949,13 @@ int tar_main(int argc, char **argv)
934 949
935 /* create an archive */ 950 /* create an archive */
936 if (opt & OPT_CREATE) { 951 if (opt & OPT_CREATE) {
952#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2
937 int zipMode = 0; 953 int zipMode = 0;
938 if (ENABLE_FEATURE_TAR_GZIP && get_header_ptr == get_header_tar_gz) 954 if (ENABLE_FEATURE_TAR_GZIP && (opt & OPT_GZIP))
939 zipMode = 1; 955 zipMode = 1;
940 if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2) 956 if (ENABLE_FEATURE_TAR_BZIP2 && (opt & OPT_BZIP2))
941 zipMode = 2; 957 zipMode = 2;
958#endif
942 /* NB: writeTarFile() closes tar_handle->src_fd */ 959 /* NB: writeTarFile() closes tar_handle->src_fd */
943 return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE, 960 return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
944 tar_handle->accept, 961 tar_handle->accept,
@@ -946,7 +963,7 @@ int tar_main(int argc, char **argv)
946 } 963 }
947 964
948 while (get_header_ptr(tar_handle) == EXIT_SUCCESS) 965 while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
949 /* nothing */; 966 continue;
950 967
951 /* Check that every file that should have been extracted was */ 968 /* Check that every file that should have been extracted was */
952 while (tar_handle->accept) { 969 while (tar_handle->accept) {