|
|
1.1 ! root 1: /* ! 2: ! 3: Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly, ! 4: Kai Uwe Rommel and Igor Mandrichenko. ! 5: Permission is granted to any individual or institution to use, copy, or ! 6: redistribute this software so long as all of the original files are included ! 7: unmodified, that it is not sold for profit, and that this copyright notice ! 8: is retained. ! 9: ! 10: */ ! 11: ! 12: /* ! 13: * zipfile.c by Mark Adler. ! 14: */ ! 15: ! 16: #include "zip.h" ! 17: ! 18: #ifdef VMS ! 19: # include "VMSmunch.h" ! 20: # include <rms.h> ! 21: #endif ! 22: ! 23: ! 24: /* Macros for converting integers in little-endian to machine format */ ! 25: #define SH(a) (((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8)) ! 26: #define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16)) ! 27: ! 28: /* Macros for writing machine integers to little-endian format */ ! 29: #define PUTSH(a,f) {putc((char)(a),(f)); putc((char)((a) >> 8),(f));} ! 30: #define PUTLG(a,f) {PUTSH(a,f) PUTSH((a) >> 16,f)} ! 31: ! 32: ! 33: /* -- Structure of a ZIP file -- */ ! 34: ! 35: /* Signatures for zip file information headers */ ! 36: #define LOCSIG 0x04034b50L ! 37: #define CENSIG 0x02014b50L ! 38: #define ENDSIG 0x06054b50L ! 39: #define EXTLOCSIG 0x08074b50L ! 40: ! 41: /* Offsets of values in headers */ ! 42: #define LOCVER 0 /* version needed to extract */ ! 43: #define LOCFLG 2 /* encrypt, deflate flags */ ! 44: #define LOCHOW 4 /* compression method */ ! 45: #define LOCTIM 6 /* last modified file time, DOS format */ ! 46: #define LOCDAT 8 /* last modified file date, DOS format */ ! 47: #define LOCCRC 10 /* uncompressed crc-32 for file */ ! 48: #define LOCSIZ 14 /* compressed size in zip file */ ! 49: #define LOCLEN 18 /* uncompressed size */ ! 50: #define LOCNAM 22 /* length of filename */ ! 51: #define LOCEXT 24 /* length of extra field */ ! 52: ! 53: #define CENVEM 0 /* version made by */ ! 54: #define CENVER 2 /* version needed to extract */ ! 55: #define CENFLG 4 /* encrypt, deflate flags */ ! 56: #define CENHOW 6 /* compression method */ ! 57: #define CENTIM 8 /* last modified file time, DOS format */ ! 58: #define CENDAT 10 /* last modified file date, DOS format */ ! 59: #define CENCRC 12 /* uncompressed crc-32 for file */ ! 60: #define CENSIZ 16 /* compressed size in zip file */ ! 61: #define CENLEN 20 /* uncompressed size */ ! 62: #define CENNAM 24 /* length of filename */ ! 63: #define CENEXT 26 /* length of extra field */ ! 64: #define CENCOM 28 /* file comment length */ ! 65: #define CENDSK 30 /* disk number start */ ! 66: #define CENATT 32 /* internal file attributes */ ! 67: #define CENATX 34 /* external file attributes */ ! 68: #define CENOFF 38 /* relative offset of local header */ ! 69: ! 70: #define ENDDSK 0 /* number of this disk */ ! 71: #define ENDBEG 2 /* number of the starting disk */ ! 72: #define ENDSUB 4 /* entries on this disk */ ! 73: #define ENDTOT 6 /* total number of entries */ ! 74: #define ENDSIZ 8 /* size of entire central directory */ ! 75: #define ENDOFF 12 /* offset of central on starting disk */ ! 76: #define ENDCOM 16 /* length of zip file comment */ ! 77: ! 78: ! 79: /* Local functions */ ! 80: #ifdef PROTO ! 81: local int zqcmp(voidp *, voidp *); ! 82: # ifndef UTIL ! 83: local int zbcmp(voidp *, voidp far *); ! 84: local char *cutpath(char *); ! 85: # endif /* !UTIL */ ! 86: #endif /* PROTO */ ! 87: ! 88: ! 89: local int zqcmp(a, b) ! 90: voidp *a, *b; /* pointers to pointers to zip entries */ ! 91: /* Used by qsort() to compare entries in the zfile list. */ ! 92: { ! 93: return namecmp((*(struct zlist far **)a)->zname, ! 94: (*(struct zlist far **)b)->zname); ! 95: } ! 96: ! 97: ! 98: #ifndef UTIL ! 99: ! 100: local int zbcmp(n, z) ! 101: voidp *n; /* string to search for */ ! 102: voidp far *z; /* pointer to a pointer to a zip entry */ ! 103: /* Used by search() to compare a target to an entry in the zfile list. */ ! 104: { ! 105: return namecmp((char *)n, ((struct zlist far *)z)->zname); ! 106: } ! 107: ! 108: ! 109: struct zlist far *zsearch(n) ! 110: char *n; /* name to find */ ! 111: /* Return a pointer to the entry in zfile with the name n, or NULL if ! 112: not found. */ ! 113: { ! 114: voidp far **p; /* result of search() */ ! 115: ! 116: if (zcount && (p = search(n, (voidp far **)zsort, zcount, zbcmp)) != NULL) ! 117: return *(struct zlist far **)p; ! 118: else ! 119: return NULL; ! 120: } ! 121: ! 122: #endif /* !UTIL */ ! 123: ! 124: #ifndef VMS ! 125: # define PATHCUT '/' ! 126: ! 127: char *ziptyp(s) ! 128: char *s; /* file name to force to zip */ ! 129: /* If the file name *s has a dot (other than the first char), then return ! 130: the name, otherwise append .zip to the name. Allocate the space for ! 131: the name in either case. Return a pointer to the new name, or NULL ! 132: if malloc() fails. */ ! 133: { ! 134: char *q; /* temporary pointer */ ! 135: char *t; /* pointer to malloc'ed string */ ! 136: ! 137: if ((t = malloc(strlen(s) + 5)) == NULL) ! 138: return NULL; ! 139: strcpy(t, s); ! 140: #ifdef MSDOS ! 141: for (q = t; *q; q++) ! 142: if (*q == '\\') ! 143: *q = '/'; ! 144: #endif /* MSDOS */ ! 145: if (strrchr((q = strrchr(t, PATHCUT)) == NULL ? t : q + 1, '.') == NULL) ! 146: strcat(t, ".zip"); ! 147: #if defined(FORCE_UPPER) && defined(MSDOS) && !defined(OS2) ! 148: strupr(t); ! 149: #endif ! 150: return t; ! 151: } ! 152: ! 153: #else /* VMS */ ! 154: ! 155: # define PATHCUT ']' ! 156: ! 157: char *ziptyp(s) ! 158: char *s; ! 159: { int status; ! 160: struct FAB fab; ! 161: struct NAM nam; ! 162: static char zero=0; ! 163: char result[NAM$C_MAXRSS+1],exp[NAM$C_MAXRSS+1]; ! 164: char *p; ! 165: ! 166: fab = cc$rms_fab; ! 167: nam = cc$rms_nam; ! 168: ! 169: fab.fab$l_fna = s; ! 170: fab.fab$b_fns = strlen(fab.fab$l_fna); ! 171: ! 172: fab.fab$l_dna = "sys$disk:[].zip"; /* Default fspec */ ! 173: fab.fab$b_dns = strlen(fab.fab$l_dna); ! 174: ! 175: fab.fab$l_nam = &nam; ! 176: ! 177: nam.nam$l_rsa = result; /* Put resultant name of */ ! 178: nam.nam$b_rss = sizeof(result)-1; /* existing zipfile here */ ! 179: ! 180: nam.nam$l_esa = exp; /* For full spec of */ ! 181: nam.nam$b_ess = sizeof(exp)-1; /* file to create */ ! 182: ! 183: status = sys$parse(&fab); ! 184: if( (status & 1) == 0 ) ! 185: return &zero; ! 186: ! 187: status = sys$search(&fab); ! 188: if( status & 1 ) ! 189: { /* Existing ZIP file */ ! 190: int l; ! 191: if( (p=malloc( (l=nam.nam$b_rsl) + 1 )) != NULL ) ! 192: { result[l] = 0; ! 193: strcpy(p,result); ! 194: } ! 195: } ! 196: else ! 197: { /* New ZIP file */ ! 198: int l; ! 199: if( (p=malloc( (l=nam.nam$b_esl) + 1 )) != NULL ) ! 200: { exp[l] = 0; ! 201: strcpy(p,exp); ! 202: } ! 203: } ! 204: return p; ! 205: } ! 206: ! 207: #endif /* VMS */ ! 208: ! 209: ! 210: int readzipfile() ! 211: /* ! 212: Make first pass through zip file, reading information from local file ! 213: headers and then verifying that information with the central file ! 214: headers. Any deviation from the expected zip file format returns an ! 215: error. At the end, a sorted list of file names in the zip file is made ! 216: to facilitate searching by name. ! 217: ! 218: The name of the zip file is pointed to by the global "zipfile". The ! 219: globals zfiles, zcount, zcomlen, zcomment, and zsort are filled in. ! 220: Return an error code in the ZE_ class. ! 221: */ ! 222: { ! 223: char b[CENHEAD]; /* buffer for central headers */ ! 224: FILE *f; /* zip file */ ! 225: ush flg; /* general purpose bit flag */ ! 226: int m; /* mismatch flag */ ! 227: extent n; /* length of name */ ! 228: ulg p; /* current file offset */ ! 229: char r; /* holds reserved bits during memcmp() */ ! 230: ulg s; /* size of data, start of central */ ! 231: char *t; /* temporary variable */ ! 232: char far *u; /* temporary variable */ ! 233: struct zlist far * far *x; /* pointer last entry's link */ ! 234: struct zlist far *z; /* current zip entry structure */ ! 235: ! 236: /* Initialize zip file info */ ! 237: zipbeg = 0; ! 238: zfiles = NULL; /* Points to first header */ ! 239: zcomlen = 0; /* zip file comment length */ ! 240: ! 241: /* If zip file exists, read headers and check structure */ ! 242: #ifdef VMS ! 243: if (zipfile == NULL || !(*zipfile) || !strcmp(zipfile, "-")) ! 244: return ZE_OK; ! 245: { ! 246: int rtype; ! 247: VMSmunch(zipfile, GET_RTYPE, (char *)&rtype); ! 248: if (rtype == FAT$C_VARIABLE) { ! 249: fprintf(stderr, ! 250: "\n Error: zipfile is in variable-length record format. Please\n\ ! 251: run \"bilf b %s\" to convert the zipfile to fixed-length\n\ ! 252: record format. (Bilf.exe, bilf.c and make_bilf.com are included\n\ ! 253: in the VMS UnZip distribution.)\n\n", zipfile); ! 254: return ZE_FORM; ! 255: } ! 256: } ! 257: if ((f = fopen(zipfile, FOPR)) != NULL) ! 258: #else /* !VMS */ ! 259: if (zipfile != NULL && *zipfile && strcmp(zipfile, "-") && ! 260: (f = fopen(zipfile, FOPR)) != NULL) ! 261: #endif /* ?VMS */ ! 262: { ! 263: x = &zfiles; /* first link */ ! 264: p = 0; /* starting file offset */ ! 265: zcount = 0; /* number of files */ ! 266: ! 267: /* Find start of zip structures */ ! 268: for (;;) { ! 269: while ((m = getc(f)) != EOF && m != 'P') p++; ! 270: b[0] = (char) m; ! 271: if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG || s == ENDSIG) ! 272: break; ! 273: if (fseek(f, -3L, SEEK_CUR)) ! 274: return ferror(f) ? ZE_READ : ZE_EOF; ! 275: p++; ! 276: } ! 277: zipbeg = p; ! 278: ! 279: /* Read local headers */ ! 280: while (LG(b) == LOCSIG) ! 281: { ! 282: /* Read local header raw to compare later with central header ! 283: (this requires that the offest of ext in the zlist structure ! 284: be greater than or equal to LOCHEAD) */ ! 285: if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) ! 286: return ZE_MEM; ! 287: if (fread(b, LOCHEAD, 1, f) != 1) ! 288: return ferror(f) ? ZE_READ : ZE_EOF; ! 289: t = b; u = (char far *)z; n = LOCHEAD; ! 290: do { ! 291: *u++ = *t++; ! 292: } while (--n); ! 293: ! 294: /* Link into list */ ! 295: *x = z; ! 296: z->nxt = NULL; ! 297: x = &z->nxt; ! 298: ! 299: /* Read file name and extra field and skip data */ ! 300: n = SH(LOCNAM + (uch far *)z); ! 301: z->ext = SH(LOCEXT + (uch far *)z); ! 302: s = LG(LOCSIZ + (uch far *)z); ! 303: if (n == 0) ! 304: { ! 305: sprintf(errbuf, "%d", zcount + 1); ! 306: warn("zero-length name for entry #", errbuf); ! 307: return ZE_FORM; ! 308: } ! 309: if ((z->zname = malloc(n+1)) == NULL || ! 310: (z->ext && (z->extra = malloc(z->ext)) == NULL)) ! 311: return ZE_MEM; ! 312: if (fread(z->zname, n, 1, f) != 1 || ! 313: (z->ext && fread(z->extra, z->ext, 1, f) != 1) || ! 314: fseek(f, (long)s, SEEK_CUR)) ! 315: return ferror(f) ? ZE_READ : ZE_EOF; ! 316: /* If there is an extended local header, s is either 0 or ! 317: * the correct compressed size. ! 318: */ ! 319: z->zname[n] = 0; /* terminate name */ ! 320: #ifdef UTIL ! 321: z->name = z->zname; ! 322: #else /* !UTIL */ ! 323: z->name = in2ex(z->zname); /* convert to external name */ ! 324: if (z->name == NULL) ! 325: return ZE_MEM; ! 326: #endif /* ?UTIL */ ! 327: ! 328: /* Save offset, update for next header */ ! 329: z->off = p; ! 330: p += 4 + LOCHEAD + n + z->ext + s; ! 331: zcount++; ! 332: ! 333: /* Skip extended local header if there is one */ ! 334: flg = SH(b+LOCFLG); ! 335: if ((flg & 8) != 0) { ! 336: /* Skip the compressed data if compressed size is unknown. ! 337: * For safety, we should use the central directory. ! 338: */ ! 339: if (s == 0) { ! 340: for (;;) { ! 341: while ((m = getc(f)) != EOF && m != 'P') ; ! 342: b[0] = (char) m; ! 343: if (fread(b+1, 15, 1, f) != 1 || LG(b) == EXTLOCSIG) ! 344: break; ! 345: if (fseek(f, -15L, SEEK_CUR)) ! 346: return ferror(f) ? ZE_READ : ZE_EOF; ! 347: } ! 348: s = LG(b+8); ! 349: p += s; ! 350: if ((ulg) ftell(f) != p+16L) { ! 351: warn("bad extended local header for ", z->zname); ! 352: return ZE_FORM; ! 353: } ! 354: } else { ! 355: /* compressed size non zero, assume that it is valid: */ ! 356: if (fseek(f, p, SEEK_SET) || fread(b, 16, 1, f) != 1) ! 357: return ferror(f) ? ZE_READ : ZE_EOF; ! 358: if (LG(b) != EXTLOCSIG) { ! 359: warn("extended local header not found for ", z->zname); ! 360: return ZE_FORM; ! 361: } ! 362: } ! 363: /* overwrite the unknown values of the local header: */ ! 364: t = b+4; u = (char far *)z+LOCCRC; n = 12; ! 365: do { ! 366: *u++ = *t++; ! 367: } while (--n); ! 368: p += 16L; ! 369: } ! 370: /* Read next signature */ ! 371: if (fread(b, 4, 1, f) != 1) ! 372: return ferror(f) ? ZE_READ : ZE_EOF; ! 373: } ! 374: ! 375: /* Point to start of header list and read central headers */ ! 376: z = zfiles; ! 377: s = p; /* save start of central */ ! 378: while (LG(b) == CENSIG) ! 379: { ! 380: if (z == NULL) ! 381: { ! 382: warn("extraneous central header signature", ""); ! 383: return ZE_FORM; ! 384: } ! 385: ! 386: /* Read central header */ ! 387: if (fread(b, CENHEAD, 1, f) != 1) ! 388: return ferror(f) ? ZE_READ : ZE_EOF; ! 389: ! 390: /* Compare local header with that part of central header (except ! 391: for the reserved bits in the general purpose flags and except ! 392: for length of extra fields--authentication can make these ! 393: different in central and local headers) */ ! 394: z->lflg = SH(LOCFLG + (uch far *)z); /* Save reserved bits */ ! 395: r = b[CENFLG+1]; ! 396: ((uch far *)z)[LOCFLG+1] &= 0x1f; /* Zero out reserved bits */ ! 397: b[CENFLG+1] &= 0x1f; ! 398: for (m = 0, u = (char far *)z, n = 0; n < LOCHEAD - 2; n++) ! 399: if (u[n] != b[n+2]) ! 400: { ! 401: if (!m) ! 402: warn("local and central headers differ for ", z->zname); ! 403: m = 1; ! 404: sprintf(errbuf, " offset %d--local = %02x, central = %02x", ! 405: n, (uch)u[n], (uch)b[n+2]); ! 406: warn(errbuf, ""); ! 407: } ! 408: if (m) ! 409: return ZE_FORM; ! 410: b[CENFLG+1] = r; /* Restore reserved bits */ ! 411: ! 412: /* Overwrite local header with translated central header */ ! 413: z->vem = SH(CENVEM + b); ! 414: z->ver = SH(CENVER + b); ! 415: z->flg = SH(CENFLG + b); /* may be different from z->lflg */ ! 416: z->how = SH(CENHOW + b); ! 417: z->tim = LG(CENTIM + b); /* time and date into one long */ ! 418: z->crc = LG(CENCRC + b); ! 419: z->siz = LG(CENSIZ + b); ! 420: z->len = LG(CENLEN + b); ! 421: z->nam = SH(CENNAM + b); ! 422: z->cext = SH(CENEXT + b); /* may be different from z->ext */ ! 423: z->com = SH(CENCOM + b); ! 424: z->dsk = SH(CENDSK + b); ! 425: z->att = SH(CENATT + b); ! 426: z->atx = LG(CENATX + b); ! 427: if (z->off != LG(CENOFF + b)) ! 428: { ! 429: warn("local offset in central header incorrect for ", z->zname); ! 430: return ZE_FORM; ! 431: } ! 432: ! 433: /* Compare name and extra fields and read comment field */ ! 434: if ((t = malloc(z->nam)) == NULL) ! 435: return ZE_MEM; ! 436: if (fread(t, z->nam, 1, f) != 1) ! 437: { ! 438: free((voidp *)t); ! 439: return ferror(f) ? ZE_READ : ZE_EOF; ! 440: } ! 441: if (memcmp(t, z->zname, z->nam)) ! 442: { ! 443: free((voidp *)t); ! 444: warn("names in local and central differ for ", z->zname); ! 445: return ZE_FORM; ! 446: } ! 447: free((voidp *)t); ! 448: if (z->cext) ! 449: { ! 450: if ((z->cextra = malloc(z->cext)) == NULL) ! 451: return ZE_MEM; ! 452: if (fread(z->cextra, z->cext, 1, f) != 1) ! 453: { ! 454: free((voidp *)(z->cextra)); ! 455: return ferror(f) ? ZE_READ : ZE_EOF; ! 456: } ! 457: if (z->ext == z->cext && memcmp(z->extra, z->cextra, z->ext) == 0) ! 458: { ! 459: free((voidp *)(z->cextra)); ! 460: z->cextra = z->extra; ! 461: } ! 462: } ! 463: if (z->com) ! 464: { ! 465: if ((z->comment = malloc(z->com)) == NULL) ! 466: return ZE_MEM; ! 467: if (fread(z->comment, z->com, 1, f) != 1) ! 468: { ! 469: free((voidp *)(z->comment)); ! 470: return ferror(f) ? ZE_READ : ZE_EOF; ! 471: } ! 472: } ! 473: ! 474: /* Note oddities */ ! 475: if (verbose) ! 476: { ! 477: if (z->vem != 10 && z->vem != 11 && z->vem != 20 && ! 478: (n = z->vem >> 8) != 3 && n != 2 && n != 6 && n != 0) ! 479: { ! 480: sprintf(errbuf, "made by version %d.%d on system type %d: ", ! 481: (ush)(z->vem & 0xff) / (ush)10, ! 482: (ush)(z->vem & 0xff) % (ush)10, z->vem >> 8); ! 483: warn(errbuf, z->zname); ! 484: } ! 485: if (z->ver != 10 && z->ver != 11 && z->ver != 20) ! 486: { ! 487: sprintf(errbuf, "needs unzip %d.%d on system type %d: ", ! 488: (ush)(z->ver & 0xff) / (ush)10, ! 489: (ush)(z->ver & 0xff) % (ush)10, z->ver >> 8); ! 490: warn(errbuf, z->zname); ! 491: } ! 492: if (z->flg != z->lflg) ! 493: { ! 494: sprintf(errbuf, "local flags = 0x%04x, central = 0x%04x: ", ! 495: z->lflg, z->flg); ! 496: warn(errbuf, z->zname); ! 497: } ! 498: else if (z->flg & ~0xf) ! 499: { ! 500: sprintf(errbuf, "undefined bits used in flags = 0x%04x: ", z->flg); ! 501: warn(errbuf, z->zname); ! 502: } ! 503: if (z->how > DEFLATE) ! 504: { ! 505: sprintf(errbuf, "unknown compression method %u: ", z->how); ! 506: warn(errbuf, z->zname); ! 507: } ! 508: if (z->dsk) ! 509: { ! 510: sprintf(errbuf, "starts on disk %u: ", z->dsk); ! 511: warn(errbuf, z->zname); ! 512: } ! 513: if (z->att & ~1) ! 514: { ! 515: sprintf(errbuf, "unknown internal attributes = 0x%04x: ", z->att); ! 516: warn(errbuf, z->zname); ! 517: } ! 518: if (((n = z->vem >> 8) != 3) && n != 2 && z->atx & ~0xffL) ! 519: { ! 520: sprintf(errbuf, "unknown external attributes = 0x%08lx: ", z->atx); ! 521: warn(errbuf, z->zname); ! 522: } ! 523: if (z->ext || z->cext) ! 524: if (z->ext == z->cext && z->extra == z->cextra) ! 525: { ! 526: sprintf(errbuf, "has %d bytes of extra data: ", z->ext); ! 527: warn(errbuf, z->zname); ! 528: } ! 529: else ! 530: { ! 531: sprintf(errbuf, ! 532: "local extra (%d bytes) != central extra (%d bytes): ", ! 533: z->ext, z->cext); ! 534: warn(errbuf, z->zname); ! 535: } ! 536: } ! 537: ! 538: /* Clear actions */ ! 539: z->mark = 0; ! 540: z->trash = 0; ! 541: ! 542: /* Update file offset */ ! 543: p += 4 + CENHEAD + z->nam + z->cext + z->com; ! 544: ! 545: /* Advance to next header structure */ ! 546: z = z->nxt; ! 547: ! 548: /* Read next signature */ ! 549: if (fread(b, 4, 1, f) != 1) ! 550: return ferror(f) ? ZE_READ : ZE_EOF; ! 551: } ! 552: ! 553: /* Read end header */ ! 554: if (z != NULL || LG(b) != ENDSIG) ! 555: { ! 556: warn("missing end signature--probably not a zip file (did you", ""); ! 557: warn("remember to use binary mode when you transferred it?)", ""); ! 558: return ZE_FORM; ! 559: } ! 560: if (fread(b, ENDHEAD, 1, f) != 1) ! 561: return ferror(f) ? ZE_READ : ZE_EOF; ! 562: if (SH(ENDDSK + b) || SH(ENDBEG + b) || ! 563: SH(ENDSUB + b) != SH(ENDTOT + b)) ! 564: warn("multiple disk information ignored", ""); ! 565: if (zcount != SH(ENDSUB + b)) ! 566: { ! 567: warn("count in end of central directory incorrect", ""); ! 568: return ZE_FORM; ! 569: } ! 570: if (LG(ENDSIZ + b) != p - s) ! 571: { ! 572: warn("central directory size is incorrect (made by stzip?)", ""); ! 573: /* stzip 0.9 gets this wrong, so be tolerant */ ! 574: /* return ZE_FORM; */ ! 575: } ! 576: if (LG(ENDOFF + b) != s) ! 577: { ! 578: warn("central directory start is incorrect", ""); ! 579: return ZE_FORM; ! 580: } ! 581: cenbeg = s; ! 582: zcomlen = SH(ENDCOM + b); ! 583: if (zcomlen) ! 584: { ! 585: if ((zcomment = malloc(zcomlen)) == NULL) ! 586: return ZE_MEM; ! 587: if (fread(zcomment, zcomlen, 1, f) != 1) ! 588: { ! 589: free((voidp *)zcomment); ! 590: return ferror(f) ? ZE_READ : ZE_EOF; ! 591: } ! 592: } ! 593: if (zipbeg) ! 594: { ! 595: sprintf(errbuf, " has a preamble of %ld bytes", zipbeg); ! 596: warn(zipfile, errbuf); ! 597: } ! 598: if (getc(f) != EOF) ! 599: warn("garbage at end of zip file ignored", ""); ! 600: ! 601: /* Done with zip file for now */ ! 602: fclose(f); ! 603: ! 604: /* If one or more files, sort by name */ ! 605: if (zcount) ! 606: { ! 607: if ((x = zsort = ! 608: (struct zlist far **)malloc(zcount * sizeof(struct zlist far *))) == ! 609: NULL) ! 610: return ZE_MEM; ! 611: for (z = zfiles; z != NULL; z = z->nxt) ! 612: *x++ = z; ! 613: qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp); ! 614: } ! 615: } ! 616: return ZE_OK; ! 617: } ! 618: ! 619: ! 620: int putlocal(z, f) ! 621: struct zlist far *z; /* zip entry to write local header for */ ! 622: FILE *f; /* file to write to */ ! 623: /* Write a local header described by *z to file *f. Return an error code ! 624: in the ZE_ class. */ ! 625: { ! 626: PUTLG(LOCSIG, f); ! 627: PUTSH(z->ver, f); ! 628: PUTSH(z->lflg, f); ! 629: PUTSH(z->how, f); ! 630: PUTLG(z->tim, f); ! 631: PUTLG(z->crc, f); ! 632: PUTLG(z->siz, f); ! 633: PUTLG(z->len, f); ! 634: PUTSH(z->nam, f); ! 635: PUTSH(z->ext, f); ! 636: if (fwrite(z->zname, 1, z->nam, f) != z->nam || ! 637: (z->ext && fwrite(z->extra, 1, z->ext, f) != z->ext)) ! 638: return ZE_TEMP; ! 639: return ZE_OK; ! 640: } ! 641: ! 642: int putextended(z, f) ! 643: struct zlist far *z; /* zip entry to write local header for */ ! 644: FILE *f; /* file to write to */ ! 645: /* Write an extended local header described by *z to file *f. ! 646: * Return an error code in the ZE_ class. */ ! 647: { ! 648: PUTLG(EXTLOCSIG, f); ! 649: PUTLG(z->crc, f); ! 650: PUTLG(z->siz, f); ! 651: PUTLG(z->len, f); ! 652: return ZE_OK; ! 653: } ! 654: ! 655: int putcentral(z, f) ! 656: struct zlist far *z; /* zip entry to write central header for */ ! 657: FILE *f; /* file to write to */ ! 658: /* Write a central header described by *z to file *f. Return an error code ! 659: in the ZE_ class. */ ! 660: { ! 661: PUTLG(CENSIG, f); ! 662: PUTSH(z->vem, f); ! 663: PUTSH(z->ver, f); ! 664: PUTSH(z->flg, f); ! 665: PUTSH(z->how, f); ! 666: PUTLG(z->tim, f); ! 667: PUTLG(z->crc, f); ! 668: PUTLG(z->siz, f); ! 669: PUTLG(z->len, f); ! 670: PUTSH(z->nam, f); ! 671: PUTSH(z->cext, f); ! 672: PUTSH(z->com, f); ! 673: PUTSH(z->dsk, f); ! 674: PUTSH(z->att, f); ! 675: PUTLG(z->atx, f); ! 676: PUTLG(z->off, f); ! 677: if (fwrite(z->zname, 1, z->nam, f) != z->nam || ! 678: (z->cext && fwrite(z->cextra, 1, z->cext, f) != z->cext) || ! 679: (z->com && fwrite(z->comment, 1, z->com, f) != z->com)) ! 680: return ZE_TEMP; ! 681: return ZE_OK; ! 682: } ! 683: ! 684: ! 685: int putend(n, s, c, m, z, f) ! 686: int n; /* number of entries in central directory */ ! 687: ulg s, c; /* size and offset of central directory */ ! 688: extent m; /* length of zip file comment (0 if none) */ ! 689: char *z; /* zip file comment if m != 0 */ ! 690: FILE *f; /* file to write to */ ! 691: /* Write the end of central directory data to file *f. Return an error code ! 692: in the ZE_ class. */ ! 693: { ! 694: PUTLG(ENDSIG, f); ! 695: PUTSH(0, f); ! 696: PUTSH(0, f); ! 697: PUTSH(n, f); ! 698: PUTSH(n, f); ! 699: PUTLG(s, f); ! 700: PUTLG(c, f); ! 701: PUTSH(m, f); ! 702: if (m && fwrite(z, 1, m, f) != m) ! 703: return ZE_TEMP; ! 704: return ZE_OK; ! 705: } ! 706: ! 707: ! 708: #ifndef UTIL ! 709: ! 710: local char *cutpath(p) ! 711: char *p; /* path string */ ! 712: /* Cut the last path component off the name *p in place. Return p. */ ! 713: { ! 714: char *r; /* pointer to last path delimiter */ ! 715: ! 716: #ifdef VMS /* change [w.x.y]z to [w.x]y.DIR */ ! 717: if ((r = strrchr(p, ']')) != NULL) ! 718: { ! 719: *r = 0; ! 720: if ((r = strrchr(p, '.')) != NULL) ! 721: { ! 722: *r = ']'; ! 723: strcat(r, ".DIR"); /* this assumes a little padding--see PAD */ ! 724: } ! 725: else ! 726: *p = 0; ! 727: } ! 728: else ! 729: *p = 0; ! 730: #else /* !VMS */ /* change w/x/y/z to w/x/y */ ! 731: if ((r = strrchr(p, '/')) != NULL) ! 732: *r = 0; ! 733: else ! 734: *p = 0; ! 735: #endif /* ?VMS */ ! 736: return p; ! 737: } ! 738: ! 739: ! 740: int trash() ! 741: /* Delete the compressed files and the directories that contained the deleted ! 742: files, if empty. Return an error code in the ZE_ class. Failure of ! 743: destroy() or deletedir() is ignored. */ ! 744: { ! 745: extent i; /* counter on deleted names */ ! 746: extent k; /* number of deleted directories this pass */ ! 747: extent n; /* number of deleted names left to handle */ ! 748: struct zlist far **s; /* table of zip entries to handle, sorted */ ! 749: struct zlist far *z; /* current zip entry */ ! 750: ! 751: /* Count and delete marked names */ ! 752: n = 0; ! 753: for (z = zfiles; z != NULL; z = z->nxt) ! 754: if (z->mark || z->trash) ! 755: { ! 756: if (z->zname[z->nam - 1] == '/') /* directory */ ! 757: z->mark = z->trash = 0; ! 758: else { ! 759: z->mark = 1; ! 760: n++; ! 761: if (verbose) ! 762: printf("zip diagnostic: trashing file %s\n", z->name); ! 763: destroy(z->name); ! 764: } ! 765: } ! 766: ! 767: /* Try to delete all paths that lead up to marked names */ ! 768: if (n) ! 769: { ! 770: if ((s = (struct zlist far **)malloc((n+1)*sizeof(struct zlist far *))) == ! 771: NULL || ! 772: (s[0] = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) ! 773: return ZE_MEM; ! 774: s[0]->name = ""; ! 775: s++; ! 776: do { ! 777: n = k = 0; ! 778: for (z = zfiles; z != NULL; z = z->nxt) ! 779: if (z->mark) ! 780: s[n++] = z; ! 781: qsort((char *)s, n, sizeof(struct zlist far *), zqcmp); ! 782: for (i = 0; i < n; i++) ! 783: if (*cutpath(s[i]->name) && strcmp(s[i]->name, s[i-1]->name)) ! 784: { ! 785: if (verbose) ! 786: printf("zip diagnostic: trashing directory %s (if empty)\n", ! 787: s[i]->name); ! 788: deletedir(s[i]->name); ! 789: k++; ! 790: } ! 791: else ! 792: s[i]->mark = 0; ! 793: } while (k); ! 794: farfree((voidp far *)((--s)[0])); ! 795: free((voidp *)s); ! 796: } ! 797: return ZE_OK; ! 798: } ! 799: ! 800: #endif /* !UTIL */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.