diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-19 11:26:28 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-19 11:26:28 +0000 |
commit | 431a7c9c53b69a7416091721da673bcff7c91a02 (patch) | |
tree | 03cbe0e15af01d82b05138f0db41d44179262a3f | |
parent | a37e7134f76b7661b86bb9cc926f28f81b1e1109 (diff) | |
download | busybox-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.in | 36 | ||||
-rw-r--r-- | archival/libunarchive/get_header_tar.c | 52 | ||||
-rw-r--r-- | archival/tar.c | 35 |
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 | ||
169 | config 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 | |||
169 | config FEATURE_TAR_BZIP2 | 177 | config 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 | ||
185 | config FEATURE_TAR_FROM | 193 | config 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 | ||
193 | config FEATURE_TAR_GZIP | 201 | config 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 | ||
201 | config FEATURE_TAR_COMPRESS | 209 | config 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 | ||
209 | config FEATURE_TAR_OLDGNU_COMPATIBILITY | 217 | config 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); | |||
46 | char get_header_tar(archive_handle_t *archive_handle) | 46 | char 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) { |