unzip.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini unzip implementation for busybox
  4. *
  5. * Copyright (C) 2004 by Ed Clark
  6. *
  7. * Loosely based on original busybox unzip applet by Laurence Anderson.
  8. * All options and features should work in this version.
  9. *
  10. * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  11. */
  12. /* For reference see
  13. * http://www.pkware.com/company/standards/appnote/
  14. * http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
  15. */
  16. /* TODO
  17. * Zip64 + other methods
  18. */
  19. #include "libbb.h"
  20. #include "unarchive.h"
  21. enum {
  22. #if BB_BIG_ENDIAN
  23. ZIP_FILEHEADER_MAGIC = 0x504b0304,
  24. ZIP_CDF_MAGIC = 0x504b0102, /* central directory's file header */
  25. ZIP_CDE_MAGIC = 0x504b0506, /* "end of central directory" record */
  26. ZIP_DD_MAGIC = 0x504b0708,
  27. #else
  28. ZIP_FILEHEADER_MAGIC = 0x04034b50,
  29. ZIP_CDF_MAGIC = 0x02014b50,
  30. ZIP_CDE_MAGIC = 0x06054b50,
  31. ZIP_DD_MAGIC = 0x08074b50,
  32. #endif
  33. };
  34. #define ZIP_HEADER_LEN 26
  35. typedef union {
  36. uint8_t raw[ZIP_HEADER_LEN];
  37. struct {
  38. uint16_t version; /* 0-1 */
  39. uint16_t zip_flags; /* 2-3 */
  40. uint16_t method; /* 4-5 */
  41. uint16_t modtime; /* 6-7 */
  42. uint16_t moddate; /* 8-9 */
  43. uint32_t crc32 PACKED; /* 10-13 */
  44. uint32_t cmpsize PACKED; /* 14-17 */
  45. uint32_t ucmpsize PACKED; /* 18-21 */
  46. uint16_t filename_len; /* 22-23 */
  47. uint16_t extra_len; /* 24-25 */
  48. } formatted PACKED;
  49. } zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */
  50. /* Check the offset of the last element, not the length. This leniency
  51. * allows for poor packing, whereby the overall struct may be too long,
  52. * even though the elements are all in the right place.
  53. */
  54. struct BUG_zip_header_must_be_26_bytes {
  55. char BUG_zip_header_must_be_26_bytes[
  56. offsetof(zip_header_t, formatted.extra_len) + 2
  57. == ZIP_HEADER_LEN ? 1 : -1];
  58. };
  59. #define FIX_ENDIANNESS_ZIP(zip_header) do { \
  60. (zip_header).formatted.version = SWAP_LE16((zip_header).formatted.version ); \
  61. (zip_header).formatted.method = SWAP_LE16((zip_header).formatted.method ); \
  62. (zip_header).formatted.modtime = SWAP_LE16((zip_header).formatted.modtime ); \
  63. (zip_header).formatted.moddate = SWAP_LE16((zip_header).formatted.moddate ); \
  64. (zip_header).formatted.crc32 = SWAP_LE32((zip_header).formatted.crc32 ); \
  65. (zip_header).formatted.cmpsize = SWAP_LE32((zip_header).formatted.cmpsize ); \
  66. (zip_header).formatted.ucmpsize = SWAP_LE32((zip_header).formatted.ucmpsize ); \
  67. (zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \
  68. (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \
  69. } while (0)
  70. #define CDF_HEADER_LEN 42
  71. typedef union {
  72. uint8_t raw[CDF_HEADER_LEN];
  73. struct {
  74. /* uint32_t signature; 50 4b 01 02 */
  75. uint16_t version_made_by; /* 0-1 */
  76. uint16_t version_needed; /* 2-3 */
  77. uint16_t cdf_flags; /* 4-5 */
  78. uint16_t method; /* 6-7 */
  79. uint16_t mtime; /* 8-9 */
  80. uint16_t mdate; /* 10-11 */
  81. uint32_t crc32; /* 12-15 */
  82. uint32_t cmpsize; /* 16-19 */
  83. uint32_t ucmpsize; /* 20-23 */
  84. uint16_t file_name_length; /* 24-25 */
  85. uint16_t extra_field_length; /* 26-27 */
  86. uint16_t file_comment_length; /* 28-29 */
  87. uint16_t disk_number_start; /* 30-31 */
  88. uint16_t internal_file_attributes; /* 32-33 */
  89. uint32_t external_file_attributes PACKED; /* 34-37 */
  90. uint32_t relative_offset_of_local_header PACKED; /* 38-41 */
  91. } formatted PACKED;
  92. } cdf_header_t;
  93. struct BUG_cdf_header_must_be_42_bytes {
  94. char BUG_cdf_header_must_be_42_bytes[
  95. offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4
  96. == CDF_HEADER_LEN ? 1 : -1];
  97. };
  98. #define FIX_ENDIANNESS_CDF(cdf_header) do { \
  99. (cdf_header).formatted.crc32 = SWAP_LE32((cdf_header).formatted.crc32 ); \
  100. (cdf_header).formatted.cmpsize = SWAP_LE32((cdf_header).formatted.cmpsize ); \
  101. (cdf_header).formatted.ucmpsize = SWAP_LE32((cdf_header).formatted.ucmpsize ); \
  102. (cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \
  103. (cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \
  104. (cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \
  105. IF_DESKTOP( \
  106. (cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \
  107. (cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \
  108. ) \
  109. } while (0)
  110. #define CDE_HEADER_LEN 16
  111. typedef union {
  112. uint8_t raw[CDE_HEADER_LEN];
  113. struct {
  114. /* uint32_t signature; 50 4b 05 06 */
  115. uint16_t this_disk_no;
  116. uint16_t disk_with_cdf_no;
  117. uint16_t cdf_entries_on_this_disk;
  118. uint16_t cdf_entries_total;
  119. uint32_t cdf_size;
  120. uint32_t cdf_offset;
  121. /* uint16_t file_comment_length; */
  122. /* .ZIP file comment (variable size) */
  123. } formatted PACKED;
  124. } cde_header_t;
  125. struct BUG_cde_header_must_be_16_bytes {
  126. char BUG_cde_header_must_be_16_bytes[
  127. sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1];
  128. };
  129. #define FIX_ENDIANNESS_CDE(cde_header) do { \
  130. (cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \
  131. } while (0)
  132. enum { zip_fd = 3 };
  133. #if ENABLE_DESKTOP
  134. #define PEEK_FROM_END 16384
  135. /* NB: does not preserve file position! */
  136. static uint32_t find_cdf_offset(void)
  137. {
  138. cde_header_t cde_header;
  139. unsigned char *p;
  140. off_t end;
  141. unsigned char *buf = xzalloc(PEEK_FROM_END);
  142. end = xlseek(zip_fd, 0, SEEK_END);
  143. end -= PEEK_FROM_END;
  144. if (end < 0)
  145. end = 0;
  146. xlseek(zip_fd, end, SEEK_SET);
  147. full_read(zip_fd, buf, PEEK_FROM_END);
  148. p = buf;
  149. while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) {
  150. if (*p != 'P') {
  151. p++;
  152. continue;
  153. }
  154. if (*++p != 'K')
  155. continue;
  156. if (*++p != 5)
  157. continue;
  158. if (*++p != 6)
  159. continue;
  160. /* we found CDE! */
  161. memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);
  162. FIX_ENDIANNESS_CDE(cde_header);
  163. free(buf);
  164. return cde_header.formatted.cdf_offset;
  165. }
  166. //free(buf);
  167. bb_error_msg_and_die("can't find file table");
  168. };
  169. static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
  170. {
  171. off_t org;
  172. org = xlseek(zip_fd, 0, SEEK_CUR);
  173. if (!cdf_offset)
  174. cdf_offset = find_cdf_offset();
  175. xlseek(zip_fd, cdf_offset + 4, SEEK_SET);
  176. xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN);
  177. FIX_ENDIANNESS_CDF(*cdf_ptr);
  178. cdf_offset += 4 + CDF_HEADER_LEN
  179. + cdf_ptr->formatted.file_name_length
  180. + cdf_ptr->formatted.extra_field_length
  181. + cdf_ptr->formatted.file_comment_length;
  182. xlseek(zip_fd, org, SEEK_SET);
  183. return cdf_offset;
  184. };
  185. #endif
  186. static void unzip_skip(off_t skip)
  187. {
  188. if (lseek(zip_fd, skip, SEEK_CUR) == (off_t)-1)
  189. bb_copyfd_exact_size(zip_fd, -1, skip);
  190. }
  191. static void unzip_create_leading_dirs(const char *fn)
  192. {
  193. /* Create all leading directories */
  194. char *name = xstrdup(fn);
  195. if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
  196. bb_error_msg_and_die("exiting"); /* bb_make_directory is noisy */
  197. }
  198. free(name);
  199. }
  200. static void unzip_extract(zip_header_t *zip_header, int dst_fd)
  201. {
  202. if (zip_header->formatted.method == 0) {
  203. /* Method 0 - stored (not compressed) */
  204. off_t size = zip_header->formatted.ucmpsize;
  205. if (size)
  206. bb_copyfd_exact_size(zip_fd, dst_fd, size);
  207. } else {
  208. /* Method 8 - inflate */
  209. inflate_unzip_result res;
  210. if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0)
  211. bb_error_msg_and_die("inflate error");
  212. /* Validate decompression - crc */
  213. if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) {
  214. bb_error_msg_and_die("crc error");
  215. }
  216. /* Validate decompression - size */
  217. if (zip_header->formatted.ucmpsize != res.bytes_out) {
  218. /* Don't die. Who knows, maybe len calculation
  219. * was botched somewhere. After all, crc matched! */
  220. bb_error_msg("bad length");
  221. }
  222. }
  223. }
  224. int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  225. int unzip_main(int argc, char **argv)
  226. {
  227. enum { O_PROMPT, O_NEVER, O_ALWAYS };
  228. zip_header_t zip_header;
  229. smallint quiet = 0;
  230. IF_NOT_DESKTOP(const) smallint verbose = 0;
  231. smallint listing = 0;
  232. smallint overwrite = O_PROMPT;
  233. #if ENABLE_DESKTOP
  234. uint32_t cdf_offset;
  235. #endif
  236. unsigned long total_usize;
  237. unsigned long total_size;
  238. unsigned total_entries;
  239. int dst_fd = -1;
  240. char *src_fn = NULL;
  241. char *dst_fn = NULL;
  242. llist_t *zaccept = NULL;
  243. llist_t *zreject = NULL;
  244. char *base_dir = NULL;
  245. int i, opt;
  246. int opt_range = 0;
  247. char key_buf[80];
  248. struct stat stat_buf;
  249. /* -q, -l and -v: UnZip 5.52 of 28 February 2005, by Info-ZIP:
  250. *
  251. * # /usr/bin/unzip -qq -v decompress_unlzma.i.zip
  252. * 204372 Defl:N 35278 83% 09-06-09 14:23 0d056252 decompress_unlzma.i
  253. * # /usr/bin/unzip -q -v decompress_unlzma.i.zip
  254. * Length Method Size Ratio Date Time CRC-32 Name
  255. * -------- ------ ------- ----- ---- ---- ------ ----
  256. * 204372 Defl:N 35278 83% 09-06-09 14:23 0d056252 decompress_unlzma.i
  257. * -------- ------- --- -------
  258. * 204372 35278 83% 1 file
  259. * # /usr/bin/unzip -v decompress_unlzma.i.zip
  260. * Archive: decompress_unlzma.i.zip
  261. * Length Method Size Ratio Date Time CRC-32 Name
  262. * -------- ------ ------- ----- ---- ---- ------ ----
  263. * 204372 Defl:N 35278 83% 09-06-09 14:23 0d056252 decompress_unlzma.i
  264. * -------- ------- --- -------
  265. * 204372 35278 83% 1 file
  266. * # unzip -v decompress_unlzma.i.zip
  267. * Archive: decompress_unlzma.i.zip
  268. * Length Date Time Name
  269. * -------- ---- ---- ----
  270. * 204372 09-06-09 14:23 decompress_unlzma.i
  271. * -------- -------
  272. * 204372 1 files
  273. * # /usr/bin/unzip -l -qq decompress_unlzma.i.zip
  274. * 204372 09-06-09 14:23 decompress_unlzma.i
  275. * # /usr/bin/unzip -l -q decompress_unlzma.i.zip
  276. * Length Date Time Name
  277. * -------- ---- ---- ----
  278. * 204372 09-06-09 14:23 decompress_unlzma.i
  279. * -------- -------
  280. * 204372 1 file
  281. * # /usr/bin/unzip -l decompress_unlzma.i.zip
  282. * Archive: decompress_unlzma.i.zip
  283. * Length Date Time Name
  284. * -------- ---- ---- ----
  285. * 204372 09-06-09 14:23 decompress_unlzma.i
  286. * -------- -------
  287. * 204372 1 file
  288. */
  289. /* '-' makes getopt return 1 for non-options */
  290. while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) {
  291. switch (opt_range) {
  292. case 0: /* Options */
  293. switch (opt) {
  294. case 'l': /* List */
  295. listing = 1;
  296. break;
  297. case 'n': /* Never overwrite existing files */
  298. overwrite = O_NEVER;
  299. break;
  300. case 'o': /* Always overwrite existing files */
  301. overwrite = O_ALWAYS;
  302. break;
  303. case 'p': /* Extract files to stdout and fall through to set verbosity */
  304. dst_fd = STDOUT_FILENO;
  305. case 'q': /* Be quiet */
  306. quiet++;
  307. break;
  308. case 'v': /* Verbose list */
  309. IF_DESKTOP(verbose++;)
  310. listing = 1;
  311. break;
  312. case 1: /* The zip file */
  313. /* +5: space for ".zip" and NUL */
  314. src_fn = xmalloc(strlen(optarg) + 5);
  315. strcpy(src_fn, optarg);
  316. opt_range++;
  317. break;
  318. default:
  319. bb_show_usage();
  320. }
  321. break;
  322. case 1: /* Include files */
  323. if (opt == 1) {
  324. llist_add_to(&zaccept, optarg);
  325. break;
  326. }
  327. if (opt == 'd') {
  328. base_dir = optarg;
  329. opt_range += 2;
  330. break;
  331. }
  332. if (opt == 'x') {
  333. opt_range++;
  334. break;
  335. }
  336. bb_show_usage();
  337. case 2 : /* Exclude files */
  338. if (opt == 1) {
  339. llist_add_to(&zreject, optarg);
  340. break;
  341. }
  342. if (opt == 'd') { /* Extract to base directory */
  343. base_dir = optarg;
  344. opt_range++;
  345. break;
  346. }
  347. /* fall through */
  348. default:
  349. bb_show_usage();
  350. }
  351. }
  352. if (src_fn == NULL) {
  353. bb_show_usage();
  354. }
  355. /* Open input file */
  356. if (LONE_DASH(src_fn)) {
  357. xdup2(STDIN_FILENO, zip_fd);
  358. /* Cannot use prompt mode since zip data is arriving on STDIN */
  359. if (overwrite == O_PROMPT)
  360. overwrite = O_NEVER;
  361. } else {
  362. static const char extn[][5] = {"", ".zip", ".ZIP"};
  363. int orig_src_fn_len = strlen(src_fn);
  364. int src_fd = -1;
  365. for (i = 0; (i < 3) && (src_fd == -1); i++) {
  366. strcpy(src_fn + orig_src_fn_len, extn[i]);
  367. src_fd = open(src_fn, O_RDONLY);
  368. }
  369. if (src_fd == -1) {
  370. src_fn[orig_src_fn_len] = '\0';
  371. bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);
  372. }
  373. xmove_fd(src_fd, zip_fd);
  374. }
  375. /* Change dir if necessary */
  376. if (base_dir)
  377. xchdir(base_dir);
  378. if (quiet <= 1) { /* not -qq */
  379. if (quiet == 0)
  380. printf("Archive: %s\n", src_fn);
  381. if (listing) {
  382. puts(verbose ?
  383. " Length Method Size Ratio Date Time CRC-32 Name\n"
  384. "-------- ------ ------- ----- ---- ---- ------ ----"
  385. :
  386. " Length Date Time Name\n"
  387. " -------- ---- ---- ----"
  388. );
  389. }
  390. }
  391. /* Example of an archive with one 0-byte long file named 'z'
  392. * created by Zip 2.31 on Unix:
  393. * 0000 [50 4b]03 04 0a 00 00 00 00 00 42 1a b8 3c 00 00 |PK........B..<..|
  394. * sig........ vneed flags compr mtime mdate crc32>
  395. * 0010 00 00 00 00 00 00 00 00 00 00 01 00 15 00 7a 55 |..............zU|
  396. * >..... csize...... usize...... fnlen exlen fn ex>
  397. * 0020 54 09 00 03 cc d3 f9 4b cc d3 f9 4b 55 78 04 00 |T......K...KUx..|
  398. * >tra_field......................................
  399. * 0030 00 00 00 00[50 4b]01 02 17 03 0a 00 00 00 00 00 |....PK..........|
  400. * ........... sig........ vmade vneed flags compr
  401. * 0040 42 1a b8 3c 00 00 00 00 00 00 00 00 00 00 00 00 |B..<............|
  402. * mtime mdate crc32...... csize...... usize......
  403. * 0050 01 00 0d 00 00 00 00 00 00 00 00 00 a4 81 00 00 |................|
  404. * fnlen exlen clen. dnum. iattr eattr...... relofs> (eattr = rw-r--r--)
  405. * 0060 00 00 7a 55 54 05 00 03 cc d3 f9 4b 55 78 00 00 |..zUT......KUx..|
  406. * >..... fn extra_field...........................
  407. * 0070 [50 4b]05 06 00 00 00 00 01 00 01 00 3c 00 00 00 |PK..........<...|
  408. * 0080 34 00 00 00 00 00 |4.....|
  409. */
  410. total_usize = 0;
  411. total_size = 0;
  412. total_entries = 0;
  413. #if ENABLE_DESKTOP
  414. cdf_offset = 0;
  415. #endif
  416. while (1) {
  417. uint32_t magic;
  418. mode_t dir_mode = 0777;
  419. #if ENABLE_DESKTOP
  420. mode_t file_mode = 0666;
  421. #endif
  422. /* Check magic number */
  423. xread(zip_fd, &magic, 4);
  424. /* Central directory? It's at the end, so exit */
  425. if (magic == ZIP_CDF_MAGIC)
  426. break;
  427. #if ENABLE_DESKTOP
  428. /* Data descriptor? It was a streaming file, go on */
  429. if (magic == ZIP_DD_MAGIC) {
  430. /* skip over duplicate crc32, cmpsize and ucmpsize */
  431. unzip_skip(3 * 4);
  432. continue;
  433. }
  434. #endif
  435. if (magic != ZIP_FILEHEADER_MAGIC)
  436. bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
  437. /* Read the file header */
  438. xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN);
  439. FIX_ENDIANNESS_ZIP(zip_header);
  440. if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {
  441. bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
  442. }
  443. #if !ENABLE_DESKTOP
  444. if (zip_header.formatted.zip_flags & SWAP_LE16(0x0009)) {
  445. bb_error_msg_and_die("zip flags 1 and 8 are not supported");
  446. }
  447. #else
  448. if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) {
  449. /* 0x0001 - encrypted */
  450. bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
  451. }
  452. {
  453. cdf_header_t cdf_header;
  454. cdf_offset = read_next_cdf(cdf_offset, &cdf_header);
  455. if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) {
  456. /* 0x0008 - streaming. [u]cmpsize can be reliably gotten
  457. * only from Central Directory. See unzip_doc.txt */
  458. zip_header.formatted.crc32 = cdf_header.formatted.crc32;
  459. zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize;
  460. zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize;
  461. }
  462. if ((cdf_header.formatted.version_made_by >> 8) == 3) {
  463. /* this archive is created on Unix */
  464. dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16);
  465. }
  466. }
  467. #endif
  468. /* Read filename */
  469. free(dst_fn);
  470. dst_fn = xzalloc(zip_header.formatted.filename_len + 1);
  471. xread(zip_fd, dst_fn, zip_header.formatted.filename_len);
  472. /* Skip extra header bytes */
  473. unzip_skip(zip_header.formatted.extra_len);
  474. /* Filter zip entries */
  475. if (find_list_entry(zreject, dst_fn)
  476. || (zaccept && !find_list_entry(zaccept, dst_fn))
  477. ) { /* Skip entry */
  478. i = 'n';
  479. } else { /* Extract entry */
  480. if (listing) { /* List entry */
  481. unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
  482. if (!verbose) {
  483. // " Length Date Time Name\n"
  484. // " -------- ---- ---- ----"
  485. printf( "%9u %02u-%02u-%02u %02u:%02u %s\n",
  486. (unsigned)zip_header.formatted.ucmpsize,
  487. (dostime & 0x01e00000) >> 21,
  488. (dostime & 0x001f0000) >> 16,
  489. (((dostime & 0xfe000000) >> 25) + 1980) % 100,
  490. (dostime & 0x0000f800) >> 11,
  491. (dostime & 0x000007e0) >> 5,
  492. dst_fn);
  493. total_usize += zip_header.formatted.ucmpsize;
  494. } else {
  495. unsigned long percents = zip_header.formatted.ucmpsize - zip_header.formatted.cmpsize;
  496. percents = percents * 100;
  497. if (zip_header.formatted.ucmpsize)
  498. percents /= zip_header.formatted.ucmpsize;
  499. // " Length Method Size Ratio Date Time CRC-32 Name\n"
  500. // "-------- ------ ------- ----- ---- ---- ------ ----"
  501. printf( "%8u Defl:N" "%9u%4u%% %02u-%02u-%02u %02u:%02u %08x %s\n",
  502. (unsigned)zip_header.formatted.ucmpsize,
  503. (unsigned)zip_header.formatted.cmpsize,
  504. (unsigned)percents,
  505. (dostime & 0x01e00000) >> 21,
  506. (dostime & 0x001f0000) >> 16,
  507. (((dostime & 0xfe000000) >> 25) + 1980) % 100,
  508. (dostime & 0x0000f800) >> 11,
  509. (dostime & 0x000007e0) >> 5,
  510. zip_header.formatted.crc32,
  511. dst_fn);
  512. total_usize += zip_header.formatted.ucmpsize;
  513. total_size += zip_header.formatted.cmpsize;
  514. }
  515. i = 'n';
  516. } else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */
  517. i = -1;
  518. } else if (last_char_is(dst_fn, '/')) { /* Extract directory */
  519. if (stat(dst_fn, &stat_buf) == -1) {
  520. if (errno != ENOENT) {
  521. bb_perror_msg_and_die("can't stat '%s'", dst_fn);
  522. }
  523. if (!quiet) {
  524. printf(" creating: %s\n", dst_fn);
  525. }
  526. unzip_create_leading_dirs(dst_fn);
  527. if (bb_make_directory(dst_fn, dir_mode, 0)) {
  528. bb_error_msg_and_die("exiting");
  529. }
  530. } else {
  531. if (!S_ISDIR(stat_buf.st_mode)) {
  532. bb_error_msg_and_die("'%s' exists but is not directory", dst_fn);
  533. }
  534. }
  535. i = 'n';
  536. } else { /* Extract file */
  537. check_file:
  538. if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */
  539. if (errno != ENOENT) {
  540. bb_perror_msg_and_die("can't stat '%s'", dst_fn);
  541. }
  542. i = 'y';
  543. } else { /* File already exists */
  544. if (overwrite == O_NEVER) {
  545. i = 'n';
  546. } else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */
  547. if (overwrite == O_ALWAYS) {
  548. i = 'y';
  549. } else {
  550. printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
  551. if (!fgets(key_buf, sizeof(key_buf), stdin)) {
  552. bb_perror_msg_and_die("can't read input");
  553. }
  554. i = key_buf[0];
  555. }
  556. } else { /* File is not regular file */
  557. bb_error_msg_and_die("'%s' exists but is not regular file", dst_fn);
  558. }
  559. }
  560. }
  561. }
  562. switch (i) {
  563. case 'A':
  564. overwrite = O_ALWAYS;
  565. case 'y': /* Open file and fall into unzip */
  566. unzip_create_leading_dirs(dst_fn);
  567. #if ENABLE_DESKTOP
  568. dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode);
  569. #else
  570. dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
  571. #endif
  572. case -1: /* Unzip */
  573. if (!quiet) {
  574. printf(" inflating: %s\n", dst_fn);
  575. }
  576. unzip_extract(&zip_header, dst_fd);
  577. if (dst_fd != STDOUT_FILENO) {
  578. /* closing STDOUT is potentially bad for future business */
  579. close(dst_fd);
  580. }
  581. break;
  582. case 'N':
  583. overwrite = O_NEVER;
  584. case 'n':
  585. /* Skip entry data */
  586. unzip_skip(zip_header.formatted.cmpsize);
  587. break;
  588. case 'r':
  589. /* Prompt for new name */
  590. printf("new name: ");
  591. if (!fgets(key_buf, sizeof(key_buf), stdin)) {
  592. bb_perror_msg_and_die("can't read input");
  593. }
  594. free(dst_fn);
  595. dst_fn = xstrdup(key_buf);
  596. chomp(dst_fn);
  597. goto check_file;
  598. default:
  599. printf("error: invalid response [%c]\n", (char)i);
  600. goto check_file;
  601. }
  602. total_entries++;
  603. }
  604. if (listing && quiet <= 1) {
  605. if (!verbose) {
  606. // " Length Date Time Name\n"
  607. // " -------- ---- ---- ----"
  608. printf( " -------- -------\n"
  609. "%9lu" " %u files\n",
  610. total_usize, total_entries);
  611. } else {
  612. unsigned long percents = total_usize - total_size;
  613. percents = percents * 100;
  614. if (total_usize)
  615. percents /= total_usize;
  616. // " Length Method Size Ratio Date Time CRC-32 Name\n"
  617. // "-------- ------ ------- ----- ---- ---- ------ ----"
  618. printf( "-------- ------- --- -------\n"
  619. "%8lu" "%17lu%4u%% %u files\n",
  620. total_usize, total_size, (unsigned)percents,
  621. total_entries);
  622. }
  623. }
  624. return 0;
  625. }