1 /*---------------------------------------------------------------------------
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.
9 Contains: extract_or_test_files()
11 extract_or_test_member()
18 ---------------------------------------------------------------------------*/
22 #define UNZIP_INTERNAL
27 # include "wince/intrface.h"
29 # include "windll/windll.h"
33 off_t
acelseek(off_t offset
, int whence
);
34 int aceread(void *buf
, size_t count
);
35 int aceopen(const char *path
, int flags
);
39 char *replacestr(char *str1
, char *str2
, char *str3
);
41 #define GRRDUMP(buf,len) { \
44 for (j = 0; j < (len)/16; ++j) { \
46 for (i = 0; i < 16; ++i) \
47 pipeit("%02x ", (uch)(buf)[i+(j<<4)]); \
49 for (i = 0; i < 16; ++i) { \
50 char c = (char)(buf)[i+(j<<4)]; \
63 for (i = j<<4; i < (len); ++i) \
64 pipeit("%02x ", (uch)(buf)[i]); \
66 for (i = j<<4; i < (len); ++i) { \
67 char c = (char)(buf)[i]; \
80 static int store_info
OF((__GPRO
));
81 static int extract_or_test_member
OF((__GPRO
));
83 static int TestExtraField
OF((__GPRO__ uch
*ef
, unsigned ef_len
));
84 static int test_compr_eb
OF((__GPRO__ uch
*eb
, unsigned eb_size
,
85 unsigned compr_offset
,
86 int (*test_uc_ebdata
)(__GPRO__ uch
*eb
, unsigned eb_size
,
87 uch
*eb_ucptr
, ulg eb_ucsize
)));
90 static int dircomp
OF((ZCONST zvoid
*a
, ZCONST zvoid
*b
));
95 /*******************************/
96 /* Strings used in extract.c */
97 /*******************************/
99 static ZCONST
char Far VersionMsg
[] =
100 " skipping: %-22s need %s compat. v%u.%u (can do v%u.%u)\n";
101 static ZCONST
char Far ComprMsgNum
[] =
102 " skipping: %-22s unsupported compression method %u\n";
104 static ZCONST
char Far ComprMsgName
[] =
105 " skipping: %-22s `%s' method not supported\n";
106 static ZCONST
char Far CmprNone
[] = "store";
107 static ZCONST
char Far CmprShrink
[] = "shrink";
108 static ZCONST
char Far CmprReduce
[] = "reduce";
109 static ZCONST
char Far CmprImplode
[] = "implode";
110 static ZCONST
char Far CmprTokenize
[] = "tokenize";
111 static ZCONST
char Far CmprDeflate
[] = "deflate";
112 static ZCONST
char Far CmprEnDeflate
[] = "enhanced deflate";
113 static ZCONST
char Far CmprDCLImplode
[] = "DCL implode";
114 static ZCONST
char Far
*ComprNames
[NUM_METHODS
] = {
115 CmprNone
, CmprShrink
, CmprReduce
, CmprReduce
, CmprReduce
, CmprReduce
,
116 CmprImplode
, CmprTokenize
, CmprDeflate
, CmprEnDeflate
, CmprDCLImplode
119 static ZCONST
char Far FilNamMsg
[] =
120 "%s: bad filename length (%s)\n";
121 static ZCONST
char Far ExtFieldMsg
[] =
122 "%s: bad extra field length (%s)\n";
123 static ZCONST
char Far OffsetMsg
[] =
124 "file #%u: bad zipfile offset (%s): %ld\n";
125 static ZCONST
char Far ExtractMsg
[] =
126 "%8sing: %-22s %s%s";
128 static ZCONST
char Far LengthMsg
[] =
129 "%s %s: %ld bytes required to uncompress to %lu bytes;\n %s\
130 supposed to require %lu bytes%s%s%s\n";
133 static ZCONST
char Far BadFileCommLength
[] = "%s: bad file comment length\n";
134 static ZCONST
char Far LocalHdrSig
[] = "local header sig";
135 static ZCONST
char Far BadLocalHdr
[] = "file #%u: bad local header\n";
136 static ZCONST
char Far AttemptRecompensate
[] =
137 " (attempting to re-compensate)\n";
139 static ZCONST
char Far BackslashPathSep
[] =
140 "warning: %s appears to use backslashes as path separators\n";
142 static ZCONST
char Far SkipVolumeLabel
[] =
143 " skipping: %-22s %svolume label\n";
145 #ifdef SET_DIR_ATTRIB /* messages of code for setting directory attributes */
146 static ZCONST
char Far DirlistEntryNoMem
[] =
147 "warning: cannot alloc memory for dir times/permissions/UID/GID\n";
148 static ZCONST
char Far DirlistSortNoMem
[] =
149 "warning: cannot alloc memory to sort dir times/perms/etc.\n";
150 static ZCONST
char Far DirlistSetAttrFailed
[] =
151 "warning: set times/attribs failed for %s\n";
155 static ZCONST
char Far ReplaceQuery
[] =
156 "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ";
157 static ZCONST
char Far AssumeNone
[] = " NULL\n(assuming [N]one)\n";
158 static ZCONST
char Far NewNameQuery
[] = "new name: ";
159 static ZCONST
char Far InvalidResponse
[] = "error: invalid response [%c]\n";
162 static ZCONST
char Far ErrorInArchive
[] =
163 "At least one %serror was detected in %s.\n";
164 static ZCONST
char Far ZeroFilesTested
[] =
165 "Caution: zero files tested in %s.\n";
168 static ZCONST
char Far VMSFormatQuery
[] =
169 "\n%s: stored in VMS format. Extract anyway? (y/n) ";
173 static ZCONST
char Far SkipCannotGetPasswd
[] =
174 " skipping: %-22s unable to get password\n";
175 static ZCONST
char Far SkipIncorrectPasswd
[] =
176 " skipping: %-22s incorrect password\n";
177 static ZCONST
char Far FilesSkipBadPasswd
[] =
178 "%u file%s skipped because of incorrect password.\n";
179 static ZCONST
char Far MaybeBadPasswd
[] =
180 " (may instead be incorrect password)\n";
182 static ZCONST
char Far SkipEncrypted
[] =
183 " skipping: %-22s encrypted (not supported)\n";
186 static ZCONST
char Far NoErrInCompData
[] =
187 "No errors detected in compressed data of %s.\n";
188 static ZCONST
char Far NoErrInTestedFiles
[] =
189 "No errors detected in %s for the %u file%s tested.\n";
190 static ZCONST
char Far FilesSkipped
[] =
191 "%u file%s skipped because of unsupported compression or encoding.\n";
193 static ZCONST
char Far ErrUnzipFile
[] = " error: %s%s %s\n";
194 static ZCONST
char Far ErrUnzipNoFile
[] = "\n error: %s%s\n";
195 static ZCONST
char Far NotEnoughMem
[] = "not enough memory to ";
196 static ZCONST
char Far InvalidComprData
[] = "invalid compressed data to ";
197 static ZCONST
char Far Inflate
[] = "inflate";
200 static ZCONST
char Far Explode
[] = "explode";
202 static ZCONST
char Far Unshrink
[] = "unshrink";
206 #if (!defined(DELETE_IF_FULL) || !defined(HAVE_UNLINK))
207 static ZCONST
char Far FileTruncated
[] =
208 "warning: %s is probably truncated\n";
211 static ZCONST
char Far FileUnknownCompMethod
[] =
212 "%s: unknown compression method\n";
213 static ZCONST
char Far BadCRC
[] = " bad CRC %08lx (should be %08lx)\n";
215 /* TruncEAs[] also used in OS/2 mapname(), close_outfile() */
216 char ZCONST Far TruncEAs
[] = " compressed EA data missing (%d bytes)%s";
217 char ZCONST Far TruncNTSD
[] =
218 " compressed WinNT security data missing (%d bytes)%s";
221 static ZCONST
char Far InconsistEFlength
[] = "bad extra-field entry:\n \
222 EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n";
223 static ZCONST
char Far InvalidComprDataEAs
[] =
224 " invalid compressed data for EAs\n";
225 # if (defined(WIN32) && defined(NTSD_EAS))
226 static ZCONST
char Far InvalidSecurityEAs
[] =
227 " EAs fail security check\n";
229 static ZCONST
char Far UnsuppNTSDVersEAs
[] =
230 " unsupported NTSD EAs version %d\n";
231 static ZCONST
char Far BadCRC_EAs
[] = " bad CRC for extended attributes\n";
232 static ZCONST
char Far UnknComprMethodEAs
[] =
233 " unknown compression method for EAs (%u)\n";
234 static ZCONST
char Far NotEnoughMemEAs
[] =
235 " out of memory while inflating EAs\n";
236 static ZCONST
char Far UnknErrorEAs
[] =
237 " unknown error on extended attributes\n";
240 static ZCONST
char Far UnsupportedExtraField
[] =
241 "\nerror: unsupported extra-field compression type (%u)--skipping\n";
242 static ZCONST
char Far BadExtraFieldCRC
[] =
243 "error [%s]: bad extra-field CRC %08lx (should be %08lx)\n";
249 /**************************************/
250 /* Function extract_or_test_files() */
251 /**************************************/
253 int extract_or_test_files(__G
) /* return PK-type error code */
257 unsigned i
, j
, filnum
=0, blknum
=0;
258 int cd_incnt
, renamed
, query
;
259 int error
, error_in_archive
=PK_COOL
, *fn_matched
=NULL
, *xn_matched
=NULL
;
265 unsigned members_remaining
, num_skipped
=0, num_bad_pwd
=0;
266 long cd_bufstart
, bufstart
, inbuf_offset
, request
;
267 LONGINT old_extra_bytes
= 0L;
268 #ifdef SET_DIR_ATTRIB
270 dirtime
*dirlist
=(dirtime
*)NULL
, **sorted_dirlist
=(dirtime
**)NULL
;
274 /*---------------------------------------------------------------------------
275 The basic idea of this function is as follows. Since the central di-
276 rectory lies at the end of the zipfile and the member files lie at the
277 beginning or middle or wherever, it is not very desirable to simply
278 read a central directory entry, jump to the member and extract it, and
279 then jump back to the central directory. In the case of a large zipfile
280 this would lead to a whole lot of disk-grinding, especially if each mem-
281 ber file is small. Instead, we read from the central directory the per-
282 tinent information for a block of files, then go extract/test the whole
283 block. Thus this routine contains two small(er) loops within a very
284 large outer loop: the first of the small ones reads a block of files
285 from the central directory; the second extracts or tests each file; and
286 the outer one loops over blocks. There's some file-pointer positioning
287 stuff in between, but that's about it. Btw, it's because of this jump-
288 ing around that we can afford to be lenient if an error occurs in one of
289 the member files: we should still be able to go find the other members,
290 since we know the offset of each from the beginning of the zipfile.
291 ---------------------------------------------------------------------------*/
294 members_remaining
= (unsigned)G
.ecrec
.total_entries_central_dir
;
300 G
.reported_backslash
= FALSE
;
303 /* malloc space for check on unmatched filespecs (OK if one or both NULL) */
304 if (G
.filespecs
> 0 &&
305 (fn_matched
=(int *)malloc(G
.filespecs
*sizeof(int))) != (int *)NULL
)
306 for (i
= 0; i
< G
.filespecs
; ++i
)
307 fn_matched
[i
] = FALSE
;
308 if (G
.xfilespecs
> 0 &&
309 (xn_matched
=(int *)malloc(G
.xfilespecs
*sizeof(int))) != (int *)NULL
)
310 for (i
= 0; i
< G
.xfilespecs
; ++i
)
311 xn_matched
[i
] = FALSE
;
313 /*---------------------------------------------------------------------------
314 Begin main loop over blocks of member files. We know the entire central
315 directory is on this disk: we would not have any of this information un-
316 less the end-of-central-directory record was on this disk, and we would
317 not have gotten to this routine unless this is also the disk on which
318 the central directory starts. In practice, this had better be the ONLY
319 disk in the archive, but we'll add multi-disk support soon.
320 ---------------------------------------------------------------------------*/
322 while (members_remaining
) {
325 memzero(G
.filenotes
, DIR_BLKSIZ
* sizeof(char *));
329 * Loop through files in central directory, storing offsets, file
330 * attributes, case-conversion and text-conversion flags until block
334 while (members_remaining
&& (j
< DIR_BLKSIZ
)) {
336 G
.pInfo
= &G
.info
[j
];
338 if (readbuf(__G__ G
.sig
, 4) == 0) {
339 error_in_archive
= PK_EOF
;
340 members_remaining
= 0; /* ...so no more left to do */
343 if (strncmp(G
.sig
, central_hdr_sig
, 4)) { /* just to make sure */
344 Info(slide
, 0x401, ((char *)slide
, LoadFarString(CentSigMsg
),
345 j
+ blknum
*DIR_BLKSIZ
+ 1));
346 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ReportMsg
)));
347 error_in_archive
= PK_BADERR
;
348 members_remaining
= 0; /* ...so no more left to do */
351 /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */
352 if ((error
= process_cdir_file_hdr(__G
)) != PK_COOL
) {
353 error_in_archive
= error
; /* only PK_EOF defined */
354 members_remaining
= 0; /* ...so no more left to do */
357 if ((error
= do_string(__G__ G
.crec
.filename_length
, DS_FN
)) !=
360 if (error
> error_in_archive
)
361 error_in_archive
= error
;
362 if (error
> PK_WARN
) { /* fatal: no more left to do */
363 Info(slide
, 0x401, ((char *)slide
, LoadFarString(FilNamMsg
),
364 FnFilter1(G
.filename
), "central"));
365 members_remaining
= 0;
369 if ((error
= do_string(__G__ G
.crec
.extra_field_length
,
372 if (error
> error_in_archive
)
373 error_in_archive
= error
;
374 if (error
> PK_WARN
) { /* fatal */
375 Info(slide
, 0x401, ((char *)slide
,
376 LoadFarString(ExtFieldMsg
),
377 FnFilter1(G
.filename
), "central"));
378 members_remaining
= 0;
384 if ((error
= do_string(__G__ G
.crec
.file_comment_length
,
385 uO
.N_flag
? FILENOTE
: SKIP
)) != PK_COOL
)
387 if ((error
= do_string(__G__ G
.crec
.file_comment_length
, SKIP
))
391 if (error
> error_in_archive
)
392 error_in_archive
= error
;
393 if (error
> PK_WARN
) { /* fatal */
394 Info(slide
, 0x421, ((char *)slide
,
395 LoadFarString(BadFileCommLength
),
396 FnFilter1(G
.filename
)));
397 members_remaining
= 0;
401 if (G
.process_all_files
) {
403 ++j
; /* file is OK; info[] stored; continue with next */
409 if (G
.filespecs
== 0)
411 else { /* check if this entry matches an `include' argument */
412 do_this_file
= FALSE
;
413 for (i
= 0; i
< G
.filespecs
; i
++)
414 if (match(G
.filename
, G
.pfnames
[i
], uO
.C_flag
)) {
415 do_this_file
= TRUE
; /* ^-- ignore case or not? */
417 fn_matched
[i
] = TRUE
;
418 break; /* found match, so stop looping */
421 if (do_this_file
) { /* check if this is an excluded file */
422 for (i
= 0; i
< G
.xfilespecs
; i
++)
423 if (match(G
.filename
, G
.pxnames
[i
], uO
.C_flag
)) {
424 do_this_file
= FALSE
; /* ^-- ignore case or not? */
426 xn_matched
[i
] = TRUE
;
432 ++j
; /* file is OK */
434 ++num_skipped
; /* unsupp. compression or encryption */
436 } /* end if (process_all_files) */
439 } /* end while-loop (adding files to current block) */
441 /* save position in central directory so can come back later */
442 cd_bufstart
= G
.cur_zipfile_bufstart
;
446 /*-----------------------------------------------------------------------
447 Second loop: process files in current block, extracting or testing
449 -----------------------------------------------------------------------*/
451 for (i
= 0; i
< j
; ++i
) {
452 filnum
++; /* filnum = i + blknum*DIR_BLKSIZ + 1; */
453 G
.pInfo
= &G
.info
[i
];
454 #ifdef NOVELL_BUG_FAILSAFE
455 G
.dne
= FALSE
; /* assume file exists until stat() says otherwise */
458 /* if the target position is not within the current input buffer
459 * (either haven't yet read far enough, or (maybe) skipping back-
460 * ward), skip to the target position and reset readbuf(). */
462 /* ZLSEEK(pInfo->offset): */
463 request
= G
.pInfo
->offset
+ G
.extra_bytes
;
464 inbuf_offset
= request
% INBUFSIZ
;
465 bufstart
= request
- inbuf_offset
;
467 Trace((stderr
, "\ndebug: request = %ld, inbuf_offset = %ld\n",
468 request
, inbuf_offset
));
470 "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
471 bufstart
, G
.cur_zipfile_bufstart
));
473 Info(slide
, 0x401, ((char *)slide
, LoadFarStringSmall(SeekMsg
),
474 G
.zipfn
, LoadFarString(ReportMsg
)));
475 error_in_archive
= PK_ERR
;
476 if (filnum
== 1 && G
.extra_bytes
!= 0L) {
477 Info(slide
, 0x401, ((char *)slide
,
478 LoadFarString(AttemptRecompensate
)));
479 old_extra_bytes
= G
.extra_bytes
;
481 request
= G
.pInfo
->offset
; /* could also check if != 0 */
482 inbuf_offset
= request
% INBUFSIZ
;
483 bufstart
= request
- inbuf_offset
;
484 Trace((stderr
, "debug: request = %ld, inbuf_offset = %ld\n",
485 request
, inbuf_offset
));
487 "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
488 bufstart
, G
.cur_zipfile_bufstart
));
490 error_in_archive
= PK_BADERR
;
491 continue; /* this one hosed; try next */
496 Trace((stderr
, "debug: recompensated request still < 0\n"));
497 Info(slide
, 0x401, ((char *)slide
, LoadFarStringSmall(SeekMsg
),
498 G
.zipfn
, LoadFarString(ReportMsg
)));
499 error_in_archive
= PK_BADERR
;
501 } else if (bufstart
!= G
.cur_zipfile_bufstart
) {
502 Trace((stderr
, "debug: bufstart != cur_zipfile_bufstart\n"));
503 #ifdef USE_STRM_INPUT
504 fseek((FILE *)G
.zipfd
,(LONGINT
)bufstart
,SEEK_SET
);
505 G
.cur_zipfile_bufstart
= ftell((FILE *)G
.zipfd
);
506 #else /* !USE_STRM_INPUT */
507 G
.cur_zipfile_bufstart
=
508 acelseek((LONGINT
)bufstart
,SEEK_SET
);
509 #endif /* ?USE_STRM_INPUT */
510 if ((G
.incnt
= aceread((char *)G
.inbuf
,INBUFSIZ
)) <= 0)
512 Info(slide
, 0x401, ((char *)slide
, LoadFarString(OffsetMsg
),
513 filnum
, "lseek", bufstart
));
514 error_in_archive
= PK_BADERR
;
515 continue; /* can still do next file */
517 G
.inptr
= G
.inbuf
+ (int)inbuf_offset
;
518 G
.incnt
-= (int)inbuf_offset
;
520 G
.incnt
+= (int)(G
.inptr
-G
.inbuf
) - (int)inbuf_offset
;
521 G
.inptr
= G
.inbuf
+ (int)inbuf_offset
;
524 /* should be in proper position now, so check for sig */
525 if (readbuf(__G__ G
.sig
, 4) == 0) { /* bad offset */
526 Info(slide
, 0x401, ((char *)slide
, LoadFarString(OffsetMsg
),
527 filnum
, "EOF", request
));
528 error_in_archive
= PK_BADERR
;
529 continue; /* but can still try next one */
531 if (strncmp(G
.sig
, local_hdr_sig
, 4)) {
532 Info(slide
, 0x401, ((char *)slide
, LoadFarString(OffsetMsg
),
533 filnum
, LoadFarStringSmall(LocalHdrSig
), request
));
536 GRRDUMP(local_hdr_sig, 4)
538 error_in_archive
= PK_ERR
;
539 if ((filnum
== 1 && G
.extra_bytes
!= 0L) ||
540 (G
.extra_bytes
== 0L && old_extra_bytes
!= 0L)) {
541 Info(slide
, 0x401, ((char *)slide
,
542 LoadFarString(AttemptRecompensate
)));
544 old_extra_bytes
= G
.extra_bytes
;
547 G
.extra_bytes
= old_extra_bytes
; /* third attempt */
548 ZLSEEK(G
.pInfo
->offset
)
549 if (readbuf(__G__ G
.sig
, 4) == 0) { /* bad offset */
550 Info(slide
, 0x401, ((char *)slide
,
551 LoadFarString(OffsetMsg
), filnum
, "EOF", request
));
552 error_in_archive
= PK_BADERR
;
553 continue; /* but can still try next one */
555 if (strncmp(G
.sig
, local_hdr_sig
, 4)) {
556 Info(slide
, 0x401, ((char *)slide
,
557 LoadFarString(OffsetMsg
), filnum
,
558 LoadFarStringSmall(LocalHdrSig
), request
));
559 error_in_archive
= PK_BADERR
;
563 continue; /* this one hosed; try next */
565 if ((error
= process_local_file_hdr(__G
)) != PK_COOL
) {
566 Info(slide
, 0x421, ((char *)slide
, LoadFarString(BadLocalHdr
),
568 error_in_archive
= error
; /* only PK_EOF defined */
569 continue; /* can still try next one */
571 if ((error
= do_string(__G__ G
.lrec
.filename_length
, DS_FN
)) !=
574 if (error
> error_in_archive
)
575 error_in_archive
= error
;
576 if (error
> PK_WARN
) {
577 Info(slide
, 0x401, ((char *)slide
, LoadFarString(FilNamMsg
),
578 FnFilter1(G
.filename
), "local"));
579 continue; /* go on to next one */
582 if (G
.extra_field
!= (uch
*)NULL
) {
584 G
.extra_field
= (uch
*)NULL
;
587 do_string(__G__ G
.lrec
.extra_field_length
, EXTRA_FIELD
)) != 0)
589 if (error
> error_in_archive
)
590 error_in_archive
= error
;
591 if (error
> PK_WARN
) {
592 Info(slide
, 0x401, ((char *)slide
,
593 LoadFarString(ExtFieldMsg
),
594 FnFilter1(G
.filename
), "local"));
595 continue; /* go on */
600 if (G
.pInfo
->encrypted
&&
601 (error
= decrypt(__G__ uO
.pwdarg
)) != PK_COOL
) {
602 if (error
== PK_WARN
) {
603 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
)))
604 Info(slide
, 0x401, ((char *)slide
,
605 LoadFarString(SkipIncorrectPasswd
),
606 FnFilter1(G
.filename
)));
608 } else { /* (error > PK_WARN) */
609 if (error
> error_in_archive
)
610 error_in_archive
= error
;
611 Info(slide
, 0x401, ((char *)slide
,
612 LoadFarString(SkipCannotGetPasswd
),
613 FnFilter1(G
.filename
)));
615 continue; /* go on to next file */
620 * just about to extract file: if extracting to disk, check if
621 * already exists, and if so, take appropriate action according to
622 * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
623 * loop because we don't store the possibly renamed filename[] in
627 if (!uO
.tflag
&& !uO
.cflag
&& !G
.redirect_data
)
629 if (!uO
.tflag
&& !uO
.cflag
)
632 renamed
= FALSE
; /* user hasn't renamed output file yet */
636 /* for files from DOS FAT, check for use of backslash instead
637 * of slash as directory separator (bug in some zipper(s); so
638 * far, not a problem in HPFS, NTFS or VFAT systems)
641 if (G
.pInfo
->hostnum
== FS_FAT_
&& !strchr(G
.filename
, '/')) {
642 char *p
=G
.filename
-1;
646 if (!G
.reported_backslash
) {
647 Info(slide
, 0x21, ((char *)slide
,
648 LoadFarString(BackslashPathSep
), G
.zipfn
));
649 G
.reported_backslash
= TRUE
;
650 if (!error_in_archive
)
651 error_in_archive
= PK_WARN
;
659 /* mapname can create dirs if not freshening or if renamed */
660 if ((error
= mapname(__G__ renamed
)) > PK_WARN
) {
661 if (error
== IZ_CREATED_DIR
) {
662 #ifdef SET_DIR_ATTRIB
665 d_entry
= (dirtime
*)malloc(sizeof(dirtime
));
666 if (d_entry
== (dirtime
*)NULL
) {
667 Info(slide
, 0x401, ((char *)slide
,
668 LoadFarString(DirlistEntryNoMem
)));
670 unsigned eb_izux_flg
;
672 d_entry
->next
= dirlist
;
675 (char *)malloc(strlen(G
.filename
) + 1);
676 if (dirlist
->fn
== (char *)NULL
) {
677 Info(slide
, 0x401, ((char *)slide
,
678 LoadFarString(DirlistEntryNoMem
)));
679 dirlist
= d_entry
->next
;
681 if (!error_in_archive
)
682 error_in_archive
= PK_WARN
;
685 strcpy(dirlist
->fn
, G
.filename
);
686 dirlist
->perms
= G
.pInfo
->file_attr
;
687 #ifdef USE_EF_UT_TIME
688 eb_izux_flg
= G
.extra_field
? ef_scan_for_izux(
689 G
.extra_field
, G
.lrec
.extra_field_length
, 0,
690 G
.lrec
.last_mod_dos_datetime
,
692 (G
.tz_is_valid
? &(dirlist
->u
.t3
) : NULL
),
698 #else /* !USE_EF_UT_TIME */
700 #endif /* ?USE_EF_UT_TIME */
701 if (eb_izux_flg
& EB_UT_FL_MTIME
) {
703 "\nextract: Unix dir e.f. modtime = %ld\n",
704 dirlist
->u
.t3
.mtime
));
706 dirlist
->u
.t3
.mtime
= dos_to_unix_time(
707 G
.lrec
.last_mod_dos_datetime
);
709 if (eb_izux_flg
& EB_UT_FL_ATIME
) {
711 "\nextract: Unix dir e.f. actime = %ld\n",
712 dirlist
->u
.t3
.atime
));
714 dirlist
->u
.t3
.atime
=
717 dirlist
->have_uidgid
=
718 (uO
.X_flag
&& (eb_izux_flg
& EB_UX2_VALID
));
721 #endif /* SET_DIR_ATTRIB */
722 } else if (error
== IZ_VOL_LABEL
) {
724 Info(slide
, 0x401, ((char *)slide
,
725 LoadFarString(SkipVolumeLabel
),
726 FnFilter1(G
.filename
),
727 uO
.volflag
? "hard disk " : ""));
729 Info(slide
, 1, ((char *)slide
,
730 LoadFarString(SkipVolumeLabel
),
731 FnFilter1(G
.filename
), ""));
733 /* if (!error_in_archive)
734 error_in_archive = PK_WARN; */
735 } else if (error
> PK_ERR
&& error_in_archive
< PK_ERR
)
736 error_in_archive
= PK_ERR
;
737 Trace((stderr
, "mapname(%s) returns error = %d\n",
738 FnFilter1(G
.filename
), error
));
739 continue; /* go on to next file */
743 QFilename(__G__ G
.filename
);
745 switch (check_for_newer(__G__ G
.filename
)) {
747 #ifdef NOVELL_BUG_FAILSAFE
748 G
.dne
= TRUE
; /* stat() says file DOES NOT EXIST */
750 /* if freshening, don't skip if just renamed */
751 if (uO
.fflag
&& !renamed
)
752 continue; /* freshen (no new files): skip */
754 case EXISTS_AND_OLDER
:
755 if (uO
.overwrite_none
) {
757 char szStr
[FILNAMSIZ
+40]; /* add. space for text */
759 if ((!G
.prompt_always
) || (done_once
)) {
761 "Target file exists.\nSkipping %s\n",
762 FnFilter1(G
.filename
));
763 win_fprintf((zvoid
*)&G
, stdout
,
764 strlen(szStr
), szStr
);
770 continue; /* never overwrite: skip file */
773 if (!uO
.overwrite_all
&& !uO
.B_flag
)
775 if (!uO
.overwrite_all
)
779 case EXISTS_AND_NEWER
: /* (or equal) */
780 if (uO
.overwrite_none
|| (uO
.uflag
&& !renamed
)) {
782 char szStr
[FILNAMSIZ
+40]; /* add. space for text */
784 if ((!G
.prompt_always
) || (done_once
)) {
786 "Target file newer.\nSkipping %s\n",
787 FnFilter1(G
.filename
));
788 win_fprintf((zvoid
*)&G
, stdout
,
789 strlen(szStr
), szStr
);
795 continue; /* skip if update/freshen & orig name */
798 if (!uO
.overwrite_all
&& !uO
.B_flag
)
800 if (!uO
.overwrite_all
)
807 switch (G
.lpUserFunctions
->replace
!= NULL
?
808 (*G
.lpUserFunctions
->replace
)(G
.filename
) :
810 case IDM_REPLACE_RENAME
:
811 _ISO_INTERN(G
.filename
);
814 case IDM_REPLACE_YES
:
816 case IDM_REPLACE_ALL
:
817 uO
.overwrite_all
= TRUE
;
818 uO
.overwrite_none
= FALSE
; /* just to make sure */
820 case IDM_REPLACE_NONE
:
821 uO
.overwrite_none
= TRUE
;
822 uO
.overwrite_all
= FALSE
; /* make sure */
824 /* FALL THROUGH, skip */
827 char szStr
[FILNAMSIZ
+40];
830 "Target file newer.\nSkipping %s\n",
831 FnFilter1(G
.filename
));
832 win_fprintf((zvoid
*)&G
, stdout
,
833 strlen(szStr
), szStr
);
839 Info(slide
, 0x81, ((char *)slide
,
840 LoadFarString(ReplaceQuery
),
841 FnFilter1(G
.filename
)));
842 if (fgets(G
.answerbuf
, 9, stdin
) == (char *)NULL
) {
843 Info(slide
, 1, ((char *)slide
,
844 LoadFarString(AssumeNone
)));
846 if (!error_in_archive
)
847 error_in_archive
= 1; /* not extracted: warning */
849 switch (*G
.answerbuf
) {
850 case 'A': /* dangerous option: force caps */
851 uO
.overwrite_all
= TRUE
;
852 uO
.overwrite_none
= FALSE
; /* just to make sure */
857 Info(slide
, 0x81, ((char *)slide
,
858 LoadFarString(NewNameQuery
)));
859 fgets(G
.filename
, FILNAMSIZ
, stdin
);
860 /* usually get \n here: better check for it */
861 len
= strlen(G
.filename
);
862 if (G
.filename
[len
-1] == '\n')
863 G
.filename
[--len
] = '\0';
865 #ifdef WIN32 /* WIN32 fgets( ... , stdin) returns OEM coded strings */
866 _OEM_INTERN(G
.filename
);
869 goto startover
; /* sorry for a goto */
874 uO
.overwrite_none
= TRUE
;
875 uO
.overwrite_all
= FALSE
; /* make sure */
876 /* FALL THROUGH, skip */
878 continue; /* skip file */
880 Info(slide
, 1, ((char *)slide
,
881 LoadFarString(InvalidResponse
), *G
.answerbuf
));
882 goto reprompt
; /* yet another goto? */
883 } /* end switch (*answerbuf) */
885 } /* end if (query) */
886 } /* end if (extracting to disk) */
889 if ((G
.statreportcb
!= NULL
) &&
890 (*G
.statreportcb
)(__G__ UZ_ST_START_EXTRACT
, G
.zipfn
,
893 free((zvoid
*)fn_matched
);
895 free((zvoid
*)xn_matched
);
896 return IZ_CTRLC
; /* cancel operation by user request */
899 #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
906 if ((error
= extract_or_test_member(__G
)) != PK_COOL
) {
907 if (error
> error_in_archive
)
908 error_in_archive
= error
; /* ...and keep going */
910 if (G
.disk_full
> 1 || error_in_archive
== IZ_CTRLC
) {
912 if (G
.disk_full
> 1) {
915 free((zvoid
*)fn_matched
);
917 free((zvoid
*)xn_matched
);
918 return error_in_archive
; /* (unless disk full) */
922 if ((G
.statreportcb
!= NULL
) &&
923 (*G
.statreportcb
)(__G__ UZ_ST_FINISH_MEMBER
, G
.zipfn
,
924 G
.filename
, (zvoid
*)&G
.lrec
.ucsize
)) {
926 free((zvoid
*)fn_matched
);
928 free((zvoid
*)xn_matched
);
929 return IZ_CTRLC
; /* cancel operation by user request */
932 #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
935 } /* end for-loop (i: files in current block) */
939 * Jump back to where we were in the central directory, then go and do
940 * the next batch of files.
943 #ifdef USE_STRM_INPUT
944 fseek((FILE *)G
.zipfd
, (LONGINT
)cd_bufstart
, SEEK_SET
);
945 G
.cur_zipfile_bufstart
= ftell((FILE *)G
.zipfd
);
946 #else /* !USE_STRM_INPUT */
947 G
.cur_zipfile_bufstart
= acelseek((LONGINT
)cd_bufstart
,SEEK_SET
);
948 #endif /* ?USE_STRM_INPUT */
949 aceread((char *)G
.inbuf
, INBUFSIZ
); /* been here before... */
955 pipeit("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart
, cd_bufstart
);
956 pipeit("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart
,
957 cur_zipfile_bufstart
);
958 pipeit("inptr-inbuf = %d\n", G
.inptr
-G
.inbuf
);
959 pipeit("incnt = %d\n\n", G
.incnt
);
962 } /* end while-loop (blocks of files in central directory) */
964 /*---------------------------------------------------------------------------
965 Go back through saved list of directories, sort and set times/perms/UIDs
966 and GIDs from the deepest level on up.
967 ---------------------------------------------------------------------------*/
969 #ifdef SET_DIR_ATTRIB
971 sorted_dirlist
= (dirtime
**)malloc(num_dirs
*sizeof(dirtime
*));
972 if (sorted_dirlist
== (dirtime
**)NULL
) {
973 Info(slide
, 0x401, ((char *)slide
,
974 LoadFarString(DirlistSortNoMem
)));
975 while (dirlist
!= (dirtime
*)NULL
) {
976 dirtime
*d
= dirlist
;
978 dirlist
= dirlist
->next
;
983 sorted_dirlist
[0] = dirlist
;
985 for (i
= 0; i
< num_dirs
; ++i
) {
986 sorted_dirlist
[i
] = dirlist
;
987 dirlist
= dirlist
->next
;
989 qsort((char *)sorted_dirlist
, num_dirs
, sizeof(dirtime
*),
993 Trace((stderr
, "setting directory times/perms/attributes\n"));
994 for (i
= 0; i
< num_dirs
; ++i
) {
995 dirtime
*d
= sorted_dirlist
[i
];
997 Trace((stderr
, "dir = %s\n", d
->fn
));
998 if ((error
= set_direc_attribs(__G__ d
)) != PK_OK
) {
999 Info(slide
, 0x201, ((char *)slide
,
1000 LoadFarString(DirlistSetAttrFailed
), d
->fn
));
1001 if (!error_in_archive
)
1002 error_in_archive
= error
;
1007 free(sorted_dirlist
);
1010 #endif /* SET_DIR_ATTRIB */
1012 #if (defined(WIN32) && defined(NTSD_EAS))
1013 process_defer_NT(__G
); /* process any deferred items for this .zip file */
1016 /*---------------------------------------------------------------------------
1017 Check for unmatched filespecs on command line and print warning if any
1018 found. Free allocated memory.
1019 ---------------------------------------------------------------------------*/
1022 for (i
= 0; i
< G
.filespecs
; ++i
)
1023 if (!fn_matched
[i
]) {
1025 if (!G
.redirect_data
&& !G
.redirect_text
)
1026 Info(slide
, 0x401, ((char *)slide
,
1027 LoadFarString(FilenameNotMatched
), G
.pfnames
[i
]));
1029 setFileNotFound(__G
);
1031 Info(slide
, 1, ((char *)slide
,
1032 LoadFarString(FilenameNotMatched
), G
.pfnames
[i
]));
1034 if (error_in_archive
<= PK_WARN
)
1035 error_in_archive
= PK_FIND
; /* some files not found */
1037 free((zvoid
*)fn_matched
);
1040 for (i
= 0; i
< G
.xfilespecs
; ++i
)
1042 Info(slide
, 0x401, ((char *)slide
,
1043 LoadFarString(ExclFilenameNotMatched
), G
.pxnames
[i
]));
1044 free((zvoid
*)xn_matched
);
1047 /*---------------------------------------------------------------------------
1048 Double-check that we're back at the end-of-central-directory record, and
1049 print quick summary of results, if we were just testing the archive. We
1050 send the summary to stdout so that people doing the testing in the back-
1051 ground and redirecting to a file can just do a "tail" on the output file.
1052 ---------------------------------------------------------------------------*/
1055 if (readbuf(__G__ G
.sig
, 4) == 0)
1056 error_in_archive
= PK_EOF
;
1057 if (strncmp(G
.sig
, end_central_sig
, 4)) { /* just to make sure */
1058 Info(slide
, 0x401, ((char *)slide
, LoadFarString(EndSigMsg
)));
1059 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ReportMsg
)));
1060 if (!error_in_archive
) /* don't overwrite stronger error */
1061 error_in_archive
= PK_WARN
;
1065 unsigned num
= filnum
- num_bad_pwd
;
1067 if (uO
.qflag
< 2) { /* GRR 930710: was (uO.qflag == 1) */
1068 if (error_in_archive
)
1069 Info(slide
, 0, ((char *)slide
, LoadFarString(ErrorInArchive
),
1070 (error_in_archive
== 1)? "warning-" : "", G
.zipfn
));
1072 Info(slide
, 0, ((char *)slide
, LoadFarString(ZeroFilesTested
),
1074 else if (G
.process_all_files
&& (num_skipped
+num_bad_pwd
== 0))
1075 Info(slide
, 0, ((char *)slide
, LoadFarString(NoErrInCompData
),
1078 Info(slide
, 0, ((char *)slide
, LoadFarString(NoErrInTestedFiles
)
1079 , G
.zipfn
, num
, (num
==1)? "":"s"));
1080 if (num_skipped
> 0)
1081 Info(slide
, 0, ((char *)slide
, LoadFarString(FilesSkipped
),
1082 num_skipped
, (num_skipped
==1)? "":"s"));
1084 if (num_bad_pwd
> 0)
1085 Info(slide
, 0, ((char *)slide
, LoadFarString(FilesSkipBadPasswd
)
1086 , num_bad_pwd
, (num_bad_pwd
==1)? "":"s"));
1088 } else if ((uO
.qflag
== 0) && !error_in_archive
&& (num
== 0))
1089 Info(slide
, 0, ((char *)slide
, LoadFarString(ZeroFilesTested
),
1093 /* give warning if files not tested or extracted (first condition can still
1094 * happen if zipfile is empty and no files specified on command line) */
1096 if ((filnum
== 0) && error_in_archive
<= PK_WARN
) {
1097 if (num_skipped
> 0)
1098 error_in_archive
= IZ_UNSUP
; /* unsupport. compression/encryption */
1100 error_in_archive
= PK_FIND
; /* no files found at all */
1103 else if ((filnum
== num_bad_pwd
) && error_in_archive
<= PK_WARN
)
1104 error_in_archive
= IZ_BADPWD
; /* bad passwd => all files skipped */
1106 else if ((num_skipped
> 0) && error_in_archive
<= PK_WARN
)
1107 error_in_archive
= IZ_UNSUP
; /* was PK_WARN; Jean-loup complained */
1109 else if ((num_bad_pwd
> 0) && !error_in_archive
)
1110 error_in_archive
= PK_WARN
;
1113 return error_in_archive
;
1115 } /* end function extract_or_test_files() */
1121 /***************************/
1122 /* Function store_info() */
1123 /***************************/
1125 static int store_info(__G
) /* return 0 if skipping, 1 if OK */
1129 # define UNKN_COMPR \
1130 (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED)
1132 # ifdef COPYRIGHT_CLEAN /* no reduced files */
1133 # define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
1134 G.crec.compression_method <= REDUCED4)
1136 # define UNKN_RED FALSE /* reducing not unknown */
1138 # ifdef LZW_CLEAN /* no shrunk files */
1139 # define UNKN_SHR (G.crec.compression_method == SHRUNK)
1141 # define UNKN_SHR FALSE /* unshrinking not unknown */
1143 # define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
1144 G.crec.compression_method==TOKENIZED || G.crec.compression_method>DEFLATED)
1147 /*---------------------------------------------------------------------------
1148 Check central directory info for version/compatibility requirements.
1149 ---------------------------------------------------------------------------*/
1151 G
.pInfo
->encrypted
= G
.crec
.general_purpose_bit_flag
& 1; /* bit field */
1152 G
.pInfo
->ExtLocHdr
= (G
.crec
.general_purpose_bit_flag
& 8) == 8; /* bit */
1153 G
.pInfo
->textfile
= G
.crec
.internal_file_attributes
& 1; /* bit field */
1154 G
.pInfo
->crc
= G
.crec
.crc32
;
1155 G
.pInfo
->compr_size
= G
.crec
.csize
;
1156 G
.pInfo
->uncompr_size
= G
.crec
.ucsize
;
1160 G
.pInfo
->textmode
= FALSE
; /* bit field */
1163 G
.pInfo
->textmode
= G
.pInfo
->textfile
; /* auto-convert mode */
1165 default: /* case 2: */
1166 G
.pInfo
->textmode
= TRUE
;
1170 if (G
.crec
.version_needed_to_extract
[1] == VMS_
) {
1171 if (G
.crec
.version_needed_to_extract
[0] > VMS_UNZIP_VERSION
) {
1172 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
)))
1173 Info(slide
, 0x401, ((char *)slide
, LoadFarString(VersionMsg
),
1174 FnFilter1(G
.filename
), "VMS",
1175 G
.crec
.version_needed_to_extract
[0] / 10,
1176 G
.crec
.version_needed_to_extract
[0] % 10,
1177 VMS_UNZIP_VERSION
/ 10, VMS_UNZIP_VERSION
% 10));
1180 #ifndef VMS /* won't be able to use extra field, but still have data */
1181 else if (!uO
.tflag
&& !uO
.overwrite_all
) { /* if -o, extract anyway */
1182 Info(slide
, 0x481, ((char *)slide
, LoadFarString(VMSFormatQuery
),
1183 FnFilter1(G
.filename
)));
1184 fgets(G
.answerbuf
, 9, stdin
);
1185 if ((*G
.answerbuf
!= 'y') && (*G
.answerbuf
!= 'Y'))
1189 /* usual file type: don't need VMS to extract */
1190 } else if (G
.crec
.version_needed_to_extract
[0] > UNZIP_VERSION
) {
1191 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
)))
1192 Info(slide
, 0x401, ((char *)slide
, LoadFarString(VersionMsg
),
1193 FnFilter1(G
.filename
), "PK",
1194 G
.crec
.version_needed_to_extract
[0] / 10,
1195 G
.crec
.version_needed_to_extract
[0] % 10,
1196 UNZIP_VERSION
/ 10, UNZIP_VERSION
% 10));
1201 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))) {
1203 if (G
.crec
.compression_method
< NUM_METHODS
)
1204 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ComprMsgName
),
1205 FnFilter1(G
.filename
),
1206 LoadFarStringSmall(ComprNames
[G
.crec
.compression_method
])));
1209 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ComprMsgNum
),
1210 FnFilter1(G
.filename
),
1211 G
.crec
.compression_method
));
1216 if (G
.pInfo
->encrypted
) {
1217 if (!((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
)))
1218 Info(slide
, 0x401, ((char *)slide
, LoadFarString(SkipEncrypted
),
1219 FnFilter1(G
.filename
)));
1224 /* map whatever file attributes we have into the local format */
1225 mapattr(__G
); /* GRR: worry about return value later */
1227 G
.pInfo
->offset
= (long)G
.crec
.relative_offset_local_header
;
1230 } /* end function store_info() */
1236 /***************************************/
1237 /* Function extract_or_test_member() */
1238 /***************************************/
1240 static int extract_or_test_member(__G
) /* return PK-type error code */
1243 char *nul
="[empty] ", *txt
="[text] ", *bin
="[binary]";
1245 char *ebc
="[ebcdic]";
1248 int r
, error
=PK_COOL
;
1249 #if (defined(DLL) && !defined(NO_SLIDE_REDIR))
1252 # define wsize WSIZE
1256 /*---------------------------------------------------------------------------
1257 Initialize variables, buffers, etc.
1258 ---------------------------------------------------------------------------*/
1261 G
.bitbuf
= 0L; /* unreduce and unshrink only */
1264 G
.crc32val
= CRCVAL_INITIAL
;
1267 /* if file came from Unix and is a symbolic link and we are extracting
1268 * to disk, prepare to restore the link */
1269 if (S_ISLNK(G
.pInfo
->file_attr
) &&
1270 (G
.pInfo
->hostnum
== UNIX_
|| G
.pInfo
->hostnum
== ATARI_
||
1271 G
.pInfo
->hostnum
== BEOS_
) &&
1272 !uO
.tflag
&& !uO
.cflag
&& (G
.lrec
.ucsize
> 0))
1276 #endif /* SYMLINKS */
1280 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
), "test",
1281 FnFilter1(G
.filename
), "", ""));
1284 if (uO
.cflag
&& !G
.redirect_data
)
1289 #if (defined(OS2) && defined(__IBMC__) && (__IBMC__ >= 200))
1290 G
.outfile
= freopen("", "wb", stdout
); /* VAC++ ignores setmode */
1294 #ifdef DOS_FLX_H68_OS2_W32
1295 #if (defined(__HIGHC__) && !defined(FLEXOS))
1296 setmode(G
.outfile
, _BINARY
);
1297 #else /* !(defined(__HIGHC__) && !defined(FLEXOS)) */
1298 setmode(fileno(G
.outfile
), O_BINARY
);
1299 #endif /* ?(defined(__HIGHC__) && !defined(FLEXOS)) */
1300 # define NEWLINE "\r\n"
1301 #else /* !DOS_FLX_H68_OS2_W32 */
1302 # define NEWLINE "\n"
1303 #endif /* ?DOS_FLX_H68_OS2_W32 */
1305 if (open_outfile(__G
)) /* VMS: required even for stdout! */
1308 } else if (open_outfile(__G
))
1312 /*---------------------------------------------------------------------------
1314 ---------------------------------------------------------------------------*/
1316 defer_leftover_input(__G
); /* so NEXTBYTE bounds check will work */
1317 switch (G
.lrec
.compression_method
) {
1319 if (!uO
.tflag
&& QCOND2
) {
1321 if (G
.symlnk
) /* can also be deflated, but rarer... */
1322 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1323 "link", FnFilter1(G
.filename
), "", ""));
1325 #endif /* SYMLINKS */
1326 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1327 "extract", FnFilter1(G
.filename
),
1328 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1329 "" : (G
.lrec
.ucsize
== 0L? nul
: (G
.pInfo
->textfile
? txt
:
1330 bin
)), uO
.cflag
? NEWLINE
: ""));
1332 #if (defined(DLL) && !defined(NO_SLIDE_REDIR))
1333 if (G
.redirect_slide
) {
1334 wsize
= G
.redirect_size
; redirSlide
= G
.redirect_buffer
;
1336 wsize
= WSIZE
; redirSlide
= slide
;
1339 G
.outptr
= redirSlide
;
1341 while ((b
= NEXTBYTE
) != EOF
&& !G
.disk_full
) {
1342 *G
.outptr
++ = (uch
)b
;
1343 if (++G
.outcnt
== wsize
) {
1344 flush(__G__ redirSlide
, G
.outcnt
, 0);
1345 G
.outptr
= redirSlide
;
1349 if (G
.outcnt
) /* flush final (partial) buffer */
1350 flush(__G__ redirSlide
, G
.outcnt
, 0);
1356 if (!uO
.tflag
&& QCOND2
) {
1357 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1358 LoadFarStringSmall(Unshrink
), FnFilter1(G
.filename
),
1359 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1360 "" : (G
.pInfo
->textfile
? txt
: bin
), uO
.cflag
? NEWLINE
: ""));
1362 if ((r
= unshrink(__G
)) != PK_COOL
) {
1363 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1364 Info(slide
, 0x401, ((char *)slide
,
1365 LoadFarStringSmall(ErrUnzipFile
),
1366 LoadFarString(NotEnoughMem
),
1367 LoadFarStringSmall2(Unshrink
),
1368 FnFilter1(G
.filename
)));
1370 Info(slide
, 0x401, ((char *)slide
,
1371 LoadFarStringSmall(ErrUnzipNoFile
),
1372 LoadFarString(NotEnoughMem
),
1373 LoadFarStringSmall2(Unshrink
)));
1377 #endif /* !LZW_CLEAN */
1379 #ifndef COPYRIGHT_CLEAN
1384 if (!uO
.tflag
&& QCOND2
) {
1385 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1386 "unreduc", FnFilter1(G
.filename
),
1387 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1388 "" : (G
.pInfo
->textfile
? txt
: bin
), uO
.cflag
? NEWLINE
: ""));
1392 #endif /* !COPYRIGHT_CLEAN */
1395 if (!uO
.tflag
&& QCOND2
) {
1396 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1397 "explod", FnFilter1(G
.filename
),
1398 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1399 "" : (G
.pInfo
->textfile
? txt
: bin
), uO
.cflag
? NEWLINE
: ""));
1401 if (((r
= explode(__G
)) != 0) && (r
!= 5)) { /* treat 5 specially */
1402 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1403 Info(slide
, 0x401, ((char *)slide
,
1404 LoadFarStringSmall(ErrUnzipFile
), r
== 3?
1405 LoadFarString(NotEnoughMem
) :
1406 LoadFarString(InvalidComprData
),
1407 LoadFarStringSmall2(Explode
),
1408 FnFilter1(G
.filename
)));
1410 Info(slide
, 0x401, ((char *)slide
,
1411 LoadFarStringSmall(ErrUnzipNoFile
), r
== 3?
1412 LoadFarString(NotEnoughMem
) :
1413 LoadFarString(InvalidComprData
),
1414 LoadFarStringSmall2(Explode
)));
1415 error
= (r
== 3)? PK_MEM3
: PK_ERR
;
1418 int warning
= ((ulg
)G
.used_csize
<= G
.lrec
.csize
);
1420 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1421 Info(slide
, 0x401, ((char *)slide
, LoadFarString(LengthMsg
),
1422 "", warning
? "warning" : "error", G
.used_csize
,
1423 G
.lrec
.ucsize
, warning
? " " : "", G
.lrec
.csize
,
1424 " [", FnFilter1(G
.filename
), "]"));
1426 Info(slide
, 0x401, ((char *)slide
, LoadFarString(LengthMsg
),
1427 "\n", warning
? "warning" : "error", G
.used_csize
,
1428 G
.lrec
.ucsize
, warning
? " ":"", G
.lrec
.csize
,
1430 error
= warning
? PK_WARN
: PK_ERR
;
1436 if (!uO
.tflag
&& QCOND2
) {
1437 Info(slide
, 0, ((char *)slide
, LoadFarString(ExtractMsg
),
1438 "inflat", FnFilter1(G
.filename
),
1439 (uO
.aflag
!= 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1440 "" : (G
.pInfo
->textfile
? txt
: bin
), uO
.cflag
? NEWLINE
: ""));
1442 #ifndef USE_ZLIB /* zlib's function is called inflate(), too */
1443 # define UZinflate inflate
1445 if ((r
= UZinflate(__G
)) != 0) {
1446 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1447 Info(slide
, 0x401, ((char *)slide
,
1448 LoadFarStringSmall(ErrUnzipFile
), r
== 3?
1449 LoadFarString(NotEnoughMem
) :
1450 LoadFarString(InvalidComprData
),
1451 LoadFarStringSmall2(Inflate
),
1452 FnFilter1(G
.filename
)));
1454 Info(slide
, 0x401, ((char *)slide
,
1455 LoadFarStringSmall(ErrUnzipNoFile
), r
== 3?
1456 LoadFarString(NotEnoughMem
) :
1457 LoadFarString(InvalidComprData
),
1458 LoadFarStringSmall2(Inflate
)));
1459 error
= (r
== 3)? PK_MEM3
: PK_ERR
;
1463 default: /* should never get to this point */
1464 Info(slide
, 0x401, ((char *)slide
,
1465 LoadFarString(FileUnknownCompMethod
), FnFilter1(G
.filename
)));
1466 /* close and delete file before return? */
1470 } /* end switch (compression method) */
1472 /*---------------------------------------------------------------------------
1473 Close the file and set its date and time (not necessarily in that order),
1474 and make sure the CRC checked out OK. Logical-AND the CRC for 64-bit
1475 machines (redundant on 32-bit machines).
1476 ---------------------------------------------------------------------------*/
1478 #ifdef VMS /* VMS: required even for stdout! (final flush) */
1479 if (!uO
.tflag
) /* don't close NULL file */
1483 if (!uO
.tflag
&& (!uO
.cflag
|| G
.redirect_data
)) {
1484 if (G
.redirect_data
)
1490 if (!uO
.tflag
&& !uO
.cflag
) /* don't close NULL file or stdout */
1495 /* GRR: CONVERT close_outfile() TO NON-VOID: CHECK FOR ERRORS! */
1498 if (G
.disk_full
) { /* set by flush() */
1499 if (G
.disk_full
> 1) {
1500 #if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK))
1501 /* delete the incomplete file if we can */
1502 if (unlink(G
.filename
) != 0)
1503 Trace((stderr
, "extract.c: could not delete %s\n",
1504 FnFilter1(G
.filename
)));
1506 /* warn user about the incomplete file */
1507 Info(slide
, 0x421, ((char *)slide
, LoadFarString(FileTruncated
),
1508 FnFilter1(G
.filename
)));
1516 if (error
> PK_WARN
) {/* don't print redundant CRC error if error already */
1520 if (G
.crc32val
!= G
.lrec
.crc32
) {
1521 /* if quiet enough, we haven't output the filename yet: do it */
1522 if ((uO
.tflag
&& uO
.qflag
) || (!uO
.tflag
&& !QCOND2
))
1523 Info(slide
, 0x401, ((char *)slide
, "%-22s ",
1524 FnFilter1(G
.filename
)));
1525 Info(slide
, 0x401, ((char *)slide
, LoadFarString(BadCRC
), G
.crc32val
,
1528 if (G
.pInfo
->encrypted
)
1529 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybeBadPasswd
)));
1532 } else if (uO
.tflag
) {
1534 if (G
.extra_field
) {
1535 if ((r
= TestExtraField(__G__ G
.extra_field
,
1536 G
.lrec
.extra_field_length
)) > error
)
1541 Info(slide
, 0, ((char *)slide
, " OK\n"));
1543 if (QCOND2
&& !error
) /* GRR: is stdout reset to text mode yet? */
1544 Info(slide
, 0, ((char *)slide
, "\n"));
1550 } /* end function extract_or_test_member() */
1558 /*******************************/
1559 /* Function TestExtraField() */
1560 /*******************************/
1562 static int TestExtraField(__G__ ef
, ef_len
)
1569 unsigned eb_cmpr_offs
= 0;
1572 /* we know the regular compressed file data tested out OK, or else we
1573 * wouldn't be here ==> print filename if any extra-field errors found
1575 while (ef_len
>= EB_HEADSIZE
) {
1576 ebID
= makeword(ef
);
1577 ebLen
= (unsigned)makeword(ef
+EB_LEN
);
1579 if (ebLen
> (ef_len
- EB_HEADSIZE
)) {
1580 /* Discovered some extra field inconsistency! */
1582 Info(slide
, 1, ((char *)slide
, "%-22s ",
1583 FnFilter1(G
.filename
)));
1584 Info(slide
, 1, ((char *)slide
, LoadFarString(InconsistEFlength
),
1585 ebLen
, (ef_len
- EB_HEADSIZE
)));
1597 eb_cmpr_offs
= EB_OS2_HLEN
;
1600 if (ebLen
>= EB_MAC3_HLEN
&&
1601 (makeword(ef
+(EB_HEADSIZE
+EB_FLGS_OFFS
))
1602 & EB_M3_FL_UNCMPR
) &&
1603 (makelong(ef
+EB_HEADSIZE
) == ebLen
- EB_MAC3_HLEN
))
1606 eb_cmpr_offs
= EB_MAC3_HLEN
;
1609 if (ebLen
>= EB_BEOS_HLEN
&&
1610 (*(ef
+(EB_HEADSIZE
+EB_FLGS_OFFS
)) & EB_BE_FL_UNCMPR
) &&
1611 (makelong(ef
+EB_HEADSIZE
) == ebLen
- EB_BEOS_HLEN
))
1614 eb_cmpr_offs
= EB_BEOS_HLEN
;
1617 if ((r
= test_compr_eb(__G__ ef
, ebLen
, eb_cmpr_offs
, NULL
))
1620 Info(slide
, 1, ((char *)slide
, "%-22s ",
1621 FnFilter1(G
.filename
)));
1624 Info(slide
, 1, ((char *)slide
,
1625 LoadFarString(TruncEAs
),
1626 ebLen
-(eb_cmpr_offs
+EB_CMPRHEADLEN
), "\n"));
1629 Info(slide
, 1, ((char *)slide
,
1630 LoadFarString(InvalidComprDataEAs
)));
1634 Info(slide
, 1, ((char *)slide
,
1635 LoadFarString(NotEnoughMemEAs
)));
1638 if ((r
& 0xff) != PK_ERR
)
1639 Info(slide
, 1, ((char *)slide
,
1640 LoadFarString(UnknErrorEAs
)));
1642 ush m
= (ush
)(r
>> 8);
1643 if (m
== DEFLATED
) /* GRR KLUDGE! */
1644 Info(slide
, 1, ((char *)slide
,
1645 LoadFarString(BadCRC_EAs
)));
1647 Info(slide
, 1, ((char *)slide
,
1648 LoadFarString(UnknComprMethodEAs
), m
));
1657 Trace((stderr
, "ebID: %i / ebLen: %u\n", ebID
, ebLen
));
1658 r
= ebLen
< EB_NTSD_L_LEN
? IZ_EF_TRUNC
:
1659 ((ef
[EB_HEADSIZE
+EB_NTSD_VERSION
] > EB_NTSD_MAX_VER
) ?
1660 (PK_WARN
| 0x4000) :
1661 test_compr_eb(__G__ ef
, ebLen
, EB_NTSD_L_LEN
, TEST_NTSD
));
1664 Info(slide
, 1, ((char *)slide
, "%-22s ",
1665 FnFilter1(G
.filename
)));
1668 Info(slide
, 1, ((char *)slide
,
1669 LoadFarString(TruncNTSD
),
1670 ebLen
-(EB_NTSD_L_LEN
+EB_CMPRHEADLEN
), "\n"));
1672 #if (defined(WIN32) && defined(NTSD_EAS))
1674 Info(slide
, 1, ((char *)slide
,
1675 LoadFarString(InvalidSecurityEAs
)));
1679 Info(slide
, 1, ((char *)slide
,
1680 LoadFarString(InvalidComprDataEAs
)));
1684 Info(slide
, 1, ((char *)slide
,
1685 LoadFarString(NotEnoughMemEAs
)));
1687 case (PK_WARN
| 0x4000):
1688 Info(slide
, 1, ((char *)slide
,
1689 LoadFarString(UnsuppNTSDVersEAs
),
1690 (int)ef
[EB_HEADSIZE
+EB_NTSD_VERSION
]));
1694 if ((r
& 0xff) != PK_ERR
)
1695 Info(slide
, 1, ((char *)slide
,
1696 LoadFarString(UnknErrorEAs
)));
1698 ush m
= (ush
)(r
>> 8);
1699 if (m
== DEFLATED
) /* GRR KLUDGE! */
1700 Info(slide
, 1, ((char *)slide
,
1701 LoadFarString(BadCRC_EAs
)));
1703 Info(slide
, 1, ((char *)slide
,
1704 LoadFarString(UnknComprMethodEAs
), m
));
1724 ef_len
-= (ebLen
+ EB_HEADSIZE
);
1725 ef
+= (ebLen
+ EB_HEADSIZE
);
1729 Info(slide
, 0, ((char *)slide
, " OK\n"));
1733 } /* end function TestExtraField() */
1739 /******************************/
1740 /* Function test_compr_eb() */
1741 /******************************/
1744 static int test_compr_eb(
1748 unsigned compr_offset
,
1749 int (*test_uc_ebdata
)(__GPRO__ uch
*eb
, unsigned eb_size
,
1750 uch
*eb_ucptr
, ulg eb_ucsize
))
1752 static int test_compr_eb(__G__ eb
, eb_size
, compr_offset
, test_uc_ebdata
)
1756 unsigned compr_offset
;
1757 int (*test_uc_ebdata
)();
1764 if (compr_offset
< 4) /* field is not compressed: */
1765 return PK_OK
; /* do nothing and signal OK */
1767 if ((eb_size
< (EB_UCSIZE_P
+ 4)) ||
1768 ((eb_ucsize
= makelong(eb
+(EB_HEADSIZE
+EB_UCSIZE_P
))) > 0L &&
1769 eb_size
<= (compr_offset
+ EB_CMPRHEADLEN
)))
1770 return IZ_EF_TRUNC
; /* no compressed data! */
1772 if ((eb_ucptr
= (uch
*)malloc((extent
)eb_ucsize
)) == (uch
*)NULL
)
1775 r
= memextract(__G__ eb_ucptr
, eb_ucsize
,
1776 eb
+ (EB_HEADSIZE
+ compr_offset
),
1777 (ulg
)(eb_size
- compr_offset
));
1779 if (r
== PK_OK
&& test_uc_ebdata
!= NULL
)
1780 r
= (*test_uc_ebdata
)(__G__ eb
, eb_size
, eb_ucptr
, eb_ucsize
);
1785 } /* end function test_compr_eb() */
1793 /***************************/
1794 /* Function memextract() */
1795 /***************************/
1797 int memextract(__G__ tgt
, tgtsize
, src
, srcsize
) /* extract compressed */
1798 __GDEF
/* extra field block; */
1799 uch
*tgt
, *src
; /* return PK-type error */
1800 ulg tgtsize
, srcsize
; /* level */
1802 long old_csize
=G
.csize
;
1803 uch
*old_inptr
=G
.inptr
;
1804 int old_incnt
=G
.incnt
;
1807 ulg extra_field_crc
;
1810 method
= makeword(src
);
1811 extra_field_crc
= makelong(src
+2);
1813 /* compressed extra field exists completely in memory at this location: */
1814 G
.inptr
= src
+ 2 + 4; /* method and extra_field_crc */
1815 G
.incnt
= (int)(G
.csize
= (long)(srcsize
- (2 + 4)));
1818 G
.outsize
= tgtsize
;
1822 memcpy((char *)tgt
, (char *)G
.inptr
, (extent
)G
.incnt
);
1823 G
.outcnt
= G
.csize
; /* for CRC calculation */
1827 if ((r
= UZinflate(__G
)) != 0) {
1829 Info(slide
, 0x401, ((char *)slide
,
1830 LoadFarStringSmall(ErrUnzipNoFile
), r
== 3?
1831 LoadFarString(NotEnoughMem
) :
1832 LoadFarString(InvalidComprData
),
1833 LoadFarStringSmall2(Inflate
)));
1834 error
= (r
== 3)? PK_MEM3
: PK_ERR
;
1836 if (G
.outcnt
== 0L) /* inflate's final FLUSH sets outcnt */
1841 error
= PK_ERR
| ((int)method
<< 8);
1843 Info(slide
, 0x401, ((char *)slide
,
1844 LoadFarString(UnsupportedExtraField
), method
));
1845 error
= PK_ERR
; /* GRR: should be passed on up via SetEAs() */
1850 G
.inptr
= old_inptr
;
1851 G
.incnt
= old_incnt
;
1852 G
.csize
= old_csize
;
1856 register ulg crcval
= crc32(CRCVAL_INITIAL
, tgt
, (extent
)G
.outcnt
);
1858 if (crcval
!= extra_field_crc
) {
1860 error
= PK_ERR
| (DEFLATED
<< 8); /* kludge for now */
1862 Info(slide
, 0x401, ((char *)slide
,
1863 LoadFarString(BadExtraFieldCRC
), G
.zipfn
, crcval
,
1871 } /* end function memextract() */
1877 /*************************/
1878 /* Function memflush() */
1879 /*************************/
1881 int memflush(__G__ rawbuf
, size
)
1886 if (size
> G
.outsize
)
1887 return 50; /* more data than output buffer can hold */
1889 memcpy((char *)G
.outbufptr
, (char *)rawbuf
, (extent
)size
);
1890 G
.outbufptr
+= (unsigned int)size
;
1896 } /* end function memflush() */
1902 /*************************/
1903 /* Function fnfilter() */ /* here instead of in list.c for SFX */
1904 /*************************/
1906 char *fnfilter(raw
, space
) /* convert name to safely printable form */
1910 #ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */
1911 uch
*r
=(uch
*)raw
, *s
=space
;
1916 if (*r
== '/' || *r
== '.') {
1924 *s
++ = '^', *s
++ = (uch
)(64 + *r
++);
1931 INTERN_TO_ISO((char *)space
, (char *)space
); /* translate to ANSI */
1934 /* Win9x console always uses OEM character coding, and
1935 WinNT console is set to OEM charset by default, too */
1936 INTERN_TO_OEM((char *)space
, (char *)space
);
1938 #endif /* ?WINDLL */
1940 return (char *)space
;
1942 #else /* NATIVE: EBCDIC or whatever */
1946 } /* end function fnfilter() */
1952 #ifdef SET_DIR_ATTRIB
1953 /* must sort saved directories so can set perms from bottom up */
1955 /************************/
1956 /* Function dircomp() */
1957 /************************/
1959 static int dircomp(a
, b
) /* used by qsort(); swiped from Zip */
1960 ZCONST zvoid
*a
, *b
;
1962 /* order is significant: this sorts in reverse order (deepest first) */
1963 return strcmp((*(dirtime
**)b
)->fn
, (*(dirtime
**)a
)->fn
);
1964 /* return namecmp((*(dirtime **)b)->fn, (*(dirtime **)a)->fn); */
1969 #if 0 /* not used in Unix, but maybe for future OSes? */
1971 /************************/
1972 /* Function namecmp() */
1973 /************************/
1975 static int namecmp(s1
, s2
) /* [not] used by dircomp(); swiped from Zip */
1976 ZCONST
char *s1
, *s2
;
1981 d
= (int)(uch
)case_map(*s1
)
1982 - (int)(uch
)case_map(*s2
);
1984 if (d
|| *s1
== 0 || *s2
== 0)
1993 #endif /* SET_DIR_ATTRIB */