|
|
1.1 root 1: /*---------------------------------------------------------------------------
2:
3: extract.c
4:
5: This file contains the high-level routines ("driver routines") for extrac-
6: ting and testing zipfile members. It calls the low-level routines in files
7: explode.c, inflate.c, unreduce.c and unshrink.c.
8:
9: ---------------------------------------------------------------------------*/
10:
11:
12: #include "unzip.h"
13: #ifdef MSWIN
14: # include "wizunzip.h"
15: # include "replace.h"
16: #endif /* MSWIN */
17:
18:
19: /************************************/
20: /* Extract Local Prototypes, etc. */
21: /************************************/
22:
23: static int store_info __((void));
24: static int extract_or_test_member __((void));
25: #ifdef CRYPT
26: static int decrypt_member __((void));
27: static int testp __((byte *hdr));
28: #endif
29:
30: static byte *mem_i_buffer;
31: static byte *mem_o_buffer;
32: static ULONG mem_i_size, mem_i_offset;
33: static ULONG mem_o_size, mem_o_offset;
34:
35: static char *VersionMsg =
36: " skipping: %-22s need %s compat. v%u.%u (can do v%u.%u)\n";
37: static char *ComprMsg =
38: " skipping: %-22s compression method %d\n";
39: static char *FilNamMsg =
40: "%s: bad filename length (%s)\n";
41: static char *ExtFieldMsg =
42: "%s: bad extra field length (%s)\n";
43: static char *OffsetMsg =
44: "file #%d: bad zipfile offset (%s)\n";
45:
46:
47:
48:
49:
50: /**************************************/
51: /* Function extract_or_test_files() */
52: /**************************************/
53:
54: int extract_or_test_files() /* return PK-type error code */
55: {
56: char **fnamev;
57: byte *cd_inptr;
58: int cd_incnt, error, error_in_archive=0;
59: int renamed, query, len, filnum=(-1), blknum=0;
60: #ifdef OS2
61: extern int longname; /* from os2unzip.c */
62: #endif
63: UWORD i, j, members_remaining, num_skipped=0, num_bad_pwd=0;
64: longint cd_bufstart, bufstart, inbuf_offset, request;
65: min_info info[DIR_BLKSIZ];
66:
67:
68: /*---------------------------------------------------------------------------
69: The basic idea of this function is as follows. Since the central di-
70: rectory lies at the end of the zipfile and the member files lie at the
71: beginning or middle or wherever, it is not very desirable to simply
72: read a central directory entry, jump to the member and extract it, and
73: then jump back to the central directory. In the case of a large zipfile
74: this would lead to a whole lot of disk-grinding, especially if each mem-
75: ber file is small. Instead, we read from the central directory the per-
76: tinent information for a block of files, then go extract/test the whole
77: block. Thus this routine contains two small(er) loops within a very
78: large outer loop: the first of the small ones reads a block of files
79: from the central directory; the second extracts or tests each file; and
80: the outer one loops over blocks. There's some file-pointer positioning
81: stuff in between, but that's about it. Btw, it's because of this jump-
82: ing around that we can afford to be lenient if an error occurs in one of
83: the member files: we should still be able to go find the other members,
84: since we know the offset of each from the beginning of the zipfile.
85:
86: Begin main loop over blocks of member files. We know the entire central
87: directory is on this disk: we would not have any of this information un-
88: less the end-of-central-directory record was on this disk, and we would
89: not have gotten to this routine unless this is also the disk on which
90: the central directory starts. In practice, this had better be the ONLY
91: disk in the archive, but maybe someday we'll add multi-disk support.
92: ---------------------------------------------------------------------------*/
93:
94: pInfo = info;
95: members_remaining = ecrec.total_entries_central_dir;
96:
97: while (members_remaining) {
98: j = 0;
99:
100: /*
101: * Loop through files in central directory, storing offsets, file
102: * attributes, and case-conversion flags until block size is reached.
103: */
104:
105: while (members_remaining && (j < DIR_BLKSIZ)) {
106: --members_remaining;
107: pInfo = &info[j];
108:
109: if (readbuf(sig, 4) <= 0) {
110: error_in_archive = 51; /* 51: unexpected EOF */
111: members_remaining = 0; /* ...so no more left to do */
112: break;
113: }
114: if (strncmp(sig, central_hdr_sig, 4)) { /* just to make sure */
115: fprintf(stderr, CentSigMsg, j); /* sig not found */
116: fprintf(stderr, ReportMsg); /* check binary transfers */
117: error_in_archive = 3; /* 3: error in zipfile */
118: members_remaining = 0; /* ...so no more left to do */
119: break;
120: }
121: /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */
122: if ((error = process_cdir_file_hdr()) != 0) {
123: error_in_archive = error; /* only 51 (EOF) defined */
124: members_remaining = 0; /* ...so no more left to do */
125: break;
126: }
127: if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
128: if (error > error_in_archive)
129: error_in_archive = error;
130: if (error > 1) { /* fatal: no more left to do */
131: fprintf(stderr, FilNamMsg, filename, "central");
132: members_remaining = 0;
133: break;
134: }
135: }
136: if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0)
137: {
138: if (error > error_in_archive)
139: error_in_archive = error;
140: if (error > 1) { /* fatal */
141: fprintf(stderr, ExtFieldMsg, filename, "central");
142: members_remaining = 0;
143: break;
144: }
145: }
146: if ((error = do_string(crec.file_comment_length, SKIP)) != 0) {
147: if (error > error_in_archive)
148: error_in_archive = error;
149: if (error > 1) { /* fatal */
150: fprintf(stderr, "\n%s: bad file comment length\n",
151: filename);
152: members_remaining = 0;
153: break;
154: }
155: }
156: if (process_all_files) {
157: if (store_info())
158: ++num_skipped;
159: else
160: ++j; /* file is OK: save info[] and continue with next */
161: } else {
162: fnamev = fnv; /* don't destroy permanent filename pointer */
163: for (--fnamev; *++fnamev;)
164: if (match(filename, *fnamev)) {
165: if (store_info())
166: ++num_skipped;
167: else
168: ++j; /* file is OK */
169: break; /* found match for filename, so stop looping */
170: } /* end if (match), for-loop (fnamev) */
171: } /* end if (process_all_files) */
172:
173: } /* end while-loop (adding files to current block) */
174:
175: /* save position in central directory so can come back later */
176: cd_bufstart = cur_zipfile_bufstart;
177: cd_inptr = inptr;
178: cd_incnt = incnt;
179:
180: /*-----------------------------------------------------------------------
181: Second loop: process files in current block, extracting or testing
182: each one.
183: -----------------------------------------------------------------------*/
184:
185: for (i = 0; i < j; ++i) {
186: filnum = i + blknum*DIR_BLKSIZ;
187: pInfo = &info[i];
188: /*
189: * if the target position is not within the current input buffer
190: * (either haven't yet read far enough, or (maybe) skipping back-
191: * ward) skip to the target position and reset readbuf().
192: */
193: /* LSEEK(pInfo->offset): */
194: request = pInfo->offset + extra_bytes;
195: inbuf_offset = request % INBUFSIZ;
196: bufstart = request - inbuf_offset;
197:
198: if (request < 0) {
199: fprintf(stderr, SeekMsg, ReportMsg);
200: error_in_archive = 3; /* 3: severe error in zipfile, */
201: continue; /* but can still go on */
202: } else if (bufstart != cur_zipfile_bufstart) {
203: cur_zipfile_bufstart = lseek(zipfd, bufstart, SEEK_SET);
204: if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) <= 0) {
205: fprintf(stderr, OffsetMsg, filnum, "lseek");
206: error_in_archive = 3; /* 3: error in zipfile, but */
207: continue; /* can still do next file */
208: }
209: inptr = inbuf + (int)inbuf_offset;
210: incnt -= (int)inbuf_offset;
211: } else {
212: incnt += (inptr-inbuf) - (int)inbuf_offset;
213: inptr = inbuf + (int)inbuf_offset;
214: }
215:
216: /* should be in proper position now, so check for sig */
217: if (readbuf(sig, 4) <= 0) { /* bad offset */
218: fprintf(stderr, OffsetMsg, filnum, "EOF");
219: error_in_archive = 3; /* 3: error in zipfile */
220: continue; /* but can still try next one */
221: }
222: if (strncmp(sig, local_hdr_sig, 4)) {
223: fprintf(stderr, OffsetMsg, filnum,
224: "can't find local header sig"); /* bad offset */
225: error_in_archive = 3;
226: continue;
227: }
228: if ((error = process_local_file_hdr()) != 0) {
229: fprintf(stderr, "\nfile #%d: bad local header\n", filnum);
230: error_in_archive = error; /* only 51 (EOF) defined */
231: continue; /* can still try next one */
232: }
233: if ((error = do_string(lrec.filename_length, FILENAME)) != 0) {
234: if (error > error_in_archive)
235: error_in_archive = error;
236: if (error > 1) {
237: fprintf(stderr, FilNamMsg, filename, "local");
238: continue; /* go on to next one */
239: }
240: }
241: if (extra_field != (byte *)NULL)
242: free(extra_field);
243: extra_field = (byte *)NULL;
244: if ((error = do_string(lrec.extra_field_length, EXTRA_FIELD)) != 0)
245: {
246: if (error > error_in_archive)
247: error_in_archive = error;
248: if (error > 1) {
249: fprintf(stderr, ExtFieldMsg, filename, "local");
250: continue; /* go on */
251: }
252: }
253:
254: /*
255: * just about to extract file: if extracting to disk, check if
256: * already exists, and if so, take appropriate action according to
257: * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
258: * loop because we don't store the possibly renamed filename[] in
259: * info[])
260: */
261: if (!tflag && !cflag) {
262: renamed = FALSE; /* user hasn't renamed output file yet */
263: #ifdef OS2
264: longname = FALSE; /* no long name has yet been stored */
265: #endif
266:
267: startover:
268: query = FALSE;
269: #ifdef MACOS
270: macflag = (pInfo->hostnum == MAC_);
271: #endif
272: /* mapname can create dirs if not freshening or if renamed */
273: if ((error = mapname(!fflag || renamed)) > 1) { /* skip */
274: if ((error > 2) && (error_in_archive < 2))
275: error_in_archive = 2; /* (weak) error in zipfile */
276: continue; /* go on to next file */
277: }
278:
279: switch (check_for_newer(filename)) {
280: case DOES_NOT_EXIST:
281: if (fflag && !renamed) /* don't skip if just renamed */
282: continue; /* freshen (no new files): skip */
283: break;
284: case EXISTS_AND_OLDER:
285: if (overwrite_none)
286: continue; /* never overwrite: skip file */
287: if (!overwrite_all && !force_flag)
288: query = TRUE;
289: break;
290: case EXISTS_AND_NEWER: /* (or equal) */
291: if (overwrite_none || (uflag && !renamed))
292: continue; /* skip if update/freshen & orig name */
293: if (!overwrite_all && !force_flag)
294: query = TRUE;
295: break;
296: }
297: /*#ifndef VMS*/ /* VMS creates higher version number instead of overwriting
298: * (will have to modify for VMS-style names with specific
299: * version numbers: just check V_flag? don't use stat?) */
300: if (query) {
301: #ifdef MSWIN
302: FARPROC lpfnprocReplace;
303: int ReplaceDlgRetVal; /* replace dialog return value */
304:
305: ShowCursor(FALSE); /* turn off cursor */
306: SetCursor(hSaveCursor); /* restore the cursor */
307: lpfnprocReplace = MakeProcInstance(ReplaceProc, hInst);
308: ReplaceDlgRetVal = DialogBoxParam(hInst, "Replace",
309: hWndMain, lpfnprocReplace, (DWORD)(LPSTR)filename);
310: FreeProcInstance(lpfnprocReplace);
311: hSaveCursor = SetCursor(hHourGlass);
312: ShowCursor(TRUE);
313: switch (ReplaceDlgRetVal) {
314: case IDM_REPLACE_RENAME:
315: renamed = TRUE;
316: goto startover; /* sorry for a goto */
317: case IDM_REPLACE_YES:
318: break;
319: case IDM_REPLACE_ALL:
320: overwrite_all = TRUE;
321: overwrite_none = FALSE; /* just to make sure */
322: break;
323: case IDM_REPLACE_NONE:
324: overwrite_none = TRUE;
325: overwrite_all = FALSE; /* make sure */
326: force_flag = FALSE; /* ditto */
327: /* FALL THROUGH, skip */
328: case IDM_REPLACE_NO:
329: continue;
330: }
331: #else /* !MSWIN */
332: reprompt:
333: fprintf(stderr,
334: "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
335: filename);
336: FFLUSH /* for Amiga and Mac MPW */
337: fgets(answerbuf, 9, stdin);
338: switch (*answerbuf) {
339: case 'A': /* dangerous option: force caps */
340: overwrite_all = TRUE;
341: overwrite_none = FALSE; /* just to make sure */
342: break;
343: case 'r':
344: case 'R':
345: do {
346: fprintf(stderr, "new name: ");
347: FFLUSH /* for AMIGA and Mac MPW */
348: fgets(filename, FILNAMSIZ, stdin);
349: /* usually get \n here: better check for it */
350: len = strlen(filename);
351: if (filename[len-1] == '\n')
352: filename[--len] = 0;
353: } while (len == 0);
354: renamed = TRUE;
355: goto startover; /* sorry for a goto */
356: case 'y':
357: case 'Y':
358: break;
359: case 'N':
360: overwrite_none = TRUE;
361: overwrite_all = FALSE; /* make sure */
362: force_flag = FALSE; /* ditto */
363: /* FALL THROUGH, skip */
364: case 'n':
365: continue; /* skip file */
366: default:
367: fprintf(stderr, "error: invalid response [%c]\n",
368: *answerbuf); /* warn the user */
369: goto reprompt; /* why not another goto? */
370: } /* end switch (*answerbuf) */
371: #endif /* ?MSWIN */
372: } /* end if (query) */
373: /*#endif*/ /* !VMS */
374: } /* end if (extracting to disk) */
375:
376: #ifdef CRYPT
377: if (pInfo->encrypted && ((error = decrypt_member()) != 0)) {
378: if (error == 10) {
379: if (error > error_in_archive)
380: error_in_archive = error;
381: fprintf(stderr,
382: " skipping: %-22s unable to get password\n", filename);
383: } else { /* (error == 1) */
384: fprintf(stderr,
385: " skipping: %-22s incorrect password\n", filename);
386: ++num_bad_pwd;
387: }
388: continue; /* go on to next file */
389: }
390: #endif /* CRYPT */
391: disk_full = 0;
392: if ((error = extract_or_test_member()) != 0) {
393: if (error > error_in_archive)
394: error_in_archive = error; /* ...and keep going */
395: if (disk_full > 1)
396: return error_in_archive; /* (unless disk full) */
397: }
398: } /* end for-loop (i: files in current block) */
399:
400:
401: /*
402: * Jump back to where we were in the central directory, then go and do
403: * the next batch of files.
404: */
405:
406: cur_zipfile_bufstart = lseek(zipfd, cd_bufstart, SEEK_SET);
407: read(zipfd, (char *)inbuf, INBUFSIZ); /* were there b4 ==> no error */
408: inptr = cd_inptr;
409: incnt = cd_incnt;
410: ++blknum;
411:
412: #ifdef TEST
413: printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart);
414: printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart,
415: cur_zipfile_bufstart);
416: printf("inptr-inbuf = %d\n", inptr-inbuf);
417: printf("incnt = %d\n\n", incnt);
418: #endif
419:
420: } /* end while-loop (blocks of files in central directory) */
421:
422: /*---------------------------------------------------------------------------
423: Double-check that we're back at the end-of-central-directory record, and
424: print quick summary of results, if we were just testing the archive. We
425: send the summary to stdout so that people doing the testing in the back-
426: ground and redirecting to a file can just do a "tail" on the output file.
427: ---------------------------------------------------------------------------*/
428:
429: readbuf(sig, 4);
430: if (strncmp(sig, end_central_sig, 4)) { /* just to make sure again */
431: fprintf(stderr, EndSigMsg); /* didn't find end-of-central-dir sig */
432: fprintf(stderr, ReportMsg); /* check binary transfers */
433: if (!error_in_archive) /* don't overwrite stronger error */
434: error_in_archive = 1; /* 1: warning error */
435: }
436: if (tflag && (quietflg == 1)) {
437: int num=filnum+1 - num_bad_pwd;
438:
439: if (error_in_archive)
440: printf("At least one error was detected in %s.\n", zipfn);
441: else if (num == 0)
442: printf("Caution: zero files tested in %s.\n", zipfn);
443: else if (process_all_files && (num_skipped+num_bad_pwd == 0))
444: printf("No errors detected in %s.\n", zipfn);
445: else
446: printf("No errors detected in %s for the %d file%s tested.\n",
447: zipfn, num, (num==1)? "":"s");
448: if (num_skipped > 0)
449: printf("%d file%s skipped because of unsupported compression or\
450: encoding.\n",
451: num_skipped, (num_skipped==1)? "":"s");
452: #ifdef CRYPT
453: if (num_bad_pwd > 0)
454: printf("%d file%s skipped because of incorrect password.\n",
455: num_bad_pwd, (num_bad_pwd==1)? "":"s");
456: #endif /* CRYPT */
457: }
458: if ((num_skipped > 0) && !error_in_archive) /* files not tested or */
459: error_in_archive = 1; /* extracted: warning */
460: #ifdef CRYPT
461: if ((num_bad_pwd > 0) && !error_in_archive) /* files not tested or */
462: error_in_archive = 1; /* extracted: warning */
463: #endif /* CRYPT */
464:
465: return (error_in_archive);
466:
467: } /* end function extract_or_test_files() */
468:
469:
470:
471:
472:
473: /***************************/
474: /* Function store_info() */
475: /***************************/
476:
477: static int store_info() /* return 1 if skipping, 0 if OK */
478: {
479: ULONG tmp;
480:
481: #define UNKN_COMPR \
482: (crec.compression_method>IMPLODED && crec.compression_method!=DEFLATED)
483: #if 0 /* old */
484: # define UNKN_COMPR (crec.compression_method>IMPLODED)
485: #endif
486:
487:
488: /*---------------------------------------------------------------------------
489: Check central directory info for version/compatibility requirements.
490: ---------------------------------------------------------------------------*/
491:
492: pInfo->encrypted = crec.general_purpose_bit_flag & 1; /* bit field */
493: pInfo->ExtLocHdr = (crec.general_purpose_bit_flag & 8) == 8; /* bit */
494: pInfo->text = crec.internal_file_attributes & 1; /* bit field */
495: pInfo->crc = crec.crc32;
496: pInfo->compr_size = crec.compressed_size;
497:
498: if (crec.version_needed_to_extract[1] == VMS_) {
499: if (crec.version_needed_to_extract[0] > VMS_VERSION) {
500: fprintf(stderr, VersionMsg, filename, "VMS",
501: crec.version_needed_to_extract[0] / 10,
502: crec.version_needed_to_extract[0] % 10,
503: VMS_VERSION / 10, VMS_VERSION % 10);
504: return 1;
505: }
506: #ifndef VMS /* won't be able to use extra field, but still have data */
507: else if (!tflag && !force_flag) { /* if forcing, extract regardless */
508: fprintf(stderr,
509: "\n%s: stored in VMS format. Extract anyway? (y/n) ",
510: filename);
511: FFLUSH /* for Amiga and Mac MPW */
512: fgets(answerbuf, 9, stdin);
513: if ((*answerbuf != 'y') && (*answerbuf != 'Y'))
514: return 1;
515: }
516: #endif /* !VMS */
517: /* usual file type: don't need VMS to extract */
518: } else if (crec.version_needed_to_extract[0] > UNZIP_VERSION) {
519: fprintf(stderr, VersionMsg, filename, "PK",
520: crec.version_needed_to_extract[0] / 10,
521: crec.version_needed_to_extract[0] % 10,
522: UNZIP_VERSION / 10, UNZIP_VERSION % 10);
523: return 1;
524: }
525:
526: if UNKN_COMPR {
527: fprintf(stderr, ComprMsg, filename, crec.compression_method);
528: return 1;
529: }
530: #ifndef CRYPT
531: if (pInfo->encrypted) {
532: fprintf(stderr, " skipping: %-22s encrypted (not supported)\n",
533: filename);
534: return 1;
535: }
536: #endif /* !CRYPT */
537:
538: /*---------------------------------------------------------------------------
539: Store some central-directory information (encryption, file attributes,
540: offsets) for later use.
541: ---------------------------------------------------------------------------*/
542:
543: tmp = crec.external_file_attributes;
544:
545: pInfo->dos_attr = 32; /* set archive bit: file is not backed up */
546: switch (pInfo->hostnum) {
547: case UNIX_:
548: case VMS_:
549: pInfo->unix_attr = (unsigned) (tmp >> 16);
550: break;
551: case DOS_OS2_FAT_:
552: case OS2_HPFS_:
553: pInfo->dos_attr = (unsigned) tmp;
554: tmp = (!(tmp & 1)) << 1; /* read-only bit */
555: pInfo->unix_attr = (unsigned) (0444 | (tmp<<6) | (tmp<<3) | tmp);
556: #ifdef UNIX
557: umask( (int)(tmp=umask(0)) );
558: pInfo->unix_attr &= ~tmp;
559: #endif
560: break;
561: case MAC_:
562: pInfo->unix_attr = (unsigned) (tmp & 1); /* read-only bit */
563: break;
564: default:
565: pInfo->unix_attr = 0666;
566: break;
567: } /* end switch (host-OS-created-by) */
568:
569: pInfo->offset = (longint) crec.relative_offset_local_header;
570: return 0;
571:
572: } /* end function store_info() */
573:
574:
575:
576:
577:
578: /***************************************/
579: /* Function extract_or_test_member() */
580: /***************************************/
581:
582: static int extract_or_test_member() /* return PK-type error code */
583: {
584: #ifdef S_IFLNK
585: int symlnk=FALSE;
586: #endif /* S_IFLNK */
587: int r, error=0;
588: UWORD b;
589:
590:
591:
592: /*---------------------------------------------------------------------------
593: Initialize variables, buffers, etc.
594: ---------------------------------------------------------------------------*/
595:
596: bits_left = 0;
597: bitbuf = 0L;
598: outpos = 0L;
599: outcnt = 0;
600: outptr = outbuf;
601: zipeof = 0;
602: crc32val = 0xFFFFFFFFL;
603:
604: #ifdef S_IFLNK
605: if ((pInfo->unix_attr & S_IFMT) == S_IFLNK && (pInfo->hostnum == UNIX_)
606: && !tflag && !cflag)
607: symlnk = TRUE;
608: #endif /* S_IFLNK */
609:
610: memset(outbuf, 0xaa, OUTBUFSIZ);
611: #if (!defined(DOS_OS2) || defined(MSWIN))
612: if (aflag) /* if we have a scratchpad, clear it out */
613: #ifdef MSWIN
614: _fmemset(outout, 0xaa, OUTBUFSIZ);
615: #else /* !MSWIN */
616: memset(outout, 0xaa, OUTBUFSIZ);
617: #endif /* ?MSWIN */
618: #endif /* !DOS_OS2 || MSWIN */
619:
620: if (tflag) {
621: if (!quietflg) {
622: fprintf(stdout, " Testing: %-22s ", filename);
623: fflush(stdout);
624: }
625: } else {
626: if (cflag) { /* output to stdout (copy of it) */
627: #if (defined(MACOS) || defined(AMIGA))
628: outfd = 1;
629: #else /* !(MACOS || AMIGA) */
630: outfd = dup(1); /* GRR: change this to #define for Mac/Amiga */
631: #endif /* ?(MACOS || AMIGA) */
632: #ifdef DOS_OS2
633: if (!aflag)
634: setmode(outfd, O_BINARY);
635: #endif /* DOS_OS2 */
636: #ifdef VMS
637: if (create_output_file()) /* VMS version required for stdout! */
638: return 50; /* 50: disk full (?) */
639: #endif
640: } else
641: #ifdef S_IFLNK
642: if (!symlnk) /* symlink() takes care of file creation */
643: #endif /* !S_IFLNK */
644: {
645: if (create_output_file())
646: return 50; /* 50: disk full (?) */
647: }
648: } /* endif (!tflag) */
649:
650: /*---------------------------------------------------------------------------
651: Unpack the file.
652: ---------------------------------------------------------------------------*/
653:
654: switch (lrec.compression_method) {
655:
656: case STORED:
657: if (!tflag && (quietflg < 2)) {
658: fprintf(stdout, " Extracting: %-22s ", filename);
659: if (cflag)
660: fprintf(stdout, "\n");
661: fflush(stdout);
662: }
663: #ifdef S_IFLNK
664: /*
665: * If file came from Unix and is a symbolic link and we are extracting
666: * to disk, allocate a storage area, put the data in it, and create the
667: * link. Since we know it's a symbolic link to start with, shouldn't
668: * have to worry about overflowing unsigned ints with unsigned longs.
669: * (This doesn't do anything for compressed symlinks, but that can be
670: * added later...it also doesn't set the time or permissions of the
671: * link, but does anyone really care?)
672: */
673: if (symlnk) {
674: #if (defined(MTS) || defined(MACOS))
675: fprintf(stdout, "\n warning: symbolic link ignored\n");
676: error = 1; /* 1: warning error */
677: #else /* !(MTS || MACOS) */
678: char *orig = (char *)malloc((unsigned)lrec.uncompressed_size+1);
679: char *p = orig;
680:
681: while (ReadByte(&b))
682: *p++ = b;
683: *p = 0; /* terminate string */
684: UpdateCRC((unsigned char *)orig, p-orig);
685: if (symlink(orig, filename))
686: if ((errno == EEXIST) && overwrite_all) { /* OK to overwrite */
687: unlink(filename);
688: if (symlink(orig, filename))
689: perror("symlink error");
690: } else
691: perror("symlink error");
692: free(orig);
693: #endif /* ?(MTS || MACOS) */
694: } else
695: #endif /* S_IFLNK */
696: while (ReadByte(&b) && !disk_full)
697: OUTB(b)
698: break;
699:
700: case SHRUNK:
701: if (!tflag && (quietflg < 2)) {
702: fprintf(stdout, "UnShrinking: %-22s ", filename);
703: if (cflag)
704: fprintf(stdout, "\n");
705: fflush(stdout);
706: }
707: #ifdef S_IFLNK /* !!! This code needs to be added to unShrink, etc. !!! */
708: if (symlnk) {
709: fprintf(stdout, "\n warning: symbolic link ignored\n");
710: error = 1; /* 1: warning error */
711: }
712: #endif /* S_IFLNK */
713: unShrink();
714: break;
715:
716: case REDUCED1:
717: case REDUCED2:
718: case REDUCED3:
719: case REDUCED4:
720: if (!tflag && (quietflg < 2)) {
721: fprintf(stdout, " Expanding: %-22s ", filename);
722: if (cflag)
723: fprintf(stdout, "\n");
724: fflush(stdout);
725: }
726: #ifdef S_IFLNK /* !!! This code needs to be added to unShrink, etc. !!! */
727: if (symlnk) {
728: fprintf(stdout, "\n warning: symbolic link ignored\n");
729: error = 1; /* 1: warning error */
730: }
731: #endif /* S_IFLNK */
732: unReduce();
733: break;
734:
735: case IMPLODED:
736: if (!tflag && (quietflg < 2)) {
737: fprintf(stdout, " Exploding: %-22s ", filename);
738: if (cflag)
739: fprintf(stdout, "\n");
740: fflush(stdout);
741: }
742: #ifdef S_IFLNK /* !!! This code needs to be added to unShrink, etc. !!! */
743: if (symlnk) {
744: fprintf(stdout, "\n warning: symbolic link ignored\n");
745: error = 1; /* 1: warning error */
746: }
747: #endif /* S_IFLNK */
748: if (((r = explode()) != 0) && (r != 5)) { /* ignore 5 if seekable */
749: if ((tflag && quietflg) || (!tflag && (quietflg > 1)))
750: fprintf(stderr, " error: %s%s\n", r == 3?
751: "not enough memory to explode " :
752: "invalid compressed (imploded) data for ", filename);
753: else
754: fprintf(stderr, "\n error: %s\n", r == 3?
755: "not enough memory for explode operation" :
756: "invalid compressed data for explode format");
757: error = (r == 3)? 5 : 2;
758: }
759: break;
760:
761: case DEFLATED:
762: if (!tflag && (quietflg < 2)) {
763: fprintf(stdout, " Inflating: %-22s ", filename);
764: if (cflag)
765: fprintf(stdout, "\n");
766: fflush(stdout);
767: }
768: #ifdef S_IFLNK /* !!! This code needs to be added to unShrink, etc. !!! */
769: if (symlnk) {
770: fprintf(stdout, "\n warning: symbolic link ignored\n");
771: error = 1; /* 1: warning error */
772: }
773: #endif /* S_IFLNK */
774: if ((r = inflate()) != 0) {
775: if ((tflag && quietflg) || (!tflag && (quietflg > 1)))
776: fprintf(stderr, " error: %s%s\n", r == 3?
777: "not enough memory to inflate " :
778: "invalid compressed (deflated) data for ", filename);
779: else
780: fprintf(stderr, "\n error: %s\n", r == 3?
781: "not enough memory for inflate operation" :
782: "invalid compressed data for inflate format");
783: error = (r == 3)? 5 : 2;
784: }
785: break;
786:
787: default: /* should never get to this point */
788: fprintf(stderr, "%s: unknown compression method\n", filename);
789: /* close and delete file before return? */
790: return 1; /* 1: warning error */
791:
792: } /* end switch (compression method) */
793:
794: if (disk_full) { /* set by FlushOutput()/OUTB() macro */
795: if (disk_full > 1)
796: return 50; /* 50: disk full */
797: error = 1; /* 1: warning error */
798: }
799:
800: /*---------------------------------------------------------------------------
801: Write the last partial buffer, if any; set the file date and time; and
802: close the file (not necessarily in that order). Then make sure CRC came
803: out OK and print result.
804: ---------------------------------------------------------------------------*/
805:
806: #ifdef S_IFLNK
807: if (!symlnk) {
808: #endif /* S_IFLNK */
809: if (!disk_full && FlushOutput())
810: if (disk_full > 1)
811: return 50; /* 50: disk full */
812: else { /* disk_full == 1 */
813: fprintf(stderr, "%s: probably corrupt\n", filename);
814: error = 1; /* 1: warning error */
815: }
816:
817: if (!tflag)
818: #ifdef VMS
819: CloseOutputFile();
820: #else /* !VMS */
821: #ifdef MTS /* MTS can't set file time */
822: close(outfd);
823: #else /* !MTS */
824: set_file_time_and_close();
825: #endif /* ?MTS */
826: #endif /* ?VMS */
827:
828: #ifdef S_IFLNK
829: } /* endif (!symlnk) */
830: #endif /* S_IFLNK */
831:
832: if (error > 1) /* don't print redundant CRC error if error already */
833: return error;
834:
835: /* logical-AND crc32val for 64-bit machines */
836: if ((crc32val = ((~crc32val) & 0xFFFFFFFFL)) != lrec.crc32) {
837: /* if quietflg is set, we haven't output the filename yet: do it */
838: if (quietflg)
839: printf("%-22s: ", filename);
840: fprintf(stdout, " Bad CRC %08lx (should be %08lx)\n", crc32val,
841: lrec.crc32);
842: error = 1; /* 1: warning error */
843: } else if (tflag) {
844: if (!quietflg)
845: fprintf(stdout, " OK\n");
846: } else {
847: if ((quietflg < 2) && !error)
848: fprintf(stdout, "\n");
849: }
850:
851: return error;
852:
853: } /* end function extract_or_test_member() */
854:
855:
856:
857:
858:
859: #ifdef CRYPT
860:
861: /*******************************/
862: /* Function decrypt_member() */
863: /*******************************/
864:
865: static int decrypt_member() /* return 10 if out of memory or can't get */
866: { /* tty; 1 if password bad; 0 if password OK */
867: UWORD b;
868: int n, r;
869: static int nopwd=FALSE;
870: char *m, *prompt;
871: byte h[12];
872:
873:
874: /* get header once (turn off "encrypted" flag temporarily so we don't
875: * try to decrypt the same data twice) */
876: pInfo->encrypted = FALSE;
877: for (n = 0; n < 12; n++) {
878: ReadByte(&b);
879: h[n] = (byte) b;
880: }
881: pInfo->encrypted = TRUE;
882:
883: /* if have key already, test it; else allocate memory for it */
884: if (key) {
885: if (!testp(h))
886: return 0; /* existing password OK (else prompt for new) */
887: else if (nopwd)
888: return 1; /* user indicated no more prompting */
889: } else if ((key = (char *)malloc(PWLEN+1)) == (char *)NULL)
890: return 10;
891:
892: if ((prompt = (char *)malloc(FILNAMSIZ+15)) != (char *)NULL) {
893: sprintf(prompt, "%s password: ", filename);
894: m = prompt;
895: } else
896: m = "Enter password: ";
897:
898: /* try a few keys */
899: for (r = 0; r < 3; ++r) {
900: m = getp(m, key, PWLEN+1);
901: if (prompt != (char *)NULL) {
902: free(prompt);
903: prompt = (char *)NULL;
904: }
905: if (m == (char *)NULL)
906: return 10;
907: if (!testp(h))
908: return 0;
909: if (*key == '\0') {
910: nopwd = TRUE;
911: return 1;
912: }
913: m = "password incorrect--reenter: ";
914: }
915: return 1;
916: }
917:
918:
919:
920:
921:
922: /**********************/
923: /* Function testp() */
924: /**********************/
925:
926: static int testp(h) /* return -1 if bad password; 0 if OK */
927: byte *h;
928: {
929: UWORD b;
930: int n, t;
931: byte *p;
932:
933: /* set keys */
934: init_keys(key);
935:
936: /* check password */
937: for (n = 0; n < 12; n++)
938: b = DECRYPT(h[n]);
939:
940: #ifdef CRYPT_DEBUG
941: printf(" lrec.crc = %08lx crec.crc = %08lx pInfo->ExtLocHdr = %s\n",
942: lrec.crc32, pInfo->crc, pInfo->ExtLocHdr? "true":"false");
943: printf(" incnt = %d unzip offset into zipfile = %ld\n", incnt,
944: cur_zipfile_bufstart+(inptr-inbuf));
945: printf(" b = %02x (crc >> 24) = %02x (lrec.time >> 8) = %02x\n",
946: b, (UWORD)(lrec.crc32 >> 24), (lrec.last_mod_file_time >> 8));
947: #endif /* CRYPT_DEBUG */
948:
949: /* same test as in zipbare() in crypt.c (now check only one byte): */
950: if (b != (pInfo->ExtLocHdr? lrec.last_mod_file_time >> 8 :
951: (UWORD)(lrec.crc32 >> 24)))
952: return -1; /* bad */
953:
954: /* password OK: decrypt current buffer contents before leaving */
955: for (n = (longint)incnt > csize ? (int)csize : incnt, p = inptr; n--; p++)
956: *p = (byte) DECRYPT(*p);
957: return 0; /* OK */
958:
959: } /* end function testp() */
960:
961: #endif /* CRYPT */
962:
963:
964:
965:
966:
967: /*******************************/
968: /* Function ReadMemoryByte() */
969: /*******************************/
970:
971: int ReadMemoryByte(x) /* return PK-type error code */
972: UWORD *x;
973: {
974: if (mem_i_offset < mem_i_size) {
975: *x = (UWORD) mem_i_buffer[mem_i_offset++];
976: return 8;
977: } else
978: return 0;
979: }
980:
981:
982:
983:
984:
985: /****************************/
986: /* Function FlushMemory() */
987: /****************************/
988:
989: int FlushMemory() /* return PK-type error code */
990: {
991: if (outcnt == 0)
992: return 0;
993:
994: if (mem_o_offset + outcnt <= mem_o_size) {
995: memcpy((char *)(mem_o_buffer+(UWORD)mem_o_offset), (char *)outbuf,
996: outcnt);
997: mem_o_offset += outcnt;
998: return 0;
999: } else
1000: return 50;
1001: }
1002:
1003:
1004:
1005:
1006:
1007: /***************************/
1008: /* Function memextract() */ /* extract compressed extra field block */
1009: /***************************/
1010:
1011: int memextract(tgt, tgtsize, src, srcsize) /* return 0 if success, 1 if not */
1012: byte *tgt, *src;
1013: ULONG tgtsize, srcsize;
1014: {
1015: UWORD method, error = 0;
1016: ULONG crc, oldcrc;
1017: int r;
1018:
1019: method = makeword(src);
1020: crc = makelong(src+2);
1021:
1022: mem_i_buffer = src + 2 + 4; /* method and crc */
1023: mem_i_size = srcsize - 2 - 4;
1024: mem_i_offset = 0;
1025:
1026: mem_o_buffer = tgt;
1027: mem_o_size = tgtsize;
1028: mem_o_offset = 0;
1029:
1030: mem_mode = 1;
1031:
1032: bits_left = 0;
1033: bitbuf = 0L;
1034: outpos = 0L;
1035: outcnt = 0;
1036: outptr = outbuf;
1037: zipeof = 0;
1038:
1039: switch (method) {
1040: case STORED:
1041: memcpy(tgt, src + 2 + 4, (extent) (srcsize - 2 - 4));
1042: break;
1043: case DEFLATED:
1044: if ((r = inflate()) != 0) {
1045: fprintf(stderr, "error: %s\n", r == 3 ?
1046: "not enough memory for inflate operation" :
1047: "invalid compressed data for the inflate format");
1048: error = (r == 3)? 5 : 2;
1049: }
1050: FlushOutput();
1051: break;
1052: default:
1053: fprintf(stderr,
1054: "warning: unsupported extra field compression type--skipping\n");
1055: error = 1; /* GRR: this should be passed on up via SetEAs() */
1056: break;
1057: }
1058:
1059: mem_mode = 0;
1060:
1061: if (!error) {
1062: oldcrc = crc32val;
1063: crc32val = 0xFFFFFFFFL;
1064: UpdateCRC((unsigned char *) mem_o_buffer, (int) mem_o_size);
1065: crc32val = (~crc32val) & 0xFFFFFFFFL;
1066:
1067: if (crc32val != crc) {
1068: printf("(Bad extra field CRC %08lx, should be %08lx)\n", crc32val,
1069: crc);
1070: error = 1;
1071: }
1072: crc32val = oldcrc; /* grrr ... this ugly kludge should be fixed */
1073: }
1074:
1075: return error;
1076: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.