1 /* 2 Copyright (c) 1990-2001 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2000-Apr-09 or later 5 (the contents of which are also included in unzip.h) for terms of use. 6 If, for some reason, all these files are missing, the Info-ZIP license 7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html 8 */ 9 /*--------------------------------------------------------------------------- 10 11 process.c 12 13 This file contains the top-level routines for processing multiple zipfiles. 14 15 Contains: process_zipfiles() 16 free_G_buffers() 17 do_seekable() 18 find_ecrec() 19 uz_end_central() 20 process_cdir_file_hdr() 21 get_cdir_ent() 22 process_local_file_hdr() 23 ef_scan_for_izux() 24 getRISCOSexfield() 25 26 ---------------------------------------------------------------------------*/ 27 28 29 #define UNZIP_INTERNAL 30 #include "unzip.h" 31 #ifdef WINDLL 32 # ifdef POCKET_UNZIP 33 # include "wince/intrface.h" 34 # else 35 # include "windll/windll.h" 36 # endif 37 #endif 38 39 static int do_seekable OF((__GPRO__ int lastchance)); 40 static int find_ecrec OF((__GPRO__ long searchlen)); 41 42 static ZCONST char Far CannotAllocateBuffers[] = 43 "error: cannot allocate unzip buffers\n"; 44 45 #ifdef SFX 46 static ZCONST char Far CannotFindMyself[] = 47 "unzipsfx: cannot find myself! [%s]\n"; 48 # ifdef CHEAP_SFX_AUTORUN 49 static ZCONST char Far AutorunPrompt[] = 50 "\nAuto-run command: %s\nExecute this command? [y/n] "; 51 static ZCONST char Far NotAutoRunning[] = 52 "Not executing auto-run command."; 53 # endif 54 55 #else /* !SFX */ 56 /* process_zipfiles() strings */ 57 # if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME)) 58 static ZCONST char Far WarnInvalidTZ[] = 59 "Warning: TZ environment variable not found, cannot use UTC times!!\n"; 60 # endif 61 static ZCONST char Far FilesProcessOK[] = 62 "%d archive%s successfully processed.\n"; 63 static ZCONST char Far ArchiveWarning[] = 64 "%d archive%s had warnings but no fatal errors.\n"; 65 static ZCONST char Far ArchiveFatalError[] = 66 "%d archive%s had fatal errors.\n"; 67 static ZCONST char Far FileHadNoZipfileDir[] = 68 "%d file%s had no zipfile directory.\n"; 69 static ZCONST char Far ZipfileWasDir[] = "1 \"zipfile\" was a directory.\n"; 70 static ZCONST char Far ManyZipfilesWereDir[] = 71 "%d \"zipfiles\" were directories.\n"; 72 static ZCONST char Far NoZipfileFound[] = "No zipfiles found.\n"; 73 74 /* do_seekable() strings */ 75 # ifdef UNIX 76 static ZCONST char Far CannotFindZipfileDirMsg[] = 77 "%s: cannot find zipfile directory in one of %s or\n\ 78 %s%s.zip, and cannot find %s, period.\n"; 79 static ZCONST char Far CannotFindEitherZipfile[] = 80 "%s: cannot find %s, %s.zip or %s.\n"; 81 # else /* !UNIX */ 82 # ifndef AMIGA 83 static ZCONST char Far CannotFindWildcardMatch[] = 84 "%s: cannot find any matches for wildcard specification \"%s\".\n"; 85 # endif /* !AMIGA */ 86 static ZCONST char Far CannotFindZipfileDirMsg[] = 87 "%s: cannot find zipfile directory in %s,\n\ 88 %sand cannot find %s, period.\n"; 89 static ZCONST char Far CannotFindEitherZipfile[] = 90 "%s: cannot find either %s or %s.\n"; 91 # endif /* ?UNIX */ 92 extern ZCONST char Far Zipnfo[]; /* in unzip.c */ 93 #ifndef WINDLL 94 static ZCONST char Far Unzip[] = "unzip"; 95 #else 96 static ZCONST char Far Unzip[] = "UnZip DLL"; 97 #endif 98 static ZCONST char Far MaybeExe[] = 99 "note: %s may be a plain executable, not an archive\n"; 100 static ZCONST char Far CentDirNotInZipMsg[] = "\n\ 101 [%s]:\n\ 102 Zipfile is disk %u of a multi-disk archive, and this is not the disk on\n\ 103 which the central zipfile directory begins (disk %u).\n"; 104 static ZCONST char Far EndCentDirBogus[] = 105 "\nwarning [%s]: end-of-central-directory record claims this\n\ 106 is disk %u but that the central directory starts on disk %u; this is a\n\ 107 contradiction. Attempting to process anyway.\n"; 108 # ifdef NO_MULTIPART 109 static ZCONST char Far NoMultiDiskArcSupport[] = 110 "\nerror [%s]: zipfile is part of multi-disk archive\n\ 111 (sorry, not yet supported).\n"; 112 static ZCONST char Far MaybePakBug[] = "warning [%s]:\ 113 zipfile claims to be 2nd disk of a 2-part archive;\n\ 114 attempting to process anyway. If no further errors occur, this archive\n\ 115 was probably created by PAK v2.51 or earlier. This bug was reported to\n\ 116 NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\ 117 of mid-1992 it still hadn't been. (If further errors do occur, archive\n\ 118 was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\ 119 multi-part archives.)\n"; 120 # else 121 static ZCONST char Far MaybePakBug[] = "warning [%s]:\ 122 zipfile claims to be last disk of a multi-part archive;\n\ 123 attempting to process anyway, assuming all parts have been concatenated\n\ 124 together in order. Expect \"errors\" and warnings...true multi-part support\ 125 \n doesn't exist yet (coming soon).\n"; 126 # endif 127 static ZCONST char Far ExtraBytesAtStart[] = 128 "warning [%s]: %ld extra byte%s at beginning or within zipfile\n\ 129 (attempting to process anyway)\n"; 130 #endif /* ?SFX */ 131 132 static ZCONST char Far MissingBytes[] = 133 "error [%s]: missing %ld bytes in zipfile\n\ 134 (attempting to process anyway)\n"; 135 static ZCONST char Far NullCentDirOffset[] = 136 "error [%s]: NULL central directory offset\n\ 137 (attempting to process anyway)\n"; 138 static ZCONST char Far ZipfileEmpty[] = "warning [%s]: zipfile is empty\n"; 139 static ZCONST char Far CentDirStartNotFound[] = 140 "error [%s]: start of central directory not found;\n\ 141 zipfile corrupt.\n%s"; 142 #ifndef SFX 143 static ZCONST char Far CentDirTooLong[] = 144 "error [%s]: reported length of central directory is\n\ 145 %ld bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1\n\ 146 zipfile?). Compensating...\n"; 147 static ZCONST char Far CentDirEndSigNotFound[] = "\ 148 End-of-central-directory signature not found. Either this file is not\n\ 149 a zipfile, or it constitutes one disk of a multi-part archive. In the\n\ 150 latter case the central directory and zipfile comment will be found on\n\ 151 the last disk(s) of this archive.\n"; 152 #else /* SFX */ 153 static ZCONST char Far CentDirEndSigNotFound[] = 154 " End-of-central-directory signature not found.\n"; 155 #endif /* ?SFX */ 156 static ZCONST char Far ZipfileCommTrunc1[] = 157 "\ncaution: zipfile comment truncated\n"; 158 159 160 161 162 /*******************************/ 163 /* Function process_zipfiles() */ 164 /*******************************/ 165 166 int process_zipfiles(__G) /* return PK-type error code */ 167 __GDEF 168 { 169 #ifndef SFX 170 char *lastzipfn = (char *)NULL; 171 int NumWinFiles, NumLoseFiles, NumWarnFiles; 172 int NumMissDirs, NumMissFiles; 173 #endif 174 int error=0, error_in_archive=0; 175 176 177 /*--------------------------------------------------------------------------- 178 Start by allocating buffers and (re)constructing the various PK signature 179 strings. 180 ---------------------------------------------------------------------------*/ 181 182 G.inbuf = (uch *)malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */ 183 G.outbuf = (uch *)malloc(OUTBUFSIZ + 1); /* 1 extra for string term. */ 184 185 if ((G.inbuf == (uch *)NULL) || (G.outbuf == (uch *)NULL)) { 186 Info(slide, 0x401, ((char *)slide, 187 LoadFarString(CannotAllocateBuffers))); 188 return(PK_MEM); 189 } 190 G.hold = G.inbuf + INBUFSIZ; /* to check for boundary-spanning sigs */ 191 #ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */ 192 #ifdef SMALL_MEM 193 G.outbuf2 = G.outbuf+RAWBUFSIZ; /* never changes */ 194 #endif 195 #endif /* !VMS */ 196 197 #if 0 /* CRC_32_TAB has been NULLified by CONSTRUCTGLOBALS !!!! */ 198 /* allocate the CRC table only later when we know we have a zipfile */ 199 CRC_32_TAB = NULL; 200 #endif /* 0 */ 201 202 /* finish up initialization of magic signature strings */ 203 local_hdr_sig[0] /* = extd_local_sig[0] */ = /* ASCII 'P', */ 204 central_hdr_sig[0] = end_central_sig[0] = 0x50; /* not EBCDIC */ 205 206 local_hdr_sig[1] /* = extd_local_sig[1] */ = /* ASCII 'K', */ 207 central_hdr_sig[1] = end_central_sig[1] = 0x4B; /* not EBCDIC */ 208 209 /*--------------------------------------------------------------------------- 210 Make sure timezone info is set correctly; localtime() returns GMT on 211 some OSes (e.g., Solaris 2.x) if this isn't done first. The ifdefs were 212 initially copied from dos_to_unix_time() in fileio.c. probably, they are 213 still too strict; any listed OS that supplies tzset(), regardless of 214 whether the function does anything, should be removed from the ifdefs. 215 ---------------------------------------------------------------------------*/ 216 217 #if (defined(WIN32) && defined(USE_EF_UT_TIME)) 218 /* For the Win32 environment, we may have to "prepare" the environment 219 prior to the tzset() call, to work around tzset() implementation bugs. 220 */ 221 iz_w32_prepareTZenv(); 222 #endif 223 224 #if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME)) 225 # ifndef VALID_TIMEZONE 226 # define VALID_TIMEZONE(tmp) \ 227 (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0')) 228 # endif 229 { 230 char *p; 231 G.tz_is_valid = VALID_TIMEZONE(p); 232 # ifndef SFX 233 if (!G.tz_is_valid) { 234 Info(slide, 0x401, ((char *)slide, LoadFarString(WarnInvalidTZ))); 235 error_in_archive = error = PK_WARN; 236 } 237 # endif /* !SFX */ 238 } 239 #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */ 240 241 /* For systems that do not have tzset() but supply this function using another 242 name (_tzset() or something similar), an appropiate "#define tzset ..." 243 should be added to the system specifc configuration section. */ 244 #if (!defined(T20_VMS) && !defined(MACOS) && !defined(RISCOS) && !defined(QDOS)) 245 #if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM)) 246 tzset(); 247 #endif 248 #endif 249 250 /*--------------------------------------------------------------------------- 251 Initialize the internal flag holding the mode of processing "overwrite 252 existing file" cases. We do not use the calling interface flags directly 253 because the overwrite mode may be changed by user interaction while 254 processing archive files. Such a change should not affect the option 255 settings as passed through the DLL calling interface. 256 In case of conflicting options, the 'safer' flag uO.overwrite_none takes 257 precedence. 258 ---------------------------------------------------------------------------*/ 259 G.overwrite_mode = (uO.overwrite_none ? OVERWRT_NEVER : 260 (uO.overwrite_all ? OVERWRT_ALWAYS : OVERWRT_QUERY)); 261 262 /*--------------------------------------------------------------------------- 263 Match (possible) wildcard zipfile specification with existing files and 264 attempt to process each. If no hits, try again after appending ".zip" 265 suffix. If still no luck, give up. 266 ---------------------------------------------------------------------------*/ 267 268 #ifdef SFX 269 if ((error = do_seekable(__G__ 0)) == PK_NOZIP) { 270 #ifdef EXE_EXTENSION 271 int len=strlen(G.argv0); 272 273 /* append .exe if appropriate; also .sfx? */ 274 if ( (G.zipfn = (char *)malloc(len+sizeof(EXE_EXTENSION))) != 275 (char *)NULL ) { 276 strcpy(G.zipfn, G.argv0); 277 strcpy(G.zipfn+len, EXE_EXTENSION); 278 error = do_seekable(__G__ 0); 279 free(G.zipfn); 280 G.zipfn = G.argv0; /* for "cannot find myself" message only */ 281 } 282 #endif /* EXE_EXTENSION */ 283 #ifdef WIN32 284 G.zipfn = G.argv0; /* for "cannot find myself" message only */ 285 #endif 286 } 287 if (error) { 288 if (error == IZ_DIR) 289 error_in_archive = PK_NOZIP; 290 else 291 error_in_archive = error; 292 if (error == PK_NOZIP) 293 Info(slide, 1, ((char *)slide, LoadFarString(CannotFindMyself), 294 G.zipfn)); 295 } 296 #ifdef CHEAP_SFX_AUTORUN 297 if (G.autorun_command[0] && !uO.qflag) { /* NO autorun without prompt! */ 298 Info(slide, 0x81, ((char *)slide, LoadFarString(AutorunPrompt), 299 FnFilter1(G.autorun_command))); 300 if (fgets(G.answerbuf, 9, stdin) != (char *)NULL 301 && toupper(*G.answerbuf) == 'Y') 302 system(G.autorun_command); 303 else 304 Info(slide, 1, ((char *)slide, LoadFarString(NotAutoRunning))); 305 } 306 #endif /* CHEAP_SFX_AUTORUN */ 307 308 #else /* !SFX */ 309 NumWinFiles = NumLoseFiles = NumWarnFiles = 0; 310 NumMissDirs = NumMissFiles = 0; 311 312 while ((G.zipfn = do_wild(__G__ G.wildzipfn)) != (char *)NULL) { 313 Trace((stderr, "do_wild( %s ) returns %s\n", G.wildzipfn, G.zipfn)); 314 315 lastzipfn = G.zipfn; 316 317 /* print a blank line between the output of different zipfiles */ 318 if (!uO.qflag && error != PK_NOZIP && error != IZ_DIR 319 #ifdef TIMESTAMP 320 && (!uO.T_flag || uO.zipinfo_mode) 321 #endif 322 && (NumWinFiles+NumLoseFiles+NumWarnFiles+NumMissFiles) > 0) 323 (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); 324 325 if ((error = do_seekable(__G__ 0)) == PK_WARN) 326 ++NumWarnFiles; 327 else if (error == IZ_DIR) 328 ++NumMissDirs; 329 else if (error == PK_NOZIP) 330 ++NumMissFiles; 331 else if (error) 332 ++NumLoseFiles; 333 else 334 ++NumWinFiles; 335 336 Trace((stderr, "do_seekable(0) returns %d\n", error)); 337 if (error != IZ_DIR && error > error_in_archive) 338 error_in_archive = error; 339 #ifdef WINDLL 340 if (error == IZ_CTRLC) { 341 free_G_buffers(__G); 342 return error; 343 } 344 #endif 345 346 } /* end while-loop (wildcard zipfiles) */ 347 348 if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0 && 349 (NumMissDirs + NumMissFiles) == 1 && lastzipfn != (char *)NULL) 350 { 351 NumMissDirs = NumMissFiles = 0; 352 if (error_in_archive == PK_NOZIP) 353 error_in_archive = PK_COOL; 354 355 #if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */ 356 if (iswild(G.wildzipfn)) 357 Info(slide, 0x401, ((char *)slide, 358 LoadFarString(CannotFindWildcardMatch), uO.zipinfo_mode? 359 LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip), 360 G.wildzipfn)); 361 else 362 #endif 363 { 364 char *p = lastzipfn + strlen(lastzipfn); 365 366 G.zipfn = lastzipfn; 367 strcpy(p, ZSUFX); 368 369 #if defined(UNIX) || defined(QDOS) 370 /* only Unix has case-sensitive filesystems */ 371 /* Well FlexOS (sometimes) also has them, but support is per media */ 372 /* and a pig to code for, so treat as case insensitive for now */ 373 /* we do this under QDOS to check for .zip as well as _zip */ 374 if ((error = do_seekable(__G__ 0)) == PK_NOZIP || error == IZ_DIR) { 375 if (error == IZ_DIR) 376 ++NumMissDirs; 377 strcpy(p, ALT_ZSUFX); 378 error = do_seekable(__G__ 1); 379 } 380 #else 381 error = do_seekable(__G__ 1); 382 #endif 383 Trace((stderr, "do_seekable(1) returns %d\n", error)); 384 switch (error) { 385 case PK_WARN: 386 ++NumWarnFiles; 387 break; 388 case IZ_DIR: 389 ++NumMissDirs; 390 error = PK_NOZIP; 391 break; 392 case PK_NOZIP: 393 /* increment again => bug: 394 "1 file had no zipfile directory." */ 395 /* ++NumMissFiles */ ; 396 break; 397 default: 398 if (error) 399 ++NumLoseFiles; 400 else 401 ++NumWinFiles; 402 break; 403 } 404 405 if (error > error_in_archive) 406 error_in_archive = error; 407 #ifdef WINDLL 408 if (error == IZ_CTRLC) { 409 free_G_buffers(__G); 410 return error; 411 } 412 #endif 413 } 414 } 415 #endif /* ?SFX */ 416 417 /*--------------------------------------------------------------------------- 418 Print summary of all zipfiles, assuming zipfile spec was a wildcard (no 419 need for a summary if just one zipfile). 420 ---------------------------------------------------------------------------*/ 421 422 #ifndef SFX 423 if (iswild(G.wildzipfn) && uO.qflag < 3 424 #ifdef TIMESTAMP 425 && !(uO.T_flag && uO.qflag && !uO.zipinfo_mode) 426 #endif 427 ) 428 { 429 if ((NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1) 430 #ifdef TIMESTAMP 431 && !(uO.T_flag && !uO.zipinfo_mode) 432 #endif 433 && !(uO.tflag && uO.qflag > 1)) 434 (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0x401); 435 if ((NumWinFiles > 1) || (NumWinFiles == 1 && 436 NumMissDirs + NumMissFiles + NumLoseFiles + NumWarnFiles > 0)) 437 Info(slide, 0x401, ((char *)slide, LoadFarString(FilesProcessOK), 438 NumWinFiles, (NumWinFiles == 1)? " was" : "s were")); 439 if (NumWarnFiles > 0) 440 Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveWarning), 441 NumWarnFiles, (NumWarnFiles == 1)? "" : "s")); 442 if (NumLoseFiles > 0) 443 Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveFatalError), 444 NumLoseFiles, (NumLoseFiles == 1)? "" : "s")); 445 if (NumMissFiles > 0) 446 Info(slide, 0x401, ((char *)slide, 447 LoadFarString(FileHadNoZipfileDir), NumMissFiles, 448 (NumMissFiles == 1)? "" : "s")); 449 if (NumMissDirs == 1) 450 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileWasDir))); 451 else if (NumMissDirs > 0) 452 Info(slide, 0x401, ((char *)slide, 453 LoadFarString(ManyZipfilesWereDir), NumMissDirs)); 454 if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0) 455 Info(slide, 0x401, ((char *)slide, LoadFarString(NoZipfileFound))); 456 } 457 #endif /* !SFX */ 458 459 /* free allocated memory */ 460 free_G_buffers(__G); 461 462 return error_in_archive; 463 464 } /* end function process_zipfiles() */ 465 466 467 468 469 470 /*****************************/ 471 /* Function free_G_buffers() */ 472 /*****************************/ 473 474 void free_G_buffers(__G) /* releases all memory allocated in global vars */ 475 __GDEF 476 { 477 inflate_free(__G); 478 checkdir(__G__ (char *)NULL, END); 479 480 #ifdef DYNALLOC_CRCTAB 481 if (CRC_32_TAB) { 482 free_crc_table(); 483 CRC_32_TAB = NULL; 484 } 485 #endif 486 487 if (G.key != (char *)NULL) { 488 free(G.key); 489 G.key = (char *)NULL; 490 } 491 492 if (G.extra_field != (uch *)NULL) { 493 free(G.extra_field); 494 G.extra_field = (uch *)NULL; 495 } 496 497 #if (!defined(VMS) && !defined(SMALL_MEM)) 498 /* VMS uses its own buffer scheme for textmode flush() */ 499 if (G.outbuf2) { 500 free(G.outbuf2); /* malloc'd ONLY if unshrink and -a */ 501 G.outbuf2 = (uch *)NULL; 502 } 503 #endif 504 505 if (G.outbuf) 506 free(G.outbuf); 507 if (G.inbuf) 508 free(G.inbuf); 509 G.inbuf = G.outbuf = (uch *)NULL; 510 511 #ifdef MALLOC_WORK 512 if (G.area.Slide) { 513 free(G.area.Slide); 514 G.area.Slide = (uch *)NULL; 515 } 516 #endif 517 518 } /* end function free_G_buffers() */ 519 520 521 522 523 524 /**************************/ 525 /* Function do_seekable() */ 526 /**************************/ 527 528 static int do_seekable(__G__ lastchance) /* return PK-type error code */ 529 __GDEF 530 int lastchance; 531 { 532 #ifndef SFX 533 /* static int no_ecrec = FALSE; SKM: moved to globals.h */ 534 int maybe_exe=FALSE; 535 int too_weird_to_continue=FALSE; 536 #ifdef TIMESTAMP 537 time_t uxstamp; 538 ulg nmember = 0L; 539 #endif 540 #endif 541 int error=0, error_in_archive; 542 543 544 /*--------------------------------------------------------------------------- 545 Open the zipfile for reading in BINARY mode to prevent CR/LF translation, 546 which would corrupt the bit streams. 547 ---------------------------------------------------------------------------*/ 548 549 if (SSTAT(G.zipfn, &G.statbuf) || 550 #ifdef THEOS 551 (error = S_ISLIB(G.statbuf.st_mode)) != 0 || 552 #endif 553 (error = S_ISDIR(G.statbuf.st_mode)) != 0) 554 { 555 #ifndef SFX 556 if (lastchance && (uO.qflag < 3)) { 557 #if defined(UNIX) || defined(QDOS) 558 if (G.no_ecrec) 559 Info(slide, 1, ((char *)slide, 560 LoadFarString(CannotFindZipfileDirMsg), uO.zipinfo_mode? 561 LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip), 562 G.wildzipfn, uO.zipinfo_mode? " " : "", G.wildzipfn, 563 G.zipfn)); 564 else 565 Info(slide, 1, ((char *)slide, 566 LoadFarString(CannotFindEitherZipfile), uO.zipinfo_mode? 567 LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip), 568 G.wildzipfn, G.wildzipfn, G.zipfn)); 569 #else /* !(UNIX || QDOS) */ 570 if (G.no_ecrec) 571 Info(slide, 0x401, ((char *)slide, 572 LoadFarString(CannotFindZipfileDirMsg), uO.zipinfo_mode? 573 LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip), 574 G.wildzipfn, uO.zipinfo_mode? " " : "", G.zipfn)); 575 else 576 Info(slide, 0x401, ((char *)slide, 577 LoadFarString(CannotFindEitherZipfile), uO.zipinfo_mode? 578 LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip), 579 G.wildzipfn, G.zipfn)); 580 #endif /* ?(UNIX || QDOS) */ 581 } 582 #endif /* !SFX */ 583 return error? IZ_DIR : PK_NOZIP; 584 } 585 G.ziplen = G.statbuf.st_size; 586 587 #ifndef SFX 588 #if defined(UNIX) || defined(DOS_OS2_W32) || defined(THEOS) 589 if (G.statbuf.st_mode & S_IEXEC) /* no extension on Unix exes: might */ 590 maybe_exe = TRUE; /* find unzip, not unzip.zip; etc. */ 591 #endif 592 #endif /* !SFX */ 593 594 #ifdef VMS 595 if (check_format(__G)) /* check for variable-length format */ 596 return PK_ERR; 597 #endif 598 599 if (open_input_file(__G)) /* this should never happen, given */ 600 return PK_NOZIP; /* the stat() test above, but... */ 601 602 /*--------------------------------------------------------------------------- 603 Find and process the end-of-central-directory header. UnZip need only 604 check last 65557 bytes of zipfile: comment may be up to 65535, end-of- 605 central-directory record is 18 bytes, and signature itself is 4 bytes; 606 add some to allow for appended garbage. Since ZipInfo is often used as 607 a debugging tool, search the whole zipfile if zipinfo_mode is true. 608 ---------------------------------------------------------------------------*/ 609 610 /* initialize the CRC table pointer (once) */ 611 if (CRC_32_TAB == NULL) { 612 if ((CRC_32_TAB = get_crc_table()) == NULL) { 613 CLOSE_INFILE(); 614 return PK_MEM; 615 } 616 } 617 618 #if (!defined(SFX) || defined(SFX_EXDIR)) 619 /* check out if specified extraction root directory exists */ 620 if (uO.exdir != (char *)NULL && G.extract_flag) { 621 G.create_dirs = !uO.fflag; 622 if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) { 623 /* out of memory, or file in way */ 624 CLOSE_INFILE(); 625 return (error == MPN_NOMEM ? PK_MEM : PK_ERR); 626 } 627 } 628 #endif /* !SFX || SFX_EXDIR */ 629 630 G.cur_zipfile_bufstart = 0; 631 G.inptr = G.inbuf; 632 633 #if (!defined(WINDLL) && !defined(SFX)) 634 #ifdef TIMESTAMP 635 if (!uO.zipinfo_mode && !uO.qflag && !uO.T_flag) 636 #else 637 if (!uO.zipinfo_mode && !uO.qflag) 638 #endif 639 #ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */ 640 Info(slide, 0, ((char *)slide, "Archive: %s\n", FnFilter1(G.zipfn))); 641 #else 642 Info(slide, 0, ((char *)slide, "Archive: %s\n", G.zipfn)); 643 #endif 644 #endif /* !WINDLL && !SFX */ 645 646 if (( 647 #ifndef NO_ZIPINFO 648 uO.zipinfo_mode && 649 ((error_in_archive = find_ecrec(__G__ G.ziplen)) != 0 || 650 (error_in_archive = zi_end_central(__G)) > PK_WARN)) 651 || (!uO.zipinfo_mode && 652 #endif 653 ((error_in_archive = find_ecrec(__G__ MIN(G.ziplen,66000L))) != 0 || 654 (error_in_archive = uz_end_central(__G)) > PK_WARN))) 655 { 656 CLOSE_INFILE(); 657 658 #ifdef SFX 659 ++lastchance; /* avoid picky compiler warnings */ 660 return error_in_archive; 661 #else 662 if (maybe_exe) 663 Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeExe), 664 G.zipfn)); 665 if (lastchance) 666 return error_in_archive; 667 else { 668 G.no_ecrec = TRUE; /* assume we found wrong file: e.g., */ 669 return PK_NOZIP; /* unzip instead of unzip.zip */ 670 } 671 #endif /* ?SFX */ 672 } 673 674 if ((uO.zflag > 0) && !uO.zipinfo_mode) { /* unzip: zflag = comment ONLY */ 675 CLOSE_INFILE(); 676 return error_in_archive; 677 } 678 679 /*--------------------------------------------------------------------------- 680 Test the end-of-central-directory info for incompatibilities (multi-disk 681 archives) or inconsistencies (missing or extra bytes in zipfile). 682 ---------------------------------------------------------------------------*/ 683 684 #ifdef NO_MULTIPART 685 error = !uO.zipinfo_mode && (G.ecrec.number_this_disk == 1) && 686 (G.ecrec.num_disk_start_cdir == 1); 687 #else 688 error = !uO.zipinfo_mode && (G.ecrec.number_this_disk != 0); 689 #endif 690 691 #ifndef SFX 692 if (uO.zipinfo_mode && 693 G.ecrec.number_this_disk != G.ecrec.num_disk_start_cdir) 694 { 695 if (G.ecrec.number_this_disk > G.ecrec.num_disk_start_cdir) { 696 Info(slide, 0x401, ((char *)slide, 697 LoadFarString(CentDirNotInZipMsg), G.zipfn, 698 G.ecrec.number_this_disk, G.ecrec.num_disk_start_cdir)); 699 error_in_archive = PK_FIND; 700 too_weird_to_continue = TRUE; 701 } else { 702 Info(slide, 0x401, ((char *)slide, 703 LoadFarString(EndCentDirBogus), G.zipfn, 704 G.ecrec.number_this_disk, G.ecrec.num_disk_start_cdir)); 705 error_in_archive = PK_WARN; 706 } 707 #ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */ 708 } else if (!uO.zipinfo_mode && !error && G.ecrec.number_this_disk != 0) { 709 Info(slide, 0x401, ((char *)slide, LoadFarString(NoMultiDiskArcSupport), 710 G.zipfn)); 711 error_in_archive = PK_FIND; 712 too_weird_to_continue = TRUE; 713 #endif 714 } 715 716 if (!too_weird_to_continue) { /* (relatively) normal zipfile: go for it */ 717 if (error) { 718 Info(slide, 0x401, ((char *)slide, LoadFarString(MaybePakBug), 719 G.zipfn)); 720 error_in_archive = PK_WARN; 721 } 722 #endif /* !SFX */ 723 if ((G.extra_bytes = G.real_ecrec_offset-G.expect_ecrec_offset) < 724 (LONGINT)0) 725 { 726 Info(slide, 0x401, ((char *)slide, LoadFarString(MissingBytes), 727 G.zipfn, (long)(-G.extra_bytes))); 728 error_in_archive = PK_ERR; 729 } else if (G.extra_bytes > 0) { 730 if ((G.ecrec.offset_start_central_directory == 0) && 731 (G.ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */ 732 { 733 Info(slide, 0x401, ((char *)slide, 734 LoadFarString(NullCentDirOffset), G.zipfn)); 735 G.ecrec.offset_start_central_directory = G.extra_bytes; 736 G.extra_bytes = 0; 737 error_in_archive = PK_ERR; 738 } 739 #ifndef SFX 740 else { 741 Info(slide, 0x401, ((char *)slide, 742 LoadFarString(ExtraBytesAtStart), G.zipfn, 743 (long)G.extra_bytes, (G.extra_bytes == 1)? "":"s")); 744 error_in_archive = PK_WARN; 745 } 746 #endif /* !SFX */ 747 } 748 749 /*----------------------------------------------------------------------- 750 Check for empty zipfile and exit now if so. 751 -----------------------------------------------------------------------*/ 752 753 if (G.expect_ecrec_offset==0L && G.ecrec.size_central_directory==0) { 754 if (uO.zipinfo_mode) 755 Info(slide, 0, ((char *)slide, "%sEmpty zipfile.\n", 756 uO.lflag>9? "\n " : "")); 757 else 758 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileEmpty), 759 G.zipfn)); 760 CLOSE_INFILE(); 761 return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN; 762 } 763 764 /*----------------------------------------------------------------------- 765 Compensate for missing or extra bytes, and seek to where the start 766 of central directory should be. If header not found, uncompensate 767 and try again (necessary for at least some Atari archives created 768 with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1). 769 -----------------------------------------------------------------------*/ 770 771 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); 772 if (error == PK_BADERR) { 773 CLOSE_INFILE(); 774 return PK_BADERR; 775 } 776 #ifdef OLD_SEEK_TEST 777 if (error != PK_OK || readbuf(__G__ G.sig, 4) == 0) { 778 CLOSE_INFILE(); 779 return PK_ERR; /* file may be locked, or possibly disk error(?) */ 780 } 781 if (strncmp(G.sig, central_hdr_sig, 4)) 782 #else 783 if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) || 784 strncmp(G.sig, central_hdr_sig, 4)) 785 #endif 786 { 787 #ifndef SFX 788 long tmp = G.extra_bytes; 789 #endif 790 791 G.extra_bytes = 0; 792 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); 793 if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) || 794 strncmp(G.sig, central_hdr_sig, 4)) 795 { 796 if (error != PK_BADERR) 797 Info(slide, 0x401, ((char *)slide, 798 LoadFarString(CentDirStartNotFound), G.zipfn, 799 LoadFarStringSmall(ReportMsg))); 800 CLOSE_INFILE(); 801 return (error != PK_OK ? error : PK_BADERR); 802 } 803 #ifndef SFX 804 Info(slide, 0x401, ((char *)slide, LoadFarString(CentDirTooLong), 805 G.zipfn, -tmp)); 806 #endif 807 error_in_archive = PK_ERR; 808 } 809 810 /*----------------------------------------------------------------------- 811 Seek to the start of the central directory one last time, since we 812 have just read the first entry's signature bytes; then list, extract 813 or test member files as instructed, and close the zipfile. 814 -----------------------------------------------------------------------*/ 815 816 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); 817 if (error != PK_OK) { 818 CLOSE_INFILE(); 819 return error; 820 } 821 822 Trace((stderr, "about to extract/list files (error = %d)\n", 823 error_in_archive)); 824 825 #ifdef DLL 826 /* G.fValidate is used only to look at an archive to see if 827 it appears to be a valid archive. There is no interest 828 in what the archive contains, nor in validating that the 829 entries in the archive are in good condition. This is 830 currently used only in the Windows DLLs for purposes of 831 checking archives within an archive to determine whether 832 or not to display the inner archives. 833 */ 834 if (!G.fValidate) 835 #endif 836 { 837 #ifndef NO_ZIPINFO 838 if (uO.zipinfo_mode) 839 error = zipinfo(__G); /* ZIPINFO 'EM */ 840 else 841 #endif 842 #ifndef SFX 843 #ifdef TIMESTAMP 844 if (uO.T_flag) 845 error = get_time_stamp(__G__ &uxstamp, &nmember); 846 else 847 #endif 848 if (uO.vflag && !uO.tflag && !uO.cflag) 849 error = list_files(__G); /* LIST 'EM */ 850 else 851 #endif /* !SFX */ 852 error = extract_or_test_files(__G); /* EXTRACT OR TEST 'EM */ 853 854 Trace((stderr, "done with extract/list files (error = %d)\n", 855 error)); 856 } 857 858 if (error > error_in_archive) /* don't overwrite stronger error */ 859 error_in_archive = error; /* with (for example) a warning */ 860 #ifndef SFX 861 } /* end if (!too_weird_to_continue) */ 862 #endif 863 864 CLOSE_INFILE(); 865 866 #ifdef TIMESTAMP 867 if (uO.T_flag && !uO.zipinfo_mode && (nmember > 0L)) { 868 # ifdef WIN32 869 if (stamp_file(__G__ G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */ 870 # else 871 if (stamp_file(G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */ 872 # endif 873 if (uO.qflag < 3) 874 Info(slide, 0x201, ((char *)slide, 875 "warning: cannot set time for %s\n", G.zipfn)); 876 if (error_in_archive < PK_WARN) 877 error_in_archive = PK_WARN; 878 } 879 } 880 #endif 881 return error_in_archive; 882 883 } /* end function do_seekable() */ 884 885 886 887 888 889 /*************************/ 890 /* Function find_ecrec() */ 891 /*************************/ 892 893 static int find_ecrec(__G__ searchlen) /* return PK-class error */ 894 __GDEF 895 long searchlen; 896 { 897 int i, numblks, found=FALSE; 898 LONGINT tail_len; 899 ec_byte_rec byterec; 900 901 902 /*--------------------------------------------------------------------------- 903 Treat case of short zipfile separately. 904 ---------------------------------------------------------------------------*/ 905 906 if (G.ziplen <= INBUFSIZ) { 907 lseek(G.zipfd, 0L, SEEK_SET); 908 if ((G.incnt = read(G.zipfd,(char *)G.inbuf,(unsigned int)G.ziplen)) 909 == (int)G.ziplen) 910 911 /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */ 912 for (G.inptr = G.inbuf+(int)G.ziplen-(ECREC_SIZE+4); 913 G.inptr >= G.inbuf; 914 --G.inptr) { 915 if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ 916 !strncmp((char *)G.inptr, end_central_sig, 4)) { 917 G.incnt -= (int)(G.inptr - G.inbuf); 918 found = TRUE; 919 break; 920 } 921 } 922 923 /*--------------------------------------------------------------------------- 924 Zipfile is longer than INBUFSIZ: may need to loop. Start with short 925 block at end of zipfile (if not TOO short). 926 ---------------------------------------------------------------------------*/ 927 928 } else { 929 if ((tail_len = G.ziplen % INBUFSIZ) > ECREC_SIZE) { 930 #ifdef USE_STRM_INPUT 931 fseek((FILE *)G.zipfd, G.ziplen-tail_len, SEEK_SET); 932 G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd); 933 #else /* !USE_STRM_INPUT */ 934 G.cur_zipfile_bufstart = lseek(G.zipfd, G.ziplen-tail_len, 935 SEEK_SET); 936 #endif /* ?USE_STRM_INPUT */ 937 if ((G.incnt = read(G.zipfd, (char *)G.inbuf, 938 (unsigned int)tail_len)) != (int)tail_len) 939 goto fail; /* it's expedient... */ 940 941 /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */ 942 for (G.inptr = G.inbuf+(int)tail_len-(ECREC_SIZE+4); 943 G.inptr >= G.inbuf; 944 --G.inptr) { 945 if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ 946 !strncmp((char *)G.inptr, end_central_sig, 4)) { 947 G.incnt -= (int)(G.inptr - G.inbuf); 948 found = TRUE; 949 break; 950 } 951 } 952 /* sig may span block boundary: */ 953 memcpy((char *)G.hold, (char *)G.inbuf, 3); 954 } else 955 G.cur_zipfile_bufstart = G.ziplen - tail_len; 956 957 /*----------------------------------------------------------------------- 958 Loop through blocks of zipfile data, starting at the end and going 959 toward the beginning. In general, need not check whole zipfile for 960 signature, but may want to do so if testing. 961 -----------------------------------------------------------------------*/ 962 963 numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ); 964 /* ==amount= ==done== ==rounding== =blksiz= */ 965 966 for (i = 1; !found && (i <= numblks); ++i) { 967 G.cur_zipfile_bufstart -= INBUFSIZ; 968 lseek(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET); 969 if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ)) 970 != INBUFSIZ) 971 break; /* fall through and fail */ 972 973 for (G.inptr = G.inbuf+INBUFSIZ-1; G.inptr >= G.inbuf; 974 --G.inptr) 975 if ((native(*G.inptr) == 'P') && 976 !strncmp((char *)G.inptr, end_central_sig, 4)) { 977 G.incnt -= (int)(G.inptr - G.inbuf); 978 found = TRUE; 979 break; 980 } 981 /* sig may span block boundary: */ 982 memcpy((char *)G.hold, (char *)G.inbuf, 3); 983 } 984 } /* end if (ziplen > INBUFSIZ) */ 985 986 /*--------------------------------------------------------------------------- 987 Searched through whole region where signature should be without finding 988 it. Print informational message and die a horrible death. 989 ---------------------------------------------------------------------------*/ 990 991 fail: 992 if (!found) { 993 if (uO.qflag || uO.zipinfo_mode) 994 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); 995 Info(slide, 0x401, ((char *)slide, 996 LoadFarString(CentDirEndSigNotFound))); 997 return PK_ERR; /* failed */ 998 } 999 1000 /*--------------------------------------------------------------------------- 1001 Found the signature, so get the end-central data before returning. Do 1002 any necessary machine-type conversions (byte ordering, structure padding 1003 compensation) by reading data into character array and copying to struct. 1004 ---------------------------------------------------------------------------*/ 1005 1006 G.real_ecrec_offset = G.cur_zipfile_bufstart + (G.inptr-G.inbuf); 1007 #ifdef TEST 1008 printf("\n found end-of-central-dir signature at offset %ld (%.8lXh)\n", 1009 G.real_ecrec_offset, G.real_ecrec_offset); 1010 printf(" from beginning of file; offset %d (%.4Xh) within block\n", 1011 G.inptr-G.inbuf, G.inptr-G.inbuf); 1012 #endif 1013 1014 if (readbuf(__G__ (char *)byterec, ECREC_SIZE+4) == 0) 1015 return PK_EOF; 1016 1017 G.ecrec.number_this_disk = 1018 makeword(&byterec[NUMBER_THIS_DISK]); 1019 G.ecrec.num_disk_start_cdir = 1020 makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]); 1021 G.ecrec.num_entries_centrl_dir_ths_disk = 1022 makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]); 1023 G.ecrec.total_entries_central_dir = 1024 makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]); 1025 G.ecrec.size_central_directory = 1026 makelong(&byterec[SIZE_CENTRAL_DIRECTORY]); 1027 G.ecrec.offset_start_central_directory = 1028 makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]); 1029 G.ecrec.zipfile_comment_length = 1030 makeword(&byterec[ZIPFILE_COMMENT_LENGTH]); 1031 1032 G.expect_ecrec_offset = G.ecrec.offset_start_central_directory + 1033 G.ecrec.size_central_directory; 1034 return PK_COOL; 1035 1036 } /* end function find_ecrec() */ 1037 1038 1039 1040 1041 1042 /*****************************/ 1043 /* Function uz_end_central() */ 1044 /*****************************/ 1045 1046 int uz_end_central(__G) /* return PK-type error code */ 1047 __GDEF 1048 { 1049 int error = PK_COOL; 1050 1051 1052 /*--------------------------------------------------------------------------- 1053 Get the zipfile comment (up to 64KB long), if any, and print it out. 1054 Then position the file pointer to the beginning of the central directory 1055 and fill buffer. 1056 ---------------------------------------------------------------------------*/ 1057 1058 #ifdef WINDLL 1059 /* for comment button: */ 1060 if ((!G.fValidate) && (G.lpUserFunctions != NULL)) 1061 G.lpUserFunctions->cchComment = G.ecrec.zipfile_comment_length; 1062 if (G.ecrec.zipfile_comment_length && (uO.zflag > 0)) 1063 #else /* !WINDLL */ 1064 if (G.ecrec.zipfile_comment_length && (uO.zflag > 0 || 1065 (uO.zflag == 0 && 1066 #ifdef TIMESTAMP 1067 !uO.T_flag && 1068 #endif 1069 !uO.qflag))) 1070 #endif /* ?WINDLL */ 1071 { 1072 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) 1073 if (do_string(__G__ G.ecrec.zipfile_comment_length, CHECK_AUTORUN)) { 1074 #else 1075 if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) { 1076 #endif 1077 Info(slide, 0x401, ((char *)slide, 1078 LoadFarString(ZipfileCommTrunc1))); 1079 error = PK_WARN; 1080 } 1081 } 1082 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) 1083 else if (G.ecrec.zipfile_comment_length) { 1084 if (do_string(__G__ G.ecrec.zipfile_comment_length, CHECK_AUTORUN_Q)) { 1085 Info(slide, 0x401, ((char *)slide, 1086 LoadFarString(ZipfileCommTrunc1))); 1087 error = PK_WARN; 1088 } 1089 } 1090 #endif 1091 return error; 1092 1093 } /* end function uz_end_central() */ 1094 1095 1096 1097 1098 1099 /************************************/ 1100 /* Function process_cdir_file_hdr() */ 1101 /************************************/ 1102 1103 int process_cdir_file_hdr(__G) /* return PK-type error code */ 1104 __GDEF 1105 { 1106 int error; 1107 1108 1109 /*--------------------------------------------------------------------------- 1110 Get central directory info, save host and method numbers, and set flag 1111 for lowercase conversion of filename, depending on the OS from which the 1112 file is coming. 1113 ---------------------------------------------------------------------------*/ 1114 1115 if ((error = get_cdir_ent(__G)) != 0) 1116 return error; 1117 1118 G.pInfo->hostver = G.crec.version_made_by[0]; 1119 G.pInfo->hostnum = MIN(G.crec.version_made_by[1], NUM_HOSTS); 1120 /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */ 1121 1122 G.pInfo->lcflag = 0; 1123 if (uO.L_flag == 1) /* name conversion for monocase systems */ 1124 switch (G.pInfo->hostnum) { 1125 case FS_FAT_: /* PKZIP and zip -k store in uppercase */ 1126 case CPM_: /* like MS-DOS, right? */ 1127 case VM_CMS_: /* all caps? */ 1128 case MVS_: /* all caps? */ 1129 case TANDEM_: 1130 case TOPS20_: 1131 case VMS_: /* our Zip uses lowercase, but ASi's doesn't */ 1132 /* case Z_SYSTEM_: ? */ 1133 /* case QDOS_: ? */ 1134 G.pInfo->lcflag = 1; /* convert filename to lowercase */ 1135 break; 1136 1137 default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */ 1138 break; /* FS_VFAT_, BEOS_ (Z_SYSTEM_), THEOS_: */ 1139 /* no conversion */ 1140 } 1141 else if (uO.L_flag > 1) /* let -LL force lower case for all names */ 1142 G.pInfo->lcflag = 1; 1143 1144 /* do Amigas (AMIGA_) also have volume labels? */ 1145 if (IS_VOLID(G.crec.external_file_attributes) && 1146 (G.pInfo->hostnum == FS_FAT_ || G.pInfo->hostnum == FS_HPFS_ || 1147 G.pInfo->hostnum == FS_NTFS_ || G.pInfo->hostnum == ATARI_)) 1148 { 1149 G.pInfo->vollabel = TRUE; 1150 G.pInfo->lcflag = 0; /* preserve case of volume labels */ 1151 } else 1152 G.pInfo->vollabel = FALSE; 1153 1154 /* this flag is needed to detect archives made by "PKZIP for Unix" when 1155 deciding which kind of codepage conversion has to be applied to 1156 strings (see do_string() function in fileio.c) */ 1157 G.pInfo->HasUxAtt = (G.crec.external_file_attributes & 0xffff0000L) != 0L; 1158 1159 return PK_COOL; 1160 1161 } /* end function process_cdir_file_hdr() */ 1162 1163 1164 1165 1166 1167 /***************************/ 1168 /* Function get_cdir_ent() */ 1169 /***************************/ 1170 1171 int get_cdir_ent(__G) /* return PK-type error code */ 1172 __GDEF 1173 { 1174 cdir_byte_hdr byterec; 1175 1176 1177 /*--------------------------------------------------------------------------- 1178 Read the next central directory entry and do any necessary machine-type 1179 conversions (byte ordering, structure padding compensation--do so by 1180 copying the data from the array into which it was read (byterec) to the 1181 usable struct (crec)). 1182 ---------------------------------------------------------------------------*/ 1183 1184 if (readbuf(__G__ (char *)byterec, CREC_SIZE) == 0) 1185 return PK_EOF; 1186 1187 G.crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0]; 1188 G.crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1]; 1189 G.crec.version_needed_to_extract[0] = 1190 byterec[C_VERSION_NEEDED_TO_EXTRACT_0]; 1191 G.crec.version_needed_to_extract[1] = 1192 byterec[C_VERSION_NEEDED_TO_EXTRACT_1]; 1193 1194 G.crec.general_purpose_bit_flag = 1195 makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]); 1196 G.crec.compression_method = 1197 makeword(&byterec[C_COMPRESSION_METHOD]); 1198 G.crec.last_mod_dos_datetime = 1199 makelong(&byterec[C_LAST_MOD_DOS_DATETIME]); 1200 G.crec.crc32 = 1201 makelong(&byterec[C_CRC32]); 1202 G.crec.csize = 1203 makelong(&byterec[C_COMPRESSED_SIZE]); 1204 G.crec.ucsize = 1205 makelong(&byterec[C_UNCOMPRESSED_SIZE]); 1206 G.crec.filename_length = 1207 makeword(&byterec[C_FILENAME_LENGTH]); 1208 G.crec.extra_field_length = 1209 makeword(&byterec[C_EXTRA_FIELD_LENGTH]); 1210 G.crec.file_comment_length = 1211 makeword(&byterec[C_FILE_COMMENT_LENGTH]); 1212 G.crec.disk_number_start = 1213 makeword(&byterec[C_DISK_NUMBER_START]); 1214 G.crec.internal_file_attributes = 1215 makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]); 1216 G.crec.external_file_attributes = 1217 makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */ 1218 G.crec.relative_offset_local_header = 1219 makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]); 1220 1221 return PK_COOL; 1222 1223 } /* end function get_cdir_ent() */ 1224 1225 1226 1227 1228 1229 /*************************************/ 1230 /* Function process_local_file_hdr() */ 1231 /*************************************/ 1232 1233 int process_local_file_hdr(__G) /* return PK-type error code */ 1234 __GDEF 1235 { 1236 local_byte_hdr byterec; 1237 1238 1239 /*--------------------------------------------------------------------------- 1240 Read the next local file header and do any necessary machine-type con- 1241 versions (byte ordering, structure padding compensation--do so by copy- 1242 ing the data from the array into which it was read (byterec) to the 1243 usable struct (lrec)). 1244 ---------------------------------------------------------------------------*/ 1245 1246 if (readbuf(__G__ (char *)byterec, LREC_SIZE) == 0) 1247 return PK_EOF; 1248 1249 G.lrec.version_needed_to_extract[0] = 1250 byterec[L_VERSION_NEEDED_TO_EXTRACT_0]; 1251 G.lrec.version_needed_to_extract[1] = 1252 byterec[L_VERSION_NEEDED_TO_EXTRACT_1]; 1253 1254 G.lrec.general_purpose_bit_flag = 1255 makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]); 1256 G.lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]); 1257 G.lrec.last_mod_dos_datetime = makelong(&byterec[L_LAST_MOD_DOS_DATETIME]); 1258 G.lrec.crc32 = makelong(&byterec[L_CRC32]); 1259 G.lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]); 1260 G.lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]); 1261 G.lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]); 1262 G.lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]); 1263 1264 if ((G.lrec.general_purpose_bit_flag & 8) != 0) { 1265 /* can't trust local header, use central directory: */ 1266 G.lrec.crc32 = G.pInfo->crc; 1267 G.lrec.csize = G.pInfo->compr_size; 1268 G.lrec.ucsize = G.pInfo->uncompr_size; 1269 } 1270 1271 G.csize = (long)G.lrec.csize; 1272 1273 return PK_COOL; 1274 1275 } /* end function process_local_file_hdr() */ 1276 1277 1278 #ifdef USE_EF_UT_TIME 1279 1280 /*******************************/ 1281 /* Function ef_scan_for_izux() */ 1282 /*******************************/ 1283 1284 unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime, 1285 z_utim, z_uidgid) 1286 ZCONST uch *ef_buf; /* buffer containing extra field */ 1287 unsigned ef_len; /* total length of extra field */ 1288 int ef_is_c; /* flag indicating "is central extra field" */ 1289 ulg dos_mdatetime; /* last_mod_file_date_time in DOS format */ 1290 iztimes *z_utim; /* return storage: atime, mtime, ctime */ 1291 ush *z_uidgid; /* return storage: uid and gid */ 1292 { 1293 unsigned flags = 0; 1294 unsigned eb_id; 1295 unsigned eb_len; 1296 int have_new_type_eb = FALSE; 1297 long i_time; /* buffer for Unix style 32-bit integer time value */ 1298 #ifdef TIME_T_TYPE_DOUBLE 1299 int ut_in_archive_sgn = 0; 1300 #else 1301 int ut_zip_unzip_compatible = FALSE; 1302 #endif 1303 1304 /*--------------------------------------------------------------------------- 1305 This function scans the extra field for EF_TIME, EF_IZUNIX2, EF_IZUNIX, or 1306 EF_PKUNIX blocks containing Unix-style time_t (GMT) values for the entry's 1307 access, creation, and modification time. 1308 If a valid block is found, the time stamps are copied to the iztimes 1309 structure (provided the z_utim pointer is not NULL). 1310 If a IZUNIX2 block is found or the IZUNIX block contains UID/GID fields, 1311 and the z_uidgid array pointer is valid (!= NULL), the owner info is 1312 transfered as well. 1313 The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring all 1314 data from probably present obsolete EF_IZUNIX blocks. 1315 If multiple blocks of the same type are found, only the information from 1316 the last block is used. 1317 The return value is a combination of the EF_TIME Flags field with an 1318 additional flag bit indicating the presence of valid UID/GID info, 1319 or 0 in case of failure. 1320 ---------------------------------------------------------------------------*/ 1321 1322 if (ef_len == 0 || ef_buf == NULL || (z_utim == 0 && z_uidgid == NULL)) 1323 return 0; 1324 1325 TTrace((stderr,"\nef_scan_for_izux: scanning extra field of length %u\n", 1326 ef_len)); 1327 1328 while (ef_len >= EB_HEADSIZE) { 1329 eb_id = makeword(EB_ID + ef_buf); 1330 eb_len = makeword(EB_LEN + ef_buf); 1331 1332 if (eb_len > (ef_len - EB_HEADSIZE)) { 1333 /* discovered some extra field inconsistency! */ 1334 TTrace((stderr, 1335 "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len, 1336 ef_len - EB_HEADSIZE)); 1337 break; 1338 } 1339 1340 switch (eb_id) { 1341 case EF_TIME: 1342 flags &= ~0x0ff; /* ignore previous IZUNIX or EF_TIME fields */ 1343 have_new_type_eb = TRUE; 1344 if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) { 1345 unsigned eb_idx = EB_UT_TIME1; 1346 TTrace((stderr,"ef_scan_for_izux: found TIME extra field\n")); 1347 flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x0ff); 1348 if ((flags & EB_UT_FL_MTIME)) { 1349 if ((eb_idx+4) <= eb_len) { 1350 i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); 1351 eb_idx += 4; 1352 TTrace((stderr," UT e.f. modification time = %ld\n", 1353 i_time)); 1354 1355 #ifdef TIME_T_TYPE_DOUBLE 1356 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 1357 if (dos_mdatetime == DOSTIME_MINIMUM) { 1358 ut_in_archive_sgn = -1; 1359 z_utim->mtime = 1360 (time_t)((long)i_time | (~(long)0x7fffffffL)); 1361 } else if (dos_mdatetime >= DOSTIME_2038_01_18) { 1362 ut_in_archive_sgn = 1; 1363 z_utim->mtime = 1364 (time_t)((ulg)i_time & (ulg)0xffffffffL); 1365 } else { 1366 ut_in_archive_sgn = 0; 1367 /* cannot determine sign of mtime; 1368 without modtime: ignore complete UT field */ 1369 flags &= ~0x0ff; /* no time_t times available */ 1370 TTrace((stderr, 1371 " UT modtime range error; ignore e.f.!\n")); 1372 break; /* stop scanning this field */ 1373 } 1374 } else { 1375 /* cannot determine, safe assumption is FALSE */ 1376 ut_in_archive_sgn = 0; 1377 z_utim->mtime = (time_t)i_time; 1378 } 1379 #else /* !TIME_T_TYPE_DOUBLE */ 1380 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 1381 ut_zip_unzip_compatible = 1382 ((time_t)0x80000000L < (time_t)0L) 1383 ? (dos_mdatetime == DOSTIME_MINIMUM) 1384 : (dos_mdatetime >= DOSTIME_2038_01_18); 1385 if (!ut_zip_unzip_compatible) { 1386 /* UnZip interprets mtime differently than Zip; 1387 without modtime: ignore complete UT field */ 1388 flags &= ~0x0ff; /* no time_t times available */ 1389 TTrace((stderr, 1390 " UT modtime range error; ignore e.f.!\n")); 1391 break; /* stop scanning this field */ 1392 } 1393 } else { 1394 /* cannot determine, safe assumption is FALSE */ 1395 ut_zip_unzip_compatible = FALSE; 1396 } 1397 z_utim->mtime = (time_t)i_time; 1398 #endif /* ?TIME_T_TYPE_DOUBLE */ 1399 } else { 1400 flags &= ~EB_UT_FL_MTIME; 1401 TTrace((stderr," UT e.f. truncated; no modtime\n")); 1402 } 1403 } 1404 if (ef_is_c) { 1405 break; /* central version of TIME field ends here */ 1406 } 1407 1408 if (flags & EB_UT_FL_ATIME) { 1409 if ((eb_idx+4) <= eb_len) { 1410 i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); 1411 eb_idx += 4; 1412 TTrace((stderr," UT e.f. access time = %ld\n", 1413 i_time)); 1414 #ifdef TIME_T_TYPE_DOUBLE 1415 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 1416 if (ut_in_archive_sgn == -1) 1417 z_utim->atime = 1418 (time_t)((long)i_time | (~(long)0x7fffffffL)); 1419 } else if (ut_in_archive_sgn == 1) { 1420 z_utim->atime = 1421 (time_t)((ulg)i_time & (ulg)0xffffffffL); 1422 } else { 1423 /* sign of 32-bit time is unknown -> ignore it */ 1424 flags &= ~EB_UT_FL_ATIME; 1425 TTrace((stderr, 1426 " UT access time range error: skip time!\n")); 1427 } 1428 } else { 1429 z_utim->atime = (time_t)i_time; 1430 } 1431 #else /* !TIME_T_TYPE_DOUBLE */ 1432 if (((ulg)(i_time) & (ulg)(0x80000000L)) && 1433 !ut_zip_unzip_compatible) { 1434 flags &= ~EB_UT_FL_ATIME; 1435 TTrace((stderr, 1436 " UT access time range error: skip time!\n")); 1437 } else { 1438 z_utim->atime = (time_t)i_time; 1439 } 1440 #endif /* ?TIME_T_TYPE_DOUBLE */ 1441 } else { 1442 flags &= ~EB_UT_FL_ATIME; 1443 } 1444 } 1445 if (flags & EB_UT_FL_CTIME) { 1446 if ((eb_idx+4) <= eb_len) { 1447 i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); 1448 TTrace((stderr," UT e.f. creation time = %ld\n", 1449 i_time)); 1450 #ifdef TIME_T_TYPE_DOUBLE 1451 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 1452 if (ut_in_archive_sgn == -1) 1453 z_utim->ctime = 1454 (time_t)((long)i_time | (~(long)0x7fffffffL)); 1455 } else if (ut_in_archive_sgn == 1) { 1456 z_utim->ctime = 1457 (time_t)((ulg)i_time & (ulg)0xffffffffL); 1458 } else { 1459 /* sign of 32-bit time is unknown -> ignore it */ 1460 flags &= ~EB_UT_FL_CTIME; 1461 TTrace((stderr, 1462 " UT creation time range error: skip time!\n")); 1463 } 1464 } else { 1465 z_utim->ctime = (time_t)i_time; 1466 } 1467 #else /* !TIME_T_TYPE_DOUBLE */ 1468 if (((ulg)(i_time) & (ulg)(0x80000000L)) && 1469 !ut_zip_unzip_compatible) { 1470 flags &= ~EB_UT_FL_CTIME; 1471 TTrace((stderr, 1472 " UT creation time range error: skip time!\n")); 1473 } else { 1474 z_utim->ctime = (time_t)i_time; 1475 } 1476 #endif /* ?TIME_T_TYPE_DOUBLE */ 1477 } else { 1478 flags &= ~EB_UT_FL_CTIME; 1479 } 1480 } 1481 } 1482 break; 1483 1484 case EF_IZUNIX2: 1485 if (!have_new_type_eb) { 1486 flags &= ~0x0ff; /* ignore any previous IZUNIX field */ 1487 have_new_type_eb = TRUE; 1488 } 1489 if (eb_len >= EB_UX2_MINLEN && z_uidgid != NULL) { 1490 z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX2_UID) + ef_buf); 1491 z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX2_GID) + ef_buf); 1492 flags |= EB_UX2_VALID; /* signal success */ 1493 } 1494 break; 1495 1496 case EF_IZUNIX: 1497 case EF_PKUNIX: /* PKUNIX e.f. layout is identical to IZUNIX */ 1498 if (eb_len >= EB_UX_MINLEN) { 1499 TTrace((stderr,"ef_scan_for_izux: found %s extra field\n", 1500 (eb_id == EF_IZUNIX ? "IZUNIX" : "PKUNIX"))); 1501 if (have_new_type_eb) { 1502 break; /* Ignore IZUNIX extra field block ! */ 1503 } 1504 if (z_utim != NULL) { 1505 flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME); 1506 i_time = (long)makelong((EB_HEADSIZE+EB_UX_MTIME)+ef_buf); 1507 TTrace((stderr," Unix EF modtime = %ld\n", i_time)); 1508 #ifdef TIME_T_TYPE_DOUBLE 1509 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 1510 if (dos_mdatetime == DOSTIME_MINIMUM) { 1511 ut_in_archive_sgn = -1; 1512 z_utim->mtime = 1513 (time_t)((long)i_time | (~(long)0x7fffffffL)); 1514 } else if (dos_mdatetime >= DOSTIME_2038_01_18) { 1515 ut_in_archive_sgn = 1; 1516 z_utim->mtime = 1517 (time_t)((ulg)i_time & (ulg)0xffffffffL); 1518 } else { 1519 ut_in_archive_sgn = 0; 1520 /* cannot determine sign of mtime; 1521 without modtime: ignore complete UT field */ 1522 flags &= ~0x0ff; /* no time_t times available */ 1523 TTrace((stderr, 1524 " UX modtime range error: ignore e.f.!\n")); 1525 } 1526 } else { 1527 /* cannot determine, safe assumption is FALSE */ 1528 ut_in_archive_sgn = 0; 1529 z_utim->mtime = (time_t)i_time; 1530 } 1531 #else /* !TIME_T_TYPE_DOUBLE */ 1532 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 1533 ut_zip_unzip_compatible = 1534 ((time_t)0x80000000L < (time_t)0L) 1535 ? (dos_mdatetime == DOSTIME_MINIMUM) 1536 : (dos_mdatetime >= DOSTIME_2038_01_18); 1537 if (!ut_zip_unzip_compatible) { 1538 /* UnZip interpretes mtime differently than Zip; 1539 without modtime: ignore complete UT field */ 1540 flags &= ~0x0ff; /* no time_t times available */ 1541 TTrace((stderr, 1542 " UX modtime range error: ignore e.f.!\n")); 1543 } 1544 } else { 1545 /* cannot determine, safe assumption is FALSE */ 1546 ut_zip_unzip_compatible = FALSE; 1547 } 1548 z_utim->mtime = (time_t)i_time; 1549 #endif /* ?TIME_T_TYPE_DOUBLE */ 1550 i_time = (long)makelong((EB_HEADSIZE+EB_UX_ATIME)+ef_buf); 1551 TTrace((stderr," Unix EF actime = %ld\n", i_time)); 1552 #ifdef TIME_T_TYPE_DOUBLE 1553 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 1554 if (ut_in_archive_sgn == -1) 1555 z_utim->atime = 1556 (time_t)((long)i_time | (~(long)0x7fffffffL)); 1557 } else if (ut_in_archive_sgn == 1) { 1558 z_utim->atime = 1559 (time_t)((ulg)i_time & (ulg)0xffffffffL); 1560 } else if (flags & 0x0ff) { 1561 /* sign of 32-bit time is unknown -> ignore it */ 1562 flags &= ~EB_UT_FL_ATIME; 1563 TTrace((stderr, 1564 " UX access time range error: skip time!\n")); 1565 } 1566 } else { 1567 z_utim->atime = (time_t)i_time; 1568 } 1569 #else /* !TIME_T_TYPE_DOUBLE */ 1570 if (((ulg)(i_time) & (ulg)(0x80000000L)) && 1571 !ut_zip_unzip_compatible && (flags & 0x0ff)) { 1572 /* atime not in range of UnZip's time_t */ 1573 flags &= ~EB_UT_FL_ATIME; 1574 TTrace((stderr, 1575 " UX access time range error: skip time!\n")); 1576 } else { 1577 z_utim->atime = (time_t)i_time; 1578 } 1579 #endif /* ?TIME_T_TYPE_DOUBLE */ 1580 } 1581 if (eb_len >= EB_UX_FULLSIZE && z_uidgid != NULL) { 1582 z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX_UID) + ef_buf); 1583 z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX_GID) + ef_buf); 1584 flags |= EB_UX2_VALID; 1585 } 1586 } 1587 break; 1588 1589 default: 1590 break; 1591 } 1592 1593 /* Skip this extra field block */ 1594 ef_buf += (eb_len + EB_HEADSIZE); 1595 ef_len -= (eb_len + EB_HEADSIZE); 1596 } 1597 1598 return flags; 1599 } 1600 1601 #endif /* USE_EF_UT_TIME */ 1602 1603 1604 #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) 1605 1606 #define SPARKID_2 0x30435241 /* = "ARC0" */ 1607 1608 /*******************************/ 1609 /* Function getRISCOSexfield() */ 1610 /*******************************/ 1611 1612 zvoid *getRISCOSexfield(ef_buf, ef_len) 1613 ZCONST uch *ef_buf; /* buffer containing extra field */ 1614 unsigned ef_len; /* total length of extra field */ 1615 { 1616 unsigned eb_id; 1617 unsigned eb_len; 1618 1619 /*--------------------------------------------------------------------------- 1620 This function scans the extra field for a Acorn SPARK filetype ef-block. 1621 If a valid block is found, the function returns a pointer to the start 1622 of the SPARK_EF block in the extra field buffer. Otherwise, a NULL 1623 pointer is returned. 1624 ---------------------------------------------------------------------------*/ 1625 1626 if (ef_len == 0 || ef_buf == NULL) 1627 return NULL; 1628 1629 TTrace((stderr,"\ngetRISCOSexfield: scanning extra field of length %u\n", 1630 ef_len)); 1631 1632 while (ef_len >= EB_HEADSIZE) { 1633 eb_id = makeword(EB_ID + ef_buf); 1634 eb_len = makeword(EB_LEN + ef_buf); 1635 1636 if (eb_len > (ef_len - EB_HEADSIZE)) { 1637 /* discovered some extra field inconsistency! */ 1638 TTrace((stderr, 1639 "getRISCOSexfield: block length %u > rest ef_size %u\n", eb_len, 1640 ef_len - EB_HEADSIZE)); 1641 break; 1642 } 1643 1644 if (eb_id == EF_SPARK && (eb_len == 24 || eb_len == 20)) { 1645 if (makelong(EB_HEADSIZE + ef_buf) == SPARKID_2) { 1646 /* Return a pointer to the valid SPARK filetype ef block */ 1647 return (zvoid *)ef_buf; 1648 } 1649 } 1650 1651 /* Skip this extra field block */ 1652 ef_buf += (eb_len + EB_HEADSIZE); 1653 ef_len -= (eb_len + EB_HEADSIZE); 1654 } 1655 1656 return NULL; 1657 } 1658 1659 #endif /* (RISCOS || ACORN_FTYPE_NFS) */ 1660