|
|
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.