1/* 2 Copyright (c) 1990-2009 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2009-Jan-02 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 file_size() 19 rec_find() 20 find_ecrec64() 21 find_ecrec() 22 process_zip_cmmnt() 23 process_cdir_file_hdr() 24 get_cdir_ent() 25 process_local_file_hdr() 26 getZip64Data() 27 ef_scan_for_izux() 28 getRISCOSexfield() 29 30 ---------------------------------------------------------------------------*/ 31 32 33#define UNZIP_INTERNAL 34#include "unzip.h" 35#ifdef WINDLL 36# ifdef POCKET_UNZIP 37# include "wince/intrface.h" 38# else 39# include "windll/windll.h" 40# endif 41#endif 42#if defined(DYNALLOC_CRCTAB) || defined(UNICODE_SUPPORT) 43# include "crc32.h" 44#endif 45 46static int do_seekable OF((__GPRO__ int lastchance)); 47#ifdef DO_SAFECHECK_2GB 48# ifdef USE_STRM_INPUT 49static zoff_t file_size OF((FILE *file)); 50# else 51static zoff_t file_size OF((int fh)); 52# endif 53#endif /* DO_SAFECHECK_2GB */ 54static int rec_find OF((__GPRO__ zoff_t, char *, int)); 55static int find_ecrec64 OF((__GPRO__ zoff_t searchlen)); 56static int find_ecrec OF((__GPRO__ zoff_t searchlen)); 57static int process_zip_cmmnt OF((__GPRO)); 58static int get_cdir_ent OF((__GPRO)); 59#ifdef IZ_HAVE_UXUIDGID 60static int read_ux3_value OF((ZCONST uch *dbuf, unsigned uidgid_sz, 61 ulg *p_uidgid)); 62#endif /* IZ_HAVE_UXUIDGID */ 63 64 65static ZCONST char Far CannotAllocateBuffers[] = 66 "error: cannot allocate unzip buffers\n"; 67 68#ifdef SFX 69 static ZCONST char Far CannotFindMyself[] = 70 "unzipsfx: cannot find myself! [%s]\n"; 71# ifdef CHEAP_SFX_AUTORUN 72 static ZCONST char Far AutorunPrompt[] = 73 "\nAuto-run command: %s\nExecute this command? [y/n] "; 74 static ZCONST char Far NotAutoRunning[] = 75 "Not executing auto-run command."; 76# endif 77 78#else /* !SFX */ 79 /* process_zipfiles() strings */ 80# if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME)) 81 static ZCONST char Far WarnInvalidTZ[] = 82 "Warning: TZ environment variable not found, cannot use UTC times!!\n"; 83# endif 84# if !(defined(UNIX) || defined(AMIGA)) 85 static ZCONST char Far CannotFindWildcardMatch[] = 86 "%s: cannot find any matches for wildcard specification \"%s\".\n"; 87# endif /* !(UNIX || AMIGA) */ 88 static ZCONST char Far FilesProcessOK[] = 89 "%d archive%s successfully processed.\n"; 90 static ZCONST char Far ArchiveWarning[] = 91 "%d archive%s had warnings but no fatal errors.\n"; 92 static ZCONST char Far ArchiveFatalError[] = 93 "%d archive%s had fatal errors.\n"; 94 static ZCONST char Far FileHadNoZipfileDir[] = 95 "%d file%s had no zipfile directory.\n"; 96 static ZCONST char Far ZipfileWasDir[] = "1 \"zipfile\" was a directory.\n"; 97 static ZCONST char Far ManyZipfilesWereDir[] = 98 "%d \"zipfiles\" were directories.\n"; 99 static ZCONST char Far NoZipfileFound[] = "No zipfiles found.\n"; 100 101 /* do_seekable() strings */ 102# ifdef UNIX 103 static ZCONST char Far CannotFindZipfileDirMsg[] = 104 "%s: cannot find zipfile directory in one of %s or\n\ 105 %s%s.zip, and cannot find %s, period.\n"; 106 static ZCONST char Far CannotFindEitherZipfile[] = 107 "%s: cannot find or open %s, %s.zip or %s.\n"; 108# else /* !UNIX */ 109 static ZCONST char Far CannotFindZipfileDirMsg[] = 110 "%s: cannot find zipfile directory in %s,\n\ 111 %sand cannot find %s, period.\n"; 112# ifdef VMS 113 static ZCONST char Far CannotFindEitherZipfile[] = 114 "%s: cannot find %s (%s).\n"; 115# else /* !VMS */ 116 static ZCONST char Far CannotFindEitherZipfile[] = 117 "%s: cannot find either %s or %s.\n"; 118# endif /* ?VMS */ 119# endif /* ?UNIX */ 120 extern ZCONST char Far Zipnfo[]; /* in unzip.c */ 121#ifndef WINDLL 122 static ZCONST char Far Unzip[] = "unzip"; 123#else 124 static ZCONST char Far Unzip[] = "UnZip DLL"; 125#endif 126#ifdef DO_SAFECHECK_2GB 127 static ZCONST char Far ZipfileTooBig[] = 128 "Trying to read large file (> 2 GiB) without large file support\n"; 129#endif /* DO_SAFECHECK_2GB */ 130 static ZCONST char Far MaybeExe[] = 131 "note: %s may be a plain executable, not an archive\n"; 132 static ZCONST char Far CentDirNotInZipMsg[] = "\n\ 133 [%s]:\n\ 134 Zipfile is disk %lu of a multi-disk archive, and this is not the disk on\n\ 135 which the central zipfile directory begins (disk %lu).\n"; 136 static ZCONST char Far EndCentDirBogus[] = 137 "\nwarning [%s]: end-of-central-directory record claims this\n\ 138 is disk %lu but that the central directory starts on disk %lu; this is a\n\ 139 contradiction. Attempting to process anyway.\n"; 140# ifdef NO_MULTIPART 141 static ZCONST char Far NoMultiDiskArcSupport[] = 142 "\nerror [%s]: zipfile is part of multi-disk archive\n\ 143 (sorry, not yet supported).\n"; 144 static ZCONST char Far MaybePakBug[] = "warning [%s]:\ 145 zipfile claims to be 2nd disk of a 2-part archive;\n\ 146 attempting to process anyway. If no further errors occur, this archive\n\ 147 was probably created by PAK v2.51 or earlier. This bug was reported to\n\ 148 NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\ 149 of mid-1992 it still hadn't been. (If further errors do occur, archive\n\ 150 was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\ 151 multi-part archives.)\n"; 152# else 153 static ZCONST char Far MaybePakBug[] = "warning [%s]:\ 154 zipfile claims to be last disk of a multi-part archive;\n\ 155 attempting to process anyway, assuming all parts have been concatenated\n\ 156 together in order. Expect \"errors\" and warnings...true multi-part support\ 157\n doesn't exist yet (coming soon).\n"; 158# endif 159 static ZCONST char Far ExtraBytesAtStart[] = 160 "warning [%s]: %s extra byte%s at beginning or within zipfile\n\ 161 (attempting to process anyway)\n"; 162#endif /* ?SFX */ 163 164#if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO)) 165 static ZCONST char Far LogInitline[] = "Archive: %s\n"; 166#endif 167 168static ZCONST char Far MissingBytes[] = 169 "error [%s]: missing %s bytes in zipfile\n\ 170 (attempting to process anyway)\n"; 171static ZCONST char Far NullCentDirOffset[] = 172 "error [%s]: NULL central directory offset\n\ 173 (attempting to process anyway)\n"; 174static ZCONST char Far ZipfileEmpty[] = "warning [%s]: zipfile is empty\n"; 175static ZCONST char Far CentDirStartNotFound[] = 176 "error [%s]: start of central directory not found;\n\ 177 zipfile corrupt.\n%s"; 178static ZCONST char Far Cent64EndSigSearchErr[] = 179 "fatal error: read failure while seeking for End-of-centdir-64 signature.\n\ 180 This zipfile is corrupt.\n"; 181static ZCONST char Far Cent64EndSigSearchOff[] = 182 "error: End-of-centdir-64 signature not where expected (prepended bytes?)\n\ 183 (attempting to process anyway)\n"; 184#ifndef SFX 185 static ZCONST char Far CentDirTooLong[] = 186 "error [%s]: reported length of central directory is\n\ 187 %s bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1\n\ 188 zipfile?). Compensating...\n"; 189 static ZCONST char Far CentDirEndSigNotFound[] = "\ 190 End-of-central-directory signature not found. Either this file is not\n\ 191 a zipfile, or it constitutes one disk of a multi-part archive. In the\n\ 192 latter case the central directory and zipfile comment will be found on\n\ 193 the last disk(s) of this archive.\n"; 194#else /* SFX */ 195 static ZCONST char Far CentDirEndSigNotFound[] = 196 " End-of-central-directory signature not found.\n"; 197#endif /* ?SFX */ 198#ifdef TIMESTAMP 199 static ZCONST char Far ZipTimeStampFailed[] = 200 "warning: cannot set time for %s\n"; 201 static ZCONST char Far ZipTimeStampSuccess[] = 202 "Updated time stamp for %s.\n"; 203#endif 204static ZCONST char Far ZipfileCommTrunc1[] = 205 "\ncaution: zipfile comment truncated\n"; 206#ifndef NO_ZIPINFO 207 static ZCONST char Far NoZipfileComment[] = 208 "There is no zipfile comment.\n"; 209 static ZCONST char Far ZipfileCommentDesc[] = 210 "The zipfile comment is %u bytes long and contains the following text:\n"; 211 static ZCONST char Far ZipfileCommBegin[] = 212 "======================== zipfile comment begins\ 213 ==========================\n"; 214 static ZCONST char Far ZipfileCommEnd[] = 215 "========================= zipfile comment ends\ 216 ===========================\n"; 217 static ZCONST char Far ZipfileCommTrunc2[] = 218 "\n The zipfile comment is truncated.\n"; 219#endif /* !NO_ZIPINFO */ 220#ifdef UNICODE_SUPPORT 221 static ZCONST char Far UnicodeVersionError[] = 222 "\nwarning: Unicode Path version > 1\n"; 223 static ZCONST char Far UnicodeMismatchError[] = 224 "\nwarning: Unicode Path checksum invalid\n"; 225#endif 226 227 228 229 230/*******************************/ 231/* Function process_zipfiles() */ 232/*******************************/ 233 234int process_zipfiles(__G) /* return PK-type error code */ 235 __GDEF 236{ 237#ifndef SFX 238 char *lastzipfn = (char *)NULL; 239 int NumWinFiles, NumLoseFiles, NumWarnFiles; 240 int NumMissDirs, NumMissFiles; 241#endif 242 int error=0, error_in_archive=0; 243 244 245/*--------------------------------------------------------------------------- 246 Start by allocating buffers and (re)constructing the various PK signature 247 strings. 248 ---------------------------------------------------------------------------*/ 249 250 G.inbuf = (uch *)malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */ 251 G.outbuf = (uch *)malloc(OUTBUFSIZ + 1); /* 1 extra for string term. */ 252 253 if ((G.inbuf == (uch *)NULL) || (G.outbuf == (uch *)NULL)) { 254 Info(slide, 0x401, ((char *)slide, 255 LoadFarString(CannotAllocateBuffers))); 256 return(PK_MEM); 257 } 258 G.hold = G.inbuf + INBUFSIZ; /* to check for boundary-spanning sigs */ 259#ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */ 260#ifdef SMALL_MEM 261 G.outbuf2 = G.outbuf+RAWBUFSIZ; /* never changes */ 262#endif 263#endif /* !VMS */ 264 265#if 0 /* CRC_32_TAB has been NULLified by CONSTRUCTGLOBALS !!!! */ 266 /* allocate the CRC table later when we know we can read zipfile data */ 267 CRC_32_TAB = NULL; 268#endif /* 0 */ 269 270 /* finish up initialization of magic signature strings */ 271 local_hdr_sig[0] /* = extd_local_sig[0] */ = /* ASCII 'P', */ 272 central_hdr_sig[0] = end_central_sig[0] = /* not EBCDIC */ 273 end_centloc64_sig[0] = end_central64_sig[0] = 0x50; 274 275 local_hdr_sig[1] /* = extd_local_sig[1] */ = /* ASCII 'K', */ 276 central_hdr_sig[1] = end_central_sig[1] = /* not EBCDIC */ 277 end_centloc64_sig[1] = end_central64_sig[1] = 0x4B; 278 279/*--------------------------------------------------------------------------- 280 Make sure timezone info is set correctly; localtime() returns GMT on some 281 OSes (e.g., Solaris 2.x) if this isn't done first. The ifdefs around 282 tzset() were initially copied from dos_to_unix_time() in fileio.c. They 283 may still be too strict; any listed OS that supplies tzset(), regardless 284 of whether the function does anything, should be removed from the ifdefs. 285 ---------------------------------------------------------------------------*/ 286 287#if (defined(WIN32) && defined(USE_EF_UT_TIME)) 288 /* For the Win32 environment, we may have to "prepare" the environment 289 prior to the tzset() call, to work around tzset() implementation bugs. 290 */ 291 iz_w32_prepareTZenv(); 292#endif 293 294#if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME)) 295# ifndef VALID_TIMEZONE 296# define VALID_TIMEZONE(tmp) \ 297 (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0')) 298# endif 299 { 300 char *p; 301 G.tz_is_valid = VALID_TIMEZONE(p); 302# ifndef SFX 303 if (!G.tz_is_valid) { 304 Info(slide, 0x401, ((char *)slide, LoadFarString(WarnInvalidTZ))); 305 error_in_archive = error = PK_WARN; 306 } 307# endif /* !SFX */ 308 } 309#endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */ 310 311/* For systems that do not have tzset() but supply this function using another 312 name (_tzset() or something similar), an appropiate "#define tzset ..." 313 should be added to the system specifc configuration section. */ 314#if (!defined(T20_VMS) && !defined(MACOS) && !defined(RISCOS) && !defined(QDOS)) 315#if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM)) 316 tzset(); 317#endif 318#endif 319 320/* Initialize UnZip's built-in pseudo hard-coded "ISO <--> OEM" translation, 321 depending on the detected codepage setup. */ 322#ifdef NEED_ISO_OEM_INIT 323 prepare_ISO_OEM_translat(__G); 324#endif 325 326/*--------------------------------------------------------------------------- 327 Initialize the internal flag holding the mode of processing "overwrite 328 existing file" cases. We do not use the calling interface flags directly 329 because the overwrite mode may be changed by user interaction while 330 processing archive files. Such a change should not affect the option 331 settings as passed through the DLL calling interface. 332 In case of conflicting options, the 'safer' flag uO.overwrite_none takes 333 precedence. 334 ---------------------------------------------------------------------------*/ 335 G.overwrite_mode = (uO.overwrite_none ? OVERWRT_NEVER : 336 (uO.overwrite_all ? OVERWRT_ALWAYS : OVERWRT_QUERY)); 337 338/*--------------------------------------------------------------------------- 339 Match (possible) wildcard zipfile specification with existing files and 340 attempt to process each. If no hits, try again after appending ".zip" 341 suffix. If still no luck, give up. 342 ---------------------------------------------------------------------------*/ 343 344#ifdef SFX 345 if ((error = do_seekable(__G__ 0)) == PK_NOZIP) { 346#ifdef EXE_EXTENSION 347 int len=strlen(G.argv0); 348 349 /* append .exe if appropriate; also .sfx? */ 350 if ( (G.zipfn = (char *)malloc(len+sizeof(EXE_EXTENSION))) != 351 (char *)NULL ) { 352 strcpy(G.zipfn, G.argv0); 353 strcpy(G.zipfn+len, EXE_EXTENSION); 354 error = do_seekable(__G__ 0); 355 free(G.zipfn); 356 G.zipfn = G.argv0; /* for "cannot find myself" message only */ 357 } 358#endif /* EXE_EXTENSION */ 359#ifdef WIN32 360 G.zipfn = G.argv0; /* for "cannot find myself" message only */ 361#endif 362 } 363 if (error) { 364 if (error == IZ_DIR) 365 error_in_archive = PK_NOZIP; 366 else 367 error_in_archive = error; 368 if (error == PK_NOZIP) 369 Info(slide, 1, ((char *)slide, LoadFarString(CannotFindMyself), 370 G.zipfn)); 371 } 372#ifdef CHEAP_SFX_AUTORUN 373 if (G.autorun_command[0] && !uO.qflag) { /* NO autorun without prompt! */ 374 Info(slide, 0x81, ((char *)slide, LoadFarString(AutorunPrompt), 375 FnFilter1(G.autorun_command))); 376 if (fgets(G.answerbuf, 9, stdin) != (char *)NULL 377 && toupper(*G.answerbuf) == 'Y') 378 system(G.autorun_command); 379 else 380 Info(slide, 1, ((char *)slide, LoadFarString(NotAutoRunning))); 381 } 382#endif /* CHEAP_SFX_AUTORUN */ 383 384#else /* !SFX */ 385 NumWinFiles = NumLoseFiles = NumWarnFiles = 0; 386 NumMissDirs = NumMissFiles = 0; 387 388 while ((G.zipfn = do_wild(__G__ G.wildzipfn)) != (char *)NULL) { 389 Trace((stderr, "do_wild( %s ) returns %s\n", G.wildzipfn, G.zipfn)); 390 391 lastzipfn = G.zipfn; 392 393 /* print a blank line between the output of different zipfiles */ 394 if (!uO.qflag && error != PK_NOZIP && error != IZ_DIR 395#ifdef TIMESTAMP 396 && (!uO.T_flag || uO.zipinfo_mode) 397#endif 398 && (NumWinFiles+NumLoseFiles+NumWarnFiles+NumMissFiles) > 0) 399 (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); 400 401 if ((error = do_seekable(__G__ 0)) == PK_WARN) 402 ++NumWarnFiles; 403 else if (error == IZ_DIR) 404 ++NumMissDirs; 405 else if (error == PK_NOZIP) 406 ++NumMissFiles; 407 else if (error != PK_OK) 408 ++NumLoseFiles; 409 else 410 ++NumWinFiles; 411 412 Trace((stderr, "do_seekable(0) returns %d\n", error)); 413 if (error != IZ_DIR && error > error_in_archive) 414 error_in_archive = error; 415#ifdef WINDLL 416 if (error == IZ_CTRLC) { 417 free_G_buffers(__G); 418 return error; 419 } 420#endif 421 422 } /* end while-loop (wildcard zipfiles) */ 423 424 if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0 && 425 (NumMissDirs + NumMissFiles) == 1 && lastzipfn != (char *)NULL) 426 { 427#if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */ 428 if (iswild(G.wildzipfn)) { 429 if (iswild(lastzipfn)) { 430 NumMissDirs = NumMissFiles = 0; 431 error_in_archive = PK_COOL; 432 if (uO.qflag < 3) 433 Info(slide, 0x401, ((char *)slide, 434 LoadFarString(CannotFindWildcardMatch), 435 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), 436 G.wildzipfn)); 437 } 438 } else 439#endif 440 { 441#ifndef VMS 442 /* 2004-11-24 SMS. 443 * VMS has already tried a default file type of ".zip" in 444 * do_wild(), so adding ZSUFX here only causes confusion by 445 * corrupting some valid (though nonexistent) file names. 446 * Complaining below about "fred;4.zip" is unlikely to be 447 * helpful to the victim. 448 */ 449 /* 2005-08-14 Chr. Spieler 450 * Although we already "know" the failure result, we call 451 * do_seekable() again with the same zipfile name (and the 452 * lastchance flag set), just to trigger the error report... 453 */ 454#if defined(UNIX) || defined(QDOS) 455 char *p = 456#endif 457 strcpy(lastzipfn + strlen(lastzipfn), ZSUFX); 458#endif /* !VMS */ 459 460 G.zipfn = lastzipfn; 461 462 NumMissDirs = NumMissFiles = 0; 463 error_in_archive = PK_COOL; 464 465#if defined(UNIX) || defined(QDOS) 466 /* only Unix has case-sensitive filesystems */ 467 /* Well FlexOS (sometimes) also has them, but support is per media */ 468 /* and a pig to code for, so treat as case insensitive for now */ 469 /* we do this under QDOS to check for .zip as well as _zip */ 470 if ((error = do_seekable(__G__ 0)) == PK_NOZIP || error == IZ_DIR) { 471 if (error == IZ_DIR) 472 ++NumMissDirs; 473 strcpy(p, ALT_ZSUFX); 474 error = do_seekable(__G__ 1); 475 } 476#else 477 error = do_seekable(__G__ 1); 478#endif 479 Trace((stderr, "do_seekable(1) returns %d\n", error)); 480 switch (error) { 481 case PK_WARN: 482 ++NumWarnFiles; 483 break; 484 case IZ_DIR: 485 ++NumMissDirs; 486 error = PK_NOZIP; 487 break; 488 case PK_NOZIP: 489 /* increment again => bug: 490 "1 file had no zipfile directory." */ 491 /* ++NumMissFiles */ ; 492 break; 493 default: 494 if (error) 495 ++NumLoseFiles; 496 else 497 ++NumWinFiles; 498 break; 499 } 500 501 if (error > error_in_archive) 502 error_in_archive = error; 503#ifdef WINDLL 504 if (error == IZ_CTRLC) { 505 free_G_buffers(__G); 506 return error; 507 } 508#endif 509 } 510 } 511#endif /* ?SFX */ 512 513/*--------------------------------------------------------------------------- 514 Print summary of all zipfiles, assuming zipfile spec was a wildcard (no 515 need for a summary if just one zipfile). 516 ---------------------------------------------------------------------------*/ 517 518#ifndef SFX 519 if (iswild(G.wildzipfn) && uO.qflag < 3 520#ifdef TIMESTAMP 521 && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag > 1) 522#endif 523 ) 524 { 525 if ((NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1) 526#ifdef TIMESTAMP 527 && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag) 528#endif 529 && !(uO.tflag && uO.qflag > 1)) 530 (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0x401); 531 if ((NumWinFiles > 1) || 532 (NumWinFiles == 1 && 533 NumMissDirs + NumMissFiles + NumLoseFiles + NumWarnFiles > 0)) 534 Info(slide, 0x401, ((char *)slide, LoadFarString(FilesProcessOK), 535 NumWinFiles, (NumWinFiles == 1)? " was" : "s were")); 536 if (NumWarnFiles > 0) 537 Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveWarning), 538 NumWarnFiles, (NumWarnFiles == 1)? "" : "s")); 539 if (NumLoseFiles > 0) 540 Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveFatalError), 541 NumLoseFiles, (NumLoseFiles == 1)? "" : "s")); 542 if (NumMissFiles > 0) 543 Info(slide, 0x401, ((char *)slide, 544 LoadFarString(FileHadNoZipfileDir), NumMissFiles, 545 (NumMissFiles == 1)? "" : "s")); 546 if (NumMissDirs == 1) 547 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileWasDir))); 548 else if (NumMissDirs > 0) 549 Info(slide, 0x401, ((char *)slide, 550 LoadFarString(ManyZipfilesWereDir), NumMissDirs)); 551 if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0) 552 Info(slide, 0x401, ((char *)slide, LoadFarString(NoZipfileFound))); 553 } 554#endif /* !SFX */ 555 556 /* free allocated memory */ 557 free_G_buffers(__G); 558 559 return error_in_archive; 560 561} /* end function process_zipfiles() */ 562 563 564 565 566 567/*****************************/ 568/* Function free_G_buffers() */ 569/*****************************/ 570 571void free_G_buffers(__G) /* releases all memory allocated in global vars */ 572 __GDEF 573{ 574#ifndef SFX 575 unsigned i; 576#endif 577 578#ifdef SYSTEM_SPECIFIC_DTOR 579 SYSTEM_SPECIFIC_DTOR(__G); 580#endif 581 582 inflate_free(__G); 583 checkdir(__G__ (char *)NULL, END); 584 585#ifdef DYNALLOC_CRCTAB 586 if (CRC_32_TAB) { 587 free_crc_table(); 588 CRC_32_TAB = NULL; 589 } 590#endif 591 592 if (G.key != (char *)NULL) { 593 free(G.key); 594 G.key = (char *)NULL; 595 } 596 597 if (G.extra_field != (uch *)NULL) { 598 free(G.extra_field); 599 G.extra_field = (uch *)NULL; 600 } 601 602#if (!defined(VMS) && !defined(SMALL_MEM)) 603 /* VMS uses its own buffer scheme for textmode flush() */ 604 if (G.outbuf2) { 605 free(G.outbuf2); /* malloc'd ONLY if unshrink and -a */ 606 G.outbuf2 = (uch *)NULL; 607 } 608#endif 609 610 if (G.outbuf) 611 free(G.outbuf); 612 if (G.inbuf) 613 free(G.inbuf); 614 G.inbuf = G.outbuf = (uch *)NULL; 615 616#ifdef UNICODE_SUPPORT 617 if (G.filename_full) { 618 free(G.filename_full); 619 G.filename_full = (char *)NULL; 620 G.fnfull_bufsize = 0; 621 } 622#endif /* UNICODE_SUPPORT */ 623 624#ifndef SFX 625 for (i = 0; i < DIR_BLKSIZ; i++) { 626 if (G.info[i].cfilname != (char Far *)NULL) { 627 zffree(G.info[i].cfilname); 628 G.info[i].cfilname = (char Far *)NULL; 629 } 630 } 631#endif 632 633#ifdef MALLOC_WORK 634 if (G.area.Slide) { 635 free(G.area.Slide); 636 G.area.Slide = (uch *)NULL; 637 } 638#endif 639 640} /* end function free_G_buffers() */ 641 642 643 644 645 646/**************************/ 647/* Function do_seekable() */ 648/**************************/ 649 650static int do_seekable(__G__ lastchance) /* return PK-type error code */ 651 __GDEF 652 int lastchance; 653{ 654#ifndef SFX 655 /* static int no_ecrec = FALSE; SKM: moved to globals.h */ 656 int maybe_exe=FALSE; 657 int too_weird_to_continue=FALSE; 658#ifdef TIMESTAMP 659 time_t uxstamp; 660 ulg nmember = 0L; 661#endif 662#endif 663 int error=0, error_in_archive; 664 665 666/*--------------------------------------------------------------------------- 667 Open the zipfile for reading in BINARY mode to prevent CR/LF translation, 668 which would corrupt the bit streams. 669 ---------------------------------------------------------------------------*/ 670 671 if (SSTAT(G.zipfn, &G.statbuf) || 672#ifdef THEOS 673 (error = S_ISLIB(G.statbuf.st_mode)) != 0 || 674#endif 675 (error = S_ISDIR(G.statbuf.st_mode)) != 0) 676 { 677#ifndef SFX 678 if (lastchance && (uO.qflag < 3)) { 679#if defined(UNIX) || defined(QDOS) 680 if (G.no_ecrec) 681 Info(slide, 1, ((char *)slide, 682 LoadFarString(CannotFindZipfileDirMsg), 683 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), 684 G.wildzipfn, uO.zipinfo_mode? " " : "", G.wildzipfn, 685 G.zipfn)); 686 else 687 Info(slide, 1, ((char *)slide, 688 LoadFarString(CannotFindEitherZipfile), 689 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), 690 G.wildzipfn, G.wildzipfn, G.zipfn)); 691#else /* !(UNIX || QDOS) */ 692 if (G.no_ecrec) 693 Info(slide, 0x401, ((char *)slide, 694 LoadFarString(CannotFindZipfileDirMsg), 695 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), 696 G.wildzipfn, uO.zipinfo_mode? " " : "", G.zipfn)); 697 else 698#ifdef VMS 699 Info(slide, 0x401, ((char *)slide, 700 LoadFarString(CannotFindEitherZipfile), 701 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), 702 G.wildzipfn, 703 (*G.zipfn ? G.zipfn : vms_msg_text()))); 704#else /* !VMS */ 705 Info(slide, 0x401, ((char *)slide, 706 LoadFarString(CannotFindEitherZipfile), 707 LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), 708 G.wildzipfn, G.zipfn)); 709#endif /* ?VMS */ 710#endif /* ?(UNIX || QDOS) */ 711 } 712#endif /* !SFX */ 713 return error? IZ_DIR : PK_NOZIP; 714 } 715 G.ziplen = G.statbuf.st_size; 716 717#ifndef SFX 718#if defined(UNIX) || defined(DOS_OS2_W32) || defined(THEOS) 719 if (G.statbuf.st_mode & S_IEXEC) /* no extension on Unix exes: might */ 720 maybe_exe = TRUE; /* find unzip, not unzip.zip; etc. */ 721#endif 722#endif /* !SFX */ 723 724#ifdef VMS 725 if (check_format(__G)) /* check for variable-length format */ 726 return PK_ERR; 727#endif 728 729 if (open_input_file(__G)) /* this should never happen, given */ 730 return PK_NOZIP; /* the stat() test above, but... */ 731 732#ifdef DO_SAFECHECK_2GB 733 /* Need more care: Do not trust the size returned by stat() but 734 determine it by reading beyond the end of the file. */ 735 G.ziplen = file_size(G.zipfd); 736 737 if (G.ziplen == EOF) { 738 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileTooBig))); 739 /* 740 printf( 741" We need a better error message for: 64-bit file, 32-bit program.\n"); 742 */ 743 CLOSE_INFILE(); 744 return IZ_ERRBF; 745 } 746#endif /* DO_SAFECHECK_2GB */ 747 748/*--------------------------------------------------------------------------- 749 Find and process the end-of-central-directory header. UnZip need only 750 check last 65557 bytes of zipfile: comment may be up to 65535, end-of- 751 central-directory record is 18 bytes, and signature itself is 4 bytes; 752 add some to allow for appended garbage. Since ZipInfo is often used as 753 a debugging tool, search the whole zipfile if zipinfo_mode is true. 754 ---------------------------------------------------------------------------*/ 755 756 G.cur_zipfile_bufstart = 0; 757 G.inptr = G.inbuf; 758 759#if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO)) 760# if (!defined(WINDLL) && !defined(SFX)) 761 if ( (!uO.zipinfo_mode && !uO.qflag 762# ifdef TIMESTAMP 763 && !uO.T_flag 764# endif 765 ) 766# ifndef NO_ZIPINFO 767 || (uO.zipinfo_mode && uO.hflag) 768# endif 769 ) 770# else /* not (!WINDLL && !SFX) ==> !NO_ZIPINFO !! */ 771 if (uO.zipinfo_mode && uO.hflag) 772# endif /* if..else..: (!WINDLL && !SFX) */ 773# ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */ 774 Info(slide, 0, ((char *)slide, LoadFarString(LogInitline), 775 FnFilter1(G.zipfn))); 776# else 777 Info(slide, 0, ((char *)slide, LoadFarString(LogInitline), G.zipfn)); 778# endif 779#endif /* (!WINDLL && !SFX) || !NO_ZIPINFO */ 780 781 if ( (error_in_archive = find_ecrec(__G__ 782#ifndef NO_ZIPINFO 783 uO.zipinfo_mode ? G.ziplen : 784#endif 785 MIN(G.ziplen, 66000L))) 786 > PK_WARN ) 787 { 788 CLOSE_INFILE(); 789 790#ifdef SFX 791 ++lastchance; /* avoid picky compiler warnings */ 792 return error_in_archive; 793#else 794 if (maybe_exe) 795 Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeExe), 796 G.zipfn)); 797 if (lastchance) 798 return error_in_archive; 799 else { 800 G.no_ecrec = TRUE; /* assume we found wrong file: e.g., */ 801 return PK_NOZIP; /* unzip instead of unzip.zip */ 802 } 803#endif /* ?SFX */ 804 } 805 806 if ((uO.zflag > 0) && !uO.zipinfo_mode) { /* unzip: zflag = comment ONLY */ 807 CLOSE_INFILE(); 808 return error_in_archive; 809 } 810 811/*--------------------------------------------------------------------------- 812 Test the end-of-central-directory info for incompatibilities (multi-disk 813 archives) or inconsistencies (missing or extra bytes in zipfile). 814 ---------------------------------------------------------------------------*/ 815 816#ifdef NO_MULTIPART 817 error = !uO.zipinfo_mode && (G.ecrec.number_this_disk == 1) && 818 (G.ecrec.num_disk_start_cdir == 1); 819#else 820 error = !uO.zipinfo_mode && (G.ecrec.number_this_disk != 0); 821#endif 822 823#ifndef SFX 824 if (uO.zipinfo_mode && 825 G.ecrec.number_this_disk != G.ecrec.num_disk_start_cdir) 826 { 827 if (G.ecrec.number_this_disk > G.ecrec.num_disk_start_cdir) { 828 Info(slide, 0x401, ((char *)slide, 829 LoadFarString(CentDirNotInZipMsg), G.zipfn, 830 (ulg)G.ecrec.number_this_disk, 831 (ulg)G.ecrec.num_disk_start_cdir)); 832 error_in_archive = PK_FIND; 833 too_weird_to_continue = TRUE; 834 } else { 835 Info(slide, 0x401, ((char *)slide, 836 LoadFarString(EndCentDirBogus), G.zipfn, 837 (ulg)G.ecrec.number_this_disk, 838 (ulg)G.ecrec.num_disk_start_cdir)); 839 error_in_archive = PK_WARN; 840 } 841#ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */ 842 } else if (!uO.zipinfo_mode && !error && G.ecrec.number_this_disk != 0) { 843 Info(slide, 0x401, ((char *)slide, LoadFarString(NoMultiDiskArcSupport), 844 G.zipfn)); 845 error_in_archive = PK_FIND; 846 too_weird_to_continue = TRUE; 847#endif 848 } 849 850 if (!too_weird_to_continue) { /* (relatively) normal zipfile: go for it */ 851 if (error) { 852 Info(slide, 0x401, ((char *)slide, LoadFarString(MaybePakBug), 853 G.zipfn)); 854 error_in_archive = PK_WARN; 855 } 856#endif /* !SFX */ 857 if ((G.extra_bytes = G.real_ecrec_offset-G.expect_ecrec_offset) < 858 (zoff_t)0) 859 { 860 Info(slide, 0x401, ((char *)slide, LoadFarString(MissingBytes), 861 G.zipfn, FmZofft((-G.extra_bytes), NULL, NULL))); 862 error_in_archive = PK_ERR; 863 } else if (G.extra_bytes > 0) { 864 if ((G.ecrec.offset_start_central_directory == 0) && 865 (G.ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */ 866 { 867 Info(slide, 0x401, ((char *)slide, 868 LoadFarString(NullCentDirOffset), G.zipfn)); 869 G.ecrec.offset_start_central_directory = G.extra_bytes; 870 G.extra_bytes = 0; 871 error_in_archive = PK_ERR; 872 } 873#ifndef SFX 874 else { 875 Info(slide, 0x401, ((char *)slide, 876 LoadFarString(ExtraBytesAtStart), G.zipfn, 877 FmZofft(G.extra_bytes, NULL, NULL), 878 (G.extra_bytes == 1)? "":"s")); 879 error_in_archive = PK_WARN; 880 } 881#endif /* !SFX */ 882 } 883 884 /*----------------------------------------------------------------------- 885 Check for empty zipfile and exit now if so. 886 -----------------------------------------------------------------------*/ 887 888 if (G.expect_ecrec_offset==0L && G.ecrec.size_central_directory==0) { 889 if (uO.zipinfo_mode) 890 Info(slide, 0, ((char *)slide, "%sEmpty zipfile.\n", 891 uO.lflag>9? "\n " : "")); 892 else 893 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileEmpty), 894 G.zipfn)); 895 CLOSE_INFILE(); 896 return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN; 897 } 898 899 /*----------------------------------------------------------------------- 900 Compensate for missing or extra bytes, and seek to where the start 901 of central directory should be. If header not found, uncompensate 902 and try again (necessary for at least some Atari archives created 903 with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1). 904 -----------------------------------------------------------------------*/ 905 906 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); 907 if (error == PK_BADERR) { 908 CLOSE_INFILE(); 909 return PK_BADERR; 910 } 911#ifdef OLD_SEEK_TEST 912 if (error != PK_OK || readbuf(__G__ G.sig, 4) == 0) { 913 CLOSE_INFILE(); 914 return PK_ERR; /* file may be locked, or possibly disk error(?) */ 915 } 916 if (memcmp(G.sig, central_hdr_sig, 4)) 917#else 918 if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) || 919 memcmp(G.sig, central_hdr_sig, 4)) 920#endif 921 { 922#ifndef SFX 923 zoff_t tmp = G.extra_bytes; 924#endif 925 926 G.extra_bytes = 0; 927 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); 928 if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) || 929 memcmp(G.sig, central_hdr_sig, 4)) 930 { 931 if (error != PK_BADERR) 932 Info(slide, 0x401, ((char *)slide, 933 LoadFarString(CentDirStartNotFound), G.zipfn, 934 LoadFarStringSmall(ReportMsg))); 935 CLOSE_INFILE(); 936 return (error != PK_OK ? error : PK_BADERR); 937 } 938#ifndef SFX 939 Info(slide, 0x401, ((char *)slide, LoadFarString(CentDirTooLong), 940 G.zipfn, FmZofft((-tmp), NULL, NULL))); 941#endif 942 error_in_archive = PK_ERR; 943 } 944 945 /*----------------------------------------------------------------------- 946 Seek to the start of the central directory one last time, since we 947 have just read the first entry's signature bytes; then list, extract 948 or test member files as instructed, and close the zipfile. 949 -----------------------------------------------------------------------*/ 950 951 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); 952 if (error != PK_OK) { 953 CLOSE_INFILE(); 954 return error; 955 } 956 957 Trace((stderr, "about to extract/list files (error = %d)\n", 958 error_in_archive)); 959 960#ifdef DLL 961 /* G.fValidate is used only to look at an archive to see if 962 it appears to be a valid archive. There is no interest 963 in what the archive contains, nor in validating that the 964 entries in the archive are in good condition. This is 965 currently used only in the Windows DLLs for purposes of 966 checking archives within an archive to determine whether 967 or not to display the inner archives. 968 */ 969 if (!G.fValidate) 970#endif 971 { 972#ifndef NO_ZIPINFO 973 if (uO.zipinfo_mode) 974 error = zipinfo(__G); /* ZIPINFO 'EM */ 975 else 976#endif 977#ifndef SFX 978#ifdef TIMESTAMP 979 if (uO.T_flag) 980 error = get_time_stamp(__G__ &uxstamp, &nmember); 981 else 982#endif 983 if (uO.vflag && !uO.tflag && !uO.cflag) 984 error = list_files(__G); /* LIST 'EM */ 985 else 986#endif /* !SFX */ 987 error = extract_or_test_files(__G); /* EXTRACT OR TEST 'EM */ 988 989 Trace((stderr, "done with extract/list files (error = %d)\n", 990 error)); 991 } 992 993 if (error > error_in_archive) /* don't overwrite stronger error */ 994 error_in_archive = error; /* with (for example) a warning */ 995#ifndef SFX 996 } /* end if (!too_weird_to_continue) */ 997#endif 998 999 CLOSE_INFILE(); 1000 1001#ifdef TIMESTAMP 1002 if (uO.T_flag && !uO.zipinfo_mode && (nmember > 0L)) { 1003# ifdef WIN32 1004 if (stamp_file(__G__ G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */ 1005# else 1006 if (stamp_file(G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */ 1007# endif 1008 if (uO.qflag < 3) 1009 Info(slide, 0x201, ((char *)slide, 1010 LoadFarString(ZipTimeStampFailed), G.zipfn)); 1011 if (error_in_archive < PK_WARN) 1012 error_in_archive = PK_WARN; 1013 } else { 1014 if (!uO.qflag) 1015 Info(slide, 0, ((char *)slide, 1016 LoadFarString(ZipTimeStampSuccess), G.zipfn)); 1017 } 1018 } 1019#endif 1020 return error_in_archive; 1021 1022} /* end function do_seekable() */ 1023 1024 1025 1026 1027#ifdef DO_SAFECHECK_2GB 1028/************************/ 1029/* Function file_size() */ 1030/************************/ 1031/* File size determination which does not mislead for large files in a 1032 small-file program. Probably should be somewhere else. 1033 The file has to be opened previously 1034*/ 1035#ifdef USE_STRM_INPUT 1036static zoff_t file_size(file) 1037 FILE *file; 1038{ 1039 int sts; 1040 size_t siz; 1041#else /* !USE_STRM_INPUT */ 1042static zoff_t file_size(fh) 1043 int fh; 1044{ 1045 int siz; 1046#endif /* ?USE_STRM_INPUT */ 1047 zoff_t ofs; 1048 char waste[4]; 1049 1050#ifdef USE_STRM_INPUT 1051 /* Seek to actual EOF. */ 1052 sts = zfseeko(file, 0, SEEK_END); 1053 if (sts != 0) { 1054 /* fseeko() failed. (Unlikely.) */ 1055 ofs = EOF; 1056 } else { 1057 /* Get apparent offset at EOF. */ 1058 ofs = zftello(file); 1059 if (ofs < 0) { 1060 /* Offset negative (overflow). File too big. */ 1061 ofs = EOF; 1062 } else { 1063 /* Seek to apparent EOF offset. 1064 Won't be at actual EOF if offset was truncated. 1065 */ 1066 sts = zfseeko(file, ofs, SEEK_SET); 1067 if (sts != 0) { 1068 /* fseeko() failed. (Unlikely.) */ 1069 ofs = EOF; 1070 } else { 1071 /* Read a byte at apparent EOF. Should set EOF flag. */ 1072 siz = fread(waste, 1, 1, file); 1073 if (feof(file) == 0) { 1074 /* Not at EOF, but should be. File too big. */ 1075 ofs = EOF; 1076 } 1077 } 1078 } 1079 } 1080#else /* !USE_STRM_INPUT */ 1081 /* Seek to actual EOF. */ 1082 ofs = zlseek(fh, 0, SEEK_END); 1083 if (ofs == (zoff_t) -1) { 1084 /* zlseek() failed. (Unlikely.) */ 1085 ofs = EOF; 1086 } else if (ofs < 0) { 1087 /* Offset negative (overflow). File too big. */ 1088 ofs = EOF; 1089 } else { 1090 /* Seek to apparent EOF offset. 1091 Won't be at actual EOF if offset was truncated. 1092 */ 1093 ofs = zlseek(fh, ofs, SEEK_SET); 1094 if (ofs == (zoff_t) -1) { 1095 /* zlseek() failed. (Unlikely.) */ 1096 ofs = EOF; 1097 } else { 1098 /* Read a byte at apparent EOF. Should set EOF flag. */ 1099 siz = read(fh, waste, 1); 1100 if (siz != 0) { 1101 /* Not at EOF, but should be. File too big. */ 1102 ofs = EOF; 1103 } 1104 } 1105 } 1106#endif /* ?USE_STRM_INPUT */ 1107 return ofs; 1108} /* end function file_size() */ 1109#endif /* DO_SAFECHECK_2GB */ 1110 1111 1112 1113 1114/***********************/ 1115/* Function rec_find() */ 1116/***********************/ 1117 1118static int rec_find(__G__ searchlen, signature, rec_size) 1119 /* return 0 when rec found, 1 when not found, 2 in case of read error */ 1120 __GDEF 1121 zoff_t searchlen; 1122 char* signature; 1123 int rec_size; 1124{ 1125 int i, numblks, found=FALSE; 1126 zoff_t tail_len; 1127 1128/*--------------------------------------------------------------------------- 1129 Zipfile is longer than INBUFSIZ: may need to loop. Start with short 1130 block at end of zipfile (if not TOO short). 1131 ---------------------------------------------------------------------------*/ 1132 1133 if ((tail_len = G.ziplen % INBUFSIZ) > rec_size) { 1134#ifdef USE_STRM_INPUT 1135 zfseeko(G.zipfd, G.ziplen-tail_len, SEEK_SET); 1136 G.cur_zipfile_bufstart = zftello(G.zipfd); 1137#else /* !USE_STRM_INPUT */ 1138 G.cur_zipfile_bufstart = zlseek(G.zipfd, G.ziplen-tail_len, SEEK_SET); 1139#endif /* ?USE_STRM_INPUT */ 1140 if ((G.incnt = read(G.zipfd, (char *)G.inbuf, 1141 (unsigned int)tail_len)) != (int)tail_len) 1142 return 2; /* it's expedient... */ 1143 1144 /* 'P' must be at least (rec_size+4) bytes from end of zipfile */ 1145 for (G.inptr = G.inbuf+(int)tail_len-(rec_size+4); 1146 G.inptr >= G.inbuf; 1147 --G.inptr) { 1148 if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ 1149 !memcmp((char *)G.inptr, signature, 4) ) { 1150 G.incnt -= (int)(G.inptr - G.inbuf); 1151 found = TRUE; 1152 break; 1153 } 1154 } 1155 /* sig may span block boundary: */ 1156 memcpy((char *)G.hold, (char *)G.inbuf, 3); 1157 } else 1158 G.cur_zipfile_bufstart = G.ziplen - tail_len; 1159 1160/*----------------------------------------------------------------------- 1161 Loop through blocks of zipfile data, starting at the end and going 1162 toward the beginning. In general, need not check whole zipfile for 1163 signature, but may want to do so if testing. 1164 -----------------------------------------------------------------------*/ 1165 1166 numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ); 1167 /* ==amount= ==done== ==rounding== =blksiz= */ 1168 1169 for (i = 1; !found && (i <= numblks); ++i) { 1170 G.cur_zipfile_bufstart -= INBUFSIZ; 1171#ifdef USE_STRM_INPUT 1172 zfseeko(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET); 1173#else /* !USE_STRM_INPUT */ 1174 zlseek(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET); 1175#endif /* ?USE_STRM_INPUT */ 1176 if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ)) 1177 != INBUFSIZ) 1178 return 2; /* read error is fatal failure */ 1179 1180 for (G.inptr = G.inbuf+INBUFSIZ-1; G.inptr >= G.inbuf; --G.inptr) 1181 if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ 1182 !memcmp((char *)G.inptr, signature, 4) ) { 1183 G.incnt -= (int)(G.inptr - G.inbuf); 1184 found = TRUE; 1185 break; 1186 } 1187 /* sig may span block boundary: */ 1188 memcpy((char *)G.hold, (char *)G.inbuf, 3); 1189 } 1190 return (found ? 0 : 1); 1191} /* end function rec_find() */ 1192 1193 1194 1195 1196#if 0 1197/********************************/ 1198/* Function check_ecrec_zip64() */ 1199/********************************/ 1200 1201static int check_ecrec_zip64(__G) 1202 __GDEF 1203{ 1204 return G.ecrec.offset_start_central_directory == 0xFFFFFFFFL 1205 || G.ecrec.size_central_directory == 0xFFFFFFFFL 1206 || G.ecrec.total_entries_central_dir == 0xFFFF 1207 || G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF 1208 || G.ecrec.num_disk_start_cdir == 0xFFFF 1209 || G.ecrec.number_this_disk == 0xFFFF; 1210} /* end function check_ecrec_zip64() */ 1211#endif /* never */ 1212 1213 1214 1215/***************************/ 1216/* Function find_ecrec64() */ 1217/***************************/ 1218 1219static int find_ecrec64(__G__ searchlen) /* return PK-class error */ 1220 __GDEF 1221 zoff_t searchlen; 1222{ 1223 ec_byte_rec64 byterec; /* buf for ecrec64 */ 1224 ec_byte_loc64 byterecL; /* buf for ecrec64 locator */ 1225 zoff_t ecloc64_start_offset; /* start offset of ecrec64 locator */ 1226 zusz_t ecrec64_start_offset; /* start offset of ecrec64 */ 1227 zuvl_t ecrec64_start_disk; /* start disk of ecrec64 */ 1228 zuvl_t ecloc64_total_disks; /* total disks */ 1229 zuvl_t ecrec64_disk_cdstart; /* disk number of central dir start */ 1230 zucn_t ecrec64_this_entries; /* entries on disk with ecrec64 */ 1231 zucn_t ecrec64_tot_entries; /* total number of entries */ 1232 zusz_t ecrec64_cdirsize; /* length of central dir */ 1233 zusz_t ecrec64_offs_cdstart; /* offset of central dir start */ 1234 1235 /* First, find the ecrec64 locator. By definition, this must be before 1236 ecrec with nothing in between. We back up the size of the ecrec64 1237 locator and check. */ 1238 1239 ecloc64_start_offset = G.real_ecrec_offset - (ECLOC64_SIZE+4); 1240 if (ecloc64_start_offset < 0) 1241 /* Seeking would go past beginning, so probably empty archive */ 1242 return PK_COOL; 1243 1244#ifdef USE_STRM_INPUT 1245 zfseeko(G.zipfd, ecloc64_start_offset, SEEK_SET); 1246 G.cur_zipfile_bufstart = zftello(G.zipfd); 1247#else /* !USE_STRM_INPUT */ 1248 G.cur_zipfile_bufstart = zlseek(G.zipfd, ecloc64_start_offset, SEEK_SET); 1249#endif /* ?USE_STRM_INPUT */ 1250 1251 if ((G.incnt = read(G.zipfd, (char *)byterecL, ECLOC64_SIZE+4)) 1252 != (ECLOC64_SIZE+4)) { 1253 if (uO.qflag || uO.zipinfo_mode) 1254 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); 1255 Info(slide, 0x401, ((char *)slide, 1256 LoadFarString(Cent64EndSigSearchErr))); 1257 return PK_ERR; 1258 } 1259 1260 if (memcmp((char *)byterecL, end_centloc64_sig, 4) ) { 1261 /* not found */ 1262 return PK_COOL; 1263 } 1264 1265 /* Read the locator. */ 1266 ecrec64_start_disk = (zuvl_t)makelong(&byterecL[NUM_DISK_START_EOCDR64]); 1267 ecrec64_start_offset = (zusz_t)makeint64(&byterecL[OFFSET_START_EOCDR64]); 1268 ecloc64_total_disks = (zuvl_t)makelong(&byterecL[NUM_THIS_DISK_LOC64]); 1269 1270 /* Check for consistency */ 1271#ifdef TEST 1272 fprintf(stdout,"\nnumber of disks (ECR) %u, (ECLOC64) %lu\n", 1273 G.ecrec.number_this_disk, ecloc64_total_disks); fflush(stdout); 1274#endif 1275 if ((G.ecrec.number_this_disk != 0xFFFF) && 1276 (G.ecrec.number_this_disk != ecloc64_total_disks - 1)) { 1277 /* Note: For some unknown reason, the developers at PKWARE decided to 1278 store the "zip64 total disks" value as a counter starting from 1, 1279 whereas all other "split/span volume" related fields use 0-based 1280 volume numbers. Sigh... */ 1281 /* When the total number of disks as found in the traditional ecrec 1282 is not 0xFFFF, the disk numbers in ecrec and ecloc64 must match. 1283 When this is not the case, the found ecrec64 locator cannot be valid. 1284 -> This is not a Zip64 archive. 1285 */ 1286 Trace((stderr, 1287 "\ninvalid ECLOC64, differing disk# (ECR %u, ECL64 %lu)\n", 1288 G.ecrec.number_this_disk, ecloc64_total_disks - 1)); 1289 return PK_COOL; 1290 } 1291 1292 /* If found locator, look for ecrec64 where the locator says it is. */ 1293 1294 /* For now assume that ecrec64 is on the same disk as ecloc64 and ecrec, 1295 which is usually the case and is how Zip writes it. To do this right, 1296 however, we should allow the ecrec64 to be on another disk since 1297 the AppNote allows it and the ecrec64 can be large, especially if 1298 Version 2 is used (AppNote uses 8 bytes for the size of this record). */ 1299 1300 /* FIX BELOW IF ADD SUPPORT FOR MULTIPLE DISKS */ 1301 1302 if (ecrec64_start_offset > (zusz_t)ecloc64_start_offset) { 1303 /* ecrec64 has to be before ecrec64 locator */ 1304 if (uO.qflag || uO.zipinfo_mode) 1305 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); 1306 Info(slide, 0x401, ((char *)slide, 1307 LoadFarString(Cent64EndSigSearchErr))); 1308 return PK_ERR; 1309 } 1310 1311#ifdef USE_STRM_INPUT 1312 zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET); 1313 G.cur_zipfile_bufstart = zftello(G.zipfd); 1314#else /* !USE_STRM_INPUT */ 1315 G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET); 1316#endif /* ?USE_STRM_INPUT */ 1317 1318 if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4)) 1319 != (ECREC64_SIZE+4)) { 1320 if (uO.qflag || uO.zipinfo_mode) 1321 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); 1322 Info(slide, 0x401, ((char *)slide, 1323 LoadFarString(Cent64EndSigSearchErr))); 1324 return PK_ERR; 1325 } 1326 1327 if (memcmp((char *)byterec, end_central64_sig, 4) ) { 1328 /* Zip64 EOCD Record not found */ 1329 /* Since we already have seen the Zip64 EOCD Locator, it's 1330 possible we got here because there are bytes prepended 1331 to the archive, like the sfx prefix. */ 1332 1333 /* Make a guess as to where the Zip64 EOCD Record might be */ 1334 ecrec64_start_offset = ecloc64_start_offset - ECREC64_SIZE - 4; 1335 1336#ifdef USE_STRM_INPUT 1337 zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET); 1338 G.cur_zipfile_bufstart = zftello(G.zipfd); 1339#else /* !USE_STRM_INPUT */ 1340 G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET); 1341#endif /* ?USE_STRM_INPUT */ 1342 1343 if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4)) 1344 != (ECREC64_SIZE+4)) { 1345 if (uO.qflag || uO.zipinfo_mode) 1346 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); 1347 Info(slide, 0x401, ((char *)slide, 1348 LoadFarString(Cent64EndSigSearchErr))); 1349 return PK_ERR; 1350 } 1351 1352 if (memcmp((char *)byterec, end_central64_sig, 4) ) { 1353 /* Zip64 EOCD Record not found */ 1354 /* Probably something not so easy to handle so exit */ 1355 if (uO.qflag || uO.zipinfo_mode) 1356 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); 1357 Info(slide, 0x401, ((char *)slide, 1358 LoadFarString(Cent64EndSigSearchErr))); 1359 return PK_ERR; 1360 } 1361 1362 if (uO.qflag || uO.zipinfo_mode) 1363 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); 1364 Info(slide, 0x401, ((char *)slide, 1365 LoadFarString(Cent64EndSigSearchOff))); 1366 } 1367 1368 /* Check consistency of found ecrec64 with ecloc64 (and ecrec): */ 1369 if ( (zuvl_t)makelong(&byterec[NUMBER_THIS_DSK_REC64]) 1370 != ecrec64_start_disk ) 1371 /* found ecrec64 does not match ecloc64 info -> no Zip64 archive */ 1372 return PK_COOL; 1373 /* Read all relevant ecrec64 fields and compare them to the corresponding 1374 ecrec fields unless those are set to "all-ones". 1375 */ 1376 ecrec64_disk_cdstart = 1377 (zuvl_t)makelong(&byterec[NUM_DISK_START_CEN_DIR64]); 1378 if ( (G.ecrec.num_disk_start_cdir != 0xFFFF) && 1379 (G.ecrec.num_disk_start_cdir != ecrec64_disk_cdstart) ) 1380 return PK_COOL; 1381 ecrec64_this_entries 1382 = makeint64(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK64]); 1383 if ( (G.ecrec.num_entries_centrl_dir_ths_disk != 0xFFFF) && 1384 (G.ecrec.num_entries_centrl_dir_ths_disk != ecrec64_this_entries) ) 1385 return PK_COOL; 1386 ecrec64_tot_entries 1387 = makeint64(&byterec[TOTAL_ENTRIES_CENTRAL_DIR64]); 1388 if ( (G.ecrec.total_entries_central_dir != 0xFFFF) && 1389 (G.ecrec.total_entries_central_dir != ecrec64_tot_entries) ) 1390 return PK_COOL; 1391 ecrec64_cdirsize 1392 = makeint64(&byterec[SIZE_CENTRAL_DIRECTORY64]); 1393 if ( (G.ecrec.size_central_directory != 0xFFFFFFFFL) && 1394 (G.ecrec.size_central_directory != ecrec64_cdirsize) ) 1395 return PK_COOL; 1396 ecrec64_offs_cdstart 1397 = makeint64(&byterec[OFFSET_START_CENTRAL_DIRECT64]); 1398 if ( (G.ecrec.offset_start_central_directory != 0xFFFFFFFFL) && 1399 (G.ecrec.offset_start_central_directory != ecrec64_offs_cdstart) ) 1400 return PK_COOL; 1401 1402 /* Now, we are (almost) sure that we have a Zip64 archive. */ 1403 G.ecrec.have_ecr64 = 1; 1404 1405 /* Update the "end-of-central-dir offset" for later checks. */ 1406 G.real_ecrec_offset = ecrec64_start_offset; 1407 1408 /* Update all ecdir_rec data that are flagged to be invalid 1409 in Zip64 mode. Set the ecrec64-mandatory flag when such a 1410 case is found. */ 1411 if (G.ecrec.number_this_disk == 0xFFFF) { 1412 G.ecrec.number_this_disk = ecrec64_start_disk; 1413 if (ecrec64_start_disk != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; 1414 } 1415 if (G.ecrec.num_disk_start_cdir == 0xFFFF) { 1416 G.ecrec.num_disk_start_cdir = ecrec64_disk_cdstart; 1417 if (ecrec64_disk_cdstart != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; 1418 } 1419 if (G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF) { 1420 G.ecrec.num_entries_centrl_dir_ths_disk = ecrec64_this_entries; 1421 if (ecrec64_this_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; 1422 } 1423 if (G.ecrec.total_entries_central_dir == 0xFFFF) { 1424 G.ecrec.total_entries_central_dir = ecrec64_tot_entries; 1425 if (ecrec64_tot_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; 1426 } 1427 if (G.ecrec.size_central_directory == 0xFFFFFFFFL) { 1428 G.ecrec.size_central_directory = ecrec64_cdirsize; 1429 if (ecrec64_cdirsize != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE; 1430 } 1431 if (G.ecrec.offset_start_central_directory == 0xFFFFFFFFL) { 1432 G.ecrec.offset_start_central_directory = ecrec64_offs_cdstart; 1433 if (ecrec64_offs_cdstart != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE; 1434 } 1435 1436 return PK_COOL; 1437} /* end function find_ecrec64() */ 1438 1439 1440 1441/*************************/ 1442/* Function find_ecrec() */ 1443/*************************/ 1444 1445static int find_ecrec(__G__ searchlen) /* return PK-class error */ 1446 __GDEF 1447 zoff_t searchlen; 1448{ 1449 int found = FALSE; 1450 int error_in_archive; 1451 int result; 1452 ec_byte_rec byterec; 1453 1454/*--------------------------------------------------------------------------- 1455 Treat case of short zipfile separately. 1456 ---------------------------------------------------------------------------*/ 1457 1458 if (G.ziplen <= INBUFSIZ) { 1459#ifdef USE_STRM_INPUT 1460 zfseeko(G.zipfd, 0L, SEEK_SET); 1461#else /* !USE_STRM_INPUT */ 1462 zlseek(G.zipfd, 0L, SEEK_SET); 1463#endif /* ?USE_STRM_INPUT */ 1464 if ((G.incnt = read(G.zipfd,(char *)G.inbuf,(unsigned int)G.ziplen)) 1465 == (int)G.ziplen) 1466 1467 /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */ 1468 for (G.inptr = G.inbuf+(int)G.ziplen-(ECREC_SIZE+4); 1469 G.inptr >= G.inbuf; 1470 --G.inptr) { 1471 if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ 1472 !memcmp((char *)G.inptr, end_central_sig, 4)) { 1473 G.incnt -= (int)(G.inptr - G.inbuf); 1474 found = TRUE; 1475 break; 1476 } 1477 } 1478 1479/*--------------------------------------------------------------------------- 1480 Zipfile is longer than INBUFSIZ: 1481 1482 MB - this next block of code moved to rec_find so that same code can be 1483 used to look for zip64 ec record. No need to include code above since 1484 a zip64 ec record will only be looked for if it is a BIG file. 1485 ---------------------------------------------------------------------------*/ 1486 1487 } else { 1488 found = 1489 (rec_find(__G__ searchlen, end_central_sig, ECREC_SIZE) == 0 1490 ? TRUE : FALSE); 1491 } /* end if (ziplen > INBUFSIZ) */ 1492 1493/*--------------------------------------------------------------------------- 1494 Searched through whole region where signature should be without finding 1495 it. Print informational message and die a horrible death. 1496 ---------------------------------------------------------------------------*/ 1497 1498 if (!found) { 1499 if (uO.qflag || uO.zipinfo_mode) 1500 Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); 1501 Info(slide, 0x401, ((char *)slide, 1502 LoadFarString(CentDirEndSigNotFound))); 1503 return PK_ERR; /* failed */ 1504 } 1505 1506/*--------------------------------------------------------------------------- 1507 Found the signature, so get the end-central data before returning. Do 1508 any necessary machine-type conversions (byte ordering, structure padding 1509 compensation) by reading data into character array and copying to struct. 1510 ---------------------------------------------------------------------------*/ 1511 1512 G.real_ecrec_offset = G.cur_zipfile_bufstart + (G.inptr-G.inbuf); 1513#ifdef TEST 1514 printf("\n found end-of-central-dir signature at offset %s (%sh)\n", 1515 FmZofft(G.real_ecrec_offset, NULL, NULL), 1516 FmZofft(G.real_ecrec_offset, FZOFFT_HEX_DOT_WID, "X")); 1517 printf(" from beginning of file; offset %d (%.4Xh) within block\n", 1518 G.inptr-G.inbuf, G.inptr-G.inbuf); 1519#endif 1520 1521 if (readbuf(__G__ (char *)byterec, ECREC_SIZE+4) == 0) 1522 return PK_EOF; 1523 1524 G.ecrec.number_this_disk = 1525 makeword(&byterec[NUMBER_THIS_DISK]); 1526 G.ecrec.num_disk_start_cdir = 1527 makeword(&byterec[NUM_DISK_WITH_START_CEN_DIR]); 1528 G.ecrec.num_entries_centrl_dir_ths_disk = 1529 makeword(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK]); 1530 G.ecrec.total_entries_central_dir = 1531 makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]); 1532 G.ecrec.size_central_directory = 1533 makelong(&byterec[SIZE_CENTRAL_DIRECTORY]); 1534 G.ecrec.offset_start_central_directory = 1535 makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]); 1536 G.ecrec.zipfile_comment_length = 1537 makeword(&byterec[ZIPFILE_COMMENT_LENGTH]); 1538 1539 /* Now, we have to read the archive comment, BEFORE the file pointer 1540 is moved away backwards to seek for a Zip64 ECLOC64 structure. 1541 */ 1542 if ( (error_in_archive = process_zip_cmmnt(__G)) > PK_WARN ) 1543 return error_in_archive; 1544 1545 /* Next: Check for existence of Zip64 end-of-cent-dir locator 1546 ECLOC64. This structure must reside on the same volume as the 1547 classic ECREC, at exactly (ECLOC64_SIZE+4) bytes in front 1548 of the ECREC. 1549 The ECLOC64 structure directs to the longer ECREC64 structure 1550 A ECREC64 will ALWAYS exist for a proper Zip64 archive, as 1551 the "Version Needed To Extract" field is required to be set 1552 to 4.5 or higher whenever any Zip64 features are used anywhere 1553 in the archive, so just check for that to see if this is a 1554 Zip64 archive. 1555 */ 1556 result = find_ecrec64(__G__ searchlen+76); 1557 /* 76 bytes for zip64ec & zip64 locator */ 1558 if (result != PK_COOL) { 1559 if (error_in_archive < result) 1560 error_in_archive = result; 1561 return error_in_archive; 1562 } 1563 1564 G.expect_ecrec_offset = G.ecrec.offset_start_central_directory + 1565 G.ecrec.size_central_directory; 1566 1567#ifndef NO_ZIPINFO 1568 if (uO.zipinfo_mode) { 1569 /* In ZipInfo mode, additional info about the data found in the 1570 end-of-central-directory areas is printed out. 1571 */ 1572 zi_end_central(__G); 1573 } 1574#endif 1575 1576 return error_in_archive; 1577 1578} /* end function find_ecrec() */ 1579 1580 1581 1582 1583 1584/********************************/ 1585/* Function process_zip_cmmnt() */ 1586/********************************/ 1587 1588static int process_zip_cmmnt(__G) /* return PK-type error code */ 1589 __GDEF 1590{ 1591 int error = PK_COOL; 1592 1593 1594/*--------------------------------------------------------------------------- 1595 Get the zipfile comment (up to 64KB long), if any, and print it out. 1596 ---------------------------------------------------------------------------*/ 1597 1598#ifdef WINDLL 1599 /* for comment button: */ 1600 if ((!G.fValidate) && (G.lpUserFunctions != NULL)) 1601 G.lpUserFunctions->cchComment = G.ecrec.zipfile_comment_length; 1602#endif /* WINDLL */ 1603 1604#ifndef NO_ZIPINFO 1605 /* ZipInfo, verbose format */ 1606 if (uO.zipinfo_mode && uO.lflag > 9) { 1607 /*------------------------------------------------------------------- 1608 Get the zipfile comment, if any, and print it out. 1609 (Comment may be up to 64KB long. May the fleas of a thousand 1610 camels infest the arm-pits of anyone who actually takes advantage 1611 of this fact.) 1612 -------------------------------------------------------------------*/ 1613 1614 if (!G.ecrec.zipfile_comment_length) 1615 Info(slide, 0, ((char *)slide, LoadFarString(NoZipfileComment))); 1616 else { 1617 Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommentDesc), 1618 G.ecrec.zipfile_comment_length)); 1619 Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommBegin))); 1620 if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) 1621 error = PK_WARN; 1622 Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommEnd))); 1623 if (error) 1624 Info(slide, 0, ((char *)slide, 1625 LoadFarString(ZipfileCommTrunc2))); 1626 } /* endif (comment exists) */ 1627 1628 /* ZipInfo, non-verbose mode: print zipfile comment only if requested */ 1629 } else if (G.ecrec.zipfile_comment_length && 1630 (uO.zflag > 0) && uO.zipinfo_mode) { 1631 if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) { 1632 Info(slide, 0x401, ((char *)slide, 1633 LoadFarString(ZipfileCommTrunc1))); 1634 error = PK_WARN; 1635 } 1636 } else 1637#endif /* !NO_ZIPINFO */ 1638 if ( G.ecrec.zipfile_comment_length && 1639 (uO.zflag > 0 1640#ifndef WINDLL 1641 || (uO.zflag == 0 1642# ifndef NO_ZIPINFO 1643 && !uO.zipinfo_mode 1644# endif 1645# ifdef TIMESTAMP 1646 && !uO.T_flag 1647# endif 1648 && !uO.qflag) 1649#endif /* !WINDLL */ 1650 ) ) 1651 { 1652 if (do_string(__G__ G.ecrec.zipfile_comment_length, 1653#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) 1654# ifndef NO_ZIPINFO 1655 (oU.zipinfo_mode ? DISPLAY : CHECK_AUTORUN) 1656# else 1657 CHECK_AUTORUN 1658# endif 1659#else 1660 DISPLAY 1661#endif 1662 )) 1663 { 1664 Info(slide, 0x401, ((char *)slide, 1665 LoadFarString(ZipfileCommTrunc1))); 1666 error = PK_WARN; 1667 } 1668 } 1669#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) 1670 else if (G.ecrec.zipfile_comment_length) { 1671 if (do_string(__G__ G.ecrec.zipfile_comment_length, CHECK_AUTORUN_Q)) 1672 { 1673 Info(slide, 0x401, ((char *)slide, 1674 LoadFarString(ZipfileCommTrunc1))); 1675 error = PK_WARN; 1676 } 1677 } 1678#endif 1679 return error; 1680 1681} /* end function process_zip_cmmnt() */ 1682 1683 1684 1685 1686 1687/************************************/ 1688/* Function process_cdir_file_hdr() */ 1689/************************************/ 1690 1691int process_cdir_file_hdr(__G) /* return PK-type error code */ 1692 __GDEF 1693{ 1694 int error; 1695 1696 1697/*--------------------------------------------------------------------------- 1698 Get central directory info, save host and method numbers, and set flag 1699 for lowercase conversion of filename, depending on the OS from which the 1700 file is coming. 1701 ---------------------------------------------------------------------------*/ 1702 1703 if ((error = get_cdir_ent(__G)) != 0) 1704 return error; 1705 1706 G.pInfo->hostver = G.crec.version_made_by[0]; 1707 G.pInfo->hostnum = MIN(G.crec.version_made_by[1], NUM_HOSTS); 1708/* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */ 1709 1710 G.pInfo->lcflag = 0; 1711 if (uO.L_flag == 1) /* name conversion for monocase systems */ 1712 switch (G.pInfo->hostnum) { 1713 case FS_FAT_: /* PKZIP and zip -k store in uppercase */ 1714 case CPM_: /* like MS-DOS, right? */ 1715 case VM_CMS_: /* all caps? */ 1716 case MVS_: /* all caps? */ 1717 case TANDEM_: 1718 case TOPS20_: 1719 case VMS_: /* our Zip uses lowercase, but ASi's doesn't */ 1720 /* case Z_SYSTEM_: ? */ 1721 /* case QDOS_: ? */ 1722 G.pInfo->lcflag = 1; /* convert filename to lowercase */ 1723 break; 1724 1725 default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */ 1726 break; /* FS_VFAT_, ATHEOS_, BEOS_ (Z_SYSTEM_), THEOS_: */ 1727 /* no conversion */ 1728 } 1729 else if (uO.L_flag > 1) /* let -LL force lower case for all names */ 1730 G.pInfo->lcflag = 1; 1731 1732 /* do Amigas (AMIGA_) also have volume labels? */ 1733 if (IS_VOLID(G.crec.external_file_attributes) && 1734 (G.pInfo->hostnum == FS_FAT_ || G.pInfo->hostnum == FS_HPFS_ || 1735 G.pInfo->hostnum == FS_NTFS_ || G.pInfo->hostnum == ATARI_)) 1736 { 1737 G.pInfo->vollabel = TRUE; 1738 G.pInfo->lcflag = 0; /* preserve case of volume labels */ 1739 } else 1740 G.pInfo->vollabel = FALSE; 1741 1742 /* this flag is needed to detect archives made by "PKZIP for Unix" when 1743 deciding which kind of codepage conversion has to be applied to 1744 strings (see do_string() function in fileio.c) */ 1745 G.pInfo->HasUxAtt = (G.crec.external_file_attributes & 0xffff0000L) != 0L; 1746 1747#ifdef UNICODE_SUPPORT 1748 /* remember the state of GPB11 (General Purpuse Bit 11) which indicates 1749 that the standard path and comment are UTF-8. */ 1750 G.pInfo->GPFIsUTF8 1751 = (G.crec.general_purpose_bit_flag & (1 << 11)) == (1 << 11); 1752#endif 1753 1754 return PK_COOL; 1755 1756} /* end function process_cdir_file_hdr() */ 1757 1758 1759 1760 1761 1762/***************************/ 1763/* Function get_cdir_ent() */ 1764/***************************/ 1765 1766static int get_cdir_ent(__G) /* return PK-type error code */ 1767 __GDEF 1768{ 1769 cdir_byte_hdr byterec; 1770 1771 1772/*--------------------------------------------------------------------------- 1773 Read the next central directory entry and do any necessary machine-type 1774 conversions (byte ordering, structure padding compensation--do so by 1775 copying the data from the array into which it was read (byterec) to the 1776 usable struct (crec)). 1777 ---------------------------------------------------------------------------*/ 1778 1779 if (readbuf(__G__ (char *)byterec, CREC_SIZE) == 0) 1780 return PK_EOF; 1781 1782 G.crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0]; 1783 G.crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1]; 1784 G.crec.version_needed_to_extract[0] = 1785 byterec[C_VERSION_NEEDED_TO_EXTRACT_0]; 1786 G.crec.version_needed_to_extract[1] = 1787 byterec[C_VERSION_NEEDED_TO_EXTRACT_1]; 1788 1789 G.crec.general_purpose_bit_flag = 1790 makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]); 1791 G.crec.compression_method = 1792 makeword(&byterec[C_COMPRESSION_METHOD]); 1793 G.crec.last_mod_dos_datetime = 1794 makelong(&byterec[C_LAST_MOD_DOS_DATETIME]); 1795 G.crec.crc32 = 1796 makelong(&byterec[C_CRC32]); 1797 G.crec.csize = 1798 makelong(&byterec[C_COMPRESSED_SIZE]); 1799 G.crec.ucsize = 1800 makelong(&byterec[C_UNCOMPRESSED_SIZE]); 1801 G.crec.filename_length = 1802 makeword(&byterec[C_FILENAME_LENGTH]); 1803 G.crec.extra_field_length = 1804 makeword(&byterec[C_EXTRA_FIELD_LENGTH]); 1805 G.crec.file_comment_length = 1806 makeword(&byterec[C_FILE_COMMENT_LENGTH]); 1807 G.crec.disk_number_start = 1808 makeword(&byterec[C_DISK_NUMBER_START]); 1809 G.crec.internal_file_attributes = 1810 makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]); 1811 G.crec.external_file_attributes = 1812 makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */ 1813 G.crec.relative_offset_local_header = 1814 makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]); 1815 1816 return PK_COOL; 1817 1818} /* end function get_cdir_ent() */ 1819 1820 1821 1822 1823 1824/*************************************/ 1825/* Function process_local_file_hdr() */ 1826/*************************************/ 1827 1828int process_local_file_hdr(__G) /* return PK-type error code */ 1829 __GDEF 1830{ 1831 local_byte_hdr byterec; 1832 1833 1834/*--------------------------------------------------------------------------- 1835 Read the next local file header and do any necessary machine-type con- 1836 versions (byte ordering, structure padding compensation--do so by copy- 1837 ing the data from the array into which it was read (byterec) to the 1838 usable struct (lrec)). 1839 ---------------------------------------------------------------------------*/ 1840 1841 if (readbuf(__G__ (char *)byterec, LREC_SIZE) == 0) 1842 return PK_EOF; 1843 1844 G.lrec.version_needed_to_extract[0] = 1845 byterec[L_VERSION_NEEDED_TO_EXTRACT_0]; 1846 G.lrec.version_needed_to_extract[1] = 1847 byterec[L_VERSION_NEEDED_TO_EXTRACT_1]; 1848 1849 G.lrec.general_purpose_bit_flag = 1850 makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]); 1851 G.lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]); 1852 G.lrec.last_mod_dos_datetime = makelong(&byterec[L_LAST_MOD_DOS_DATETIME]); 1853 G.lrec.crc32 = makelong(&byterec[L_CRC32]); 1854 G.lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]); 1855 G.lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]); 1856 G.lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]); 1857 G.lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]); 1858 1859 if ((G.lrec.general_purpose_bit_flag & 8) != 0) { 1860 /* can't trust local header, use central directory: */ 1861 G.lrec.crc32 = G.pInfo->crc; 1862 G.lrec.csize = G.pInfo->compr_size; 1863 G.lrec.ucsize = G.pInfo->uncompr_size; 1864 } 1865 1866 G.csize = G.lrec.csize; 1867 1868 return PK_COOL; 1869 1870} /* end function process_local_file_hdr() */ 1871 1872 1873/*******************************/ 1874/* Function getZip64Data() */ 1875/*******************************/ 1876 1877int getZip64Data(__G__ ef_buf, ef_len) 1878 __GDEF 1879 ZCONST uch *ef_buf; /* buffer containing extra field */ 1880 unsigned ef_len; /* total length of extra field */ 1881{ 1882 unsigned eb_id; 1883 unsigned eb_len; 1884 1885/*--------------------------------------------------------------------------- 1886 This function scans the extra field for zip64 information, ie 8-byte 1887 versions of compressed file size, uncompressed file size, relative offset 1888 and a 4-byte version of disk start number. 1889 Sets both local header and central header fields. Not terribly clever, 1890 but it means that this procedure is only called in one place. 1891 ---------------------------------------------------------------------------*/ 1892 1893 if (ef_len == 0 || ef_buf == NULL) 1894 return PK_COOL; 1895 1896 Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n", 1897 ef_len)); 1898 1899 while (ef_len >= EB_HEADSIZE) { 1900 eb_id = makeword(EB_ID + ef_buf); 1901 eb_len = makeword(EB_LEN + ef_buf); 1902 1903 if (eb_len > (ef_len - EB_HEADSIZE)) { 1904 /* discovered some extra field inconsistency! */ 1905 Trace((stderr, 1906 "getZip64Data: block length %u > rest ef_size %u\n", eb_len, 1907 ef_len - EB_HEADSIZE)); 1908 break; 1909 } 1910 if (eb_id == EF_PKSZ64) { 1911 1912 int offset = EB_HEADSIZE; 1913 1914 if (G.crec.ucsize == 0xffffffff || G.lrec.ucsize == 0xffffffff){ 1915 G.lrec.ucsize = G.crec.ucsize = makeint64(offset + ef_buf); 1916 offset += sizeof(G.crec.ucsize); 1917 } 1918 if (G.crec.csize == 0xffffffff || G.lrec.csize == 0xffffffff){ 1919 G.csize = G.lrec.csize = G.crec.csize = makeint64(offset + ef_buf); 1920 offset += sizeof(G.crec.csize); 1921 } 1922 if (G.crec.relative_offset_local_header == 0xffffffff){ 1923 G.crec.relative_offset_local_header = makeint64(offset + ef_buf); 1924 offset += sizeof(G.crec.relative_offset_local_header); 1925 } 1926 if (G.crec.disk_number_start == 0xffff){ 1927 G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf); 1928 offset += sizeof(G.crec.disk_number_start); 1929 } 1930 } 1931 1932 /* Skip this extra field block */ 1933 ef_buf += (eb_len + EB_HEADSIZE); 1934 ef_len -= (eb_len + EB_HEADSIZE); 1935 } 1936 1937 return PK_COOL; 1938} /* end function getZip64Data() */ 1939 1940 1941#ifdef UNICODE_SUPPORT 1942 1943/*******************************/ 1944/* Function getUnicodeData() */ 1945/*******************************/ 1946 1947int getUnicodeData(__G__ ef_buf, ef_len) 1948 __GDEF 1949 ZCONST uch *ef_buf; /* buffer containing extra field */ 1950 unsigned ef_len; /* total length of extra field */ 1951{ 1952 unsigned eb_id; 1953 unsigned eb_len; 1954 1955/*--------------------------------------------------------------------------- 1956 This function scans the extra field for Unicode information, ie UTF-8 1957 path extra fields. 1958 1959 On return, G.unipath_filename = 1960 NULL, if no Unicode path extra field or error 1961 "", if the standard path is UTF-8 (free when done) 1962 null-terminated UTF-8 path (free when done) 1963 Return PK_COOL if no error. 1964 ---------------------------------------------------------------------------*/ 1965 1966 G.unipath_filename = NULL; 1967 1968 if (ef_len == 0 || ef_buf == NULL) 1969 return PK_COOL; 1970 1971 Trace((stderr,"\ngetUnicodeData: scanning extra field of length %u\n", 1972 ef_len)); 1973 1974 while (ef_len >= EB_HEADSIZE) { 1975 eb_id = makeword(EB_ID + ef_buf); 1976 eb_len = makeword(EB_LEN + ef_buf); 1977 1978 if (eb_len > (ef_len - EB_HEADSIZE)) { 1979 /* discovered some extra field inconsistency! */ 1980 Trace((stderr, 1981 "getUnicodeData: block length %u > rest ef_size %u\n", eb_len, 1982 ef_len - EB_HEADSIZE)); 1983 break; 1984 } 1985 if (eb_id == EF_UNIPATH) { 1986 1987 int offset = EB_HEADSIZE; 1988 ush ULen = eb_len - 5; 1989 ulg chksum = CRCVAL_INITIAL; 1990 1991 /* version */ 1992 G.unipath_version = (uch) *(offset + ef_buf); 1993 offset += 1; 1994 if (G.unipath_version > 1) { 1995 /* can do only version 1 */ 1996 Info(slide, 0x401, ((char *)slide, 1997 LoadFarString(UnicodeVersionError))); 1998 return PK_ERR; 1999 } 2000 2001 /* filename CRC */ 2002 G.unipath_checksum = makelong(offset + ef_buf); 2003 offset += 4; 2004 2005 /* 2006 * Compute 32-bit crc 2007 */ 2008 2009 chksum = crc32(chksum, (uch *)(G.filename_full), 2010 strlen(G.filename_full)); 2011 2012 /* If the checksums's don't match then likely filename has been 2013 * modified and the Unicode Path is no longer valid. 2014 */ 2015 if (chksum != G.unipath_checksum) { 2016 Info(slide, 0x401, ((char *)slide, 2017 LoadFarString(UnicodeMismatchError))); 2018 if (G.unicode_mismatch == 1) { 2019 /* warn and continue */ 2020 } else if (G.unicode_mismatch == 2) { 2021 /* ignore and continue */ 2022 } else if (G.unicode_mismatch == 0) { 2023 } 2024 return PK_ERR; 2025 } 2026 2027 /* UTF-8 Path */ 2028 if ((G.unipath_filename = malloc(ULen + 1)) == NULL) { 2029 return PK_ERR; 2030 } 2031 if (ULen == 0) { 2032 /* standard path is UTF-8 so use that */ 2033 G.unipath_filename[0] = '\0'; 2034 } else { 2035 /* UTF-8 path */ 2036 strncpy(G.unipath_filename, 2037 (ZCONST char *)(offset + ef_buf), ULen); 2038 G.unipath_filename[ULen] = '\0'; 2039 } 2040 } 2041 2042 /* Skip this extra field block */ 2043 ef_buf += (eb_len + EB_HEADSIZE); 2044 ef_len -= (eb_len + EB_HEADSIZE); 2045 } 2046 2047 return PK_COOL; 2048} /* end function getUnicodeData() */ 2049 2050 2051 2052 2053#ifdef UNICODE_WCHAR 2054 /*--------------------------------------------- 2055 * Unicode conversion functions 2056 * 2057 * Based on functions provided by Paul Kienitz 2058 * 2059 *--------------------------------------------- 2060 */ 2061 2062/* 2063 NOTES APPLICABLE TO ALL STRING FUNCTIONS: 2064 2065 All of the x_to_y functions take parameters for an output buffer and 2066 its available length, and return an int. The value returned is the 2067 length of the string that the input produces, which may be larger than 2068 the provided buffer length. If the returned value is less than the 2069 buffer length, then the contents of the buffer will be null-terminated; 2070 otherwise, it will not be terminated and may be invalid, possibly 2071 stopping in the middle of a multibyte sequence. 2072 2073 In all cases you may pass NULL as the buffer and/or 0 as the length, if 2074 you just want to learn how much space the string is going to require. 2075 2076 The functions will return -1 if the input is invalid UTF-8 or cannot be 2077 encoded as UTF-8. 2078*/ 2079 2080static int utf8_char_bytes OF((ZCONST char *utf8)); 2081static ulg ucs4_char_from_utf8 OF((ZCONST char **utf8)); 2082static int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *ucs4buf, 2083 int buflen)); 2084 2085/* utility functions for managing UTF-8 and UCS-4 strings */ 2086 2087 2088/* utf8_char_bytes 2089 * 2090 * Returns the number of bytes used by the first character in a UTF-8 2091 * string, or -1 if the UTF-8 is invalid or null. 2092 */ 2093static int utf8_char_bytes(utf8) 2094 ZCONST char *utf8; 2095{ 2096 int t, r; 2097 unsigned lead; 2098 2099 if (!utf8) 2100 return -1; /* no input */ 2101 lead = (unsigned char) *utf8; 2102 if (lead < 0x80) 2103 r = 1; /* an ascii-7 character */ 2104 else if (lead < 0xC0) 2105 return -1; /* error: trailing byte without lead byte */ 2106 else if (lead < 0xE0) 2107 r = 2; /* an 11 bit character */ 2108 else if (lead < 0xF0) 2109 r = 3; /* a 16 bit character */ 2110 else if (lead < 0xF8) 2111 r = 4; /* a 21 bit character (the most currently used) */ 2112 else if (lead < 0xFC) 2113 r = 5; /* a 26 bit character (shouldn't happen) */ 2114 else if (lead < 0xFE) 2115 r = 6; /* a 31 bit character (shouldn't happen) */ 2116 else 2117 return -1; /* error: invalid lead byte */ 2118 for (t = 1; t < r; t++) 2119 if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0) 2120 return -1; /* error: not enough valid trailing bytes */ 2121 return r; 2122} 2123 2124 2125/* ucs4_char_from_utf8 2126 * 2127 * Given a reference to a pointer into a UTF-8 string, returns the next 2128 * UCS-4 character and advances the pointer to the next character sequence. 2129 * Returns ~0 (= -1 in twos-complement notation) and does not advance the 2130 * pointer when input is ill-formed. 2131 */ 2132static ulg ucs4_char_from_utf8(utf8) 2133 ZCONST char **utf8; 2134{ 2135 ulg ret; 2136 int t, bytes; 2137 2138 if (!utf8) 2139 return ~0L; /* no input */ 2140 bytes = utf8_char_bytes(*utf8); 2141 if (bytes <= 0) 2142 return ~0L; /* invalid input */ 2143 if (bytes == 1) 2144 ret = **utf8; /* ascii-7 */ 2145 else 2146 ret = **utf8 & (0x7F >> bytes); /* lead byte of a multibyte sequence */ 2147 (*utf8)++; 2148 for (t = 1; t < bytes; t++) /* consume trailing bytes */ 2149 ret = (ret << 6) | (*((*utf8)++) & 0x3F); 2150 return (zwchar) ret; 2151} 2152 2153 2154#if 0 /* currently unused */ 2155/* utf8_from_ucs4_char - Convert UCS char to UTF-8 2156 * 2157 * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6, 2158 * or -1 if ch is too large to represent. utf8buf must have room for 6 bytes. 2159 */ 2160static int utf8_from_ucs4_char(utf8buf, ch) 2161 char *utf8buf; 2162 ulg ch; 2163{ 2164 int trailing = 0; 2165 int leadmask = 0x80; 2166 int leadbits = 0x3F; 2167 int tch = ch; 2168 int ret; 2169 2170 if (ch > 0x7FFFFFFFL) 2171 return -1; /* UTF-8 can represent 31 bits */ 2172 if (ch < 0x7F) 2173 { 2174 *utf8buf++ = (char) ch; /* ascii-7 */ 2175 return 1; 2176 } 2177 do { 2178 trailing++; 2179 leadmask = (leadmask >> 1) | 0x80; 2180 leadbits >>= 1; 2181 tch >>= 6; 2182 } while (tch & ~leadbits); 2183 ret = trailing + 1; 2184 /* produce lead byte */ 2185 *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing))); 2186 while (--trailing >= 0) 2187 /* produce trailing bytes */ 2188 *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F)); 2189 return ret; 2190} 2191#endif /* unused */ 2192 2193 2194/*===================================================================*/ 2195 2196/* utf8_to_ucs4_string - convert UTF-8 string to UCS string 2197 * 2198 * Return UCS count. Now returns int so can return -1. 2199 */ 2200static int utf8_to_ucs4_string(utf8, ucs4buf, buflen) 2201 ZCONST char *utf8; 2202 ulg *ucs4buf; 2203 int buflen; 2204{ 2205 int count = 0; 2206 2207 for (;;) 2208 { 2209 ulg ch = ucs4_char_from_utf8(&utf8); 2210 if (ch == ~0L) 2211 return -1; 2212 else 2213 { 2214 if (ucs4buf && count < buflen) 2215 ucs4buf[count] = ch; 2216 if (ch == 0) 2217 return count; 2218 count++; 2219 } 2220 } 2221} 2222 2223 2224#if 0 /* currently unused */ 2225/* ucs4_string_to_utf8 2226 * 2227 * 2228 */ 2229static int ucs4_string_to_utf8(ucs4, utf8buf, buflen) 2230 ZCONST ulg *ucs4; 2231 char *utf8buf; 2232 int buflen; 2233{ 2234 char mb[6]; 2235 int count = 0; 2236 2237 if (!ucs4) 2238 return -1; 2239 for (;;) 2240 { 2241 int mbl = utf8_from_ucs4_char(mb, *ucs4++); 2242 int c; 2243 if (mbl <= 0) 2244 return -1; 2245 /* We could optimize this a bit by passing utf8buf + count */ 2246 /* directly to utf8_from_ucs4_char when buflen >= count + 6... */ 2247 c = buflen - count; 2248 if (mbl < c) 2249 c = mbl; 2250 if (utf8buf && count < buflen) 2251 strncpy(utf8buf + count, mb, c); 2252 if (mbl == 1 && !mb[0]) 2253 return count; /* terminating nul */ 2254 count += mbl; 2255 } 2256} 2257 2258 2259/* utf8_chars 2260 * 2261 * Wrapper: counts the actual unicode characters in a UTF-8 string. 2262 */ 2263static int utf8_chars(utf8) 2264 ZCONST char *utf8; 2265{ 2266 return utf8_to_ucs4_string(utf8, NULL, 0); 2267} 2268#endif /* unused */ 2269 2270/* --------------------------------------------------- */ 2271/* Unicode Support 2272 * 2273 * These functions common for all Unicode ports. 2274 * 2275 * These functions should allocate and return strings that can be 2276 * freed with free(). 2277 * 2278 * 8/27/05 EG 2279 * 2280 * Use zwchar for wide char which is unsigned long 2281 * in zip.h and 32 bits. This avoids problems with 2282 * different sizes of wchar_t. 2283 */ 2284 2285#if 0 /* currently unused */ 2286/* is_ascii_string 2287 * Checks if a string is all ascii 2288 */ 2289int is_ascii_string(mbstring) 2290 ZCONST char *mbstring; 2291{ 2292 char *p; 2293 uch c; 2294 2295 for (p = mbstring; c = (uch)*p; p++) { 2296 if (c > 0x7F) { 2297 return 0; 2298 } 2299 } 2300 return 1; 2301} 2302 2303/* local to UTF-8 */ 2304char *local_to_utf8_string(local_string) 2305 ZCONST char *local_string; 2306{ 2307 return wide_to_utf8_string(local_to_wide_string(local_string)); 2308} 2309# endif /* unused */ 2310 2311/* wide_to_escape_string 2312 provides a string that represents a wide char not in local char set 2313 2314 An initial try at an algorithm. Suggestions welcome. 2315 2316 According to the standard, Unicode character points are restricted to 2317 the number range from 0 to 0x10FFFF, respective 21 bits. 2318 For a hexadecimal notation, 2 octets are sufficient for the mostly 2319 used characters from the "Basic Multilingual Plane", all other 2320 Unicode characters can be represented by 3 octets (= 6 hex digits). 2321 The Unicode standard suggests to write Unicode character points 2322 as 4 resp. 6 hex digits, preprended by "U+". 2323 (e.g.: U+10FFFF for the highest character point, or U+0030 for the ASCII 2324 digit "0") 2325 2326 However, for the purpose of escaping non-ASCII chars in an ASCII character 2327 stream, the "U" is not a very good escape initializer. Therefore, we 2328 use the following convention within our Info-ZIP code: 2329 2330 If not an ASCII char probably need 2 bytes at least. So if 2331 a 2-byte wide encode it as 4 hex digits with a leading #U. If 2332 needs 3 bytes then prefix the string with #L. So 2333 #U1234 2334 is a 2-byte wide character with bytes 0x12 and 0x34 while 2335 #L123456 2336 is a 3-byte wide character with bytes 0x12, 0x34, 0x56. 2337 On Windows, wide that need two wide characters need to be converted 2338 to a single number. 2339 */ 2340 2341 /* set this to the max bytes an escape can be */ 2342#define MAX_ESCAPE_BYTES 8 2343 2344char *wide_to_escape_string(wide_char) 2345 zwchar wide_char; 2346{ 2347 int i; 2348 zwchar w = wide_char; 2349 uch b[sizeof(zwchar)]; 2350 char d[3]; 2351 char e[11]; 2352 int len; 2353 char *r; 2354 2355 /* fill byte array with zeros */ 2356 memzero(b, sizeof(zwchar)); 2357 /* get bytes in right to left order */ 2358 for (len = 0; w; len++) { 2359 b[len] = (char)(w % 0x100); 2360 w /= 0x100; 2361 } 2362 strcpy(e, "#"); 2363 /* either 2 bytes or 3 bytes */ 2364 if (len <= 2) { 2365 len = 2; 2366 strcat(e, "U"); 2367 } else { 2368 strcat(e, "L"); 2369 } 2370 for (i = len - 1; i >= 0; i--) { 2371 sprintf(d, "%02x", b[i]); 2372 strcat(e, d); 2373 } 2374 if ((r = malloc(strlen(e) + 1)) == NULL) { 2375 return NULL; 2376 } 2377 strcpy(r, e); 2378 return r; 2379} 2380 2381#if 0 /* currently unused */ 2382/* returns the wide character represented by the escape string */ 2383zwchar escape_string_to_wide(escape_string) 2384 ZCONST char *escape_string; 2385{ 2386 int i; 2387 zwchar w; 2388 char c; 2389 int len; 2390 ZCONST char *e = escape_string; 2391 2392 if (e == NULL) { 2393 return 0; 2394 } 2395 if (e[0] != '#') { 2396 /* no leading # */ 2397 return 0; 2398 } 2399 len = strlen(e); 2400 /* either #U1234 or #L123456 format */ 2401 if (len != 6 && len != 8) { 2402 return 0; 2403 } 2404 w = 0; 2405 if (e[1] == 'L') { 2406 if (len != 8) { 2407 return 0; 2408 } 2409 /* 3 bytes */ 2410 for (i = 2; i < 8; i++) { 2411 c = e[i]; 2412 if (c < '0' || c > '9') { 2413 return 0; 2414 } 2415 w = w * 0x10 + (zwchar)(c - '0'); 2416 } 2417 } else if (e[1] == 'U') { 2418 /* 2 bytes */ 2419 for (i = 2; i < 6; i++) { 2420 c = e[i]; 2421 if (c < '0' || c > '9') { 2422 return 0; 2423 } 2424 w = w * 0x10 + (zwchar)(c - '0'); 2425 } 2426 } 2427 return w; 2428} 2429#endif /* unused */ 2430 2431#ifndef WIN32 /* WIN32 supplies a special variant of this function */ 2432/* convert wide character string to multi-byte character string */ 2433char *wide_to_local_string(wide_string, escape_all) 2434 ZCONST zwchar *wide_string; 2435 int escape_all; 2436{ 2437 int i; 2438 wchar_t wc; 2439 int b; 2440 int state_dependent; 2441 int wsize = 0; 2442 int max_bytes = MB_CUR_MAX; 2443 char buf[9]; 2444 char *buffer = NULL; 2445 char *local_string = NULL; 2446 2447 for (wsize = 0; wide_string[wsize]; wsize++) ; 2448 2449 if (max_bytes < MAX_ESCAPE_BYTES) 2450 max_bytes = MAX_ESCAPE_BYTES; 2451 2452 if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) { 2453 return NULL; 2454 } 2455 2456 /* convert it */ 2457 buffer[0] = '\0'; 2458 /* set initial state if state-dependent encoding */ 2459 wc = (wchar_t)'a'; 2460 b = wctomb(NULL, wc); 2461 if (b == 0) 2462 state_dependent = 0; 2463 else 2464 state_dependent = 1; 2465 for (i = 0; i < wsize; i++) { 2466 if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) { 2467 /* wchar_t probably 2 bytes */ 2468 /* could do surrogates if state_dependent and wctomb can do */ 2469 wc = zwchar_to_wchar_t_default_char; 2470 } else { 2471 wc = (wchar_t)wide_string[i]; 2472 } 2473 b = wctomb(buf, wc); 2474 if (escape_all) { 2475 if (b == 1 && (uch)buf[0] <= 0x7f) { 2476 /* ASCII */ 2477 strncat(buffer, buf, b); 2478 } else { 2479 /* use escape for wide character */ 2480 char *escape_string = wide_to_escape_string(wide_string[i]); 2481 strcat(buffer, escape_string); 2482 free(escape_string); 2483 } 2484 } else if (b > 0) { 2485 /* multi-byte char */ 2486 strncat(buffer, buf, b); 2487 } else { 2488 /* no MB for this wide */ 2489 /* use escape for wide character */ 2490 char *escape_string = wide_to_escape_string(wide_string[i]); 2491 strcat(buffer, escape_string); 2492 free(escape_string); 2493 } 2494 } 2495 if ((local_string = (char *)malloc(strlen(buffer) + 1)) != NULL) { 2496 strcpy(local_string, buffer); 2497 } 2498 free(buffer); 2499 2500 return local_string; 2501} 2502#endif /* !WIN32 */ 2503 2504#if 0 /* currently unused */ 2505/* convert local string to display character set string */ 2506char *local_to_display_string(local_string) 2507 ZCONST char *local_string; 2508{ 2509 char *display_string; 2510 2511 /* For Windows, OEM string should never be bigger than ANSI string, says 2512 CharToOem description. 2513 For all other ports, just make a copy of local_string. 2514 */ 2515 if ((display_string = (char *)malloc(strlen(local_string) + 1)) == NULL) { 2516 return NULL; 2517 } 2518 2519 strcpy(display_string, local_string); 2520 2521#ifdef EBCDIC 2522 { 2523 char *ebc; 2524 2525 if ((ebc = malloc(strlen(display_string) + 1)) == NULL) { 2526 return NULL; 2527 } 2528 strtoebc(ebc, display_string); 2529 free(display_string); 2530 display_string = ebc; 2531 } 2532#endif 2533 2534 return display_string; 2535} 2536#endif /* unused */ 2537 2538/* UTF-8 to local */ 2539char *utf8_to_local_string(utf8_string, escape_all) 2540 ZCONST char *utf8_string; 2541 int escape_all; 2542{ 2543 zwchar *wide = utf8_to_wide_string(utf8_string); 2544 char *loc = wide_to_local_string(wide, escape_all); 2545 free(wide); 2546 return loc; 2547} 2548 2549#if 0 /* currently unused */ 2550/* convert multi-byte character string to wide character string */ 2551zwchar *local_to_wide_string(local_string) 2552 ZCONST char *local_string; 2553{ 2554 int wsize; 2555 wchar_t *wc_string; 2556 zwchar *wide_string; 2557 2558 /* for now try to convert as string - fails if a bad char in string */ 2559 wsize = mbstowcs(NULL, local_string, strlen(local_string) + 1); 2560 if (wsize == (size_t)-1) { 2561 /* could not convert */ 2562 return NULL; 2563 } 2564 2565 /* convert it */ 2566 if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) { 2567 return NULL; 2568 } 2569 wsize = mbstowcs(wc_string, local_string, strlen(local_string) + 1); 2570 wc_string[wsize] = (wchar_t) 0; 2571 2572 /* in case wchar_t is not zwchar */ 2573 if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) { 2574 return NULL; 2575 } 2576 for (wsize = 0; wide_string[wsize] = (zwchar)wc_string[wsize]; wsize++) ; 2577 wide_string[wsize] = (zwchar) 0; 2578 free(wc_string); 2579 2580 return wide_string; 2581} 2582 2583 2584/* convert wide string to UTF-8 */ 2585char *wide_to_utf8_string(wide_string) 2586 ZCONST zwchar *wide_string; 2587{ 2588 int mbcount; 2589 char *utf8_string; 2590 2591 /* get size of utf8 string */ 2592 mbcount = ucs4_string_to_utf8(wide_string, NULL, 0); 2593 if (mbcount == -1) 2594 return NULL; 2595 if ((utf8_string = (char *) malloc(mbcount + 1)) == NULL) { 2596 return NULL; 2597 } 2598 mbcount = ucs4_string_to_utf8(wide_string, utf8_string, mbcount + 1); 2599 if (mbcount == -1) 2600 return NULL; 2601 2602 return utf8_string; 2603} 2604#endif /* unused */ 2605 2606/* convert UTF-8 string to wide string */ 2607zwchar *utf8_to_wide_string(utf8_string) 2608 ZCONST char *utf8_string; 2609{ 2610 int wcount; 2611 zwchar *wide_string; 2612 2613 wcount = utf8_to_ucs4_string(utf8_string, NULL, 0); 2614 if (wcount == -1) 2615 return NULL; 2616 if ((wide_string = (zwchar *) malloc((wcount + 1) * sizeof(zwchar))) 2617 == NULL) { 2618 return NULL; 2619 } 2620 wcount = utf8_to_ucs4_string(utf8_string, wide_string, wcount + 1); 2621 2622 return wide_string; 2623} 2624 2625#endif /* UNICODE_WCHAR */ 2626#endif /* UNICODE_SUPPORT */ 2627 2628 2629 2630 2631 2632#ifdef USE_EF_UT_TIME 2633 2634#ifdef IZ_HAVE_UXUIDGID 2635static int read_ux3_value(dbuf, uidgid_sz, p_uidgid) 2636 ZCONST uch *dbuf; /* buffer a uid or gid value */ 2637 unsigned uidgid_sz; /* size of uid/gid value */ 2638 ulg *p_uidgid; /* return storage: uid or gid value */ 2639{ 2640 zusz_t uidgid64; 2641 2642 switch (uidgid_sz) { 2643 case 2: 2644 *p_uidgid = (ulg)makeword(dbuf); 2645 break; 2646 case 4: 2647 *p_uidgid = (ulg)makelong(dbuf); 2648 break; 2649 case 8: 2650 uidgid64 = makeint64(dbuf); 2651#ifndef LARGE_FILE_SUPPORT 2652 if (uidgid64 == (zusz_t)0xffffffffL) 2653 return FALSE; 2654#endif 2655 *p_uidgid = (ulg)uidgid64; 2656 if ((zusz_t)(*p_uidgid) != uidgid64) 2657 return FALSE; 2658 break; 2659 } 2660 return TRUE; 2661} 2662#endif /* IZ_HAVE_UXUIDGID */ 2663 2664 2665/*******************************/ 2666/* Function ef_scan_for_izux() */ 2667/*******************************/ 2668 2669unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime, 2670 z_utim, z_uidgid) 2671 ZCONST uch *ef_buf; /* buffer containing extra field */ 2672 unsigned ef_len; /* total length of extra field */ 2673 int ef_is_c; /* flag indicating "is central extra field" */ 2674 ulg dos_mdatetime; /* last_mod_file_date_time in DOS format */ 2675 iztimes *z_utim; /* return storage: atime, mtime, ctime */ 2676 ulg *z_uidgid; /* return storage: uid and gid */ 2677{ 2678 unsigned flags = 0; 2679 unsigned eb_id; 2680 unsigned eb_len; 2681 int have_new_type_eb = 0; 2682 long i_time; /* buffer for Unix style 32-bit integer time value */ 2683#ifdef TIME_T_TYPE_DOUBLE 2684 int ut_in_archive_sgn = 0; 2685#else 2686 int ut_zip_unzip_compatible = FALSE; 2687#endif 2688 2689/*--------------------------------------------------------------------------- 2690 This function scans the extra field for EF_TIME, EF_IZUNIX2, EF_IZUNIX, or 2691 EF_PKUNIX blocks containing Unix-style time_t (GMT) values for the entry's 2692 access, creation, and modification time. 2693 If a valid block is found, the time stamps are copied to the iztimes 2694 structure (provided the z_utim pointer is not NULL). 2695 If a IZUNIX2 block is found or the IZUNIX block contains UID/GID fields, 2696 and the z_uidgid array pointer is valid (!= NULL), the owner info is 2697 transfered as well. 2698 The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring all 2699 data from probably present obsolete EF_IZUNIX blocks. 2700 If multiple blocks of the same type are found, only the information from 2701 the last block is used. 2702 The return value is a combination of the EF_TIME Flags field with an 2703 additional flag bit indicating the presence of valid UID/GID info, 2704 or 0 in case of failure. 2705 ---------------------------------------------------------------------------*/ 2706 2707 if (ef_len == 0 || ef_buf == NULL || (z_utim == 0 && z_uidgid == NULL)) 2708 return 0; 2709 2710 TTrace((stderr,"\nef_scan_for_izux: scanning extra field of length %u\n", 2711 ef_len)); 2712 2713 while (ef_len >= EB_HEADSIZE) { 2714 eb_id = makeword(EB_ID + ef_buf); 2715 eb_len = makeword(EB_LEN + ef_buf); 2716 2717 if (eb_len > (ef_len - EB_HEADSIZE)) { 2718 /* discovered some extra field inconsistency! */ 2719 TTrace((stderr, 2720 "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len, 2721 ef_len - EB_HEADSIZE)); 2722 break; 2723 } 2724 2725 switch (eb_id) { 2726 case EF_TIME: 2727 flags &= ~0x0ff; /* ignore previous IZUNIX or EF_TIME fields */ 2728 have_new_type_eb = 1; 2729 if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) { 2730 unsigned eb_idx = EB_UT_TIME1; 2731 TTrace((stderr,"ef_scan_for_izux: found TIME extra field\n")); 2732 flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x0ff); 2733 if ((flags & EB_UT_FL_MTIME)) { 2734 if ((eb_idx+4) <= eb_len) { 2735 i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); 2736 eb_idx += 4; 2737 TTrace((stderr," UT e.f. modification time = %ld\n", 2738 i_time)); 2739 2740#ifdef TIME_T_TYPE_DOUBLE 2741 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 2742 if (dos_mdatetime == DOSTIME_MINIMUM) { 2743 ut_in_archive_sgn = -1; 2744 z_utim->mtime = 2745 (time_t)((long)i_time | (~(long)0x7fffffffL)); 2746 } else if (dos_mdatetime >= DOSTIME_2038_01_18) { 2747 ut_in_archive_sgn = 1; 2748 z_utim->mtime = 2749 (time_t)((ulg)i_time & (ulg)0xffffffffL); 2750 } else { 2751 ut_in_archive_sgn = 0; 2752 /* cannot determine sign of mtime; 2753 without modtime: ignore complete UT field */ 2754 flags &= ~0x0ff; /* no time_t times available */ 2755 TTrace((stderr, 2756 " UT modtime range error; ignore e.f.!\n")); 2757 break; /* stop scanning this field */ 2758 } 2759 } else { 2760 /* cannot determine, safe assumption is FALSE */ 2761 ut_in_archive_sgn = 0; 2762 z_utim->mtime = (time_t)i_time; 2763 } 2764#else /* !TIME_T_TYPE_DOUBLE */ 2765 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 2766 ut_zip_unzip_compatible = 2767 ((time_t)0x80000000L < (time_t)0L) 2768 ? (dos_mdatetime == DOSTIME_MINIMUM) 2769 : (dos_mdatetime >= DOSTIME_2038_01_18); 2770 if (!ut_zip_unzip_compatible) { 2771 /* UnZip interprets mtime differently than Zip; 2772 without modtime: ignore complete UT field */ 2773 flags &= ~0x0ff; /* no time_t times available */ 2774 TTrace((stderr, 2775 " UT modtime range error; ignore e.f.!\n")); 2776 break; /* stop scanning this field */ 2777 } 2778 } else { 2779 /* cannot determine, safe assumption is FALSE */ 2780 ut_zip_unzip_compatible = FALSE; 2781 } 2782 z_utim->mtime = (time_t)i_time; 2783#endif /* ?TIME_T_TYPE_DOUBLE */ 2784 } else { 2785 flags &= ~EB_UT_FL_MTIME; 2786 TTrace((stderr," UT e.f. truncated; no modtime\n")); 2787 } 2788 } 2789 if (ef_is_c) { 2790 break; /* central version of TIME field ends here */ 2791 } 2792 2793 if (flags & EB_UT_FL_ATIME) { 2794 if ((eb_idx+4) <= eb_len) { 2795 i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); 2796 eb_idx += 4; 2797 TTrace((stderr," UT e.f. access time = %ld\n", 2798 i_time)); 2799#ifdef TIME_T_TYPE_DOUBLE 2800 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 2801 if (ut_in_archive_sgn == -1) 2802 z_utim->atime = 2803 (time_t)((long)i_time | (~(long)0x7fffffffL)); 2804 } else if (ut_in_archive_sgn == 1) { 2805 z_utim->atime = 2806 (time_t)((ulg)i_time & (ulg)0xffffffffL); 2807 } else { 2808 /* sign of 32-bit time is unknown -> ignore it */ 2809 flags &= ~EB_UT_FL_ATIME; 2810 TTrace((stderr, 2811 " UT access time range error: skip time!\n")); 2812 } 2813 } else { 2814 z_utim->atime = (time_t)i_time; 2815 } 2816#else /* !TIME_T_TYPE_DOUBLE */ 2817 if (((ulg)(i_time) & (ulg)(0x80000000L)) && 2818 !ut_zip_unzip_compatible) { 2819 flags &= ~EB_UT_FL_ATIME; 2820 TTrace((stderr, 2821 " UT access time range error: skip time!\n")); 2822 } else { 2823 z_utim->atime = (time_t)i_time; 2824 } 2825#endif /* ?TIME_T_TYPE_DOUBLE */ 2826 } else { 2827 flags &= ~EB_UT_FL_ATIME; 2828 } 2829 } 2830 if (flags & EB_UT_FL_CTIME) { 2831 if ((eb_idx+4) <= eb_len) { 2832 i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); 2833 TTrace((stderr," UT e.f. creation time = %ld\n", 2834 i_time)); 2835#ifdef TIME_T_TYPE_DOUBLE 2836 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 2837 if (ut_in_archive_sgn == -1) 2838 z_utim->ctime = 2839 (time_t)((long)i_time | (~(long)0x7fffffffL)); 2840 } else if (ut_in_archive_sgn == 1) { 2841 z_utim->ctime = 2842 (time_t)((ulg)i_time & (ulg)0xffffffffL); 2843 } else { 2844 /* sign of 32-bit time is unknown -> ignore it */ 2845 flags &= ~EB_UT_FL_CTIME; 2846 TTrace((stderr, 2847 " UT creation time range error: skip time!\n")); 2848 } 2849 } else { 2850 z_utim->ctime = (time_t)i_time; 2851 } 2852#else /* !TIME_T_TYPE_DOUBLE */ 2853 if (((ulg)(i_time) & (ulg)(0x80000000L)) && 2854 !ut_zip_unzip_compatible) { 2855 flags &= ~EB_UT_FL_CTIME; 2856 TTrace((stderr, 2857 " UT creation time range error: skip time!\n")); 2858 } else { 2859 z_utim->ctime = (time_t)i_time; 2860 } 2861#endif /* ?TIME_T_TYPE_DOUBLE */ 2862 } else { 2863 flags &= ~EB_UT_FL_CTIME; 2864 } 2865 } 2866 } 2867 break; 2868 2869 case EF_IZUNIX2: 2870 if (have_new_type_eb == 0) { 2871 flags &= ~0x0ff; /* ignore any previous IZUNIX field */ 2872 have_new_type_eb = 1; 2873 } 2874#ifdef IZ_HAVE_UXUIDGID 2875 if (have_new_type_eb > 1) 2876 break; /* IZUNIX3 overrides IZUNIX2 e.f. block ! */ 2877 if (eb_len == EB_UX2_MINLEN && z_uidgid != NULL) { 2878 z_uidgid[0] = (ulg)makeword((EB_HEADSIZE+EB_UX2_UID) + ef_buf); 2879 z_uidgid[1] = (ulg)makeword((EB_HEADSIZE+EB_UX2_GID) + ef_buf); 2880 flags |= EB_UX2_VALID; /* signal success */ 2881 } 2882#endif 2883 break; 2884 2885 case EF_IZUNIX3: 2886 /* new 3rd generation Unix ef */ 2887 have_new_type_eb = 2; 2888 2889 /* 2890 Version 1 byte version of this extra field, currently 1 2891 UIDSize 1 byte Size of UID field 2892 UID Variable UID for this entry 2893 GIDSize 1 byte Size of GID field 2894 GID Variable GID for this entry 2895 */ 2896 2897#ifdef IZ_HAVE_UXUIDGID 2898 if (eb_len >= EB_UX3_MINLEN 2899 && z_uidgid != NULL 2900 && (*((EB_HEADSIZE + 0) + ef_buf) == 1) 2901 /* only know about version 1 */ 2902 { 2903 uch uid_size; 2904 uch gid_size; 2905 2906 uid_size = *((EB_HEADSIZE + 1) + ef_buf); 2907 gid_size = *((EB_HEADSIZE + uid_size + 2) + ef_buf); 2908 2909 flags &= ~0x0ff; /* ignore any previous UNIX field */ 2910 2911 if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf, 2912 uid_size, z_uidgid[0]) 2913 && 2914 read_ux3_value((EB_HEADSIZE + uid_size + 3) + ef_buf, 2915 gid_size, z_uidgid[1]) ) 2916 { 2917 flags |= EB_UX2_VALID; /* signal success */ 2918 } 2919 } 2920#endif /* IZ_HAVE_UXUIDGID */ 2921 break; 2922 2923 case EF_IZUNIX: 2924 case EF_PKUNIX: /* PKUNIX e.f. layout is identical to IZUNIX */ 2925 if (eb_len >= EB_UX_MINLEN) { 2926 TTrace((stderr,"ef_scan_for_izux: found %s extra field\n", 2927 (eb_id == EF_IZUNIX ? "IZUNIX" : "PKUNIX"))); 2928 if (have_new_type_eb > 0) { 2929 break; /* Ignore IZUNIX extra field block ! */ 2930 } 2931 if (z_utim != NULL) { 2932 flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME); 2933 i_time = (long)makelong((EB_HEADSIZE+EB_UX_MTIME)+ef_buf); 2934 TTrace((stderr," Unix EF modtime = %ld\n", i_time)); 2935#ifdef TIME_T_TYPE_DOUBLE 2936 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 2937 if (dos_mdatetime == DOSTIME_MINIMUM) { 2938 ut_in_archive_sgn = -1; 2939 z_utim->mtime = 2940 (time_t)((long)i_time | (~(long)0x7fffffffL)); 2941 } else if (dos_mdatetime >= DOSTIME_2038_01_18) { 2942 ut_in_archive_sgn = 1; 2943 z_utim->mtime = 2944 (time_t)((ulg)i_time & (ulg)0xffffffffL); 2945 } else { 2946 ut_in_archive_sgn = 0; 2947 /* cannot determine sign of mtime; 2948 without modtime: ignore complete UT field */ 2949 flags &= ~0x0ff; /* no time_t times available */ 2950 TTrace((stderr, 2951 " UX modtime range error: ignore e.f.!\n")); 2952 } 2953 } else { 2954 /* cannot determine, safe assumption is FALSE */ 2955 ut_in_archive_sgn = 0; 2956 z_utim->mtime = (time_t)i_time; 2957 } 2958#else /* !TIME_T_TYPE_DOUBLE */ 2959 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 2960 ut_zip_unzip_compatible = 2961 ((time_t)0x80000000L < (time_t)0L) 2962 ? (dos_mdatetime == DOSTIME_MINIMUM) 2963 : (dos_mdatetime >= DOSTIME_2038_01_18); 2964 if (!ut_zip_unzip_compatible) { 2965 /* UnZip interpretes mtime differently than Zip; 2966 without modtime: ignore complete UT field */ 2967 flags &= ~0x0ff; /* no time_t times available */ 2968 TTrace((stderr, 2969 " UX modtime range error: ignore e.f.!\n")); 2970 } 2971 } else { 2972 /* cannot determine, safe assumption is FALSE */ 2973 ut_zip_unzip_compatible = FALSE; 2974 } 2975 z_utim->mtime = (time_t)i_time; 2976#endif /* ?TIME_T_TYPE_DOUBLE */ 2977 i_time = (long)makelong((EB_HEADSIZE+EB_UX_ATIME)+ef_buf); 2978 TTrace((stderr," Unix EF actime = %ld\n", i_time)); 2979#ifdef TIME_T_TYPE_DOUBLE 2980 if ((ulg)(i_time) & (ulg)(0x80000000L)) { 2981 if (ut_in_archive_sgn == -1) 2982 z_utim->atime = 2983 (time_t)((long)i_time | (~(long)0x7fffffffL)); 2984 } else if (ut_in_archive_sgn == 1) { 2985 z_utim->atime = 2986 (time_t)((ulg)i_time & (ulg)0xffffffffL); 2987 } else if (flags & 0x0ff) { 2988 /* sign of 32-bit time is unknown -> ignore it */ 2989 flags &= ~EB_UT_FL_ATIME; 2990 TTrace((stderr, 2991 " UX access time range error: skip time!\n")); 2992 } 2993 } else { 2994 z_utim->atime = (time_t)i_time; 2995 } 2996#else /* !TIME_T_TYPE_DOUBLE */ 2997 if (((ulg)(i_time) & (ulg)(0x80000000L)) && 2998 !ut_zip_unzip_compatible && (flags & 0x0ff)) { 2999 /* atime not in range of UnZip's time_t */ 3000 flags &= ~EB_UT_FL_ATIME; 3001 TTrace((stderr, 3002 " UX access time range error: skip time!\n")); 3003 } else { 3004 z_utim->atime = (time_t)i_time; 3005 } 3006#endif /* ?TIME_T_TYPE_DOUBLE */ 3007 } 3008#ifdef IZ_HAVE_UXUIDGID 3009 if (eb_len >= EB_UX_FULLSIZE && z_uidgid != NULL) { 3010 z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX_UID) + ef_buf); 3011 z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX_GID) + ef_buf); 3012 flags |= EB_UX2_VALID; 3013 } 3014#endif /* IZ_HAVE_UXUIDGID */ 3015 } 3016 break; 3017 3018 default: 3019 break; 3020 } 3021 3022 /* Skip this extra field block */ 3023 ef_buf += (eb_len + EB_HEADSIZE); 3024 ef_len -= (eb_len + EB_HEADSIZE); 3025 } 3026 3027 return flags; 3028} 3029 3030#endif /* USE_EF_UT_TIME */ 3031 3032 3033#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) 3034 3035#define SPARKID_2 0x30435241 /* = "ARC0" */ 3036 3037/*******************************/ 3038/* Function getRISCOSexfield() */ 3039/*******************************/ 3040 3041zvoid *getRISCOSexfield(ef_buf, ef_len) 3042 ZCONST uch *ef_buf; /* buffer containing extra field */ 3043 unsigned ef_len; /* total length of extra field */ 3044{ 3045 unsigned eb_id; 3046 unsigned eb_len; 3047 3048/*--------------------------------------------------------------------------- 3049 This function scans the extra field for a Acorn SPARK filetype ef-block. 3050 If a valid block is found, the function returns a pointer to the start 3051 of the SPARK_EF block in the extra field buffer. Otherwise, a NULL 3052 pointer is returned. 3053 ---------------------------------------------------------------------------*/ 3054 3055 if (ef_len == 0 || ef_buf == NULL) 3056 return NULL; 3057 3058 Trace((stderr,"\ngetRISCOSexfield: scanning extra field of length %u\n", 3059 ef_len)); 3060 3061 while (ef_len >= EB_HEADSIZE) { 3062 eb_id = makeword(EB_ID + ef_buf); 3063 eb_len = makeword(EB_LEN + ef_buf); 3064 3065 if (eb_len > (ef_len - EB_HEADSIZE)) { 3066 /* discovered some extra field inconsistency! */ 3067 Trace((stderr, 3068 "getRISCOSexfield: block length %u > rest ef_size %u\n", eb_len, 3069 ef_len - EB_HEADSIZE)); 3070 break; 3071 } 3072 3073 if (eb_id == EF_SPARK && (eb_len == 24 || eb_len == 20)) { 3074 if (makelong(EB_HEADSIZE + ef_buf) == SPARKID_2) { 3075 /* Return a pointer to the valid SPARK filetype ef block */ 3076 return (zvoid *)ef_buf; 3077 } 3078 } 3079 3080 /* Skip this extra field block */ 3081 ef_buf += (eb_len + EB_HEADSIZE); 3082 ef_len -= (eb_len + EB_HEADSIZE); 3083 } 3084 3085 return NULL; 3086} 3087 3088#endif /* (RISCOS || ACORN_FTYPE_NFS) */ 3089