*/
//usage:#define unzip_trivial_usage
-//usage: "[-opts[modifiers]] FILE[.zip] [LIST] [-x XLIST] [-d DIR]"
+//usage: "[-lnopq] FILE[.zip] [FILE]... [-x FILE...] [-d DIR]"
//usage:#define unzip_full_usage "\n\n"
-//usage: "Extract files from ZIP archives\n"
-//usage: "\n -l List archive contents (with -q for short form)"
-//usage: "\n -n Never overwrite files (default)"
+//usage: "Extract FILEs from ZIP archive\n"
+//usage: "\n -l List contents (with -q for short form)"
+//usage: "\n -n Never overwrite files (default: ask)"
//usage: "\n -o Overwrite"
-//usage: "\n -p Send output to stdout"
+//usage: "\n -p Print to stdout"
//usage: "\n -q Quiet"
-//usage: "\n -x XLST Exclude these files"
-//usage: "\n -d DIR Extract files into DIR"
+//usage: "\n -x FILE Exclude FILEs"
+//usage: "\n -d DIR Extract into DIR"
#include "libbb.h"
-#include "archive.h"
+#include "bb_archive.h"
enum {
#if BB_BIG_ENDIAN
/* Create all leading directories */
char *name = xstrdup(fn);
if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
- bb_error_msg_and_die("exiting"); /* bb_make_directory is noisy */
+ xfunc_die(); /* bb_make_directory is noisy */
}
free(name);
}
bb_copyfd_exact_size(zip_fd, dst_fd, size);
} else {
/* Method 8 - inflate */
- inflate_unzip_result res;
- if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0)
+ transformer_aux_data_t aux;
+ init_transformer_aux_data(&aux);
+ aux.bytes_in = zip_header->formatted.cmpsize;
+ if (inflate_unzip(&aux, zip_fd, dst_fd) < 0)
bb_error_msg_and_die("inflate error");
/* Validate decompression - crc */
- if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) {
+ if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) {
bb_error_msg_and_die("crc error");
}
/* Validate decompression - size */
- if (zip_header->formatted.ucmpsize != res.bytes_out) {
+ if (zip_header->formatted.ucmpsize != aux.bytes_out) {
/* Don't die. Who knows, maybe len calculation
* was botched somewhere. After all, crc matched! */
bb_error_msg("bad length");
}
}
+static void my_fgets80(char *buf80)
+{
+ fflush_all();
+ if (!fgets(buf80, 80, stdin)) {
+ bb_perror_msg_and_die("can't read standard input");
+ }
+}
+
int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int unzip_main(int argc, char **argv)
{
IF_NOT_DESKTOP(const) smallint verbose = 0;
smallint listing = 0;
smallint overwrite = O_PROMPT;
+ smallint x_opt_seen;
#if ENABLE_DESKTOP
uint32_t cdf_offset;
#endif
llist_t *zreject = NULL;
char *base_dir = NULL;
int i, opt;
- int opt_range = 0;
- char key_buf[80];
+ char key_buf[80]; /* must match size used by my_fgets80 */
struct stat stat_buf;
/* -q, -l and -v: UnZip 5.52 of 28 February 2005, by Info-ZIP:
* 204372 1 file
*/
+ x_opt_seen = 0;
/* '-' makes getopt return 1 for non-options */
while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) {
- switch (opt_range) {
- case 0: /* Options */
- switch (opt) {
- case 'l': /* List */
- listing = 1;
- break;
+ switch (opt) {
+ case 'd': /* Extract to base directory */
+ base_dir = optarg;
+ break;
- case 'n': /* Never overwrite existing files */
- overwrite = O_NEVER;
- break;
+ case 'l': /* List */
+ listing = 1;
+ break;
- case 'o': /* Always overwrite existing files */
- overwrite = O_ALWAYS;
- break;
+ case 'n': /* Never overwrite existing files */
+ overwrite = O_NEVER;
+ break;
- case 'p': /* Extract files to stdout and fall through to set verbosity */
- dst_fd = STDOUT_FILENO;
+ case 'o': /* Always overwrite existing files */
+ overwrite = O_ALWAYS;
+ break;
- case 'q': /* Be quiet */
- quiet++;
- break;
+ case 'p': /* Extract files to stdout and fall through to set verbosity */
+ dst_fd = STDOUT_FILENO;
- case 'v': /* Verbose list */
- IF_DESKTOP(verbose++;)
- listing = 1;
- break;
+ case 'q': /* Be quiet */
+ quiet++;
+ break;
- case 1: /* The zip file */
- /* +5: space for ".zip" and NUL */
- src_fn = xmalloc(strlen(optarg) + 5);
- strcpy(src_fn, optarg);
- opt_range++;
- break;
+ case 'v': /* Verbose list */
+ IF_DESKTOP(verbose++;)
+ listing = 1;
+ break;
- default:
- bb_show_usage();
- }
+ case 'x':
+ x_opt_seen = 1;
break;
- case 1: /* Include files */
- if (opt == 1) {
+ case 1:
+ if (!src_fn) {
+ /* The zip file */
+ /* +5: space for ".zip" and NUL */
+ src_fn = xmalloc(strlen(optarg) + 5);
+ strcpy(src_fn, optarg);
+ } else if (!x_opt_seen) {
+ /* Include files */
llist_add_to(&zaccept, optarg);
- break;
- }
- if (opt == 'd') {
- base_dir = optarg;
- opt_range += 2;
- break;
- }
- if (opt == 'x') {
- opt_range++;
- break;
- }
- bb_show_usage();
-
- case 2 : /* Exclude files */
- if (opt == 1) {
+ } else {
+ /* Exclude files */
llist_add_to(&zreject, optarg);
- break;
- }
- if (opt == 'd') { /* Extract to base directory */
- base_dir = optarg;
- opt_range++;
- break;
}
- /* fall through */
+ break;
default:
bb_show_usage();
}
}
- if (src_fn == NULL) {
+#ifndef __GLIBC__
+ /*
+ * This code is needed for non-GNU getopt
+ * which doesn't understand "-" in option string.
+ * The -x option won't work properly in this case:
+ * "unzip a.zip q -x w e" will be interpreted as
+ * "unzip a.zip q w e -x" = "unzip a.zip q w e"
+ */
+ argv += optind;
+ if (argv[0]) {
+ /* +5: space for ".zip" and NUL */
+ src_fn = xmalloc(strlen(argv[0]) + 5);
+ strcpy(src_fn, argv[0]);
+ while (*++argv)
+ llist_add_to(&zaccept, *argv);
+ }
+#endif
+
+ if (!src_fn) {
bb_show_usage();
}
if (overwrite == O_PROMPT)
overwrite = O_NEVER;
} else {
- static const char extn[][5] = {"", ".zip", ".ZIP"};
- int orig_src_fn_len = strlen(src_fn);
- int src_fd = -1;
+ static const char extn[][5] = { ".zip", ".ZIP" };
+ char *ext = src_fn + strlen(src_fn);
+ int src_fd;
- for (i = 0; (i < 3) && (src_fd == -1); i++) {
- strcpy(src_fn + orig_src_fn_len, extn[i]);
+ i = 0;
+ for (;;) {
src_fd = open(src_fn, O_RDONLY);
- }
- if (src_fd == -1) {
- src_fn[orig_src_fn_len] = '\0';
- bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);
+ if (src_fd >= 0)
+ break;
+ if (++i > 2) {
+ *ext = '\0';
+ bb_error_msg_and_die("can't open %s[.zip]", src_fn);
+ }
+ strcpy(ext, extn[i - 1]);
}
xmove_fd(src_fd, zip_fd);
}
printf(" creating: %s\n", dst_fn);
}
unzip_create_leading_dirs(dst_fn);
- if (bb_make_directory(dst_fn, dir_mode, 0)) {
- bb_error_msg_and_die("exiting");
+ if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) {
+ xfunc_die();
}
} else {
if (!S_ISDIR(stat_buf.st_mode)) {
i = 'y';
} else {
printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
- if (!fgets(key_buf, sizeof(key_buf), stdin)) {
- bb_perror_msg_and_die("can't read input");
- }
+ my_fgets80(key_buf);
i = key_buf[0];
}
} else { /* File is not regular file */
case 'r':
/* Prompt for new name */
printf("new name: ");
- if (!fgets(key_buf, sizeof(key_buf), stdin)) {
- bb_perror_msg_and_die("can't read input");
- }
+ my_fgets80(key_buf);
free(dst_fn);
dst_fn = xstrdup(key_buf);
chomp(dst_fn);