1/* 2 Copyright (c) 1990-2006 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2005-Feb-10 or later 5 (the contents of which are also included in zip.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 * zipfile.c by Mark Adler. 11 */ 12#define __ZIPFILE_C 13 14#include "zip.h" 15#include "revision.h" 16 17#ifdef VMS 18# include <rms.h> 19# include "vms/vmsmunch.h" 20# include "vms/vmsdefs.h" 21#endif 22 23#ifdef __RSXNT__ 24# include <windows.h> 25#endif 26 27/* 28 * XXX start of zipfile.h 29 */ 30#ifdef THEOS 31/* Macros cause stack overflow in compiler */ 32ush SH(uch* p) { return ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)); } 33ulg LG(uch* p) { return ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)); } 34#else /* !THEOS */ 35/* Macros for converting integers in little-endian to machine format */ 36#define SH(a) ((ush)(((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8))) 37#define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16)) 38#endif /* ?THEOS */ 39 40/* Macros for writing machine integers to little-endian format */ 41#define PUTSH(a,f) {putc((char)((a) & 0xff),(f)); putc((char)((a) >> 8),(f));} 42#define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))} 43 44 45/* -- Structure of a ZIP file -- */ 46 47/* Signatures for zip file information headers */ 48#define LOCSIG 0x04034b50L 49#define CENSIG 0x02014b50L 50#define ENDSIG 0x06054b50L 51#define EXTLOCSIG 0x08074b50L 52 53/* Offsets of values in headers */ 54#define LOCVER 0 /* version needed to extract */ 55#define LOCFLG 2 /* encrypt, deflate flags */ 56#define LOCHOW 4 /* compression method */ 57#define LOCTIM 6 /* last modified file time, DOS format */ 58#define LOCDAT 8 /* last modified file date, DOS format */ 59#define LOCCRC 10 /* uncompressed crc-32 for file */ 60#define LOCSIZ 14 /* compressed size in zip file */ 61#define LOCLEN 18 /* uncompressed size */ 62#define LOCNAM 22 /* length of filename */ 63#define LOCEXT 24 /* length of extra field */ 64 65#define EXTCRC 0 /* uncompressed crc-32 for file */ 66#define EXTSIZ 4 /* compressed size in zip file */ 67#define EXTLEN 8 /* uncompressed size */ 68 69#define CENVEM 0 /* version made by */ 70#define CENVER 2 /* version needed to extract */ 71#define CENFLG 4 /* encrypt, deflate flags */ 72#define CENHOW 6 /* compression method */ 73#define CENTIM 8 /* last modified file time, DOS format */ 74#define CENDAT 10 /* last modified file date, DOS format */ 75#define CENCRC 12 /* uncompressed crc-32 for file */ 76#define CENSIZ 16 /* compressed size in zip file */ 77#define CENLEN 20 /* uncompressed size */ 78#define CENNAM 24 /* length of filename */ 79#define CENEXT 26 /* length of extra field */ 80#define CENCOM 28 /* file comment length */ 81#define CENDSK 30 /* disk number start */ 82#define CENATT 32 /* internal file attributes */ 83#define CENATX 34 /* external file attributes */ 84#define CENOFF 38 /* relative offset of local header */ 85 86#define ENDDSK 0 /* number of this disk */ 87#define ENDBEG 2 /* number of the starting disk */ 88#define ENDSUB 4 /* entries on this disk */ 89#define ENDTOT 6 /* total number of entries */ 90#define ENDSIZ 8 /* size of entire central directory */ 91#define ENDOFF 12 /* offset of central on starting disk */ 92#define ENDCOM 16 /* length of zip file comment */ 93 94 95 96/* Local functions */ 97 98local int zqcmp OF((ZCONST zvoid *, ZCONST zvoid *)); 99local int scanzipf_reg OF((FILE *f)); 100#ifndef UTIL 101 local int rqcmp OF((ZCONST zvoid *, ZCONST zvoid *)); 102 local int zbcmp OF((ZCONST zvoid *, ZCONST zvoid far *)); 103 local void zipoddities OF((struct zlist far *)); 104 local int scanzipf_fix OF((FILE *f)); 105# ifdef USE_EF_UT_TIME 106 local int ef_scan_ut_time OF((char *ef_buf, extent ef_len, int ef_is_cent, 107 iztimes *z_utim)); 108# endif /* USE_EF_UT_TIME */ 109 local void cutpath OF((char *p, int delim)); 110#endif /* !UTIL */ 111 112/* 113 * XXX end of zipfile.h 114 */ 115 116/* Local data */ 117 118#ifdef HANDLE_AMIGA_SFX 119 ulg amiga_sfx_offset; /* place where size field needs updating */ 120#endif 121 122 123local int zqcmp(a, b) 124ZCONST zvoid *a, *b; /* pointers to pointers to zip entries */ 125/* Used by qsort() to compare entries in the zfile list. 126 * Compares the internal names z->iname */ 127{ 128 return namecmp((*(struct zlist far **)a)->iname, 129 (*(struct zlist far **)b)->iname); 130} 131 132#ifndef UTIL 133 134local int rqcmp(a, b) 135ZCONST zvoid *a, *b; /* pointers to pointers to zip entries */ 136/* Used by qsort() to compare entries in the zfile list. 137 * Compare the internal names z->iname, but in reverse order. */ 138{ 139 return namecmp((*(struct zlist far **)b)->iname, 140 (*(struct zlist far **)a)->iname); 141} 142 143 144local int zbcmp(n, z) 145ZCONST zvoid *n; /* string to search for */ 146ZCONST zvoid far *z; /* pointer to a pointer to a zip entry */ 147/* Used by search() to compare a target to an entry in the zfile list. */ 148{ 149 return namecmp((char *)n, ((struct zlist far *)z)->zname); 150} 151 152 153struct zlist far *zsearch(n) 154ZCONST char *n; /* name to find */ 155/* Return a pointer to the entry in zfile with the name n, or NULL if 156 not found. */ 157{ 158 zvoid far **p; /* result of search() */ 159 160 if (zcount && 161 (p = search(n, (ZCONST zvoid far **)zsort, zcount, zbcmp)) != NULL) 162 return *(struct zlist far **)p; 163 else 164 return NULL; 165} 166 167#endif /* !UTIL */ 168 169#ifndef VMS /* See vms/vms.c for VMS-specific ziptyp(). */ 170# ifndef PATHCUT 171# define PATHCUT '/' 172# endif 173 174char *ziptyp(s) 175char *s; /* file name to force to zip */ 176/* If the file name *s has a dot (other than the first char), or if 177 the -A option is used (adjust self-extracting file) then return 178 the name, otherwise append .zip to the name. Allocate the space for 179 the name in either case. Return a pointer to the new name, or NULL 180 if malloc() fails. */ 181{ 182 char *q; /* temporary pointer */ 183 char *t; /* pointer to malloc'ed string */ 184#ifdef THEOS 185 char *r; /* temporary pointer */ 186 char *disk; 187#endif 188 189 if ((t = malloc(strlen(s) + 5)) == NULL) 190 return NULL; 191 strcpy(t, s); 192#ifdef __human68k__ 193 _toslash(t); 194#endif 195#ifdef MSDOS 196 for (q = t; *q; INCSTR(q)) 197 if (*q == '\\') 198 *q = '/'; 199#endif /* MSDOS */ 200#ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */ 201 AnsiToOem(t, t); 202#endif 203 if (adjust) return t; 204#ifndef RISCOS 205# ifndef QDOS 206# ifdef AMIGA 207 if ((q = MBSRCHR(t, '/')) == NULL) 208 q = MBSRCHR(t, ':'); 209 if (MBSRCHR((q ? q + 1 : t), '.') == NULL) 210# else /* !AMIGA */ 211# ifdef THEOS 212 /* the argument expansion add a dot to the end of file names when 213 * there is no extension and at least one of a argument has wild cards. 214 * So check for at least one character in the extension if there is a dot 215 * in file name */ 216 if ((q = MBSRCHR((q = MBSRCHR(t, PATHCUT)) == NULL ? t : q + 1, '.')) == NULL 217 || q[1] == '\0') { 218# else /* !THEOS */ 219# ifdef TANDEM 220 if (MBSRCHR((q = MBSRCHR(t, '.')) == NULL ? t : q + 1, ' ') == NULL) 221# else /* !TANDEM */ 222 if (MBSRCHR((q = MBSRCHR(t, PATHCUT)) == NULL ? t : q + 1, '.') == NULL) 223# endif /* ?TANDEM */ 224# endif /* ?THEOS */ 225# endif /* ?AMIGA */ 226# ifdef CMS_MVS 227 if (strncmp(t,"dd:",3) != 0 && strncmp(t,"DD:",3) != 0) 228# endif /* CMS_MVS */ 229# ifdef THEOS 230 /* insert .zip extension before disk name */ 231 if ((r = MBSRCHR(t, ':')) != NULL) { 232 /* save disk name */ 233 if ((disk = strdup(r)) == NULL) 234 return NULL; 235 strcpy(r[-1] == '.' ? r - 1 : r, ".zip"); 236 strcat(t, disk); 237 free(disk); 238 } else { 239 if (q != NULL && *q == '.') 240 strcpy(q, ".zip"); 241 else 242 strcat(t, ".zip"); 243 } 244 } 245# else /* !THEOS */ 246# ifdef TANDEM /* Tandem can't cope with extensions */ 247 strcat(t, " ZIP"); 248# else /* !TANDEM */ 249 strcat(t, ".zip"); 250# endif /* ?TANDEM */ 251# endif /* ?THEOS */ 252# else /* QDOS */ 253 q = LastDir(t); 254 if(MBSRCHR(q, '_') == NULL && MBSRCHR(q, '.') == NULL) 255 { 256 strcat(t, "_zip"); 257 } 258# endif /* QDOS */ 259#endif /* !RISCOS */ 260 return t; 261} 262#endif /* !VMS */ 263 264#ifndef UTIL 265 266local void zipoddities(z) 267struct zlist far *z; 268{ 269 if ((z->vem >> 8) >= NUM_HOSTS) 270 { 271 sprintf(errbuf, "made by version %d.%d on system type %d: ", 272 (ush)(z->vem & 0xff) / (ush)10, (ush)(z->vem & 0xff) % (ush)10, 273 z->vem >> 8); 274 zipwarn(errbuf, z->zname); 275 } 276 if (z->ver != 10 && z->ver != 11 && z->ver != 20) 277 { 278 sprintf(errbuf, "needs unzip %d.%d on system type %d: ", 279 (ush)(z->ver & 0xff) / (ush)10, 280 (ush)(z->ver & 0xff) % (ush)10, z->ver >> 8); 281 zipwarn(errbuf, z->zname); 282 } 283 if (z->flg != z->lflg) 284 { 285 sprintf(errbuf, "local flags = 0x%04x, central = 0x%04x: ", 286 z->lflg, z->flg); 287 zipwarn(errbuf, z->zname); 288 } 289 else if (z->flg & ~0xf) 290 { 291 sprintf(errbuf, "undefined bits used in flags = 0x%04x: ", z->flg); 292 zipwarn(errbuf, z->zname); 293 } 294 if (z->how > DEFLATE) 295 { 296 sprintf(errbuf, "unknown compression method %u: ", z->how); 297 zipwarn(errbuf, z->zname); 298 } 299 if (z->dsk) 300 { 301 sprintf(errbuf, "starts on disk %u: ", z->dsk); 302 zipwarn(errbuf, z->zname); 303 } 304 if (z->att!=ASCII && z->att!=BINARY && z->att!=__EBCDIC) 305 { 306 sprintf(errbuf, "unknown internal attributes = 0x%04x: ", z->att); 307 zipwarn(errbuf, z->zname); 308 } 309#if 0 310/* This test is ridiculous, it produces an error message for almost every */ 311/* platform of origin other than MS-DOS, Unix, VMS, and Acorn! Perhaps */ 312/* we could test "if (z->dosflag && z->atx & ~0xffL)", but what for? */ 313 if (((n = z->vem >> 8) != 3) && n != 2 && n != 13 && z->atx & ~0xffL) 314 { 315 sprintf(errbuf, "unknown external attributes = 0x%08lx: ", z->atx); 316 zipwarn(errbuf, z->zname); 317 } 318#endif 319 if (z->ext || z->cext) 320 { 321 if (z->ext && z->cext && z->extra != z->cextra) 322 { 323 sprintf(errbuf, 324 "local extra (%ld bytes) != central extra (%ld bytes): ", 325 (ulg)z->ext, (ulg)z->cext); 326 if (noisy) fprintf(stderr, "\tzip info: %s%s\n", errbuf, z->zname); 327 } 328#if (!defined(RISCOS) && !defined(CMS_MVS)) 329 /* in noisy mode, extra field sizes are always reported */ 330 else if (noisy) 331#else /* RISCOS || CMS_MVS */ 332/* avoid warnings for zipfiles created on the same type of OS system! */ 333/* or, was this warning really intended (eg. OS/2)? */ 334 /* Only give info if extra bytes were added by another system */ 335 else if (noisy && ((z->vem >> 8) != (OS_CODE >> 8))) 336#endif /* ?(RISCOS || CMS_MVS) */ 337 { 338 fprintf(stderr, "zip info: %s has %ld bytes of %sextra data\n", 339 z->zname, z->ext ? (ulg)z->ext : (ulg)z->cext, 340 z->ext ? (z->cext ? "" : "local ") : "central "); 341 } 342 } 343} 344 345/* 346 * scanzipf_fix is called with zip -F or zip -FF 347 * read the file from front to back and pick up the pieces 348 * NOTE: there are still checks missing to see if the header 349 * that was found is *VALID* 350 */ 351local int scanzipf_fix(f) 352 FILE *f; /* zip file */ 353/* 354 The name of the zip file is pointed to by the global "zipfile". The globals 355 zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in. 356 Return an error code in the ZE_ class. 357*/ 358{ 359 ulg a = 0L; /* attributes returned by filetime() */ 360 char b[CENHEAD]; /* buffer for central headers */ 361 ush flg; /* general purpose bit flag */ 362 int m; /* mismatch flag */ 363 extent n; /* length of name */ 364 ulg p; /* current file offset */ 365 ulg s; /* size of data, start of central */ 366 struct zlist far * far *x; /* pointer last entry's link */ 367 struct zlist far *z; /* current zip entry structure */ 368 369 /* Get any file attribute valid for this OS, to set in the central 370 * directory when fixing the archive: 371 */ 372#ifndef UTIL 373 filetime(zipfile, &a, (long*)&s, NULL); 374#endif 375 x = &zfiles; /* first link */ 376 p = 0; /* starting file offset */ 377#ifdef HANDLE_AMIGA_SFX 378 amiga_sfx_offset = 0L; 379#endif 380 381 /* Find start of zip structures */ 382 for (;;) { 383 while ((m = getc(f)) != EOF && m != 0x50) /* 0x50 == 'P' */ 384 { 385#ifdef HANDLE_AMIGA_SFX 386 if (p == 0 && m == 0) 387 amiga_sfx_offset = 1L; 388 else if (amiga_sfx_offset) { 389 if ((p == 1 && m != 0) || (p == 2 && m != 3) 390 || (p == 3 && (uch) m != 0xF3)) 391 amiga_sfx_offset = 0L; 392 } 393#endif /* HANDLE_AMIGA_SFX */ 394 p++; 395 } 396 b[0] = (char) m; 397 if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG || s == ENDSIG) 398 break; 399 if (fseek(f, -3L, SEEK_CUR)) 400 return ferror(f) ? ZE_READ : ZE_EOF; 401 p++; 402 } 403 zipbeg = p; 404#ifdef HANDLE_AMIGA_SFX 405 if (amiga_sfx_offset && zipbeg >= 12 && (zipbeg & 3) == 0 406 && fseek(f, -12L, SEEK_CUR) == 0 && fread(b, 12, 1, f) == 1 407 && LG(b + 4) == 0xF1030000 /* 1009 in Motorola byte order */) 408 amiga_sfx_offset = zipbeg - 4; 409 else 410 amiga_sfx_offset = 0L; 411#endif /* HANDLE_AMIGA_SFX */ 412 413 /* Read local headers */ 414 while (LG(b) == LOCSIG) 415 { 416 if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL || 417 zcount + 1 < zcount) 418 return ZE_MEM; 419 if (fread(b, LOCHEAD, 1, f) != 1) { 420 farfree((zvoid far *)z); 421 break; 422 } 423 424 z->ver = SH(LOCVER + b); 425 z->vem = (ush)(dosify ? 20 : OS_CODE + Z_MAJORVER * 10 + Z_MINORVER); 426 z->dosflag = dosify; 427 flg = z->flg = z->lflg = SH(LOCFLG + b); 428 z->how = SH(LOCHOW + b); 429 z->tim = LG(LOCTIM + b); /* time and date into one long */ 430 z->crc = LG(LOCCRC + b); 431 z->siz = LG(LOCSIZ + b); 432 z->len = LG(LOCLEN + b); 433 n = z->nam = SH(LOCNAM + b); 434 z->cext = z->ext = SH(LOCEXT + b); 435 436 z->com = 0; 437 z->dsk = 0; 438 z->att = 0; 439 z->atx = dosify ? a & 0xff : a; /* Attributes from filetime() */ 440 z->mark = 0; 441 z->trash = 0; 442 443 s = fix > 1 ? 0L : z->siz; /* discard compressed size with -FF */ 444 445 /* Initialize all fields pointing to malloced data to NULL */ 446 z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL; 447 448 /* Link into list */ 449 *x = z; 450 z->nxt = NULL; 451 x = &z->nxt; 452 453 /* Read file name and extra field and skip data */ 454 if (n == 0) 455 { 456 sprintf(errbuf, "%lu", (ulg)zcount + 1); 457 zipwarn("zero-length name for entry #", errbuf); 458#ifndef DEBUG 459 return ZE_FORM; 460#endif 461 } 462 if ((z->iname = malloc(n+1)) == NULL || 463 (z->ext && (z->extra = malloc(z->ext)) == NULL)) 464 return ZE_MEM; 465 if (fread(z->iname, n, 1, f) != 1 || 466 (z->ext && fread(z->extra, z->ext, 1, f) != 1) || 467 (s && fseek(f, (long)s, SEEK_CUR))) 468 return ferror(f) ? ZE_READ : ZE_EOF; 469 /* If there is an extended local header, s is either 0 or 470 * the correct compressed size. 471 */ 472 z->iname[n] = '\0'; /* terminate name */ 473 z->zname = in2ex(z->iname); /* convert to external name */ 474 if (z->zname == NULL) 475 return ZE_MEM; 476 z->name = z->zname; 477 z->cextra = z->extra; 478 if (noisy) fprintf(mesg, "zip: reading %s\n", z->zname); 479 480 /* Save offset, update for next header */ 481 z->off = p; 482 p += 4 + LOCHEAD + n + z->ext + s; 483 zcount++; 484 485 /* Skip extended local header if there is one */ 486 if ((flg & 8) != 0) { 487 /* Skip the compressed data if compressed size is unknown. 488 * For safety, we should use the central directory. 489 */ 490 if (s == 0) { 491 for (;;) { 492 while ((m = getc(f)) != EOF && m != 0x50) ; /* 0x50 == 'P' */ 493 b[0] = (char) m; 494 if (fread(b+1, 15, 1, f) != 1 || LG(b) == EXTLOCSIG) 495 break; 496 if (fseek(f, -15L, SEEK_CUR)) 497 return ferror(f) ? ZE_READ : ZE_EOF; 498 } 499 s = LG(4 + EXTSIZ + b); 500 p += s; 501 if ((ulg) ftell(f) != p+16L) { 502 zipwarn("bad extended local header for ", z->zname); 503 return ZE_FORM; 504 } 505 } else { 506 /* compressed size non-zero, assume that it is valid: */ 507 Assert(p == ftell(f), "bad compressed size with extended header"); 508 509 if (fseek(f, p, SEEK_SET) || fread(b, 16, 1, f) != 1) 510 return ferror(f) ? ZE_READ : ZE_EOF; 511 if (LG(b) != EXTLOCSIG) { 512 zipwarn("extended local header not found for ", z->zname); 513 return ZE_FORM; 514 } 515 } 516 /* overwrite the unknown values of the local header: */ 517 518 /* already in host format */ 519 z->crc = LG(4 + EXTCRC + b); 520 z->siz = s; 521 z->len = LG(4 + EXTLEN + b); 522 523 p += 16L; 524 } 525 else if (fix > 1) { 526 /* Don't trust the compressed size */ 527 for (;;) { 528 while ((m = getc(f)) != EOF && m != 0x50) p++; /* 0x50 == 'P' */ 529 b[0] = (char) m; 530 if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG || s == CENSIG) 531 break; 532 if (fseek(f, -3L, SEEK_CUR)) 533 return ferror(f) ? ZE_READ : ZE_EOF; 534 p++; 535 } 536 s = p - (z->off + 4 + LOCHEAD + n + z->ext); 537 if (s != z->siz) { 538 fprintf(mesg, " compressed size %ld, actual size %ld for %s\n", 539 z->siz, s, z->zname); 540 z->siz = s; 541 } 542 /* next LOCSIG already read at this point, don't read it again: */ 543 continue; 544 } 545 546 /* Read next signature */ 547 if (fread(b, 4, 1, f) != 1) 548 break; 549 } 550 551 s = p; /* save start of central */ 552 553 if (LG(b) != CENSIG && noisy) { 554 fprintf(mesg, "zip warning: %s %s truncated.\n", zipfile, 555 fix > 1 ? "has been" : "would be"); 556 557 if (fix == 1) { 558 fprintf(mesg, 559 "Retry with option -qF to truncate, with -FF to attempt full recovery\n"); 560 ZIPERR(ZE_FORM, NULL); 561 } 562 } 563 564 cenbeg = s; 565 566 if (zipbeg && noisy) 567 fprintf(mesg, "%s: adjusting offsets for a preamble of %lu bytes\n", 568 zipfile, zipbeg); 569 570 return ZE_OK; 571} 572 573#endif /* !UTIL */ 574 575/* 576 * scanzipf_reg starts searching for the End Signature at the end of the file 577 * The End Signature points to the Central Directory Signature which points 578 * to the Local Directory Signature 579 * XXX probably some more consistency checks are needed 580 */ 581local int scanzipf_reg(f) 582 FILE *f; /* zip file */ 583/* 584 The name of the zip file is pointed to by the global "zipfile". The globals 585 zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in. 586 Return an error code in the ZE_ class. 587*/ 588{ 589 char b[CENHEAD]; /* buffer for central headers */ 590 ush flg; /* general purpose bit flag */ 591 int m; /* mismatch flag */ 592 extent n; /* length of name */ 593 struct zlist far * far *x; /* pointer last entry's link */ 594 struct zlist far *z; /* current zip entry structure */ 595 char *t; /* temporary pointer */ 596 char far *u; /* temporary variable */ 597 int found; 598 char *buf; /* temp buffer for reading zipfile */ 599 long deltaoff; 600 601 buf = malloc(4096 + 4); 602 if (buf == NULL) 603 return ZE_MEM; 604 605#ifdef HANDLE_AMIGA_SFX 606 amiga_sfx_offset = (fread(buf, 1, 4, f) == 4 && LG(buf) == 0xF3030000); 607 /* == 1 if this file is an Amiga executable (presumably UnZipSFX) */ 608#endif 609 found = 0; 610 t = &buf[4096]; 611 t[1] = '\0'; 612 t[2] = '\0'; 613 t[3] = '\0'; 614 if (fseek(f, -4096L, SEEK_END) == 0) { 615 zipbeg = (ulg) (ftell(f) + 4096L); 616 while (!found && zipbeg >= 4096) { 617 zipbeg -= 4096L; 618 buf[4096] = t[1]; 619 buf[4097] = t[2]; 620 buf[4098] = t[3]; 621/* 622 * XXX error check ?? 623 */ 624 fread(buf, 1, 4096, f); 625 fseek(f, -8192L, SEEK_CUR); 626 t = &buf[4095]; 627/* 628 * XXX far pointer arithmetic in DOS 629 */ 630 while (t >= buf) { 631 /* Check for ENDSIG the End Of Central Directory Record signature 632 ("PK\5\6" in ASCII) */ 633 if (LG(t) == ENDSIG) { 634 found = 1; 635/* 636 * XXX error check ?? 637 * XXX far pointer arithmetic in DOS 638 */ 639 zipbeg += (ulg) (t - buf); 640 fseek(f, (long) zipbeg + 4L, SEEK_SET); 641 break; 642 } 643 --t; 644 } 645 } 646 } 647 else 648 zipbeg = 4096L; 649/* 650 * XXX warn: garbage at the end of the file ignored 651 */ 652 if (!found && zipbeg > 0) { 653 size_t s; 654 655 fseek(f, 0L, SEEK_SET); 656 clearerr(f); 657 s = fread(buf, 1, (size_t) zipbeg, f); 658 buf[s] = t[1]; 659 buf[s + 1] = t[2]; 660 buf[s + 2] = t[3]; 661 t = &buf[s - 1]; 662/* 663 * XXX far pointer comparison in DOS 664 */ 665 while (t >= buf) { 666 /* Check for ENDSIG ("PK\5\6" in ASCII) */ 667 if (LG(t) == ENDSIG) { 668 found = 1; 669/* 670 * XXX far pointer arithmetic in DOS 671 */ 672 zipbeg = (ulg) (t - buf); 673 fseek(f, (long) zipbeg + 4L, SEEK_SET); 674 break; 675 } 676 --t; 677 } 678 } 679 free(buf); 680 if (!found) { 681 zipwarn("missing end signature--probably not a zip file (did you", ""); 682 zipwarn("remember to use binary mode when you transferred it?)", ""); 683 return ZE_FORM; 684 } 685 686/* 687 * Read the End Of Central Directory Record 688 */ 689 /* Read end header */ 690 if (fread(b, ENDHEAD, 1, f) != 1) 691 return ferror(f) ? ZE_READ : ZE_EOF; 692 if (SH(ENDDSK + b) || SH(ENDBEG + b) || 693 SH(ENDSUB + b) != SH(ENDTOT + b)) 694 zipwarn("multiple disk information ignored", ""); 695 zcomlen = SH(ENDCOM + b); 696 if (zcomlen) 697 { 698 if ((zcomment = malloc(zcomlen)) == NULL) 699 return ZE_MEM; 700 if (fread(zcomment, zcomlen, 1, f) != 1) 701 { 702 free((zvoid *)zcomment); 703 zcomment = NULL; 704 return ferror(f) ? ZE_READ : ZE_EOF; 705 } 706#ifdef EBCDIC 707 if (zcomment) 708 memtoebc(zcomment, zcomment, zcomlen); 709#endif /* EBCDIC */ 710 } 711/* 712 * XXX assumes central header immediately precedes end header 713 */ 714 cenbeg = zipbeg - LG(ENDSIZ + b); 715 deltaoff = adjust ? cenbeg - LG(b + ENDOFF) : 0L; 716 if (fseek(f, cenbeg, SEEK_SET) != 0) { 717 perror("fseek"); 718 return ZE_FORM; /* XXX */ 719 } 720 721 x = &zfiles; /* first link */ 722 723 if (fread(b, 4, 1, f) != 1) 724 return ferror(f) ? ZE_READ : ZE_EOF; 725 726 while (LG(b) == CENSIG) { 727 /* Read central header. The portion of the central header that should 728 be in common with local header is read raw, for later comparison. 729 (this requires that the offset of ext in the zlist structure 730 be greater than or equal to LOCHEAD) */ 731 if (fread(b, CENHEAD, 1, f) != 1) 732 return ferror(f) ? ZE_READ : ZE_EOF; 733 if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) 734 return ZE_MEM; 735 z->vem = SH(CENVEM + b); 736 for (u = (char far *)(&(z->ver)), n = 0; n < (CENNAM-CENVER); n++) 737 u[n] = b[CENVER + n]; 738 z->nam = SH(CENNAM + b); /* used before comparing cen vs. loc */ 739 z->cext = SH(CENEXT + b); /* may be different from z->ext */ 740 z->com = SH(CENCOM + b); 741 z->dsk = SH(CENDSK + b); 742 z->att = SH(CENATT + b); 743 z->atx = LG(CENATX + b); 744 z->off = LG(CENOFF + b) + deltaoff; 745 z->dosflag = (z->vem & 0xff00) == 0; 746 747 /* Initialize all fields pointing to malloced data to NULL */ 748 z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL; 749 750 /* Link into list */ 751 *x = z; 752 z->nxt = NULL; 753 x = &z->nxt; 754 755 /* Read file name, extra field and comment field */ 756 if (z->nam == 0) 757 { 758 sprintf(errbuf, "%lu", (ulg)zcount + 1); 759 zipwarn("zero-length name for entry #", errbuf); 760#ifndef DEBUG 761 farfree((zvoid far *)z); 762 return ZE_FORM; 763#endif 764 } 765 if ((z->iname = malloc(z->nam+1)) == NULL || 766 (z->cext && (z->cextra = malloc(z->cext)) == NULL) || 767 (z->com && (z->comment = malloc(z->com)) == NULL)) 768 return ZE_MEM; 769 if (fread(z->iname, z->nam, 1, f) != 1 || 770 (z->cext && fread(z->cextra, z->cext, 1, f) != 1) || 771 (z->com && fread(z->comment, z->com, 1, f) != 1)) 772 return ferror(f) ? ZE_READ : ZE_EOF; 773 z->iname[z->nam] = '\0'; /* terminate name */ 774#ifdef EBCDIC 775 if (z->com) 776 memtoebc(z->comment, z->comment, z->com); 777#endif /* EBCDIC */ 778 /* Update zipbeg offset, prepare for next header */ 779 if (z->off < zipbeg) 780 zipbeg = z->off; 781 zcount++; 782 /* Read next signature */ 783 if (fread(b, 4, 1, f) != 1) 784 return ferror(f) ? ZE_READ : ZE_EOF; 785 } 786 787 /* Point to start of header list and read local headers */ 788 z = zfiles; 789 while (z != NULL) { 790 /* Read next signature */ 791 if (fseek(f, z->off, SEEK_SET) != 0 || fread(b, 4, 1, f) != 1) 792 return ferror(f) ? ZE_READ : ZE_EOF; 793 if (LG(b) == LOCSIG) { 794 if (fread(b, LOCHEAD, 1, f) != 1) 795 return ferror(f) ? ZE_READ : ZE_EOF; 796 z->lflg = SH(LOCFLG + b); 797 n = SH(LOCNAM + b); 798 z->ext = SH(LOCEXT + b); 799 800 /* Compare name and extra fields */ 801 if (n != z->nam) 802 { 803#ifdef EBCDIC 804 strtoebc(z->iname, z->iname); 805#endif 806 zipwarn("name lengths in local and central differ for ", z->iname); 807 return ZE_FORM; 808 } 809 if ((t = malloc(z->nam)) == NULL) 810 return ZE_MEM; 811 if (fread(t, z->nam, 1, f) != 1) 812 { 813 free((zvoid *)t); 814 return ferror(f) ? ZE_READ : ZE_EOF; 815 } 816 if (memcmp(t, z->iname, z->nam)) 817 { 818 free((zvoid *)t); 819#ifdef EBCDIC 820 strtoebc(z->iname, z->iname); 821#endif 822 zipwarn("names in local and central differ for ", z->iname); 823 return ZE_FORM; 824 } 825 free((zvoid *)t); 826 if (z->ext) 827 { 828 if ((z->extra = malloc(z->ext)) == NULL) 829 return ZE_MEM; 830 if (fread(z->extra, z->ext, 1, f) != 1) 831 { 832 free((zvoid *)(z->extra)); 833 return ferror(f) ? ZE_READ : ZE_EOF; 834 } 835 if (z->ext == z->cext && memcmp(z->extra, z->cextra, z->ext) == 0) 836 { 837 free((zvoid *)(z->extra)); 838 z->extra = z->cextra; 839 } 840 } 841 842 /* Check extended local header if there is one */ 843 if ((z->lflg & 8) != 0) 844 { 845 char buf2[16]; 846 ulg s; /* size of compressed data */ 847 848 s = LG(LOCSIZ + b); 849 if (s == 0) 850 s = LG((CENSIZ-CENVER) + (char far *)(&(z->ver))); 851 if (fseek(f, (z->off + (4+LOCHEAD) + z->nam + z->ext + s), SEEK_SET) 852 || (fread(buf2, 16, 1, f) != 1)) 853 return ferror(f) ? ZE_READ : ZE_EOF; 854 if (LG(buf2) != EXTLOCSIG) 855 { 856#ifdef EBCDIC 857 strtoebc(z->iname, z->iname); 858#endif 859 zipwarn("extended local header not found for ", z->iname); 860 return ZE_FORM; 861 } 862 /* overwrite the unknown values of the local header: */ 863 for (n = 0; n < 12; n++) 864 b[LOCCRC+n] = buf2[4+n]; 865 } 866 867 /* Compare local header with that part of central header (except 868 for the reserved bits in the general purpose flags and except 869 for the already checked entry name length */ 870 u = (char far *)(&(z->ver)); 871 flg = SH((CENFLG-CENVER) + u); /* Save central flags word */ 872 u[CENFLG-CENVER+1] &= 0x1f; /* Mask reserved flag bits */ 873 b[LOCFLG+1] &= 0x1f; 874 for (m = 0, n = 0; n < LOCNAM; n++) 875 if (b[n] != u[n]) 876 { 877 if (!m) 878 { 879 zipwarn("local and central headers differ for ", z->zname); 880 m = 1; 881 } 882 if (noisy) 883 { 884 sprintf(errbuf, " offset %u--local = %02x, central = %02x", 885 (unsigned)n, (uch)b[n], (uch)u[n]); 886 zipwarn(errbuf, ""); 887 } 888 } 889 if (m && !adjust) 890 return ZE_FORM; 891 892 /* Complete the setup of the zlist entry by translating the remaining 893 * central header fields in memory, starting with the fields with 894 * highest offset. This order of the conversion commands takes into 895 * account potential buffer overlaps caused by structure padding. 896 */ 897 z->len = LG((CENLEN-CENVER) + u); 898 z->siz = LG((CENSIZ-CENVER) + u); 899 z->crc = LG((CENCRC-CENVER) + u); 900 z->tim = LG((CENTIM-CENVER) + u); /* time and date into one long */ 901 z->how = SH((CENHOW-CENVER) + u); 902 z->flg = flg; /* may be different from z->lflg */ 903 z->ver = SH((CENVER-CENVER) + u); 904 905 /* Clear actions */ 906 z->mark = 0; 907 z->trash = 0; 908#ifdef UTIL 909/* We only need z->iname in the utils */ 910 z->name = z->iname; 911#ifdef EBCDIC 912/* z->zname is used for printing and must be coded in native charset */ 913 if ((z->zname = malloc(z->nam+1)) == NULL) 914 return ZE_MEM; 915 strtoebc(z->zname, z->iname); 916#else 917 z->zname = z->iname; 918#endif 919#else /* !UTIL */ 920 z->zname = in2ex(z->iname); /* convert to external name */ 921 if (z->zname == NULL) 922 return ZE_MEM; 923 z->name = z->zname; 924#endif /* ?UTIL */ 925 } 926 else { 927#ifdef EBCDIC 928 strtoebc(z->iname, z->iname); 929#endif 930 zipwarn("local header not found for ", z->iname); 931 return ZE_FORM; 932 } 933#ifndef UTIL 934 if (verbose) 935 zipoddities(z); 936#endif 937 z = z->nxt; 938 } 939 940 if (zipbeg && noisy) 941 fprintf(mesg, "%s: %s a preamble of %lu bytes\n", 942 zipfile, adjust ? "adjusting offsets for" : "found", zipbeg); 943 944#ifdef HANDLE_AMIGA_SFX 945 if (zipbeg < 12 || (zipbeg & 3) != 0 /* must be longword aligned */) 946 amiga_sfx_offset = 0; 947 else if (amiga_sfx_offset) { 948 char buf2[16]; 949 if (!fseek(f, zipbeg - 12, SEEK_SET) && fread(buf2, 12, 1, f) == 1) { 950 if (LG(buf2 + 4) == 0xF1030000 /* 1009 in Motorola byte order */) 951 /* could also check if LG(buf2) == 0xF2030000... no for now */ 952 amiga_sfx_offset = zipbeg - 4; 953 else 954 amiga_sfx_offset = 0L; 955 } 956 } 957#endif /* HANDLE_AMIGA_SFX */ 958 return ZE_OK; 959} 960 961 962/* 963 * readzipfile initializes the global variables that hold the zipfile 964 * directory info and opens the zipfile. For the actual zipfile scan, 965 * the subroutine scanzipf_reg() or scanzipf_fix() is called, 966 * depending on the mode of operation (regular processing, or zipfix mode). 967 */ 968int readzipfile() 969/* 970 The name of the zip file is pointed to by the global "zipfile". 971 The globals zipbeg, zfiles, zcount, and zcomlen are initialized. 972 Return an error code in the ZE_ class. 973*/ 974{ 975 FILE *f; /* zip file */ 976 int retval; /* return code */ 977 int readable; /* 1 if zipfile exists and is readable */ 978 979 /* Initialize zip file info */ 980 zipbeg = 0; 981 zfiles = NULL; /* Points to first header */ 982 zcount = 0; /* number of files */ 983 zcomlen = 0; /* zip file comment length */ 984 retval = ZE_OK; 985 f = NULL; /* shut up some compilers */ 986 987 /* If zip file exists, read headers and check structure */ 988#ifdef VMS 989 if (zipfile == NULL || !(*zipfile) || !strcmp(zipfile, "-")) 990 return ZE_OK; 991 { 992 int rtype; 993 994 if ((VMSmunch(zipfile, GET_RTYPE, (char *)&rtype) == RMS$_NORMAL) && 995 (rtype == FAT$C_VARIABLE)) { 996 fprintf(stderr, 997 "\n Error: zipfile is in variable-length record format. Please\n\ 998 run \"bilf b %s\" to convert the zipfile to fixed-length\n\ 999 record format.\n\n", zipfile); 1000 return ZE_FORM; 1001 } 1002 } 1003 readable = ((f = fopen(zipfile, FOPR)) != NULL); 1004#else /* !VMS */ 1005 readable = (zipfile != NULL && *zipfile && strcmp(zipfile, "-") && 1006 (f = fopen(zipfile, FOPR)) != NULL); 1007#endif /* ?VMS */ 1008#ifdef MVS 1009 /* Very nasty special case for MVS. Just because the zipfile has been 1010 * opened for reading does not mean that we can actually read the data. 1011 * Typical JCL to create a zipfile is 1012 * 1013 * //ZIPFILE DD DISP=(NEW,CATLG),DSN=prefix.ZIP, 1014 * // SPACE=(CYL,(10,10)) 1015 * 1016 * That creates a VTOC entry with an end of file marker (DS1LSTAR) of zero. 1017 * Alas the VTOC end of file marker is only used when the file is opened in 1018 * append mode. When a file is opened in read mode, the "other" end of file 1019 * marker is used, a zero length data block signals end of file when reading. 1020 * With a brand new file which has not been written to yet, it is undefined 1021 * what you read off the disk. In fact you read whatever data was in the same 1022 * disk tracks before the zipfile was allocated. You would be amazed at the 1023 * number of application programmers who still do not understand this. Makes 1024 * for interesting and semi-random errors, GIGO. 1025 * 1026 * Newer versions of SMS will automatically write a zero length block when a 1027 * file is allocated. However not all sites run SMS or they run older levels 1028 * so we cannot rely on that. The only safe thing to do is close the file, 1029 * open in append mode (we already know that the file exists), close it again, 1030 * reopen in read mode and try to read a data block. Opening and closing in 1031 * append mode will write a zero length block where DS1LSTAR points, making 1032 * sure that the VTOC and internal end of file markers are in sync. Then it 1033 * is safe to read data. If we cannot read one byte of data after all that, 1034 * it is a brand new zipfile and must not be read. 1035 */ 1036 if (readable) 1037 { 1038 char c; 1039 fclose(f); 1040 /* append mode */ 1041 if ((f = fopen(zipfile, "ab")) == NULL) { 1042 ZIPERR(ZE_OPEN, zipfile); 1043 } 1044 fclose(f); 1045 /* read mode again */ 1046 if ((f = fopen(zipfile, FOPR)) == NULL) { 1047 ZIPERR(ZE_OPEN, zipfile); 1048 } 1049 if (fread(&c, 1, 1, f) != 1) { 1050 /* no actual data */ 1051 readable = 0; 1052 fclose(f); 1053 } 1054 else{ 1055 fseek(f, 0, SEEK_SET); /* at least one byte in zipfile, back to the start */ 1056 } 1057 } 1058#endif /* MVS */ 1059 if (readable) 1060 { 1061#ifndef UTIL 1062 retval = (fix && !adjust) ? scanzipf_fix(f) : scanzipf_reg(f); 1063#else 1064 retval = scanzipf_reg(f); 1065#endif 1066 1067 /* Done with zip file for now */ 1068 fclose(f); 1069 1070 /* If one or more files, sort by name */ 1071 if (zcount) 1072 { 1073 struct zlist far * far *x; /* pointer into zsort array */ 1074 struct zlist far *z; /* pointer into zfiles linked list */ 1075 extent zl_size = zcount * sizeof(struct zlist far *); 1076 1077 if (zl_size / sizeof(struct zlist far *) != zcount || 1078 (x = zsort = (struct zlist far **)malloc(zl_size)) == NULL) 1079 return ZE_MEM; 1080 for (z = zfiles; z != NULL; z = z->nxt) 1081 *x++ = z; 1082 qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp); 1083 } 1084 } 1085 return retval; 1086} 1087 1088 1089int putlocal(z, f) 1090struct zlist far *z; /* zip entry to write local header for */ 1091FILE *f; /* file to write to */ 1092/* Write a local header described by *z to file *f. Return an error code 1093 in the ZE_ class. */ 1094{ 1095 PUTLG(LOCSIG, f); 1096 PUTSH(z->ver, f); 1097 PUTSH(z->lflg, f); 1098 PUTSH(z->how, f); 1099 PUTLG(z->tim, f); 1100 PUTLG(z->crc, f); 1101 PUTLG(z->siz, f); 1102 PUTLG(z->len, f); 1103 PUTSH(z->nam, f); 1104 PUTSH(z->ext, f); 1105 if (fwrite(z->iname, 1, z->nam, f) != z->nam || 1106 (z->ext && fwrite(z->extra, 1, z->ext, f) != z->ext)) 1107 return ZE_TEMP; 1108 return ZE_OK; 1109} 1110 1111int putextended(z, f) 1112struct zlist far *z; /* zip entry to write local header for */ 1113FILE *f; /* file to write to */ 1114/* Write an extended local header described by *z to file *f. 1115 * Return an error code in the ZE_ class. */ 1116{ 1117 PUTLG(EXTLOCSIG, f); 1118 PUTLG(z->crc, f); 1119 PUTLG(z->siz, f); 1120 PUTLG(z->len, f); 1121 return ZE_OK; 1122} 1123 1124int putcentral(z, f) 1125struct zlist far *z; /* zip entry to write central header for */ 1126FILE *f; /* file to write to */ 1127/* Write a central header described by *z to file *f. Return an error code 1128 in the ZE_ class. */ 1129{ 1130 PUTLG(CENSIG, f); 1131 PUTSH(z->vem, f); 1132 PUTSH(z->ver, f); 1133 PUTSH(z->flg, f); 1134 PUTSH(z->how, f); 1135 PUTLG(z->tim, f); 1136 PUTLG(z->crc, f); 1137 PUTLG(z->siz, f); 1138 PUTLG(z->len, f); 1139 PUTSH(z->nam, f); 1140 PUTSH(z->cext, f); 1141 PUTSH(z->com, f); 1142 PUTSH(z->dsk, f); 1143 PUTSH(z->att, f); 1144 PUTLG(z->atx, f); 1145 PUTLG(z->off, f); 1146#ifdef EBCDIC 1147 if (z->com) 1148 memtoasc(z->comment, z->comment, z->com); 1149#endif /* EBCDIC */ 1150 if (fwrite(z->iname, 1, z->nam, f) != z->nam || 1151 (z->cext && fwrite(z->cextra, 1, z->cext, f) != z->cext) || 1152 (z->com && fwrite(z->comment, 1, z->com, f) != z->com)) 1153 return ZE_TEMP; 1154 return ZE_OK; 1155} 1156 1157 1158int putend(n, s, c, m, z, f) 1159unsigned n; /* number of entries in central directory */ 1160ulg s; /* size of central directory */ 1161ulg c; /* offset of central directory */ 1162extent m; /* length of zip file comment (0 if none) */ 1163char *z; /* zip file comment if m != 0 */ 1164FILE *f; /* file to write to */ 1165/* Write the end of central directory data to file *f. Return an error code 1166 in the ZE_ class. */ 1167{ 1168 PUTLG(ENDSIG, f); 1169 PUTSH(0, f); 1170 PUTSH(0, f); 1171 PUTSH(n, f); 1172 PUTSH(n, f); 1173 PUTLG(s, f); 1174 PUTLG(c, f); 1175 PUTSH(m, f); 1176/* Write the comment, if any */ 1177#ifdef EBCDIC 1178 memtoasc(z, z, m); 1179#endif 1180 if (m && fwrite(z, 1, m, f) != m) 1181 return ZE_TEMP; 1182 1183#ifdef HANDLE_AMIGA_SFX 1184 if (amiga_sfx_offset && zipbeg /* -J zeroes this */) { 1185 s = ftell(f); 1186 while (s & 3) s++, putc(0, f); /* final marker must be longword aligned */ 1187 PUTLG(0xF2030000 /* 1010 in Motorola byte order */, f); 1188 c = (s - amiga_sfx_offset - 4) / 4; /* size of archive part in longwords */ 1189 if (fseek(f, amiga_sfx_offset, SEEK_SET) != 0) 1190 return ZE_TEMP; 1191 c = ((c >> 24) & 0xFF) | ((c >> 8) & 0xFF00) 1192 | ((c & 0xFF00) << 8) | ((c & 0xFF) << 24); /* invert byte order */ 1193 PUTLG(c, f); 1194 fseek(f, 0, SEEK_END); /* just in case */ 1195 } 1196#endif 1197 return ZE_OK; 1198} 1199 1200 1201/* Note: a zip "entry" includes a local header (which includes the file 1202 name), an encryption header if encrypting, the compressed data 1203 and possibly an extended local header. */ 1204 1205int zipcopy(z, x, y) 1206struct zlist far *z; /* zip entry to copy */ 1207FILE *x, *y; /* source and destination files */ 1208/* Copy the zip entry described by *z from file *x to file *y. Return an 1209 error code in the ZE_ class. Also update tempzn by the number of bytes 1210 copied. */ 1211{ 1212 ulg n; /* holds local header offset */ 1213 1214 Trace((stderr, "zipcopy %s\n", z->zname)); 1215 n = (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext; 1216 1217 if (fix > 1) { 1218 if (fseek(x, z->off + n, SEEK_SET)) /* seek to compressed data */ 1219 return ferror(x) ? ZE_READ : ZE_EOF; 1220 1221 if (fix > 2) { 1222 /* Update length of entry's name, it may have been changed. This is 1223 needed to support the ZipNote ability to rename archive entries. */ 1224 z->nam = strlen(z->iname); 1225 n = (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext; 1226 } 1227 1228 /* do not trust the old compressed size */ 1229 if (putlocal(z, y) != ZE_OK) 1230 return ZE_TEMP; 1231 1232 z->off = tempzn; 1233 tempzn += n; 1234 n = z->siz; 1235 } else { 1236 if (fseek(x, z->off, SEEK_SET)) /* seek to local header */ 1237 return ferror(x) ? ZE_READ : ZE_EOF; 1238 1239 z->off = tempzn; 1240 n += z->siz; 1241 } 1242 /* copy the compressed data and the extended local header if there is one */ 1243 if (z->lflg & 8) n += 16; 1244 tempzn += n; 1245 return fcopy(x, y, n); 1246} 1247 1248 1249#ifndef UTIL 1250 1251#ifdef USE_EF_UT_TIME 1252 1253local int ef_scan_ut_time(ef_buf, ef_len, ef_is_cent, z_utim) 1254char *ef_buf; /* buffer containing extra field */ 1255extent ef_len; /* total length of extra field */ 1256int ef_is_cent; /* flag indicating "is central extra field" */ 1257iztimes *z_utim; /* return storage: atime, mtime, ctime */ 1258/* This function scans the extra field for EF_TIME or EF_IZUNIX blocks 1259 * containing Unix style time_t (GMT) values for the entry's access, creation 1260 * and modification time. 1261 * If a valid block is found, all time stamps are copied to the iztimes 1262 * structure. 1263 * The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring 1264 * all data from probably present obsolete EF_IZUNIX blocks. 1265 * If multiple blocks of the same type are found, only the information from 1266 * the last block is used. 1267 * The return value is the EF_TIME Flags field (simulated in case of an 1268 * EF_IZUNIX block) or 0 in case of failure. 1269 */ 1270{ 1271 int flags = 0; 1272 unsigned eb_id; 1273 extent eb_len; 1274 int have_new_type_eb = FALSE; 1275 1276 if (ef_len == 0 || ef_buf == NULL) 1277 return 0; 1278 1279 Trace((stderr,"\nef_scan_ut_time: scanning extra field of length %u\n", 1280 ef_len)); 1281 while (ef_len >= EB_HEADSIZE) { 1282 eb_id = SH(EB_ID + ef_buf); 1283 eb_len = SH(EB_LEN + ef_buf); 1284 1285 if (eb_len > (ef_len - EB_HEADSIZE)) { 1286 /* Discovered some extra field inconsistency! */ 1287 Trace((stderr,"ef_scan_ut_time: block length %u > rest ef_size %u\n", 1288 eb_len, ef_len - EB_HEADSIZE)); 1289 break; 1290 } 1291 1292 switch (eb_id) { 1293 case EF_TIME: 1294 flags &= ~0x00ff; /* ignore previous IZUNIX or EF_TIME fields */ 1295 have_new_type_eb = TRUE; 1296 if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) { 1297 unsigned eb_idx = EB_UT_TIME1; 1298 Trace((stderr,"ef_scan_ut_time: Found TIME extra field\n")); 1299 flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x00ff); 1300 if ((flags & EB_UT_FL_MTIME)) { 1301 if ((eb_idx+4) <= eb_len) { 1302 z_utim->mtime = LG((EB_HEADSIZE+eb_idx) + ef_buf); 1303 eb_idx += 4; 1304 Trace((stderr," Unix EF modtime = %ld\n", z_utim->mtime)); 1305 } else { 1306 flags &= ~EB_UT_FL_MTIME; 1307 Trace((stderr," Unix EF truncated, no modtime\n")); 1308 } 1309 } 1310 if (ef_is_cent) { 1311 break; /* central version of TIME field ends here */ 1312 } 1313 if (flags & EB_UT_FL_ATIME) { 1314 if ((eb_idx+4) <= eb_len) { 1315 z_utim->atime = LG((EB_HEADSIZE+eb_idx) + ef_buf); 1316 eb_idx += 4; 1317 Trace((stderr," Unix EF acctime = %ld\n", z_utim->atime)); 1318 } else { 1319 flags &= ~EB_UT_FL_ATIME; 1320 } 1321 } 1322 if (flags & EB_UT_FL_CTIME) { 1323 if ((eb_idx+4) <= eb_len) { 1324 z_utim->ctime = LG((EB_HEADSIZE+eb_idx) + ef_buf); 1325 /* eb_idx += 4; */ /* superfluous for now ... */ 1326 Trace((stderr," Unix EF cretime = %ld\n", z_utim->ctime)); 1327 } else { 1328 flags &= ~EB_UT_FL_CTIME; 1329 } 1330 } 1331 } 1332 break; 1333 1334 case EF_IZUNIX2: 1335 if (!have_new_type_eb) { 1336 flags &= ~0x00ff; /* ignore any previous IZUNIX field */ 1337 have_new_type_eb = TRUE; 1338 } 1339 break; 1340 1341 case EF_IZUNIX: 1342 if (eb_len >= EB_UX_MINLEN) { 1343 Trace((stderr,"ef_scan_ut_time: Found IZUNIX extra field\n")); 1344 if (have_new_type_eb) { 1345 break; /* Ignore IZUNIX extra field block ! */ 1346 } 1347 z_utim->atime = LG((EB_HEADSIZE+EB_UX_ATIME) + ef_buf); 1348 z_utim->mtime = LG((EB_HEADSIZE+EB_UX_MTIME) + ef_buf); 1349 Trace((stderr," Unix EF access time = %ld\n",z_utim->atime)); 1350 Trace((stderr," Unix EF modif. time = %ld\n",z_utim->mtime)); 1351 flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME); /* signal success */ 1352 } 1353 break; 1354 1355 case EF_THEOS: 1356/* printf("Not implemented yet\n"); */ 1357 break; 1358 1359 default: 1360 break; 1361 } 1362 /* Skip this extra field block */ 1363 ef_buf += (eb_len + EB_HEADSIZE); 1364 ef_len -= (eb_len + EB_HEADSIZE); 1365 } 1366 1367 return flags; 1368} 1369 1370int get_ef_ut_ztime(z, z_utim) 1371struct zlist far *z; 1372iztimes *z_utim; 1373{ 1374 int r; 1375 1376#ifdef IZ_CHECK_TZ 1377 if (!zp_tz_is_valid) return 0; 1378#endif 1379 1380 /* First, scan local extra field. */ 1381 r = ef_scan_ut_time(z->extra, z->ext, FALSE, z_utim); 1382 1383 /* If this was not successful, try central extra field, but only if 1384 it is really different. */ 1385 if (!r && z->cext > 0 && z->cextra != z->extra) 1386 r = ef_scan_ut_time(z->cextra, z->cext, TRUE, z_utim); 1387 1388 return r; 1389} 1390 1391#endif /* USE_EF_UT_TIME */ 1392 1393 1394local void cutpath(p, delim) 1395char *p; /* path string */ 1396int delim; /* path component separator char */ 1397/* Cut the last path component off the name *p in place. 1398 * This should work on both internal and external names. 1399 */ 1400{ 1401 char *r; /* pointer to last path delimiter */ 1402 1403#ifdef VMS /* change [w.x.y]z to [w.x]y.DIR */ 1404 if ((r = MBSRCHR(p, ']')) != NULL) 1405 { 1406 *r = 0; 1407 if ((r = MBSRCHR(p, '.')) != NULL) 1408 { 1409 *r = ']'; 1410 strcat(r, ".DIR;1"); /* this assumes a little padding--see PAD */ 1411 } else { 1412 *p = 0; 1413 } 1414 } else { 1415 if ((r = MBSRCHR(p, delim)) != NULL) 1416 *r = 0; 1417 else 1418 *p = 0; 1419 } 1420#else /* !VMS */ 1421 if ((r = MBSRCHR(p, delim)) != NULL) 1422 *r = 0; 1423 else 1424 *p = 0; 1425#endif /* ?VMS */ 1426} 1427 1428int trash() 1429/* Delete the compressed files and the directories that contained the deleted 1430 files, if empty. Return an error code in the ZE_ class. Failure of 1431 destroy() or deletedir() is ignored. */ 1432{ 1433 extent i; /* counter on deleted names */ 1434 extent n; /* number of directories to delete */ 1435 struct zlist far **s; /* table of zip entries to handle, sorted */ 1436 struct zlist far *z; /* current zip entry */ 1437 1438 /* Delete marked names and count directories */ 1439 n = 0; 1440 for (z = zfiles; z != NULL; z = z->nxt) 1441 if (z->mark == 1 || z->trash) 1442 { 1443 z->mark = 1; 1444 if (z->iname[z->nam - 1] != (char)0x2f) { /* don't unlink directory */ 1445 if (verbose) 1446 fprintf(mesg, "zip diagnostic: deleting file %s\n", z->name); 1447 if (destroy(z->name)) { 1448 zipwarn("error deleting ", z->name); 1449 } 1450 /* Try to delete all paths that lead up to marked names. This is 1451 * necessary only with the -D option. 1452 */ 1453 if (!dirnames) { 1454 cutpath(z->name, '/'); /* XXX wrong ??? */ 1455 cutpath(z->iname, 0x2f); /* 0x2f = ascii['/'] */ 1456 z->nam = strlen(z->iname); 1457 if (z->nam > 0) { 1458 z->iname[z->nam - 1] = (char)0x2f; 1459 z->iname[z->nam++] = '\0'; 1460 } 1461 if (z->nam > 0) n++; 1462 } 1463 } else { 1464 n++; 1465 } 1466 } 1467 1468 /* Construct the list of all marked directories. Some may be duplicated 1469 * if -D was used. 1470 */ 1471 if (n) 1472 { 1473 if ((s = (struct zlist far **)malloc(n*sizeof(struct zlist far *))) == 1474 NULL) 1475 return ZE_MEM; 1476 n = 0; 1477 for (z = zfiles; z != NULL; z = z->nxt) { 1478 if (z->mark && z->nam > 0 && z->iname[z->nam - 1] == (char)0x2f /* '/' */ 1479 && (n == 0 || strcmp(z->name, s[n-1]->name) != 0)) { 1480 s[n++] = z; 1481 } 1482 } 1483 /* Sort the files in reverse order to get subdirectories first. 1484 * To avoid problems with strange naming conventions as in VMS, 1485 * we sort on the internal names, so x/y/z will always be removed 1486 * before x/y. On VMS, x/y/z > x/y but [x.y.z] < [x.y] 1487 */ 1488 qsort((char *)s, n, sizeof(struct zlist far *), rqcmp); 1489 1490 for (i = 0; i < n; i++) { 1491 char *p = s[i]->name; 1492 if (*p == '\0') continue; 1493 if (p[strlen(p) - 1] == '/') { /* keep VMS [x.y]z.dir;1 intact */ 1494 p[strlen(p) - 1] = '\0'; 1495 } 1496 if (i == 0 || strcmp(s[i]->name, s[i-1]->name) != 0) { 1497 if (verbose) { 1498 fprintf(mesg, "deleting directory %s (if empty) \n", 1499 s[i]->name); 1500 } 1501 deletedir(s[i]->name); 1502 } 1503 } 1504 free((zvoid *)s); 1505 } 1506 return ZE_OK; 1507} 1508 1509#endif /* !UTIL */ 1510