3
0

unzip.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. * Endian issues
  18. * Zip64 + other methods
  19. * Improve handling of zip format, ie.
  20. * - deferred CRC, comp. & uncomp. lengths (zip header flags bit 3)
  21. * - unix file permissions, etc.
  22. * - central directory
  23. */
  24. #include "busybox.h"
  25. #include "unarchive.h"
  26. #define ZIP_FILEHEADER_MAGIC SWAP_LE32(0x04034b50)
  27. #define ZIP_CDS_MAGIC SWAP_LE32(0x02014b50)
  28. #define ZIP_CDS_END_MAGIC SWAP_LE32(0x06054b50)
  29. #define ZIP_DD_MAGIC SWAP_LE32(0x08074b50)
  30. extern unsigned int gunzip_crc;
  31. extern unsigned int gunzip_bytes_out;
  32. typedef union {
  33. unsigned char raw[26];
  34. struct {
  35. unsigned short version; /* 0-1 */
  36. unsigned short flags; /* 2-3 */
  37. unsigned short method; /* 4-5 */
  38. unsigned short modtime; /* 6-7 */
  39. unsigned short moddate; /* 8-9 */
  40. unsigned int crc32 ATTRIBUTE_PACKED; /* 10-13 */
  41. unsigned int cmpsize ATTRIBUTE_PACKED; /* 14-17 */
  42. unsigned int ucmpsize ATTRIBUTE_PACKED; /* 18-21 */
  43. unsigned short filename_len; /* 22-23 */
  44. unsigned short extra_len; /* 24-25 */
  45. } formatted ATTRIBUTE_PACKED;
  46. } zip_header_t;
  47. static void unzip_skip(int fd, off_t skip)
  48. {
  49. if (lseek(fd, skip, SEEK_CUR) == (off_t)-1) {
  50. if ((errno != ESPIPE) || (bb_copyfd_size(fd, -1, skip) != skip)) {
  51. bb_error_msg_and_die("seek failure");
  52. }
  53. }
  54. }
  55. static void unzip_create_leading_dirs(char *fn)
  56. {
  57. /* Create all leading directories */
  58. char *name = xstrdup(fn);
  59. if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
  60. bb_error_msg_and_die("exiting"); /* bb_make_directory is noisy */
  61. }
  62. free(name);
  63. }
  64. static int unzip_extract(zip_header_t *zip_header, int src_fd, int dst_fd)
  65. {
  66. if (zip_header->formatted.method == 0) {
  67. /* Method 0 - stored (not compressed) */
  68. off_t size = zip_header->formatted.ucmpsize;
  69. if (size && (bb_copyfd_size(src_fd, dst_fd, size) != size)) {
  70. bb_error_msg_and_die("cannot complete extraction");
  71. }
  72. } else {
  73. /* Method 8 - inflate */
  74. inflate_init(zip_header->formatted.cmpsize);
  75. inflate_unzip(src_fd, dst_fd);
  76. inflate_cleanup();
  77. /* Validate decompression - crc */
  78. if (zip_header->formatted.crc32 != (gunzip_crc ^ 0xffffffffL)) {
  79. bb_error_msg("invalid compressed data--%s error", "crc");
  80. return 1;
  81. }
  82. /* Validate decompression - size */
  83. if (zip_header->formatted.ucmpsize != gunzip_bytes_out) {
  84. bb_error_msg("invalid compressed data--%s error", "length");
  85. return 1;
  86. }
  87. }
  88. return 0;
  89. }
  90. int unzip_main(int argc, char **argv)
  91. {
  92. zip_header_t zip_header;
  93. enum {v_silent, v_normal, v_list} verbosity = v_normal;
  94. enum {o_prompt, o_never, o_always} overwrite = o_prompt;
  95. unsigned int total_size = 0;
  96. unsigned int total_entries = 0;
  97. int src_fd = -1, dst_fd = -1;
  98. char *src_fn = NULL, *dst_fn = NULL;
  99. llist_t *zaccept = NULL;
  100. llist_t *zreject = NULL;
  101. char *base_dir = NULL;
  102. int failed, i, opt, opt_range = 0, list_header_done = 0;
  103. char key_buf[512];
  104. struct stat stat_buf;
  105. while((opt = getopt(argc, argv, "-d:lnopqx")) != -1) {
  106. switch (opt_range) {
  107. case 0: /* Options */
  108. switch (opt) {
  109. case 'l': /* List */
  110. verbosity = v_list;
  111. break;
  112. case 'n': /* Never overwrite existing files */
  113. overwrite = o_never;
  114. break;
  115. case 'o': /* Always overwrite existing files */
  116. overwrite = o_always;
  117. break;
  118. case 'p': /* Extract files to stdout and fall through to set verbosity */
  119. dst_fd = STDOUT_FILENO;
  120. case 'q': /* Be quiet */
  121. verbosity = (verbosity == v_normal) ? v_silent : verbosity;
  122. break;
  123. case 1 : /* The zip file */
  124. src_fn = xstrndup(optarg, strlen(optarg)+4);
  125. opt_range++;
  126. break;
  127. default:
  128. bb_show_usage();
  129. }
  130. break;
  131. case 1: /* Include files */
  132. if (opt == 1) {
  133. llist_add_to(&zaccept, optarg);
  134. } else if (opt == 'd') {
  135. base_dir = optarg;
  136. opt_range += 2;
  137. } else if (opt == 'x') {
  138. opt_range++;
  139. } else {
  140. bb_show_usage();
  141. }
  142. break;
  143. case 2 : /* Exclude files */
  144. if (opt == 1) {
  145. llist_add_to(&zreject, optarg);
  146. } else if (opt == 'd') { /* Extract to base directory */
  147. base_dir = optarg;
  148. opt_range++;
  149. } else {
  150. bb_show_usage();
  151. }
  152. break;
  153. default:
  154. bb_show_usage();
  155. }
  156. }
  157. if (src_fn == NULL) {
  158. bb_show_usage();
  159. }
  160. /* Open input file */
  161. if (strcmp("-", src_fn) == 0) {
  162. src_fd = STDIN_FILENO;
  163. /* Cannot use prompt mode since zip data is arriving on STDIN */
  164. overwrite = (overwrite == o_prompt) ? o_never : overwrite;
  165. } else {
  166. static const char *const extn[] = {"", ".zip", ".ZIP"};
  167. int orig_src_fn_len = strlen(src_fn);
  168. for(i = 0; (i < 3) && (src_fd == -1); i++) {
  169. strcpy(src_fn + orig_src_fn_len, extn[i]);
  170. src_fd = open(src_fn, O_RDONLY);
  171. }
  172. if (src_fd == -1) {
  173. src_fn[orig_src_fn_len] = 0;
  174. bb_error_msg_and_die("cannot open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);
  175. }
  176. }
  177. /* Change dir if necessary */
  178. if (base_dir)
  179. xchdir(base_dir);
  180. if (verbosity != v_silent)
  181. printf("Archive: %s\n", src_fn);
  182. failed = 0;
  183. while (1) {
  184. unsigned int magic;
  185. /* Check magic number */
  186. xread(src_fd, &magic, 4);
  187. if (magic == ZIP_CDS_MAGIC) {
  188. break;
  189. } else if (magic != ZIP_FILEHEADER_MAGIC) {
  190. bb_error_msg_and_die("invalid zip magic %08X", magic);
  191. }
  192. /* Read the file header */
  193. xread(src_fd, zip_header.raw, 26);
  194. zip_header.formatted.version = SWAP_LE32(zip_header.formatted.version);
  195. zip_header.formatted.flags = SWAP_LE32(zip_header.formatted.flags);
  196. zip_header.formatted.method = SWAP_LE32(zip_header.formatted.method);
  197. zip_header.formatted.modtime = SWAP_LE32(zip_header.formatted.modtime);
  198. zip_header.formatted.moddate = SWAP_LE32(zip_header.formatted.moddate);
  199. zip_header.formatted.crc32 = SWAP_LE32(zip_header.formatted.crc32);
  200. zip_header.formatted.cmpsize = SWAP_LE32(zip_header.formatted.cmpsize);
  201. zip_header.formatted.ucmpsize = SWAP_LE32(zip_header.formatted.ucmpsize);
  202. zip_header.formatted.filename_len = SWAP_LE32(zip_header.formatted.filename_len);
  203. zip_header.formatted.extra_len = SWAP_LE32(zip_header.formatted.extra_len);
  204. if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {
  205. bb_error_msg_and_die("unsupported compression method %d", zip_header.formatted.method);
  206. }
  207. /* Read filename */
  208. free(dst_fn);
  209. dst_fn = xzalloc(zip_header.formatted.filename_len + 1);
  210. xread(src_fd, dst_fn, zip_header.formatted.filename_len);
  211. /* Skip extra header bytes */
  212. unzip_skip(src_fd, zip_header.formatted.extra_len);
  213. if ((verbosity == v_list) && !list_header_done){
  214. printf(" Length Date Time Name\n"
  215. " -------- ---- ---- ----\n");
  216. list_header_done = 1;
  217. }
  218. /* Filter zip entries */
  219. if (find_list_entry(zreject, dst_fn) ||
  220. (zaccept && !find_list_entry(zaccept, dst_fn))) { /* Skip entry */
  221. i = 'n';
  222. } else { /* Extract entry */
  223. total_size += zip_header.formatted.ucmpsize;
  224. if (verbosity == v_list) { /* List entry */
  225. unsigned int dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
  226. printf("%9u %02u-%02u-%02u %02u:%02u %s\n",
  227. zip_header.formatted.ucmpsize,
  228. (dostime & 0x01e00000) >> 21,
  229. (dostime & 0x001f0000) >> 16,
  230. (((dostime & 0xfe000000) >> 25) + 1980) % 100,
  231. (dostime & 0x0000f800) >> 11,
  232. (dostime & 0x000007e0) >> 5,
  233. dst_fn);
  234. total_entries++;
  235. i = 'n';
  236. } else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */
  237. i = -1;
  238. } else if (last_char_is(dst_fn, '/')) { /* Extract directory */
  239. if (stat(dst_fn, &stat_buf) == -1) {
  240. if (errno != ENOENT) {
  241. bb_perror_msg_and_die("cannot stat '%s'",dst_fn);
  242. }
  243. if (verbosity == v_normal) {
  244. printf(" creating: %s\n", dst_fn);
  245. }
  246. unzip_create_leading_dirs(dst_fn);
  247. if (bb_make_directory(dst_fn, 0777, 0)) {
  248. bb_error_msg_and_die("exiting");
  249. }
  250. } else {
  251. if (!S_ISDIR(stat_buf.st_mode)) {
  252. bb_error_msg_and_die("'%s' exists but is not directory", dst_fn);
  253. }
  254. }
  255. i = 'n';
  256. } else { /* Extract file */
  257. _check_file:
  258. if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */
  259. if (errno != ENOENT) {
  260. bb_perror_msg_and_die("cannot stat '%s'",dst_fn);
  261. }
  262. i = 'y';
  263. } else { /* File already exists */
  264. if (overwrite == o_never) {
  265. i = 'n';
  266. } else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */
  267. if (overwrite == o_always) {
  268. i = 'y';
  269. } else {
  270. printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
  271. if (!fgets(key_buf, 512, stdin)) {
  272. bb_perror_msg_and_die("cannot read input");
  273. }
  274. i = key_buf[0];
  275. }
  276. } else { /* File is not regular file */
  277. bb_error_msg_and_die("'%s' exists but is not regular file",dst_fn);
  278. }
  279. }
  280. }
  281. }
  282. switch (i) {
  283. case 'A':
  284. overwrite = o_always;
  285. case 'y': /* Open file and fall into unzip */
  286. unzip_create_leading_dirs(dst_fn);
  287. dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
  288. case -1: /* Unzip */
  289. if (verbosity == v_normal) {
  290. printf(" inflating: %s\n", dst_fn);
  291. }
  292. if (unzip_extract(&zip_header, src_fd, dst_fd)) {
  293. failed = 1;
  294. }
  295. if (dst_fd != STDOUT_FILENO) {
  296. /* closing STDOUT is potentially bad for future business */
  297. close(dst_fd);
  298. }
  299. break;
  300. case 'N':
  301. overwrite = o_never;
  302. case 'n':
  303. /* Skip entry data */
  304. unzip_skip(src_fd, zip_header.formatted.cmpsize);
  305. break;
  306. case 'r':
  307. /* Prompt for new name */
  308. printf("new name: ");
  309. if (!fgets(key_buf, 512, stdin)) {
  310. bb_perror_msg_and_die("cannot read input");
  311. }
  312. free(dst_fn);
  313. dst_fn = xstrdup(key_buf);
  314. chomp(dst_fn);
  315. goto _check_file;
  316. default:
  317. printf("error: invalid response [%c]\n",(char)i);
  318. goto _check_file;
  319. }
  320. /* Data descriptor section */
  321. if (zip_header.formatted.flags & 4) {
  322. /* skip over duplicate crc, compressed size and uncompressed size */
  323. unzip_skip(src_fd, 12);
  324. }
  325. }
  326. if (verbosity == v_list) {
  327. printf(" -------- -------\n"
  328. "%9d %d files\n", total_size, total_entries);
  329. }
  330. return failed;
  331. }