|
|
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: * zip.c by Mark Adler.
14: */
15:
16: #include "revision.h"
17: #include "zip.h"
18: #ifdef VMS
19: # include "VMSmunch.h"
20: # define echon() echo(1)
21: #endif
22: #include <signal.h>
23:
24: #ifdef MACOS
25: # include <console.h>
26: #endif
27:
28: #define PWLEN 80 /* Input buffer size for reading encryption key */
29: #define MAXCOM 256 /* Maximum one-line comment size */
30:
31:
32: /* Local option flags */
33: #define DELETE 0
34: #define ADD 1
35: #define UPDATE 2
36: #define FRESHEN 3
37: local int action = ADD; /* one of ADD, UPDATE, FRESHEN, or DELETE */
38: local int comadd = 0; /* 1=add comments for new files */
39: local int zipedit = 0; /* 1=edit zip comment and all file comments */
40: local int dispose = 0; /* 1=remove files after put in zip file */
41: local int latest = 0; /* 1=set zip file time to time of latest file */
42: local ulg before = 0; /* 0=ignore, else exclude files before this time */
43:
44:
45: /* Temporary zip file name and file pointer */
46: local char *tempzip;
47: local FILE *tempzf;
48:
49:
50: /* Local functions */
51: #ifdef PROTO
52: local void freeup(void);
53: local void leave(int);
54: local void handler(int);
55: local void license(void);
56: local void help(void);
57: local void zipstdout(void);
58: void main(int, char **);
59: local int count_args(char *s);
60: local void envargs(int *Pargc, char ***Pargv, char *envstr);
61: #endif /* PROTO */
62:
63:
64:
65: local void freeup()
66: /* Free all allocations in the found list and the zfiles list */
67: {
68: struct flist far *f; /* steps through found list */
69: struct zlist far *z; /* pointer to next entry in zfiles list */
70:
71: for (f = found; f != NULL; f = fexpel(f))
72: ;
73: while (zfiles != NULL)
74: {
75: z = zfiles->nxt;
76: free((voidp *)(zfiles->name));
77: free((voidp *)(zfiles->zname));
78: if (zfiles->ext)
79: free((voidp *)(zfiles->extra));
80: if (zfiles->cext && zfiles->cextra != zfiles->extra)
81: free((voidp *)(zfiles->cextra));
82: if (zfiles->com)
83: free((voidp *)(zfiles->comment));
84: farfree((voidp far *)zfiles);
85: zfiles = z;
86: zcount--;
87: }
88: }
89:
90:
91: local void leave(e)
92: int e; /* exit code */
93: /* Process -o and -m options (if specified), free up malloc'ed stuff, and
94: exit with the code e. */
95: {
96: int r; /* return value from trash() */
97: ulg t; /* latest time in zip file */
98: struct zlist far *z; /* pointer into zfile list */
99:
100: /* If latest, set time to zip file to latest file in zip file */
101: if (latest && strcmp(zipfile, "-"))
102: {
103: diag("changing time of zip file to time of latest file in it");
104: /* find latest time in zip file */
105: if (zfiles == NULL)
106: warn("zip file is empty, can't make it as old as latest entry", "");
107: else {
108: t = zfiles->tim;
109: for (z = zfiles->nxt; z != NULL; z = z->nxt)
110: if (t < z->tim)
111: t = z->tim;
112: /* set modified time of zip file to that time */
113: stamp(zipfile, t);
114: }
115: }
116: if (tempath != NULL)
117: {
118: free((voidp *)tempath);
119: tempath = NULL;
120: }
121: if (zipfile != NULL)
122: {
123: free((voidp *)zipfile);
124: zipfile = NULL;
125: }
126:
127:
128: /* If dispose, delete all files in the zfiles list that are marked */
129: if (dispose)
130: {
131: diag("deleting files that were added to zip file");
132: if ((r = trash()) != ZE_OK)
133: err(r, "was deleting moved files and directories");
134: }
135:
136:
137: /* Done! */
138: freeup();
139: #ifdef VMS
140: exit(0);
141: #else /* !VMS */
142: exit(e);
143: #endif /* ?VMS */
144: }
145:
146:
147: void err(c, h)
148: int c; /* error code from the ZE_ class */
149: char *h; /* message about how it happened */
150: /* Issue a message for the error, clean up files and memory, and exit. */
151: {
152: static int error_level;
153: if (error_level++ > 0) exit(0); /* avoid recursive err() */
154:
155: if (PERR(c))
156: perror("zip error");
157: fprintf(stderr, "zip error: %s (%s)\n", errors[c-1], h);
158: if (tempzip != NULL)
159: {
160: if (tempzip != zipfile) {
161: if (tempzf != NULL)
162: fclose(tempzf);
163: #ifndef DEBUG
164: destroy(tempzip);
165: #endif
166: free((voidp *)tempzip);
167: } else {
168: /* -g option, attempt to restore the old file */
169: int k = 0; /* keep count for end header */
170: ulg cb = cenbeg; /* get start of central */
171: struct zlist far *z; /* steps through zfiles linked list */
172:
173: fprintf(stderr, "attempting to restore %s to its previous state\n",
174: zipfile);
175: fseek(tempzf, cenbeg, SEEK_SET);
176: tempzn = cenbeg;
177: for (z = zfiles; z != NULL; z = z->nxt)
178: {
179: putcentral(z, tempzf);
180: tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
181: k++;
182: }
183: putend(k, tempzn - cb, cb, zcomlen, zcomment, tempzf);
184: tempzf = NULL;
185: fclose(tempzf);
186: }
187: }
188: if (key != NULL)
189: free((voidp *)key);
190: if (tempath != NULL)
191: free((voidp *)tempath);
192: if (zipfile != NULL)
193: free((voidp *)zipfile);
194: freeup();
195: #ifdef VMS
196: c = 0;
197: #endif
198: exit(c);
199: }
200:
201:
202: void error(h)
203: char *h;
204: /* Internal error, should never happen */
205: {
206: err(ZE_LOGIC, h);
207: }
208:
209: local void handler(s)
210: int s; /* signal number (ignored) */
211: /* Upon getting a user interrupt, turn echo back on for tty and abort
212: cleanly using err(). */
213: {
214: #ifndef MSDOS
215: # ifdef CRYPT
216: echon();
217: # endif
218: putc('\n', stderr);
219: #endif /* !MSDOS */
220: err(ZE_ABORT, "aborting");
221: s++; /* keep some compilers happy */
222: }
223:
224:
225: void warn(a, b)
226: char *a, *b; /* message strings juxtaposed in output */
227: /* Print a warning message to stderr and return. */
228: {
229: fprintf(stderr, "zip warning: %s%s\n", a, b);
230: }
231:
232:
233: local void license()
234: /* Print license information to stdout. */
235: {
236: extent i; /* counter for copyright array */
237:
238: for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
239: printf(copyright[i], "zip");
240: putchar('\n');
241: }
242: for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
243: puts(disclaimer[i]);
244: }
245:
246:
247: local void help()
248: /* Print help (along with license info) to stdout. */
249: {
250: extent i; /* counter for help array */
251:
252: /* help array */
253: static char *text[] = {
254: "",
255: "Zip %d.%d (%s). Usage:",
256: "zip [-options] [-b path] [-t mmddyy] [-n suffixes] [zipfile list] [-x list]",
257: " The default action is to add or replace zipfile entries from list, which",
258: " can include the special name - to compress standard input.",
259: " If zipfile and list are ommitted, zip compresses stdin to stdout.",
260: " -f freshen: only changed files -u update: only changed or new files",
261: " -d delete entries in zipfile -m move into zipfile (delete files)",
262: " -k simulate PKZIP made zipfile -g allow growing existing zipfile",
263: " -h show this help -L show software license",
264: " -r recurse into directories -j junk (don't record) directory names",
265: " -0 store only -l translate end-of-line",
266: " -1 compress faster -9 compress better",
267: " -q quiet operation -n don't compress these suffixes",
268: " -c add one-line comments -z add zipfile comment",
269: " -b use \"path\" for temp files -t only do files after \"mmddyy\"",
270: " -@ read names from stdin -o make zipfile as old as latest entry",
271: #ifdef CRYPT
272: " -e encrypt (-ee verify key)",
273: #endif
274: #ifdef VMS
275: " -w append the VMS version number to the name stored in the zip file",
276: " -V save VMS file attributes",
277: #endif /* VMS */
278: #ifdef OS2
279: " -E use the .LONGNAME Extended attribute (if found) as filename",
280: #endif /* OS2 */
281: #ifdef S_IFLNK
282: " -y store symbolic links as the link instead of the referenced file",
283: #endif /* !S_IFLNK */
284: " -x exclude the names that follow from those operated on"
285: };
286:
287: for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
288: {
289: printf(copyright[i], "zip");
290: putchar('\n');
291: }
292: for (i = 0; i < sizeof(text)/sizeof(char *); i++)
293: {
294: printf(text[i], REVISION / 10, REVISION % 10, REVDATE);
295: putchar('\n');
296: }
297: }
298:
299:
300: /* Do command line expansion for MSDOS and VMS */
301: #if defined(MSVMS) && !defined(__GO32__)
302: # define PROCNAME(n) (action==ADD||action==UPDATE?wild(n):procname(n))
303: #else /* !MSVMS */
304: # define PROCNAME(n) procname(n)
305: #endif /* ?MSVMS */
306:
307: local void zipstdout()
308: /* setup for writing zip file on stdout */
309: {
310: int r;
311: mesg = stderr;
312: if (isatty(1))
313: err(ZE_PARMS, "no zip file provided");
314: if ((zipfile = malloc(4)) == NULL)
315: err(ZE_MEM, "was processing arguments");
316: strcpy(zipfile, "-");
317: if ((r = readzipfile()) != ZE_OK)
318: err(r, zipfile);
319: }
320:
321:
322: void main(argc, argv)
323: int argc; /* number of tokens in command line */
324: char **argv; /* command line tokens */
325: /* Add, update, freshen, or delete zip entries in a zip file. See the
326: command help in help() above. */
327: {
328: int a; /* attributes of zip file */
329: ulg c; /* start of central directory */
330: int d; /* true if just adding to a zip file */
331: char *e; /* malloc'd comment buffer */
332: struct flist far *f; /* steps through found linked list */
333: int i; /* arg counter, root directory flag */
334: int k; /* next argument type, marked counter,
335: comment size, entry count */
336: ulg n; /* total of entry len's */
337: int o; /* true if there were any ZE_OPEN errors */
338: char *p; /* steps through option arguments */
339: char *pp; /* temporary pointer */
340: int r; /* temporary variable */
341: ulg t; /* file time, length of central directory */
342: struct zlist far *v; /* temporary variable */
343: struct zlist far * far *w; /* pointer to last link in zfiles list */
344: FILE *x, *y; /* input and output zip files */
345: struct zlist far *z; /* steps through zfiles linked list */
346: char *zipbuf; /* stdio buffer for the zip file */
347:
348: mesg = (FILE *) stdout; /* cannot be made at link time for VMS */
349: init_upper(); /* build case map table */
350:
351: #ifdef MACOS
352: argc = ccommand(&argv);
353: #endif
354:
355: /* Process arguments */
356: diag("processing arguments");
357: if (argc == 1 && isatty(1))
358: {
359: help();
360: exit(0);
361: }
362: envargs(&argc, &argv, "ZIPOPT"); /* get options from environment */
363:
364: zipfile = tempzip = NULL;
365: tempzf = NULL;
366: d = 0; /* disallow adding to a zip file */
367: signal(SIGINT, handler);
368: signal(SIGTERM, handler);
369: k = 0; /* Next non-option argument type */
370: for (i = 1; i < argc; i++)
371: {
372: if (argv[i][0] == '-')
373: if (argv[i][1])
374: for (p = argv[i]+1; *p; p++)
375: switch(*p)
376: {
377: case '0':
378: method = STORE; level = 0; break;
379: case '1': case '2': case '3': case '4':
380: case '5': case '6': case '7': case '8': case '9':
381: /* Set the compression efficacy */
382: level = *p - '0'; break;
383: case 'b': /* Specify path for temporary file */
384: if (k != 0)
385: err(ZE_PARMS, "use -b before zip file name");
386: else
387: k = 1; /* Next non-option is path */
388: break;
389: case 'c': /* Add comments for new files in zip file */
390: comadd = 1; break;
391: case 'd': /* Delete files from zip file */
392: if (action != ADD)
393: err(ZE_PARMS, "specify just one action");
394: action = DELETE;
395: break;
396: #ifdef CRYPT
397: case 'e': /* Encrypt */
398: e = key == NULL ? (char *)NULL : key;
399: if ((key = malloc(PWLEN+1)) == NULL)
400: err(ZE_MEM, "was getting encryption password");
401: if (getp(e == NULL ? "Enter password: " : "Verify password: ",
402: key, PWLEN+1) == NULL)
403: err(ZE_PARMS, "stderr is not a tty");
404: if (e != NULL)
405: {
406: r = strcmp(key, e);
407: free((voidp *)e);
408: if (r)
409: err(ZE_PARMS, "password not verified");
410: }
411: latest = 1; /* to make breaking the code harder */
412: break;
413: #endif /* CRYPT */
414: case 'f': /* Freshen zip file--overwrite only */
415: if (action != ADD)
416: err(ZE_PARMS, "specify just one action");
417: action = FRESHEN;
418: break;
419: case 'g': /* Allow appending to a zip file */
420: d = 1; break;
421: case 'h': case 'H': case '?': /* Help */
422: help();
423: leave(ZE_OK);
424: case 'j': /* Junk directory names */
425: pathput = 0; break;
426: case 'k': /* Make entries using DOS names (k for Katz) */
427: dosify = 1; break;
428: case 'l': /* Translate end-of-line */
429: translate_eol = 1; break;
430: case 'L': /* Show license, version */
431: license();
432: leave(ZE_OK);
433: case 'm': /* Delete files added or updated in zip file */
434: dispose = 1; break;
435: case 'n': /* Don't compress files with a special suffix */
436: special = NULL;
437: break;
438: case 'o': /* Set zip file time to time of latest file in it */
439: latest = 1; break;
440: case 'p': /* Store path with name */
441: break; /* (do nothing as annoyance avoidance) */
442: case 'q': /* Quiet operation */
443: noisy = 0; break;
444: case 'r': /* Recurse into subdirectories */
445: recurse = 1; break;
446: case 't': /* Exclude files earlier than specified date */
447: if (before)
448: err(ZE_PARMS, "can only have one -t");
449: k = 2; break;
450: case 'u': /* Update zip file--overwrite only if newer */
451: if (action != ADD)
452: err(ZE_PARMS, "specify just one action");
453: action = UPDATE;
454: break;
455: case 'v': /* Mention oddities in zip file structure */
456: verbose++;
457: break;
458: #ifdef VMS
459: case 'w': /* Append the VMS version number */
460: vmsver = 1; break;
461: case 'V': /* Store in VMS format */
462: vms_native = 1; break;
463: #endif /* VMS */
464: case 'x': /* Exclude following files */
465: if (k != 4 &&
466: (k != 3 || (action != UPDATE && action != FRESHEN)))
467: err(ZE_PARMS, "nothing to exclude (-x) from");
468: if (k == 3) /* must be -u or -f */
469: for (z = zfiles; z != NULL; z = z->nxt)
470: z->mark = 1; /* mark all of them */
471: k = 5;
472: if ((r = exclude()) != ZE_OK)
473: if (r == ZE_PARMS)
474: err(r, "cannot repeat names in zip file");
475: else
476: err(r, "was processing list of files");
477: break;
478: #ifdef S_IFLNK
479: case 'y': /* Store symbolic links as such */
480: linkput = 1; break;
481: #endif /* S_IFLNK */
482: case 'z': /* Edit zip file comment */
483: zipedit = 1; break;
484: case '@': /* read file names from stdin */
485: while ((pp = getnam(errbuf)) != NULL)
486: {
487: if ((r = PROCNAME(pp)) != ZE_OK)
488: if (r == ZE_MISS)
489: warn("name not matched: ", pp);
490: else
491: err(r, pp);
492: }
493: break;
494: #ifdef OS2
495: case 'E':
496: /* use the .LONGNAME EA (if any) as the file's name. */
497: use_longname_ea = 1;
498: break;
499: #endif
500: default:
501: {
502: sprintf(errbuf, "no such option: %c", *p);
503: err(ZE_PARMS, errbuf);
504: }
505: }
506: else /* just a dash */
507: switch (k)
508: {
509: case 0:
510: zipstdout();
511: k = 3;
512: break;
513: case 1:
514: err(ZE_PARMS, "invalid path");
515: break;
516: case 2:
517: err(ZE_PARMS, "invalid time");
518: break;
519: case 3: case 4: case 5:
520: if ((r = PROCNAME(argv[i])) != ZE_OK)
521: if (r == ZE_MISS)
522: warn("name not matched: ", argv[i]);
523: else
524: err(r, argv[i]);
525: if (k == 3)
526: k = 4;
527: }
528: else /* not an option */
529: {
530: if (special == NULL)
531: special = argv[i];
532: else
533: switch (k)
534: {
535: case 0:
536: if ((zipfile = ziptyp(argv[i])) == NULL)
537: err(ZE_MEM, "was processing arguments");
538: if ((r = readzipfile()) != ZE_OK)
539: err(r, zipfile);
540: k = 3;
541: break;
542: case 1:
543: if ((tempath = malloc(strlen(argv[i]) + 1)) == NULL)
544: err(ZE_MEM, "was processing arguments");
545: strcpy(tempath, argv[i]);
546: k = 0;
547: break;
548: case 2:
549: {
550: int yy, mm, dd; /* results of sscanf() */
551:
552: if (sscanf(argv[i], "%2d%2d%2d", &mm, &dd, &yy) != 3 ||
553: mm < 1 || mm > 12 || dd < 1 || dd > 31)
554: err(ZE_PARMS, "invalid date entered for -t option");
555: before = dostime(yy + (yy < 80 ? 2000 : 1900), mm, dd, 0, 0, 0);
556: k = 0;
557: break;
558: }
559: case 3: case 4: case 5:
560: if ((r = PROCNAME(argv[i])) != ZE_OK)
561: if (r == ZE_MISS)
562: warn("name not matched: ", argv[i]);
563: else
564: err(r, argv[i]);
565: if (k == 3)
566: k = 4;
567: }
568: }
569: }
570: if (k < 3) { /* zip used as filter */
571: zipstdout();
572: if ((r = procname("-")) != ZE_OK)
573: if (r == ZE_MISS)
574: warn("name not matched: ", "-");
575: else
576: err(r, "-");
577: k = 4;
578: }
579:
580: if (k != 5) /* Clean up selections */
581: {
582: if (k == 3 && (action == UPDATE || action == FRESHEN))
583: for (z = zfiles; z != NULL; z = z->nxt)
584: z->mark = 1; /* if -u or -f with no args, do all */
585: if ((r = exclude()) != ZE_OK) /* remove duplicates in found list */
586: if (r == ZE_PARMS)
587: err(r, "cannot repeat names in zip file");
588: else
589: err(r, "was processing list of files");
590: }
591: if (zcount)
592: free((voidp *)zsort);
593:
594: /* Check option combinations */
595: if (action == DELETE && (method != BEST || dispose || recurse ||
596: key != NULL || comadd || zipedit))
597: err(ZE_PARMS, "invalid option(s) used with -d");
598: if (linkput && dosify)
599: err(ZE_PARMS, "can't use -y with -k");
600: if ((action != ADD || d) && !strcmp(zipfile, "-"))
601: err(ZE_PARMS, "can't use -d,-f,-u or -g on standard output");
602: #ifdef VMS
603: if (vms_native && translate_eol)
604: err(ZE_PARMS, "can't use -V with -l");
605: #endif
606: if (zcount == 0 && (action != ADD || d))
607: warn(zipfile, " not found or empty");
608:
609:
610: /* If -b not specified, make temporary path the same as the zip file */
611: #ifdef MSDOS
612: if (tempath == NULL && ((p = strrchr(zipfile, '/')) != NULL ||
613: (p = strrchr(zipfile, '\\')) != NULL ||
614: (p = strrchr(zipfile, ':')) != NULL))
615: {
616: if (*p == ':')
617: p++;
618: #else /* !MSDOS */
619: if (tempath == NULL && (p = strrchr(zipfile, '/')) != NULL)
620: {
621: #endif /* ?MSDOS */
622: if ((tempath = malloc((int)(p - zipfile) + 1)) == NULL)
623: err(ZE_MEM, "was processing arguments");
624: r = *p; *p = 0;
625: strcpy(tempath, zipfile);
626: *p = (char)r;
627: }
628:
629: /* For each marked entry, if not deleting, check if it exists, and if
630: updating or freshening, compare date with entry in old zip file.
631: Unmark if it doesn't exist or is too old, else update marked count. */
632: diag("stating marked entries");
633: k = 0; /* Initialize marked count */
634: for (z = zfiles; z != NULL; z = z->nxt)
635: if (z->mark)
636: if (action != DELETE &&
637: ((t = filetime(z->name, (ulg *)NULL, (long *)NULL)) == 0 ||
638: t < before ||
639: ((action == UPDATE || action == FRESHEN) && t <= z->tim)))
640: {
641: z->mark = 0;
642: z->trash = t && t >= before; /* delete if -um or -fm */
643: if (verbose)
644: fprintf(mesg, "zip diagnostic: %s %s\n", z->name,
645: z->trash ? "up to date" : "missing or early");
646: }
647: else
648: k++;
649:
650:
651: /* Remove entries from found list that do not exist or are too old */
652: diag("stating new entries");
653: for (f = found; f != NULL;)
654: if (action == DELETE || action == FRESHEN ||
655: (t = filetime(f->name, (ulg *)NULL, (long *)NULL)) == 0 ||
656: t < before || (namecmp(f->name, zipfile) == 0 && strcmp(zipfile, "-")))
657: f = fexpel(f);
658: else
659: f = f->nxt;
660:
661: /* Make sure there's something left to do */
662: if (k == 0 && found == NULL && !(zfiles != NULL && (latest || zipedit)))
663: if (action == UPDATE || action == FRESHEN)
664: leave(ZE_OK);
665: else if (zfiles == NULL && latest)
666: err(ZE_NAME, zipfile);
667: else
668: err(ZE_NONE, zipfile);
669: d = (d && k == 0 && (zipbeg || zfiles != NULL)); /* d true if appending */
670:
671:
672: /* Before we get carried away, make sure zip file is writeable */
673: if (strcmp(zipfile, "-"))
674: {
675: x = zfiles == NULL && zipbeg == 0 ? fopen(zipfile, FOPW) :
676: fopen(zipfile, FOPM);
677: /* Note: FOPW and FOPM expand to several parameters for VMS */
678: if (x == NULL)
679: err(ZE_CREAT, zipfile);
680: fclose(x);
681: a = getfileattr(zipfile);
682: if (zfiles == NULL && zipbeg == 0)
683: destroy(zipfile);
684: }
685: else
686: a = 0;
687:
688:
689: /* Open zip file and temporary output file */
690: diag("opening zip file and creating temporary zip file");
691: x = NULL;
692: tempzn = 0;
693: if (strcmp(zipfile, "-") == 0)
694: {
695: #ifdef MSDOS
696: /* Set stdout mode to binary for MSDOS systems */
697: setmode(fileno(stdout), O_BINARY);
698: tempzf = y = fdopen(fileno(stdout), FOPW);
699: #else
700: tempzf = y = stdout;
701: #endif
702: tempzip = "-";
703: }
704: else if (d) /* d true if just appending (-g) */
705: {
706: if ((y = fopen(zipfile, FOPM)) == NULL)
707: err(ZE_NAME, zipfile);
708: tempzip = zipfile;
709: tempzf = y;
710: if (fseek(y, cenbeg, SEEK_SET))
711: err(ferror(y) ? ZE_READ : ZE_EOF, zipfile);
712: tempzn = cenbeg;
713: }
714: else
715: {
716: if ((zfiles != NULL || zipbeg) && (x = fopen(zipfile, FOPR_EX)) == NULL)
717: err(ZE_NAME, zipfile);
718: if ((tempzip = tempname(zipfile)) == NULL)
719: err(ZE_MEM, tempzip);
720: if ((tempzf = y = fopen(tempzip, FOPW)) == NULL)
721: err(ZE_TEMP, tempzip);
722: if (zipbeg && (r = fcopy(x, y, zipbeg)) != ZE_OK)
723: err(r, r == ZE_TEMP ? tempzip : zipfile);
724: tempzn = zipbeg;
725: }
726: #ifndef VMS
727: /* Use large buffer to speed up stdio: */
728: zipbuf = (char *)malloc(ZBSZ);
729: if (zipbuf == NULL)
730: err(ZE_MEM, tempzip);
731: # ifdef _IOFBF
732: setvbuf(y, zipbuf, _IOFBF, ZBSZ);
733: # else
734: setbuf(y, zipbuf);
735: # endif /* _IOBUF */
736: #endif /* VMS */
737: o = 0; /* no ZE_OPEN errors yet */
738:
739:
740: /* Process zip file, updating marked files */
741: if (zfiles != NULL)
742: diag("going through old zip file");
743: w = &zfiles;
744: while ((z = *w) != NULL)
745: if (z->mark)
746: {
747: /* if not deleting, zip it up */
748: if (action != DELETE)
749: {
750: if (noisy)
751: {
752: fprintf(mesg, "updating %s", z->zname);
753: fflush(mesg);
754: }
755: if ((r = zipup(z, y)) != ZE_OK && r != ZE_OPEN)
756: {
757: if (noisy)
758: {
759: putc('\n', mesg);
760: fflush(mesg);
761: }
762: sprintf(errbuf, "was zipping %s", z->name);
763: err(r, errbuf);
764: }
765: if (r == ZE_OPEN)
766: {
767: o = 1;
768: if (noisy)
769: {
770: putc('\n', mesg);
771: fflush(mesg);
772: }
773: perror("zip warning");
774: warn("could not open for reading: ", z->name);
775: warn("will just copy entry over: ", z->zname);
776: if ((r = zipcopy(z, x, y)) != ZE_OK)
777: {
778: sprintf(errbuf, "was copying %s", z->zname);
779: err(r, errbuf);
780: }
781: z->mark = 0;
782: }
783: w = &z->nxt;
784: }
785: else
786: {
787: if (noisy)
788: {
789: fprintf(mesg, "deleting %s\n", z->zname);
790: fflush(mesg);
791: }
792: v = z->nxt; /* delete entry from list */
793: free((voidp *)(z->name));
794: free((voidp *)(z->zname));
795: if (z->ext)
796: free((voidp *)(z->extra));
797: if (z->cext && z->cextra != z->extra)
798: free((voidp *)(z->cextra));
799: if (z->com)
800: free((voidp *)(z->comment));
801: farfree((voidp far *)z);
802: *w = v;
803: zcount--;
804: }
805: }
806: else
807: {
808: /* copy the original entry verbatim */
809: if (!d && (r = zipcopy(z, x, y)) != ZE_OK)
810: {
811: sprintf(errbuf, "was copying %s", z->zname);
812: err(r, errbuf);
813: }
814: w = &z->nxt;
815: }
816:
817:
818: /* Process the edited found list, adding them to the zip file */
819: diag("zipping up new entries, if any");
820: for (f = found; f != NULL; f = fexpel(f))
821: {
822: /* add a new zfiles entry and set the name */
823: if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL)
824: err(ZE_MEM, "was adding files to zip file");
825: z->nxt = NULL;
826: z->name = f->name;
827: f->name = NULL;
828: z->zname = f->zname;
829: f->zname = NULL;
830: z->ext = z->cext = z->com = 0;
831: z->mark = 1;
832: z->dosflag = f->dosflag;
833: /* zip it up */
834: if (noisy)
835: {
836: fprintf(mesg, "adding %s", z->zname);
837: fflush(mesg);
838: }
839: if ((r = zipup(z, y)) != ZE_OK && r != ZE_OPEN)
840: {
841: if (noisy)
842: {
843: putc('\n', mesg);
844: fflush(mesg);
845: }
846: sprintf(errbuf, "was zipping %s", z->name);
847: err(r, errbuf);
848: }
849: if (r == ZE_OPEN)
850: {
851: o = 1;
852: if (noisy)
853: {
854: putc('\n', mesg);
855: fflush(mesg);
856: }
857: perror("zip warning");
858: warn("could not open for reading: ", z->name);
859: free((voidp *)(z->name));
860: free((voidp *)(z->zname));
861: farfree((voidp far *)z);
862: }
863: else
864: {
865: *w = z;
866: w = &z->nxt;
867: zcount++;
868: }
869: }
870: if (key != NULL)
871: {
872: free((voidp *)key);
873: key = NULL;
874: }
875:
876:
877: /* Get one line comment for each new entry */
878: if (comadd)
879: {
880: if ((e = malloc(MAXCOM + 1)) == NULL)
881: err(ZE_MEM, "was reading comment lines");
882: for (z = zfiles; z != NULL; z = z->nxt)
883: if (z->mark)
884: {
885: if (noisy)
886: fprintf(mesg, "Enter comment for %s:\n", z->name);
887: /* ??? reopen /dev/tty if one file was zipped from stdin
888: * or if file names were read from stdin.
889: */
890: if (fgets(e, MAXCOM+1, stdin) != NULL)
891: {
892: if ((p = malloc((k = strlen(e))+1)) == NULL)
893: {
894: free((voidp *)e);
895: err(ZE_MEM, "was reading comment lines");
896: }
897: strcpy(p, e);
898: if (p[k-1] == '\n')
899: p[--k] = 0;
900: z->comment = p;
901: z->com = k;
902: }
903: }
904: free((voidp *)e);
905: }
906:
907: /* Get multi-line comment for the zip file */
908: if (zipedit)
909: {
910: if ((e = malloc(MAXCOM + 1)) == NULL)
911: err(ZE_MEM, "was reading comment lines");
912: if (noisy && zcomlen)
913: {
914: fputs("current zip file comment is:\n", mesg);
915: fwrite(zcomment, 1, zcomlen, mesg);
916: if (zcomment[zcomlen-1] != '\n')
917: putc('\n', mesg);
918: free((voidp *)zcomment);
919: }
920: zcomment = malloc(1);
921: *zcomment = 0;
922: if (noisy)
923: fputs("enter new zip file comment (end with .):\n", mesg);
924: /* ??? reopen /dev/tty if one file was zipped from stdin
925: * or if file names were read from stdin.
926: */
927: while (fgets(e, MAXCOM+1, stdin) != NULL && strcmp(e, ".\n"))
928: {
929: if (e[(r = strlen(e)) - 1] == '\n')
930: e[--r] = 0;
931: if ((p = malloc((*zcomment ? strlen(zcomment) + 3 : 1) + r)) == NULL)
932: {
933: free((voidp *)e);
934: err(ZE_MEM, "was reading comment lines");
935: }
936: if (*zcomment)
937: strcat(strcat(strcpy(p, zcomment), "\r\n"), e);
938: else
939: strcpy(p, *e ? e : "\r\n");
940: free((voidp *)zcomment);
941: zcomment = p;
942: }
943: zcomlen = strlen(zcomment);
944: free((voidp *)e);
945: }
946:
947:
948: /* Write central directory and end header to temporary zip */
949: diag("writing central directory");
950: k = 0; /* keep count for end header */
951: c = tempzn; /* get start of central */
952: n = t = 0;
953: for (z = zfiles; z != NULL; z = z->nxt)
954: {
955: if ((r = putcentral(z, y)) != ZE_OK)
956: err(r, tempzip);
957: tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
958: n += z->len;
959: t += z->siz;
960: k++;
961: }
962: if (k == 0)
963: warn("zip file empty", "");
964: if (verbose)
965: fprintf(mesg, "total bytes=%lu, compressed=%lu -> %d%% savings\n",
966: n, t, percent(n, t));
967: t = tempzn - c; /* compute length of central */
968: diag("writing end of central directory");
969: if ((r = putend(k, t, c, zcomlen, zcomment, y)) != ZE_OK)
970: err(r, tempzip);
971: tempzf = NULL;
972: if (fclose(y))
973: err(d ? ZE_WRITE : ZE_TEMP, tempzip);
974: if (x != NULL)
975: fclose(x);
976:
977:
978: /* Replace old zip file with new zip file, leaving only the new one */
979: if (strcmp(zipfile, "-") && !d)
980: {
981: diag("replacing old zip file with new zip file");
982: if ((r = replace(zipfile, tempzip)) != ZE_OK)
983: {
984: warn("new zip file left as: ", tempzip);
985: free((voidp *)tempzip);
986: tempzip = NULL;
987: err(r, "was replacing the original zip file");
988: }
989: free((voidp *)tempzip);
990: }
991: tempzip = NULL;
992: if (strcmp(zipfile, "-")) {
993: setfileattr(zipfile, a);
994: #ifdef VMS
995: /* If the zip file existed previously, restore its record format: */
996: if (x != NULL)
997: VMSmunch(zipfile, RESTORE_RTYPE, NULL);
998: #endif
999: }
1000:
1001: /* Finish up (process -o, -m, clean up). Exit code depends on o. */
1002: leave(o ? ZE_OPEN : ZE_OK);
1003: }
1004:
1005: /*****************************************************************
1006: | envargs - add default options from environment to command line
1007: |----------------------------------------------------------------
1008: | Author: Bill Davidsen, original 10/13/91, revised 23 Oct 1991.
1009: | This program is in the public domain.
1010: |----------------------------------------------------------------
1011: | Minor program notes:
1012: | 1. Yes, the indirection is a tad complex
1013: | 2. Parenthesis were added where not needed in some cases
1014: | to make the action of the code less obscure.
1015: ****************************************************************/
1016:
1017: local void
1018: envargs(Pargc, Pargv, envstr)
1019: int *Pargc;
1020: char ***Pargv;
1021: char *envstr;
1022: {
1023: char *getenv();
1024: char *envptr; /* value returned by getenv */
1025: char *bufptr; /* copy of env info */
1026: int argc = 0; /* internal arg count */
1027: int ch; /* spare temp value */
1028: char **argv; /* internal arg vector */
1029: char **argvect; /* copy of vector address */
1030:
1031: /* see if anything in the environment */
1032: envptr = getenv(envstr);
1033: if (envptr == NULL || *envptr == 0) return;
1034:
1035: /* count the args so we can allocate room for them */
1036: argc = count_args(envptr);
1037: bufptr = malloc(1+strlen(envptr));
1038: if (bufptr == NULL)
1039: err(ZE_MEM, "Can't get memory for arguments");
1040:
1041: strcpy(bufptr, envptr);
1042:
1043: /* allocate a vector large enough for all args */
1044: argv = (char **)malloc((argc+*Pargc+1)*sizeof(char *));
1045: if (argv == NULL)
1046: err(ZE_MEM, "Can't get memory for arguments");
1047: argvect = argv;
1048:
1049: /* copy the program name first, that's always true */
1050: *(argv++) = *((*Pargv)++);
1051:
1052: /* copy the environment args first, may be changed */
1053: do {
1054: *(argv++) = bufptr;
1055: /* skip the arg and any trailing blanks */
1056: while ((ch = *bufptr) != '\0' && ch != ' ') ++bufptr;
1057: if (ch == ' ') *(bufptr++) = '\0';
1058: while ((ch = *bufptr) != '\0' && ch == ' ') ++bufptr;
1059: } while (ch);
1060:
1061: /* now save old argc and copy in the old args */
1062: argc += *Pargc;
1063: while (--(*Pargc)) *(argv++) = *((*Pargv)++);
1064:
1065: /* finally, add a NULL after the last arg, like UNIX */
1066: *argv = NULL;
1067:
1068: /* save the values and return */
1069: *Pargv = argvect;
1070: *Pargc = argc;
1071: }
1072:
1073: static int
1074: count_args(s)
1075: char *s;
1076: {
1077: int count = 0;
1078: int ch;
1079:
1080: do {
1081: /* count and skip args */
1082: ++count;
1083: while ((ch = *s) != '\0' && ch != ' ') ++s;
1084: while ((ch = *s) != '\0' && ch == ' ') ++s;
1085: } while (ch);
1086:
1087: return count;
1088: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.