libbb/bb_strtonum: always set end ptr, even on error return
[oweals/busybox.git] / archival / unzip.c
index 5e8bac356be9b26d4d3b53fa7b3c5609dab30c22..3a11f78a553430bdaa59afcd12577452ebfa91f2 100644 (file)
@@ -7,7 +7,7 @@
  * Loosely based on original busybox unzip applet by Laurence Anderson.
  * All options and features should work in this version.
  *
- * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 
 /* For reference see
  * Zip64 + other methods
  */
 
+//usage:#define unzip_trivial_usage
+//usage:       "[-opts[modifiers]] FILE[.zip] [LIST] [-x XLIST] [-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:     "\n       -o      Overwrite"
+//usage:     "\n       -p      Send output to stdout"
+//usage:     "\n       -q      Quiet"
+//usage:     "\n       -x XLST Exclude these files"
+//usage:     "\n       -d DIR  Extract files into DIR"
+
 #include "libbb.h"
-#include "unarchive.h"
+#include "bb_archive.h"
 
 enum {
 #if BB_BIG_ENDIAN
@@ -150,23 +162,26 @@ enum { zip_fd = 3 };
 
 
 #if ENABLE_DESKTOP
+
+#define PEEK_FROM_END 16384
+
 /* NB: does not preserve file position! */
 static uint32_t find_cdf_offset(void)
 {
-       unsigned char buf[1024];
        cde_header_t cde_header;
        unsigned char *p;
        off_t end;
+       unsigned char *buf = xzalloc(PEEK_FROM_END);
 
        end = xlseek(zip_fd, 0, SEEK_END);
-       if (end < 1024)
-               end = 1024;
-       end -= 1024;
+       end -= PEEK_FROM_END;
+       if (end < 0)
+               end = 0;
        xlseek(zip_fd, end, SEEK_SET);
-       full_read(zip_fd, buf, 1024);
+       full_read(zip_fd, buf, PEEK_FROM_END);
 
        p = buf;
-       while (p <= buf + 1024 - CDE_HEADER_LEN - 4) {
+       while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) {
                if (*p != 'P') {
                        p++;
                        continue;
@@ -180,8 +195,10 @@ static uint32_t find_cdf_offset(void)
                /* we found CDE! */
                memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);
                FIX_ENDIANNESS_CDE(cde_header);
+               free(buf);
                return cde_header.formatted.cdf_offset;
        }
+       //free(buf);
        bb_error_msg_and_die("can't find file table");
 };
 
@@ -218,7 +235,7 @@ static void unzip_create_leading_dirs(const char *fn)
        /* 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);
 }
@@ -354,7 +371,6 @@ int unzip_main(int argc, char **argv)
 
                        default:
                                bb_show_usage();
-
                        }
                        break;
 
@@ -579,7 +595,7 @@ int unzip_main(int argc, char **argv)
                                        }
                                        unzip_create_leading_dirs(dst_fn);
                                        if (bb_make_directory(dst_fn, dir_mode, 0)) {
-                                               bb_error_msg_and_die("exiting");
+                                               xfunc_die();
                                        }
                                } else {
                                        if (!S_ISDIR(stat_buf.st_mode)) {
@@ -603,6 +619,7 @@ int unzip_main(int argc, char **argv)
                                                        i = 'y';
                                                } else {
                                                        printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
+                                                       fflush_all();
                                                        if (!fgets(key_buf, sizeof(key_buf), stdin)) {
                                                                bb_perror_msg_and_die("can't read input");
                                                        }