1 /*
2   zip.c - Zip 3
3 
4   Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
5 
6   See the accompanying file LICENSE, version 2007-Mar-4 or later
7   (the contents of which are also included in zip.h) for terms of use.
8   If, for some reason, all these files are missing, the Info-ZIP license
9   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
10 */
11 /*
12  *  zip.c by Mark Adler.
13  */
14 #define __ZIP_C
15 
16 #include "boinczip.h"
17 #include <time.h>       /* for tzset() declaration */
18 #if defined(WIN32) || defined(WINDLL)
19 #  define WIN32_LEAN_AND_MEAN
20 #  include <windows.h>
21 #endif
22 #ifdef WINDLL
23 #  include <setjmp.h>
24 #  include "windll/windll.h"
25 #endif
26 #define DEFCPYRT        /* main module: enable copyright string defines! */
27 #include "revision.h"
28 #include "crc32.h"
29 #include "crypt.h"
30 #include "ttyio.h"
31 #include <ctype.h>
32 #include <errno.h>
33 #ifdef VMS
34 #  include <stsdef.h>
35 #  include "vms/vmsmunch.h"
36 #  include "vms/vms.h"
37 #endif
38 
39 #ifdef MACOS
40 #  include "macglob.h"
41    extern MacZipGlobals MacZip;
42    extern int error_level;
43 #endif
44 
45 #if (defined(MSDOS) && !defined(__GO32__)) || defined(__human68k__)
46 #  include <process.h>
47 #  if (!defined(P_WAIT) && defined(_P_WAIT))
48 #    define P_WAIT _P_WAIT
49 #  endif
50 #endif
51 
52 #include <signal.h>
53 #include <stdio.h>
54 
55 #ifdef UNICODE_TEST
56 # ifdef WIN32
57 #  include <direct.h>
58 # endif
59 #endif
60 
61 #ifdef BZIP2_SUPPORT
62   /* If IZ_BZIP2 is defined as the location of the bzip2 files then
63      assume the location has been added to include path.  For Unix
64      this is done by the configure script. */
65   /* Also do not need path for bzip2 include if OS includes support
66      for bzip2 library. */
67 # include "bzlib.h"
68 #endif
69 
70 #define MAXCOM 256      /* Maximum one-line comment size */
71 
72 
73 /* Local option flags */
74 #ifndef DELETE
75 #define DELETE  0
76 #endif
77 #define ADD     1
78 #define UPDATE  2
79 #define FRESHEN 3
80 #define ARCHIVE 4
81 local int action = ADD; /* one of ADD, UPDATE, FRESHEN, DELETE, or ARCHIVE */
82 local int comadd = 0;   /* 1=add comments for new files */
83 local int zipedit = 0;  /* 1=edit zip comment and all file comments */
84 local int latest = 0;   /* 1=set zip file time to time of latest file */
85 local int test = 0;     /* 1=test zip file with unzip -t */
86 local char *unzip_path = NULL; /* where to find unzip */
87 local int tempdir = 0;  /* 1=use temp directory (-b) */
88 local int junk_sfx = 0; /* 1=junk the sfx prefix */
89 #if defined(AMIGA) || defined(MACOS)
90 local int filenotes = 0; /* 1=take comments from AmigaDOS/MACOS filenotes */
91 #endif
92 
93 #ifdef EBCDIC
94 int aflag = __EBCDIC;   /* Convert EBCDIC to ASCII or stay EBCDIC ? */
95 #endif
96 #ifdef CMS_MVS
97 int bflag = 0;          /* Use text mode as default */
98 #endif
99 
100 #ifdef QDOS
101 char _version[] = VERSION;
102 #endif
103 
104 #ifdef WINDLL
105 jmp_buf zipdll_error_return;
106 #ifdef ZIP64_SUPPORT
107   unsigned long low, high; /* returning 64 bit values for systems without an _int64 */
108   uzoff_t filesize64;
109 #endif
110 #endif
111 
112 #if CRYPT
113 /* Pointer to crc_table, needed in crypt.c */
114 # if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
115 ZCONST ulg near *crc_32_tab;
116 # else
117 ZCONST uLongf *crc_32_tab;
118 # endif
119 #endif /* CRYPT */
120 
121 /* Local functions */
122 
123 local void freeup  OF((void));
124 local int  finish  OF((int));
125 #if (!defined(MACOS) && !defined(WINDLL))
126 local void handler OF((int));
127 local void license OF((void));
128 #ifndef VMSCLI
129 local void help    OF((void));
130 local void help_extended OF((void));
131 #endif /* !VMSCLI */
132 #endif /* !MACOS && !WINDLL */
133 
134 /* prereading of arguments is not supported in new command
135    line interpreter get_option() so read filters as arguments
136    are processed and convert to expected array later */
137 local int add_filter OF((int flag, char *pattern));
138 local int filterlist_to_patterns OF((void));
139 /* not used
140  local int get_filters OF((int argc, char **argv));
141 */
142 
143 /* list to store file arguments */
144 local long add_name OF((char *filearg));
145 
146 
147 local int DisplayRunningStats OF((void));
148 local int BlankRunningStats OF((void));
149 
150 #if !defined(WINDLL)
151 local void version_info OF((void));
152 # if !defined(MACOS)
153 local void zipstdout OF((void));
154 # endif /* !MACOS */
155 local int check_unzip_version OF((char *unzippath));
156 local void check_zipfile OF((char *zipname, char *zippath));
157 #endif /* !WINDLL */
158 
159 /* structure used by add_filter to store filters */
160 struct filterlist_struct {
161   char flag;
162   char *pattern;
163   struct filterlist_struct *next;
164 };
165 struct filterlist_struct *filterlist = NULL;  /* start of list */
166 struct filterlist_struct *lastfilter = NULL;  /* last filter in list */
167 
168 /* structure used by add_filearg to store file arguments */
169 struct filelist_struct {
170   char *name;
171   struct filelist_struct *next;
172 };
173 long filearg_count = 0;
174 struct filelist_struct *filelist = NULL;  /* start of list */
175 struct filelist_struct *lastfile = NULL;  /* last file in list */
176 
freeup()177 local void freeup()
178 /* Free all allocations in the 'found' list, the 'zfiles' list and
179    the 'patterns' list. */
180 {
181   struct flist far *f;  /* steps through found list */
182   struct zlist far *z;  /* pointer to next entry in zfiles list */
183 
184   for (f = found; f != NULL; f = fexpel(f))
185     ;
186   while (zfiles != NULL)
187   {
188     z = zfiles->nxt;
189     if (zfiles->zname && zfiles->zname != zfiles->name)
190       free((zvoid *)(zfiles->zname));
191     if (zfiles->name)
192       free((zvoid *)(zfiles->name));
193     if (zfiles->iname)
194       free((zvoid *)(zfiles->iname));
195     if (zfiles->cext && zfiles->cextra && zfiles->cextra != zfiles->extra)
196       free((zvoid *)(zfiles->cextra));
197     if (zfiles->ext && zfiles->extra)
198       free((zvoid *)(zfiles->extra));
199     if (zfiles->com && zfiles->comment)
200       free((zvoid *)(zfiles->comment));
201     if (zfiles->oname)
202       free((zvoid *)(zfiles->oname));
203 #ifdef UNICODE_SUPPORT
204     if (zfiles->uname)
205       free((zvoid *)(zfiles->uname));
206     if (zfiles->zuname)
207       free((zvoid *)(zfiles->zuname));
208     if (zfiles->ouname)
209       free((zvoid *)(zfiles->ouname));
210 # ifdef WIN32
211     if (zfiles->namew)
212       free((zvoid *)(zfiles->namew));
213     if (zfiles->inamew)
214       free((zvoid *)(zfiles->inamew));
215     if (zfiles->znamew)
216       free((zvoid *)(zfiles->znamew));
217 # endif
218 #endif
219     farfree((zvoid far *)zfiles);
220     zfiles = z;
221     zcount--;
222   }
223 
224   if (patterns != NULL) {
225     while (pcount-- > 0) {
226       if (patterns[pcount].zname != NULL)
227         free((zvoid *)(patterns[pcount].zname));
228     }
229     free((zvoid *)patterns);
230     patterns = NULL;
231   }
232 
233   /* close logfile */
234   if (logfile) {
235     fclose(logfile);
236   }
237 }
238 
finish(e)239 local int finish(e)
240 int e;                  /* exit code */
241 /* Process -o and -m options (if specified), free up malloc'ed stuff, and
242    exit with the code e. */
243 {
244   int r;                /* return value from trash() */
245   ulg t;                /* latest time in zip file */
246   struct zlist far *z;  /* pointer into zfile list */
247 
248   /* If latest, set time to zip file to latest file in zip file */
249   if (latest && zipfile && strcmp(zipfile, "-"))
250   {
251     diag("changing time of zip file to time of latest file in it");
252     /* find latest time in zip file */
253     if (zfiles == NULL)
254        zipwarn("zip file is empty, can't make it as old as latest entry", "");
255     else {
256       t = 0;
257       for (z = zfiles; z != NULL; z = z->nxt)
258         /* Ignore directories in time comparisons */
259 #ifdef USE_EF_UT_TIME
260         if (z->iname[z->nam-1] != (char)0x2f)   /* ascii '/' */
261         {
262           iztimes z_utim;
263           ulg z_tim;
264 
265           z_tim = ((get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
266                    unix2dostime(&z_utim.mtime) : z->tim);
267           if (t < z_tim)
268             t = z_tim;
269         }
270 #else /* !USE_EF_UT_TIME */
271         if (z->iname[z->nam-1] != (char)0x2f    /* ascii '/' */
272             && t < z->tim)
273           t = z->tim;
274 #endif /* ?USE_EF_UT_TIME */
275       /* set modified time of zip file to that time */
276       if (t != 0)
277         stamp(zipfile, t);
278       else
279         zipwarn(
280          "zip file has only directories, can't make it as old as latest entry",
281          "");
282     }
283   }
284   if (tempath != NULL)
285   {
286     free((zvoid *)tempath);
287     tempath = NULL;
288   }
289   if (zipfile != NULL)
290   {
291     free((zvoid *)zipfile);
292     zipfile = NULL;
293   }
294   if (in_file != NULL)
295   {
296     fclose(in_file);
297     in_file = NULL;
298   }
299   if (in_path != NULL)
300   {
301     free((zvoid *)in_path);
302     in_path = NULL;
303   }
304   if (out_path != NULL)
305   {
306     free((zvoid *)out_path);
307     out_path = NULL;
308   }
309   if (zcomment != NULL)
310   {
311     free((zvoid *)zcomment);
312     zcomment = NULL;
313   }
314 
315 
316   /* If dispose, delete all files in the zfiles list that are marked */
317   if (dispose)
318   {
319     diag("deleting files that were added to zip file");
320     if ((r = trash()) != ZE_OK)
321       ZIPERR(r, "was deleting moved files and directories");
322   }
323 
324 
325   /* Done! */
326   freeup();
327   return e;
328 }
329 
ziperr(c,h)330 void ziperr(c, h)
331 int c;                  /* error code from the ZE_ class */
332 ZCONST char *h;         /* message about how it happened */
333 /* Issue a message for the error, clean up files and memory, and exit. */
334 {
335 #ifndef WINDLL
336 #ifndef MACOS
337   static int error_level = 0;
338 #endif
339 
340   if (error_level++ > 0)
341      /* avoid recursive ziperr() printouts (his should never happen) */
342      EXIT(ZE_LOGIC);  /* ziperr recursion is an internal logic error! */
343 #endif /* !WINDLL */
344 
345   if (mesg_line_started) {
346     fprintf(mesg, "\n");
347     mesg_line_started = 0;
348   }
349   if (logfile && logfile_line_started) {
350     fprintf(logfile, "\n");
351     logfile_line_started = 0;
352   }
353   if (h != NULL) {
354     if (PERR(c))
355       fprintf(mesg, "zip I/O error: %s", strerror(errno));
356       /* perror("zip I/O error"); */
357     fflush(mesg);
358     fprintf(mesg, "\nzip error: %s (%s)\n", ZIPERRORS(c), h);
359 #ifdef DOS
360     check_for_windows("Zip");
361 #endif
362     if (logfile) {
363       if (PERR(c))
364         fprintf(logfile, "zip I/O error: %s\n", strerror(errno));
365       fprintf(logfile, "\nzip error: %s (%s)\n", ZIPERRORS(c), h);
366       logfile_line_started = 0;
367     }
368   }
369   if (tempzip != NULL)
370   {
371     if (tempzip != zipfile) {
372       if (current_local_file)
373         fclose(current_local_file);
374       if (y != current_local_file && y != NULL)
375         fclose(y);
376 #ifndef DEBUG
377       destroy(tempzip);
378 #endif
379       free((zvoid *)tempzip);
380     } else {
381       /* -g option, attempt to restore the old file */
382 
383       /* zip64 support 09/05/2003 R.Nausedat */
384       uzoff_t k = 0;                        /* keep count for end header */
385       uzoff_t cb = cenbeg;                  /* get start of central */
386 
387       struct zlist far *z;  /* steps through zfiles linked list */
388 
389       fprintf(mesg, "attempting to restore %s to its previous state\n",
390          zipfile);
391       if (logfile)
392         fprintf(logfile, "attempting to restore %s to its previous state\n",
393            zipfile);
394 
395       zfseeko(y, cenbeg, SEEK_SET);
396 
397       tempzn = cenbeg;
398       for (z = zfiles; z != NULL; z = z->nxt)
399       {
400         putcentral(z);
401         tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
402         k++;
403       }
404       putend(k, tempzn - cb, cb, zcomlen, zcomment);
405       fclose(y);
406       y = NULL;
407     }
408   }
409 
410   if (key != NULL) {
411     free((zvoid *)key);
412     key = NULL;
413   }
414   if (tempath != NULL) {
415     free((zvoid *)tempath);
416     tempath = NULL;
417   }
418   if (zipfile != NULL) {
419     free((zvoid *)zipfile);
420     zipfile = NULL;
421   }
422   if (out_path != NULL) {
423     free((zvoid *)out_path);
424     out_path = NULL;
425   }
426   if (zcomment != NULL) {
427     free((zvoid *)zcomment);
428     zcomment = NULL;
429   }
430 
431   freeup();
432 #ifndef WINDLL
433   EXIT(c);
434 #else
435   longjmp(zipdll_error_return, c);
436 #endif
437 }
438 
439 
error(h)440 void error(h)
441   ZCONST char *h;
442 /* Internal error, should never happen */
443 {
444   ziperr(ZE_LOGIC, h);
445 }
446 
447 #if (!defined(MACOS) && !defined(WINDLL))
handler(s)448 local void handler(s)
449 int s;                  /* signal number (ignored) */
450 /* Upon getting a user interrupt, turn echo back on for tty and abort
451    cleanly using ziperr(). */
452 {
453 #if defined(AMIGA) && defined(__SASC)
454    _abort();
455 #else
456 #if !defined(MSDOS) && !defined(__human68k__) && !defined(RISCOS)
457   echon();
458   putc('\n', mesg);
459 #endif /* !MSDOS */
460 #endif /* AMIGA && __SASC */
461   ziperr(ZE_ABORT, "aborting");
462   s++;                                  /* keep some compilers happy */
463 }
464 #endif /* !MACOS && !WINDLL */
465 
zipmessage_nl(a,nl)466 void zipmessage_nl(a, nl)
467 ZCONST char *a;     /* message string to output */
468 int nl;             /* 1 = add nl to end */
469 /* If nl false, print a message to mesg without new line.
470    If nl true, print and add new line.  If logfile is
471    open then also write message to log file. */
472 {
473   if (noisy) {
474     if (a && strlen(a)) {
475       fprintf(mesg, "%s", a);
476       mesg_line_started = 1;
477     }
478     if (nl) {
479       if (mesg_line_started) {
480         fprintf(mesg, "\n");
481         mesg_line_started = 0;
482       }
483     } else if (a && strlen(a)) {
484       mesg_line_started = 1;
485     }
486     fflush(mesg);
487   }
488   if (logfile) {
489     if (a && strlen(a)) {
490       fprintf(logfile, "%s", a);
491       logfile_line_started = 1;
492     }
493     if (nl) {
494       if (logfile_line_started) {
495         fprintf(logfile, "\n");
496         logfile_line_started = 0;
497       }
498     } else if (a && strlen(a)) {
499       logfile_line_started = 1;
500     }
501     fflush(logfile);
502   }
503 }
504 
zipmessage(a,b)505 void zipmessage(a, b)
506 ZCONST char *a, *b;     /* message strings juxtaposed in output */
507 /* Print a message to mesg and flush.  Also write to log file if
508    open.  Write new line first if current line has output already. */
509 {
510   if (noisy) {
511     if (mesg_line_started)
512       fprintf(mesg, "\n");
513     fprintf(mesg, "%s%s\n", a, b);
514     mesg_line_started = 0;
515     fflush(mesg);
516   }
517   if (logfile) {
518     if (logfile_line_started)
519       fprintf(logfile, "\n");
520     fprintf(logfile, "%s%s\n", a, b);
521     logfile_line_started = 0;
522     fflush(logfile);
523   }
524 }
525 
zipwarn(a,b)526 void zipwarn(a, b)
527 ZCONST char *a, *b;     /* message strings juxtaposed in output */
528 /* Print a warning message to mesg (usually stderr) and return. */
529 {
530   if (noisy) {
531     if (mesg_line_started)
532       fprintf(mesg, "\n");
533     fprintf(mesg, "\tzip warning: %s%s\n", a, b);
534     mesg_line_started = 0;
535     fflush(mesg);
536   }
537   if (logfile) {
538     if (logfile_line_started)
539       fprintf(logfile, "\n");
540     fprintf(logfile, "\tzip warning: %s%s\n", a, b);
541     logfile_line_started = 0;
542     fflush(logfile);
543   }
544 }
545 
546 #ifndef WINDLL
license()547 local void license()
548 /* Print license information to stdout. */
549 {
550   extent i;             /* counter for copyright array */
551 
552   for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
553     puts(swlicense[i]);
554 }
555 
556 #ifdef VMSCLI
help()557 void help()
558 #else
559 local void help()
560 #endif
561 /* Print help (along with license info) to stdout. */
562 {
563   extent i;             /* counter for help array */
564 
565   /* help array */
566   static ZCONST char *text[] = {
567 #ifdef VMS
568 "Zip %s (%s). Usage: zip == \"$ disk:[dir]zip.exe\"",
569 #else
570 "Zip %s (%s). Usage:",
571 #endif
572 #ifdef MACOS
573 "zip [-options] [-b fm] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]",
574 "  The default action is to add or replace zipfile entries from list.",
575 " ",
576 "  -f   freshen: only changed files  -u   update: only changed or new files",
577 "  -d   delete entries in zipfile    -m   move into zipfile (delete OS files)",
578 "  -r   recurse into directories     -j   junk (don't record) directory names",
579 "  -0   store only                   -l   convert LF to CR LF (-ll CR LF to LF)",
580 "  -1   compress faster              -9   compress better",
581 "  -q   quiet operation              -v   verbose operation/print version info",
582 "  -c   add one-line comments        -z   add zipfile comment",
583 "                                    -o   make zipfile as old as latest entry",
584 "  -F   fix zipfile (-FF try harder) -D   do not add directory entries",
585 "  -T   test zipfile integrity       -X   eXclude eXtra file attributes",
586 #  if CRYPT
587 "  -e   encrypt                      -n   don't compress these suffixes"
588 #  else
589 "  -h   show this help               -n   don't compress these suffixes"
590 #  endif
591 ," -h2  show more help",
592 "  Macintosh specific:",
593 "  -jj  record Fullpath (+ Volname)  -N store finder-comments as comments",
594 "  -df  zip only datafork of a file  -S include finder invisible/system files"
595 #else /* !MACOS */
596 #ifdef VM_CMS
597 "zip [-options] [-b fm] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]",
598 #else  /* !VM_CMS */
599 "zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]",
600 #endif /* ?VM_CMS */
601 "  The default action is to add or replace zipfile entries from list, which",
602 "  can include the special name - to compress standard input.",
603 "  If zipfile and list are omitted, zip compresses stdin to stdout.",
604 "  -f   freshen: only changed files  -u   update: only changed or new files",
605 "  -d   delete entries in zipfile    -m   move into zipfile (delete OS files)",
606 "  -r   recurse into directories     -j   junk (don't record) directory names",
607 #ifdef THEOS
608 "  -0   store only                   -l   convert CR to CR LF (-ll CR LF to CR)",
609 #else
610 "  -0   store only                   -l   convert LF to CR LF (-ll CR LF to LF)",
611 #endif
612 "  -1   compress faster              -9   compress better",
613 "  -q   quiet operation              -v   verbose operation/print version info",
614 "  -c   add one-line comments        -z   add zipfile comment",
615 "  -@   read names from stdin        -o   make zipfile as old as latest entry",
616 "  -x   exclude the following names  -i   include only the following names",
617 #ifdef EBCDIC
618 #ifdef CMS_MVS
619 "  -a   translate to ASCII           -B   force binary read (text is default)",
620 #else  /* !CMS_MVS */
621 "  -a   translate to ASCII",
622 #endif /* ?CMS_MVS */
623 #endif /* EBCDIC */
624 #ifdef TANDEM
625 "                                    -Bn  set Enscribe formatting options",
626 #endif
627 "  -F   fix zipfile (-FF try harder) -D   do not add directory entries",
628 "  -A   adjust self-extracting exe   -J   junk zipfile prefix (unzipsfx)",
629 "  -T   test zipfile integrity       -X   eXclude eXtra file attributes",
630 #ifdef VMS
631 "  -C   preserve case of file names  -C-  down-case all file names",
632 "  -C2  preserve case of ODS2 names  -C2- down-case ODS2 file names* (*=default)",
633 "  -C5  preserve case of ODS5 names* -C5- down-case ODS5 file names",
634 "  -V   save VMS file attributes (-VV also save allocated blocks past EOF)",
635 "  -w   store file version numbers\
636    -ww  store file version numbers as \".nnn\"",
637 #endif /* def VMS */
638 #ifdef NTSD_EAS
639 "  -!   use privileges (if granted) to obtain all aspects of WinNT security",
640 #endif /* NTSD_EAS */
641 #ifdef OS2
642 "  -E   use the .LONGNAME Extended attribute (if found) as filename",
643 #endif /* OS2 */
644 #ifdef S_IFLNK
645 "  -y   store symbolic links as the link instead of the referenced file",
646 #endif /* !S_IFLNK */
647 /*
648 "  -R   PKZIP recursion (see manual)",
649 */
650 #if defined(MSDOS) || defined(OS2)
651 "  -$   include volume label         -S   include system and hidden files",
652 #endif
653 #ifdef AMIGA
654 #  if CRYPT
655 "  -N   store filenotes as comments  -e   encrypt",
656 "  -h   show this help               -n   don't compress these suffixes"
657 #  else
658 "  -N   store filenotes as comments  -n   don't compress these suffixes"
659 #  endif
660 #else /* !AMIGA */
661 #  if CRYPT
662 "  -e   encrypt                      -n   don't compress these suffixes"
663 #  else
664 "  -h   show this help               -n   don't compress these suffixes"
665 #  endif
666 #endif /* ?AMIGA */
667 #ifdef RISCOS
668 ,"  -h2  show more help               -I   don't scan thru Image files"
669 #else
670 ,"  -h2  show more help"
671 #endif
672 #endif /* ?MACOS */
673 #ifdef VMS
674 ,"  (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND)"
675 #endif /* def VMS */
676 ,"  "
677   };
678 
679   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
680   {
681     printf(copyright[i], "zip");
682     putchar('\n');
683   }
684   for (i = 0; i < sizeof(text)/sizeof(char *); i++)
685   {
686     printf(text[i], VERSION, REVDATE);
687     putchar('\n');
688   }
689 }
690 
691 #ifdef VMSCLI
help_extended()692 void help_extended()
693 #else
694 local void help_extended()
695 #endif
696 /* Print extended help to stdout. */
697 {
698   extent i;             /* counter for help array */
699 
700   /* help array */
701   static ZCONST char *text[] = {
702 "",
703 "Extended Help for Zip",
704 "",
705 "See the Zip Manual for more detailed help",
706 "",
707 "",
708 "Zip stores files in zip archives.  The default action is to add or replace",
709 "zipfile entries.",
710 "",
711 "Basic command line:",
712 "  zip options archive_name file file ...",
713 "",
714 "Some examples:",
715 "  Add file.txt to z.zip (create z if needed):      zip z file.txt",
716 "  Zip all files in current dir:                    zip z *",
717 "  Zip files in current dir and subdirs also:       zip -r z .",
718 "",
719 "Basic modes:",
720 " External modes (selects files from file system):",
721 "        add      - add new files/update existing files in archive (default)",
722 "  -u    update   - add new files/update existing files only if later date",
723 "  -f    freshen  - update existing files only (no files added)",
724 "  -FS   filesync - update if date or size changed, delete if no OS match",
725 " Internal modes (selects entries in archive):",
726 "  -d    delete   - delete files from archive (see below)",
727 "  -U    copy     - select files in archive to copy (use with --out)",
728 "",
729 "Basic options:",
730 "  -r        recurse into directories (see Recursion below)",
731 "  -m        after archive created, delete original files (move into archive)",
732 "  -j        junk directory names (store just file names)",
733 "  -q        quiet operation",
734 "  -v        verbose operation (just \"zip -v\" shows version information)",
735 "  -c        prompt for one-line comment for each entry",
736 "  -z        prompt for comment for archive (end with just \".\" line or EOF)",
737 "  -@        read names to zip from stdin (one path per line)",
738 "  -o        make zipfile as old as latest entry",
739 "",
740 "",
741 "Syntax:",
742 "  The full command line syntax is:",
743 "",
744 "    zip [-shortopts ...] [--longopt ...] [zipfile [path path ...]] [-xi list]",
745 "",
746 "  Any number of short option and long option arguments are allowed",
747 "  (within limits) as well as any number of path arguments for files",
748 "  to zip up.  If zipfile exists, the archive is read in.  If zipfile",
749 "  is \"-\", stream to stdout.  If any path is \"-\", zip stdin.",
750 "",
751 "Options and Values:",
752 "  For short options that take values, use -ovalue or -o value or -o=value",
753 "  For long option values, use either --longoption=value or --longoption value",
754 "  For example:",
755 "    zip -ds 10 --temp-dir=path zipfile path1 path2 --exclude pattern pattern",
756 "  Avoid -ovalue (no space between) to avoid confusion",
757 "  In particular, be aware of 2-character options.  For example:",
758 "    -d -s is (delete, split size) while -ds is (dot size)",
759 "  Usually better to break short options across multiple arguments by function",
760 "    zip -r -dbdcds 10m -lilalf logfile archive input_directory -ll",
761 "",
762 "  All args after just \"--\" arg are read verbatim as paths and not options.",
763 "    zip zipfile path path ... -- verbatimpath verbatimpath ...",
764 "  Use -nw to also disable wildcards, so paths are read literally:",
765 "    zip zipfile -nw -- \"-leadingdashpath\" \"a[path].c\" \"path*withwildcard\"",
766 "  You may still have to escape or quote arguments to avoid shell expansion",
767 "",
768 "Wildcards:",
769 "  Internally zip supports the following wildcards:",
770 "    ?       (or %% or #, depending on OS) matches any single character",
771 "    *       matches any number of characters, including zero",
772 "    [list]  matches char in list (regex), can do range [ac-f], all but [!bf]",
773 "  If port supports [], must escape [ as [[] or use -nw to turn off wildcards",
774 "  For shells that expand wildcards, escape (\\* or \"*\") so zip can recurse",
775 "    zip zipfile -r . -i \"*.h\"",
776 "",
777 "  Normally * crosses dir bounds in path, e.g. 'a*b' can match 'ac/db'.  If",
778 "   -ws option used, * does not cross dir bounds but ** does",
779 "",
780 "  For DOS and Windows, [list] is now disabled unless the new option",
781 "  -RE       enable [list] (regular expression) matching",
782 "  is used to avoid problems with file paths containing \"[\" and \"]\":",
783 "    zip files_ending_with_number -RE foo[0-9].c",
784 "",
785 "Include and Exclude:",
786 "  -i pattern pattern ...   include files that match a pattern",
787 "  -x pattern pattern ...   exclude files that match a pattern",
788 "  Patterns are paths with optional wildcards and match paths as stored in",
789 "  archive.  Exclude and include lists end at next option, @, or end of line.",
790 "    zip -x pattern pattern @ zipfile path path ...",
791 "",
792 "Case matching:",
793 "  On most OS the case of patterns must match the case in the archive, unless",
794 "  the -ic option is used.",
795 "  -ic       ignore case of archive entries",
796 "  This option not available on case-sensitive file systems.  On others, case",
797 "  ignored when matching files on file system but matching against archive",
798 "  entries remains case sensitive for modes -f (freshen), -U (archive copy),",
799 "  and -d (delete) because archive paths are always case sensitive.  With",
800 "  -ic, all matching ignores case, but it's then possible multiple archive",
801 "  entries that differ only in case will match.",
802 "",
803 "End Of Line Translation (text files only):",
804 "  -l        change CR or LF (depending on OS) line end to CR LF (Unix->Win)",
805 "  -ll       change CR LF to CR or LF (depending on OS) line end (Win->Unix)",
806 "  If first buffer read from file contains binary the translation is skipped",
807 "",
808 "Recursion:",
809 "  -r        recurse paths, include files in subdirs:  zip -r a path path ...",
810 "  -R        recurse current dir and match patterns:   zip -R a ptn ptn ...",
811 "  Use -i and -x with either to include or exclude paths",
812 "  Path root in archive starts at current dir, so if /a/b/c/file and",
813 "   current dir is /a/b, 'zip -r archive .' puts c/file in archive",
814 "",
815 "Date filtering:",
816 "  -t date   exclude before (include files modified on this date and later)",
817 "  -tt date  include before (include files modified before date)",
818 "  Can use both at same time to set a date range",
819 "  Dates are mmddyyyy or yyyy-mm-dd",
820 "",
821 "Deletion, File Sync:",
822 "  -d        delete files",
823 "  Delete archive entries matching internal archive paths in list",
824 "    zip archive -d pattern pattern ...",
825 "  Can use -t and -tt to select files in archive, but NOT -x or -i, so",
826 "    zip archive -d \"*\" -t 2005-12-27",
827 "  deletes all files from archive.zip with date of 27 Dec 2005 and later",
828 "  Note the * (escape as \"*\" on Unix) to select all files in archive",
829 "",
830 "  -FS       file sync",
831 "  Similar to update, but files updated if date or size of entry does not",
832 "  match file on OS.  Also deletes entry from archive if no matching file",
833 "  on OS.",
834 "    zip archive_to_update -FS -r dir_used_before",
835 "  Result generally same as creating new archive, but unchanged entries",
836 "  are copied instead of being read and compressed so can be faster.",
837 "      WARNING:  -FS deletes entries so make backup copy of archive first",
838 "",
839 "Compression:",
840 "  -0        store files (no compression)",
841 "  -1 to -9  compress fastest to compress best (default is 6)",
842 "  -Z cm     set compression method to cm:",
843 "              store   - store without compression, same as option -0",
844 "              deflate - original zip deflate, same as -1 to -9 (default)",
845 "            if bzip2 is enabled:",
846 "              bzip2 - use bzip2 compression (need modern unzip)",
847 "",
848 "Encryption:",
849 "  -e        use standard (weak) PKZip 2.0 encryption, prompt for password",
850 "  -P pswd   use standard encryption, password is pswd",
851 "",
852 "Splits (archives created as a set of split files):",
853 "  -s ssize  create split archive with splits of size ssize, where ssize nm",
854 "              n number and m multiplier (kmgt, default m), 100k -> 100 kB",
855 "  -sp       pause after each split closed to allow changing disks",
856 "      WARNING:  Archives created with -sp use data descriptors and should",
857 "                work with most unzips but may not work with some",
858 "  -sb       ring bell when pause",
859 "  -sv       be verbose about creating splits",
860 "      Split archives CANNOT be updated, but see --out and Copy Mode below",
861 "",
862 "Using --out (output to new archive):",
863 "  --out oa  output to new archive oa",
864 "  Instead of updating input archive, create new output archive oa.",
865 "  Result is same as without --out but in new archive.  Input archive",
866 "  unchanged.",
867 "      WARNING:  --out ALWAYS overwrites any existing output file",
868 "  For example, to create new_archive like old_archive but add newfile1",
869 "  and newfile2:",
870 "    zip old_archive newfile1 newfile2 --out new_archive",
871 "  Cannot update split archive, so use --out to out new archive:",
872 "    zip in_split_archive newfile1 newfile2 --out out_split_archive",
873 "  If input is split, output will default to same split size",
874 "  Use -s=0 or -s- to turn off splitting to convert split to single file:",
875 "    zip in_split_archive -s 0 --out out_single_file_archive",
876 "      WARNING:  If overwriting old split archive but need less splits,",
877 "                old splits not overwritten are not needed but remain",
878 "",
879 "Copy Mode (copying from archive to archive):",
880 "  -U        (also --copy) select entries in archive to copy (reverse delete)",
881 "  Copy Mode copies entries from old to new archive with --out and is used by",
882 "  zip when either no input files on command line or -U (--copy) used.",
883 "    zip inarchive --copy pattern pattern ... --out outarchive",
884 "  To copy only files matching *.c into new archive, excluding foo.c:",
885 "    zip old_archive --copy \"*.c\" --out new_archive -x foo.c",
886 "  If no input files and --out, copy all entries in old archive:",
887 "    zip old_archive --out new_archive",
888 "",
889 "Streaming and FIFOs:",
890 "  prog1 | zip -ll z -      zip output of prog1 to zipfile z, converting CR LF",
891 "  zip - -R \"*.c\" | prog2   zip *.c files in current dir and stream to prog2 ",
892 "  prog1 | zip | prog2      zip in pipe with no in or out acts like zip - -",
893 "  If Zip is Zip64 enabled, streaming stdin creates Zip64 archives by default",
894 "   that need PKZip 4.5 unzipper like UnZip 6.0",
895 "  WARNING:  Some archives created with streaming use data descriptors and",
896 "            should work with most unzips but may not work with some",
897 "  Can use -fz- to turn off Zip64 if input not large (< 4 GB):",
898 "    prog_with_small_output | zip archive -fz-",
899 "",
900 "  Zip now can read Unix FIFO (named pipes).  Off by default to prevent zip",
901 "  from stopping unexpectedly on unfed pipe, use -FI to enable:",
902 "    zip -FI archive fifo",
903 "",
904 "Dots, counts:",
905 "  -db       display running count of bytes processed and bytes to go",
906 "              (uncompressed size, except delete and copy show stored size)",
907 "  -dc       display running count of entries done and entries to go",
908 "  -dd       display dots every 10 MB (or dot size) while processing files",
909 "  -dg       display dots globally for archive instead of for each file",
910 "    zip -qdgds 10m   will turn off most output except dots every 10 MB",
911 "  -ds siz   each dot is siz processed where siz is nm as splits (0 no dots)",
912 "  -du       display original uncompressed size for each entry as added",
913 "  -dv       display volume (disk) number in format in_disk>out_disk",
914 "  Dot size is approximate, especially for dot sizes less than 1 MB",
915 "  Dot options don't apply to Scanning files dots (dot/2sec) (-q turns off)",
916 "",
917 "Logging:",
918 "  -lf path  open file at path as logfile (overwrite existing file)",
919 "  -la       append to existing logfile",
920 "  -li       include info messages (default just warnings and errors)",
921 "",
922 "Testing archives:",
923 "  -T        test completed temp archive with unzip before updating archive",
924 "  -TT cmd   use command cmd instead of 'unzip -tqq' to test archive",
925 "             On Unix, to use unzip in current directory, could use:",
926 "               zip archive file1 file2 -T -TT \"./unzip -tqq\"",
927 "             In cmd, {} replaced by temp archive path, else temp appended.",
928 "             The return code is checked for success (0 on Unix)",
929 "",
930 "Fixing archives:",
931 "  -F        attempt to fix a mostly intact archive (try this first)",
932 "  -FF       try to salvage what can (may get more but less reliable)",
933 "  Fix options copy entries from potentially bad archive to new archive.",
934 "  -F tries to read archive normally and copy only intact entries, while",
935 "  -FF tries to salvage what can and may result in incomplete entries.",
936 "  Must use --out option to specify output archive:",
937 "    zip -F bad.zip --out fixed.zip",
938 "  Use -v (verbose) with -FF to see details:",
939 "    zip reallybad.zip -FF -v --out fixed.zip",
940 "  Currently neither option fixes bad entries, as from text mode ftp get.",
941 "",
942 "Difference mode:",
943 "  -DF       (also --dif) only include files that have changed or are",
944 "             new as compared to the input archive",
945 "  Difference mode can be used to create incremental backups.  For example:",
946 "    zip --dif full_backup.zip -r somedir --out diff.zip",
947 "  will store all new files, as well as any files in full_backup.zip where",
948 "  either file time or size have changed from that in full_backup.zip,",
949 "  in new diff.zip.  Output archive not excluded automatically if exists,",
950 "  so either use -x to exclude it or put outside what is being zipped.",
951 "",
952 "DOS Archive bit (Windows only):",
953 "  -AS       include only files with the DOS Archive bit set",
954 "  -AC       after archive created, clear archive bit of included files",
955 "      WARNING: Once the archive bits are cleared they are cleared",
956 "               Use -T to test the archive before the bits are cleared",
957 "               Can also use -sf to save file list before zipping files",
958 "",
959 "Show files:",
960 "  -sf       show files to operate on and exit (-sf- logfile only)",
961 "  -su       as -sf but show escaped UTF-8 Unicode names also if exist",
962 "  -sU       as -sf but show escaped UTF-8 Unicode names instead",
963 "  Any character not in the current locale is escaped as #Uxxxx, where x",
964 "  is hex digit, if 16-bit code is sufficient, or #Lxxxxxx if 24-bits",
965 "  are needed.  If add -UN=e, Zip escapes all non-ASCII characters.",
966 "",
967 "Unicode:",
968 "  If compiled with Unicode support, Zip stores UTF-8 path of entries.",
969 "  This is backward compatible.  Unicode paths allow better conversion",
970 "  of entry names between different character sets.",
971 "",
972 "  New Unicode extra field includes checksum to verify Unicode path",
973 "  goes with standard path for that entry (as utilities like ZipNote",
974 "  can rename entries).  If these do not match, use below options to",
975 "  set what Zip does:",
976 "      -UN=Quit     - if mismatch, exit with error",
977 "      -UN=Warn     - if mismatch, warn, ignore UTF-8 (default)",
978 "      -UN=Ignore   - if mismatch, quietly ignore UTF-8",
979 "      -UN=No       - ignore any UTF-8 paths, use standard paths for all",
980 "  An exception to -UN=N are entries with new UTF-8 bit set (instead",
981 "  of using extra fields).  These are always handled as Unicode.",
982 "",
983 "  Normally Zip escapes all chars outside current char set, but leaves",
984 "  as is supported chars, which may not be OK in path names.  -UN=Escape",
985 "  escapes any character not ASCII:",
986 "    zip -sU -UN=e archive",
987 "  Can use either normal path or escaped Unicode path on command line",
988 "  to match files in archive.",
989 "",
990 "  Zip now stores UTF-8 in entry path and comment fields on systems",
991 "  where UTF-8 char set is default, such as most modern Unix, and",
992 "  and on other systems in new extra fields with escaped versions in",
993 "  entry path and comment fields for backward compatibility.",
994 "  Option -UN=UTF8 will force storing UTF-8 in entry path and comment",
995 "  fields:",
996 "      -UN=UTF8     - store UTF-8 in entry path and comment fields",
997 "  This option can be useful for multi-byte char sets on Windows where",
998 "  escaped paths and comments can be too long to be valid as the UTF-8",
999 "  versions tend to be shorter.",
1000 "",
1001 "  Only UTF-8 comments on UTF-8 native systems supported.  UTF-8 comments",
1002 "  for other systems planned in next release.",
1003 "",
1004 "Self extractor:",
1005 "  -A        Adjust offsets - a self extractor is created by prepending",
1006 "             the extractor executable to archive, but internal offsets",
1007 "             are then off.  Use -A to fix offsets.",
1008 "  -J        Junk sfx - removes prepended extractor executable from",
1009 "             self extractor, leaving a plain zip archive.",
1010 "",
1011 "More option highlights (see manual for additional options and details):",
1012 "  -b dir    when creating or updating archive, create the temp archive in",
1013 "             dir, which allows using seekable temp file when writing to a",
1014 "             write once CD, such archives compatible with more unzips",
1015 "             (could require additional file copy if on another device)",
1016 "  -MM       input patterns must match at least one file and matched files",
1017 "             must be readable or exit with OPEN error and abort archive",
1018 "             (without -MM, both are warnings only, and if unreadable files",
1019 "             are skipped OPEN error (18) returned after archive created)",
1020 "  -nw       no wildcards (wildcards are like any other character)",
1021 "  -sc       show command line arguments as processed and exit",
1022 "  -sd       show debugging as Zip does each step",
1023 "  -so       show all available options on this system",
1024 "  -X        default=strip old extra fields, -X- keep old, -X strip most",
1025 "  -ws       wildcards don't span directory boundaries in paths",
1026 ""
1027   };
1028 
1029   for (i = 0; i < sizeof(text)/sizeof(char *); i++)
1030   {
1031     printf(text[i]);
1032     putchar('\n');
1033   }
1034 #ifdef DOS
1035   check_for_windows("Zip");
1036 #endif
1037 }
1038 
1039 /*
1040  * XXX version_info() in a separate file
1041  */
version_info()1042 local void version_info()
1043 /* Print verbose info about program version and compile time options
1044    to stdout. */
1045 {
1046   extent i;             /* counter in text arrays */
1047   char *envptr;
1048 
1049   /* Bzip2 option string storage (with version). */
1050 
1051 #ifdef BZIP2_SUPPORT
1052   static char bz_opt_ver[81];
1053   static char bz_opt_ver2[81];
1054   static char bz_opt_ver3[81];
1055 #endif
1056 
1057   /* Options info array */
1058   static ZCONST char *comp_opts[] = {
1059 #ifdef ASM_CRC
1060     "ASM_CRC",
1061 #endif
1062 #ifdef ASMV
1063     "ASMV",
1064 #endif
1065 #ifdef DYN_ALLOC
1066     "DYN_ALLOC",
1067 #endif
1068 #ifdef MMAP
1069     "MMAP",
1070 #endif
1071 #ifdef BIG_MEM
1072     "BIG_MEM",
1073 #endif
1074 #ifdef MEDIUM_MEM
1075     "MEDIUM_MEM",
1076 #endif
1077 #ifdef SMALL_MEM
1078     "SMALL_MEM",
1079 #endif
1080 #ifdef DEBUG
1081     "DEBUG",
1082 #endif
1083 #ifdef USE_EF_UT_TIME
1084     "USE_EF_UT_TIME       (store Universal Time)",
1085 #endif
1086 #ifdef NTSD_EAS
1087     "NTSD_EAS             (store NT Security Descriptor)",
1088 #endif
1089 #if defined(WIN32) && defined(NO_W32TIMES_IZFIX)
1090     "NO_W32TIMES_IZFIX",
1091 #endif
1092 #ifdef VMS
1093 #ifdef VMSCLI
1094     "VMSCLI",
1095 #endif
1096 #ifdef VMS_IM_EXTRA
1097     "VMS_IM_EXTRA",
1098 #endif
1099 #ifdef VMS_PK_EXTRA
1100     "VMS_PK_EXTRA",
1101 #endif
1102 #endif /* VMS */
1103 #ifdef WILD_STOP_AT_DIR
1104     "WILD_STOP_AT_DIR     (wildcards do not cross directory boundaries)",
1105 #endif
1106 #ifdef WIN32_OEM
1107     "WIN32_OEM            (store file paths on Windows as OEM)",
1108 #endif
1109 #ifdef BZIP2_SUPPORT
1110     bz_opt_ver,
1111     bz_opt_ver2,
1112     bz_opt_ver3,
1113 #endif
1114 #ifdef S_IFLNK
1115 # ifdef VMS
1116     "SYMLINK_SUPPORT      (symbolic links supported, if C RTL permits)",
1117 # else
1118     "SYMLINK_SUPPORT      (symbolic links supported)",
1119 # endif
1120 #endif
1121 #ifdef LARGE_FILE_SUPPORT
1122 # ifdef USING_DEFAULT_LARGE_FILE_SUPPORT
1123     "LARGE_FILE_SUPPORT (default settings)",
1124 # else
1125     "LARGE_FILE_SUPPORT   (can read and write large files on file system)",
1126 # endif
1127 #endif
1128 #ifdef ZIP64_SUPPORT
1129     "ZIP64_SUPPORT        (use Zip64 to store large files in archives)",
1130 #endif
1131 #ifdef UNICODE_SUPPORT
1132     "UNICODE_SUPPORT      (store and read UTF-8 Unicode paths)",
1133 #endif
1134 
1135 #ifdef UNIX
1136     "STORE_UNIX_UIDs_GIDs (store UID/GID sizes/values using new extra field)",
1137 # ifdef UIDGID_NOT_16BIT
1138     "UIDGID_NOT_16BIT     (old Unix 16-bit UID/GID extra field not used)",
1139 # else
1140     "UIDGID_16BIT         (old Unix 16-bit UID/GID extra field also used)",
1141 # endif
1142 #endif
1143 
1144 #if CRYPT && defined(PASSWD_FROM_STDIN)
1145     "PASSWD_FROM_STDIN",
1146 #endif /* CRYPT & PASSWD_FROM_STDIN */
1147     NULL
1148   };
1149 
1150   static ZCONST char *zipenv_names[] = {
1151 #ifndef VMS
1152 #  ifndef RISCOS
1153     "ZIP"
1154 #  else /* RISCOS */
1155     "Zip$Options"
1156 #  endif /* ?RISCOS */
1157 #else /* VMS */
1158     "ZIP_OPTS"
1159 #endif /* ?VMS */
1160     ,"ZIPOPT"
1161 #ifdef AZTEC_C
1162     ,     /* extremely lame compiler bug workaround */
1163 #endif
1164 #ifndef __RSXNT__
1165 # ifdef __EMX__
1166     ,"EMX"
1167     ,"EMXOPT"
1168 # endif
1169 # if (defined(__GO32__) && (!defined(__DJGPP__) || __DJGPP__ < 2))
1170     ,"GO32"
1171     ,"GO32TMP"
1172 # endif
1173 # if (defined(__DJGPP__) && __DJGPP__ >= 2)
1174     ,"TMPDIR"
1175 # endif
1176 #endif /* !__RSXNT__ */
1177 #ifdef RISCOS
1178     ,"Zip$Exts"
1179 #endif
1180   };
1181 
1182   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
1183   {
1184     printf(copyright[i], "zip");
1185     putchar('\n');
1186   }
1187 
1188   for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
1189   {
1190     printf(versinfolines[i], "Zip", VERSION, REVDATE);
1191     putchar('\n');
1192   }
1193 
1194   version_local();
1195 
1196   puts("Zip special compilation options:");
1197 #if WSIZE != 0x8000
1198   printf("\tWSIZE=%u\n", WSIZE);
1199 #endif
1200 
1201   /* Fill in bzip2 version.  (32-char limit valid as of bzip 1.0.3.) */
1202 #ifdef BZIP2_SUPPORT
1203   sprintf( bz_opt_ver,
1204    "BZIP2_SUPPORT        (bzip2 library version %.32s)", BZ2_bzlibVersion());
1205   sprintf( bz_opt_ver2,
1206    "    bzip2 code and library copyright (c) Julian R Seward");
1207   sprintf( bz_opt_ver3,
1208    "    (See the bzip2 license for terms of use)");
1209 #endif
1210 
1211   for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
1212   {
1213     printf("\t%s\n",comp_opts[i]);
1214   }
1215 #ifdef USE_ZLIB
1216   if (strcmp(ZLIB_VERSION, zlibVersion()) == 0)
1217     printf("\tUSE_ZLIB [zlib version %s]\n", ZLIB_VERSION);
1218   else
1219     printf("\tUSE_ZLIB [compiled with version %s, using version %s]\n",
1220       ZLIB_VERSION, zlibVersion());
1221   i++;  /* zlib use means there IS at least one compilation option */
1222 #endif
1223 #if CRYPT
1224   printf("\t[encryption, version %d.%d%s of %s] (modified for Zip 3)\n\n",
1225             CR_MAJORVER, CR_MINORVER, CR_BETA_VER, CR_VERSION_DATE);
1226   for (i = 0; i < sizeof(cryptnote)/sizeof(char *); i++)
1227   {
1228     printf(cryptnote[i]);
1229     putchar('\n');
1230   }
1231   ++i;  /* crypt support means there IS at least one compilation option */
1232 #endif /* CRYPT */
1233   if (i == 0)
1234       puts("\t[none]");
1235 
1236   puts("\nZip environment options:");
1237   for (i = 0; i < sizeof(zipenv_names)/sizeof(char *); i++)
1238   {
1239     envptr = getenv(zipenv_names[i]);
1240     printf("%16s:  %s\n", zipenv_names[i],
1241            ((envptr == (char *)NULL || *envptr == 0) ? "[none]" : envptr));
1242   }
1243 #ifdef DOS
1244   check_for_windows("Zip");
1245 #endif
1246 }
1247 #endif /* !WINDLL */
1248 
1249 
1250 #ifndef PROCNAME
1251 /* Default to case-sensitive matching of archive entries for the modes
1252    that specifically operate on archive entries, as this archive may
1253    have come from a system that allows paths in the archive to differ
1254    only by case.  Except for adding ARCHIVE (copy mode), this is how it
1255    was done before.  Note that some case-insensitive ports (WIN32, VMS)
1256    define their own PROCNAME() in their respective osdep.h that use the
1257    filter_match_case flag set to FALSE by the -ic option to enable
1258    case-insensitive archive entry mathing. */
1259 #  define PROCNAME(n) procname(n, (action == ARCHIVE || action == DELETE \
1260                                    || action == FRESHEN) \
1261                                   && filter_match_case)
1262 #endif /* PROCNAME */
1263 
1264 #ifndef WINDLL
1265 #ifndef MACOS
zipstdout()1266 local void zipstdout()
1267 /* setup for writing zip file on stdout */
1268 {
1269   mesg = stderr;
1270   if (isatty(1))
1271     ziperr(ZE_PARMS, "cannot write zip file to terminal");
1272   if ((zipfile = malloc(4)) == NULL)
1273     ziperr(ZE_MEM, "was processing arguments");
1274   strcpy(zipfile, "-");
1275   /*
1276   if ((r = readzipfile()) != ZE_OK)
1277     ziperr(r, zipfile);
1278   */
1279 }
1280 #endif /* !MACOS */
1281 
check_unzip_version(unzippath)1282 local int check_unzip_version(unzippath)
1283   char *unzippath;
1284 {
1285 #ifdef ZIP64_SUPPORT
1286   /* Here is where we need to check for the version of unzip the user
1287    * has.  If creating a Zip64 archive need UnZip 6 or may fail.
1288    */
1289     char cmd[4004];
1290     FILE *unzip_out = NULL;
1291     char buf[1001];
1292     float UnZip_Version = 0.0;
1293 
1294     cmd[0] = '\0';
1295     strncat(cmd, unzippath, 4000);
1296     strcat(cmd, " -v");
1297 
1298     if ((unzip_out = popen(cmd, "r")) == NULL) {
1299       perror("unzip pipe error");
1300     } else {
1301       if (fgets(buf, 1000, unzip_out) == NULL) {
1302         zipwarn("failed to get information from UnZip", "");
1303       } else {
1304         /* the first line should start with the version */
1305         if (sscanf(buf, "UnZip %f ", &UnZip_Version) < 1) {
1306           zipwarn("unexpected output of UnZip -v", "");
1307         } else {
1308           /* printf("UnZip %f\n", UnZip_Version); */
1309 
1310           while (fgets(buf, 1000, unzip_out)) {
1311           }
1312         }
1313       }
1314       pclose(unzip_out);
1315     }
1316     if (UnZip_Version < 6.0 && zip64_archive) {
1317       sprintf(buf, "Found UnZip version %4.2f", UnZip_Version);
1318       zipwarn(buf, "");
1319       zipwarn("Need UnZip 6.00 or later to test this Zip64 archive", "");
1320       return 0;
1321     }
1322 #endif
1323   return 1;
1324 }
1325 
check_zipfile(zipname,zippath)1326 local void check_zipfile(zipname, zippath)
1327   char *zipname;
1328   char *zippath;
1329   /* Invoke unzip -t on the given zip file */
1330 {
1331 #if (defined(MSDOS) && !defined(__GO32__)) || defined(__human68k__)
1332   int status, len;
1333   char *path, *p;
1334   char *zipnam;
1335 
1336   if ((zipnam = (char *)malloc(strlen(zipname) + 3)) == NULL)
1337     ziperr(ZE_MEM, "was creating unzip zipnam");
1338 
1339 # ifdef MSDOS
1340   /* Add quotes for MSDOS.  8/11/04 */
1341   strcpy(zipnam, "\"");    /* accept spaces in name and path */
1342   strcat(zipnam, zipname);
1343   strcat(zipnam, "\"");
1344 # else
1345   strcpy(zipnam, zipname);
1346 # endif
1347 
1348   if (unzip_path) {
1349     /* if user gave us the unzip to use go with it */
1350     char *here;
1351     int len;
1352     char *cmd;
1353 
1354     /* Replace first {} with archive name.  If no {} append name to string. */
1355     here = strstr(unzip_path, "{}");
1356 
1357     if ((cmd = (char *)malloc(strlen(unzip_path) + strlen(zipnam) + 3)) == NULL)
1358       ziperr(ZE_MEM, "was creating unzip cmd");
1359 
1360     if (here) {
1361       /* have {} so replace with temp name */
1362       len = here - unzip_path;
1363       strcpy(cmd, unzip_path);
1364       cmd[len] = '\0';
1365       strcat(cmd, " ");
1366       strcat(cmd, zipnam);
1367       strcat(cmd, " ");
1368       strcat(cmd, here + 2);
1369     } else {
1370       /* No {} so append temp name to end */
1371       strcpy(cmd, unzip_path);
1372       strcat(cmd, " ");
1373       strcat(cmd, zipnam);
1374     }
1375 
1376     status = system(cmd);
1377 
1378     free(unzip_path);
1379     unzip_path = NULL;
1380     free(cmd);
1381   } else {
1382     /* Here is where we need to check for the version of unzip the user
1383      * has.  If creating a Zip64 archive need UnZip 6 or may fail.
1384      */
1385     if (check_unzip_version("unzip") == 0)
1386       ZIPERR(ZE_TEST, zipfile);
1387 
1388     status = spawnlp(P_WAIT, "unzip", "unzip", verbose ? "-t" : "-tqq",
1389                      zipnam, NULL);
1390 # ifdef __human68k__
1391     if (status == -1)
1392       perror("unzip");
1393 # else
1394 /*
1395  * unzip isn't in PATH range, assume an absolute path to zip in argv[0]
1396  * and hope that unzip is in the same directory.
1397  */
1398     if (status == -1) {
1399       p = MBSRCHR(zippath, '\\');
1400       path = MBSRCHR((p == NULL ? zippath : p), '/');
1401       if (path != NULL)
1402         p = path;
1403       if (p != NULL) {
1404         len = (int)(p - zippath) + 1;
1405         if ((path = malloc(len + sizeof("unzip.exe"))) == NULL)
1406           ziperr(ZE_MEM, "was creating unzip path");
1407         memcpy(path, zippath, len);
1408         strcpy(&path[len], "unzip.exe");
1409 
1410         if (check_unzip_version(path) == 0)
1411           ZIPERR(ZE_TEST, zipfile);
1412 
1413         status = spawnlp(P_WAIT, path, "unzip", verbose ? "-t" : "-tqq",
1414                         zipnam, NULL);
1415         free(path);
1416       }
1417       if (status == -1)
1418         perror("unzip");
1419     }
1420   }
1421 # endif /* ?__human68k__ */
1422   free(zipnam);
1423   if (status != 0) {
1424 
1425 #else /* (MSDOS && !__GO32__) || __human68k__ */
1426   char *cmd;
1427   int result;
1428 
1429   /* Tell picky compilers to shut up about unused variables */
1430   zippath = zippath;
1431 
1432   if (unzip_path) {
1433     /* user gave us a path to some unzip (may not be UnZip) */
1434     char *here;
1435     int len;
1436 
1437     /* Replace first {} with archive name.  If no {} append name to string. */
1438     here = strstr(unzip_path, "{}");
1439 
1440     if ((cmd = malloc(strlen(unzip_path) + strlen(zipname) + 3)) == NULL) {
1441       ziperr(ZE_MEM, "building command string for testing archive");
1442     }
1443 
1444     if (here) {
1445       /* have {} so replace with temp name */
1446       len = here - unzip_path;
1447       strcpy(cmd, unzip_path);
1448       cmd[len] = '\0';
1449       strcat(cmd, " ");
1450 # ifdef UNIX
1451       strcat(cmd, "'");    /* accept space or $ in name */
1452       strcat(cmd, zipname);
1453       strcat(cmd, "'");
1454 # else
1455       strcat(cmd, zipname);
1456 # endif
1457       strcat(cmd, " ");
1458       strcat(cmd, here + 2);
1459     } else {
1460       /* No {} so append temp name to end */
1461       strcpy(cmd, unzip_path);
1462       strcat(cmd, " ");
1463 # ifdef UNIX
1464       strcat(cmd, "'");    /* accept space or $ in name */
1465       strcat(cmd, zipname);
1466       strcat(cmd, "'");
1467 # else
1468       strcat(cmd, zipname);
1469 # endif
1470     }
1471     free(unzip_path);
1472     unzip_path = NULL;
1473 
1474   } else {
1475     if ((cmd = malloc(20 + strlen(zipname))) == NULL) {
1476       ziperr(ZE_MEM, "building command string for testing archive");
1477     }
1478 
1479     strcpy(cmd, "unzip -t ");
1480 # ifdef QDOS
1481     strcat(cmd, "-Q4 ");
1482 # endif
1483     if (!verbose) strcat(cmd, "-qq ");
1484     if (check_unzip_version("unzip") == 0)
1485       ZIPERR(ZE_TEST, zipfile);
1486 
1487 # ifdef UNIX
1488     strcat(cmd, "'");    /* accept space or $ in name */
1489     strcat(cmd, zipname);
1490     strcat(cmd, "'");
1491 # else
1492     strcat(cmd, zipname);
1493 # endif
1494   }
1495 
1496   result = system(cmd);
1497 # ifdef VMS
1498   /* Convert success severity to 0, others to non-zero. */
1499   result = ((result & STS$M_SEVERITY) != STS$M_SUCCESS);
1500 # endif /* def VMS */
1501   free(cmd);
1502   cmd = NULL;
1503   if (result) {
1504 #endif /* ?((MSDOS && !__GO32__) || __human68k__) */
1505 
1506     fprintf(mesg, "test of %s FAILED\n", zipfile);
1507     ziperr(ZE_TEST, "original files unmodified");
1508   }
1509   if (noisy) {
1510     fprintf(mesg, "test of %s OK\n", zipfile);
1511     fflush(mesg);
1512   }
1513   if (logfile) {
1514     fprintf(logfile, "test of %s OK\n", zipfile);
1515     fflush(logfile);
1516   }
1517 }
1518 #endif /* !WINDLL */
1519 
1520 /* get_filters() is replaced by the following
1521 local int get_filters(argc, argv)
1522 */
1523 
1524 /* The filter patterns for options -x, -i, and -R are
1525    returned by get_option() one at a time, so use a linked
1526    list to store until all args are processed.  Then convert
1527    to array for processing.
1528  */
1529 
1530 /* add a filter to the linked list */
add_filter(flag,pattern)1531 local int add_filter(flag, pattern)
1532   int flag;
1533   char *pattern;
1534 {
1535   char *iname, *p = NULL;
1536   FILE *fp;
1537   struct filterlist_struct *filter = NULL;
1538 
1539   /* should never happen */
1540   if (flag != 'R' && flag != 'x' && flag != 'i') {
1541     ZIPERR(ZE_LOGIC, "bad flag to add_filter");
1542   }
1543   if (pattern == NULL) {
1544     ZIPERR(ZE_LOGIC, "null pattern to add_filter");
1545   }
1546 
1547   if (pattern[0] == '@') {
1548     /* read file with 1 pattern per line */
1549     if (pattern[1] == '\0') {
1550       ZIPERR(ZE_PARMS, "missing file after @");
1551     }
1552     fp = fopen(pattern + 1, "r");
1553     if (fp == NULL) {
1554       sprintf(errbuf, "%c pattern file '%s'", flag, pattern);
1555       ZIPERR(ZE_OPEN, errbuf);
1556     }
1557     while ((p = getnam(fp)) != NULL) {
1558       if ((filter = (struct filterlist_struct *) malloc(sizeof(struct filterlist_struct))) == NULL) {
1559         ZIPERR(ZE_MEM, "adding filter");
1560       }
1561       if (filterlist == NULL) {
1562         /* first filter */
1563         filterlist = filter;         /* start of list */
1564         lastfilter = filter;
1565       } else {
1566         lastfilter->next = filter;   /* link to last filter in list */
1567         lastfilter = filter;
1568       }
1569       iname = ex2in(p, 0, (int *)NULL);
1570       free(p);
1571       if (iname != NULL) {
1572         lastfilter->pattern = in2ex(iname);
1573         free(iname);
1574       } else {
1575         lastfilter->pattern = NULL;
1576       }
1577       lastfilter->flag = flag;
1578       pcount++;
1579       lastfilter->next = NULL;
1580     }
1581     fclose(fp);
1582   } else {
1583     /* single pattern */
1584     if ((filter = (struct filterlist_struct *) malloc(sizeof(struct filterlist_struct))) == NULL) {
1585       ZIPERR(ZE_MEM, "adding filter");
1586     }
1587     if (filterlist == NULL) {
1588       /* first pattern */
1589       filterlist = filter;         /* start of list */
1590       lastfilter = filter;
1591     } else {
1592       lastfilter->next = filter;   /* link to last filter in list */
1593       lastfilter = filter;
1594     }
1595     iname = ex2in(pattern, 0, (int *)NULL);
1596     if (iname != NULL) {
1597        lastfilter->pattern = in2ex(iname);
1598        free(iname);
1599     } else {
1600       lastfilter->pattern = NULL;
1601     }
1602     lastfilter->flag = flag;
1603     pcount++;
1604     lastfilter->next = NULL;
1605   }
1606 
1607   return pcount;
1608 }
1609 
1610 /* convert list to patterns array */
filterlist_to_patterns()1611 local int filterlist_to_patterns()
1612 {
1613   unsigned i;
1614   struct filterlist_struct *next = NULL;
1615 
1616   if (pcount == 0) {
1617     patterns = NULL;
1618     return 0;
1619   }
1620   if ((patterns = (struct plist *) malloc((pcount + 1) * sizeof(struct plist)))
1621       == NULL) {
1622     ZIPERR(ZE_MEM, "was creating pattern list");
1623   }
1624 
1625   for (i = 0; i < pcount && filterlist != NULL; i++) {
1626     switch (filterlist->flag) {
1627       case 'i':
1628         icount++;
1629         break;
1630       case 'R':
1631         Rcount++;
1632         break;
1633     }
1634     patterns[i].select = filterlist->flag;
1635     patterns[i].zname = filterlist->pattern;
1636     next = filterlist->next;
1637     free(filterlist);
1638     filterlist = next;
1639   }
1640 
1641   return pcount;
1642 }
1643 
1644 
1645 /* add a file argument to linked list */
add_name(filearg)1646 local long add_name(filearg)
1647   char *filearg;
1648 {
1649   char *name = NULL;
1650   struct filelist_struct *fileentry = NULL;
1651 
1652   if ((fileentry = (struct filelist_struct *) malloc(sizeof(struct filelist_struct))) == NULL) {
1653     ZIPERR(ZE_MEM, "adding file");
1654   }
1655   if ((name = malloc(strlen(filearg) + 1)) == NULL) {
1656     ZIPERR(ZE_MEM, "adding file");
1657   }
1658   strcpy(name, filearg);
1659   fileentry->next = NULL;
1660   fileentry->name = name;
1661   if (filelist == NULL) {
1662     /* first file argument */
1663     filelist = fileentry;         /* start of list */
1664     lastfile = fileentry;
1665   } else {
1666     lastfile->next = fileentry;   /* link to last filter in list */
1667     lastfile = fileentry;
1668   }
1669   filearg_count++;
1670 
1671   return filearg_count;
1672 }
1673 
1674 
1675 /* Running Stats
1676    10/30/04 */
1677 
DisplayRunningStats()1678 local int DisplayRunningStats()
1679 {
1680   char tempstrg[100];
1681 
1682   if (mesg_line_started) {
1683     fprintf(mesg, "\n");
1684     mesg_line_started = 0;
1685   }
1686   if (logfile_line_started) {
1687     fprintf(logfile, "\n");
1688     logfile_line_started = 0;
1689   }
1690   if (display_volume) {
1691     if (noisy) {
1692       fprintf(mesg, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
1693       mesg_line_started = 1;
1694     }
1695     if (logall) {
1696       fprintf(logfile, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
1697       logfile_line_started = 1;
1698     }
1699   }
1700   if (display_counts) {
1701     if (noisy) {
1702       fprintf(mesg, "%3ld/%3ld ", files_so_far, files_total - files_so_far);
1703       mesg_line_started = 1;
1704     }
1705     if (logall) {
1706       fprintf(logfile, "%3ld/%3ld ", files_so_far, files_total - files_so_far);
1707       logfile_line_started = 1;
1708     }
1709   }
1710   if (display_bytes) {
1711     /* since file sizes can change as we go, use bytes_so_far from
1712        initial scan so all adds up */
1713     WriteNumString(bytes_so_far, tempstrg);
1714     if (noisy) {
1715       fprintf(mesg, "[%4s", tempstrg);
1716       mesg_line_started = 1;
1717     }
1718     if (logall) {
1719       fprintf(logfile, "[%4s", tempstrg);
1720       logfile_line_started = 1;
1721     }
1722     if (bytes_total >= bytes_so_far) {
1723       WriteNumString(bytes_total - bytes_so_far, tempstrg);
1724       if (noisy)
1725         fprintf(mesg, "/%4s] ", tempstrg);
1726       if (logall)
1727         fprintf(logfile, "/%4s] ", tempstrg);
1728     } else {
1729       WriteNumString(bytes_so_far - bytes_total, tempstrg);
1730       if (noisy)
1731         fprintf(mesg, "-%4s] ", tempstrg);
1732       if (logall)
1733         fprintf(logfile, "-%4s] ", tempstrg);
1734     }
1735   }
1736   if (noisy)
1737       fflush(mesg);
1738   if (logall)
1739       fflush(logfile);
1740 
1741   return 0;
1742 }
1743 
BlankRunningStats()1744 local int BlankRunningStats()
1745 {
1746   if (display_volume) {
1747     if (noisy) {
1748       fprintf(mesg, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
1749       mesg_line_started = 1;
1750     }
1751     if (logall) {
1752       fprintf(logfile, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
1753       logfile_line_started = 1;
1754     }
1755   }
1756   if (display_counts) {
1757     if (noisy) {
1758       fprintf(mesg, "   /    ");
1759       mesg_line_started = 1;
1760     }
1761     if (logall) {
1762       fprintf(logfile, "   /    ");
1763       logfile_line_started = 1;
1764     }
1765   }
1766   if (display_bytes) {
1767     if (noisy) {
1768       fprintf(mesg, "     /      ");
1769       mesg_line_started = 1;
1770     }
1771     if (logall) {
1772       fprintf(logfile, "     /      ");
1773       logfile_line_started = 1;
1774     }
1775   }
1776   if (noisy)
1777       fflush(mesg);
1778   if (logall)
1779       fflush(logfile);
1780 
1781   return 0;
1782 }
1783 
1784 #if CRYPT
1785 #ifndef WINDLL
encr_passwd(modeflag,pwbuf,size,zfn)1786 int encr_passwd(modeflag, pwbuf, size, zfn)
1787 int modeflag;
1788 char *pwbuf;
1789 int size;
1790 ZCONST char *zfn;
1791 {
1792     char *prompt;
1793 
1794     /* Tell picky compilers to shut up about unused variables */
1795     zfn = zfn;
1796 
1797     prompt = (modeflag == ZP_PW_VERIFY) ?
1798               "Verify password: " : "Enter password: ";
1799 
1800     if (getp(prompt, pwbuf, size) == NULL) {
1801       ziperr(ZE_PARMS, "stderr is not a tty");
1802     }
1803     return IZ_PW_ENTERED;
1804 }
1805 #endif /* !WINDLL */
1806 #else /* !CRYPT */
encr_passwd(modeflag,pwbuf,size,zfn)1807 int encr_passwd(modeflag, pwbuf, size, zfn)
1808 int modeflag;
1809 char *pwbuf;
1810 int size;
1811 ZCONST char *zfn;
1812 {
1813     /* Tell picky compilers to shut up about unused variables */
1814     modeflag = modeflag; pwbuf = pwbuf; size = size; zfn = zfn;
1815 
1816     return ZE_LOGIC;    /* This function should never be called! */
1817 }
1818 #endif /* CRYPT */
1819 
1820 
1821 /* rename a split
1822  * A split has a tempfile name until it is closed, then
1823  * here rename it as out_path the final name for the split.
1824  */
rename_split(temp_name,out_path)1825 int rename_split(temp_name, out_path)
1826   char *temp_name;
1827   char *out_path;
1828 {
1829   int r;
1830   /* Replace old zip file with new zip file, leaving only the new one */
1831   if ((r = replace(out_path, temp_name)) != ZE_OK)
1832   {
1833     zipwarn("new zip file left as: ", temp_name);
1834     free((zvoid *)tempzip);
1835     tempzip = NULL;
1836     ZIPERR(r, "was replacing split file");
1837   }
1838   if (zip_attributes) {
1839     setfileattr(out_path, zip_attributes);
1840   }
1841   return ZE_OK;
1842 }
1843 
1844 
set_filetype(out_path)1845 int set_filetype(out_path)
1846   char *out_path;
1847 {
1848 #ifdef __BEOS__
1849   /* Set the filetype of the zipfile to "application/zip" */
1850   setfiletype( out_path, "application/zip" );
1851 #endif
1852 
1853 #ifdef __ATHEOS__
1854   /* Set the filetype of the zipfile to "application/x-zip" */
1855   setfiletype(out_path, "application/x-zip");
1856 #endif
1857 
1858 #ifdef MACOS
1859   /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
1860   setfiletype(out_path, 'IZip', 'ZIP ');
1861 #endif
1862 
1863 #ifdef RISCOS
1864   /* Set the filetype of the zipfile to &DDC */
1865   setfiletype(out_path, 0xDDC);
1866 #endif
1867   return ZE_OK;
1868 }
1869 
1870 
1871 /*
1872   -------------------------------------------------------
1873   Command Line Options
1874   -------------------------------------------------------
1875 
1876   Valid command line options.
1877 
1878   The function get_option() uses this table to check if an
1879   option is valid and if it takes a value (also called an
1880   option argument).  To add an option to zip just add it
1881   to this table and add a case in the main switch to handle
1882   it.  If either shortopt or longopt not used set to "".
1883 
1884    The fields:
1885        shortopt     - short option name (1 or 2 chars)
1886        longopt      - long option name
1887        value_type   - see zip.h for constants
1888        negatable    - option is negatable with trailing -
1889        ID           - unsigned long int returned for option
1890        name         - short description of option which is
1891                         returned on some errors and when options
1892                         are listed with -so option, can be NULL
1893 */
1894 
1895 /* Most option IDs are set to the shortopt char.  For
1896    multichar short options set to arbitrary unused constant. */
1897 #define o_AC            0x101
1898 #define o_AS            0x102
1899 #define o_C2            0x103
1900 #define o_C5            0x104
1901 #define o_db            0x105
1902 #define o_dc            0x106
1903 #define o_dd            0x107
1904 #define o_des           0x108
1905 #define o_df            0x109
1906 #define o_DF            0x110
1907 #define o_dg            0x111
1908 #define o_ds            0x112
1909 #define o_du            0x113
1910 #define o_dv            0x114
1911 #define o_FF            0x115
1912 #define o_FI            0x116
1913 #define o_FS            0x117
1914 #define o_h2            0x118
1915 #define o_ic            0x119
1916 #define o_jj            0x120
1917 #define o_la            0x121
1918 #define o_lf            0x122
1919 #define o_li            0x123
1920 #define o_ll            0x124
1921 #define o_mm            0x125
1922 #define o_MM            0x126
1923 #define o_nw            0x127
1924 #define o_RE            0x128
1925 #define o_sb            0x129
1926 #define o_sc            0x130
1927 #define o_sd            0x131
1928 #define o_sf            0x132
1929 #define o_so            0x133
1930 #define o_sp            0x134
1931 #define o_su            0x135
1932 #define o_sU            0x136
1933 #define o_sv            0x137
1934 #define o_tt            0x138
1935 #define o_TT            0x139
1936 #define o_UN            0x140
1937 #define o_ve            0x141
1938 #define o_VV            0x142
1939 #define o_ws            0x143
1940 #define o_ww            0x144
1941 #define o_z64           0x145
1942 #ifdef UNICODE_TEST
1943 #define o_sC            0x146
1944 #endif
1945 
1946 
1947 /* the below is mainly from the old main command line
1948    switch with a few changes */
1949 struct option_struct far options[] = {
1950   /* short longopt        value_type        negatable        ID    name */
1951 #ifdef EBCDIC
1952     {"a",  "ascii",       o_NO_VALUE,       o_NOT_NEGATABLE, 'a',  "to ascii"},
1953 #endif /* EBCDIC */
1954 #ifdef CMS_MVS
1955     {"B",  "binary",      o_NO_VALUE,       o_NOT_NEGATABLE, 'B',  "binary"},
1956 #endif /* CMS_MVS */
1957 #ifdef TANDEM
1958     {"B",  "",            o_NUMBER_VALUE,   o_NOT_NEGATABLE, 'B',  "nsk"},
1959 #endif
1960     {"0",  "store",       o_NO_VALUE,       o_NOT_NEGATABLE, '0',  "store"},
1961     {"1",  "compress-1",  o_NO_VALUE,       o_NOT_NEGATABLE, '1',  "compress 1"},
1962     {"2",  "compress-2",  o_NO_VALUE,       o_NOT_NEGATABLE, '2',  "compress 2"},
1963     {"3",  "compress-3",  o_NO_VALUE,       o_NOT_NEGATABLE, '3',  "compress 3"},
1964     {"4",  "compress-4",  o_NO_VALUE,       o_NOT_NEGATABLE, '4',  "compress 4"},
1965     {"5",  "compress-5",  o_NO_VALUE,       o_NOT_NEGATABLE, '5',  "compress 5"},
1966     {"6",  "compress-6",  o_NO_VALUE,       o_NOT_NEGATABLE, '6',  "compress 6"},
1967     {"7",  "compress-7",  o_NO_VALUE,       o_NOT_NEGATABLE, '7',  "compress 7"},
1968     {"8",  "compress-8",  o_NO_VALUE,       o_NOT_NEGATABLE, '8',  "compress 8"},
1969     {"9",  "compress-9",  o_NO_VALUE,       o_NOT_NEGATABLE, '9',  "compress 9"},
1970     {"A",  "adjust-sfx",  o_NO_VALUE,       o_NOT_NEGATABLE, 'A',  "adjust self extractor offsets"},
1971 #if defined(WIN32)
1972     {"AC", "archive-clear", o_NO_VALUE,     o_NOT_NEGATABLE, o_AC, "clear DOS archive bit of included files"},
1973     {"AS", "archive-set", o_NO_VALUE,       o_NOT_NEGATABLE, o_AS, "include only files with archive bit set"},
1974 #endif
1975     {"b",  "temp-path",   o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'b',  "dir to use for temp archive"},
1976     {"c",  "entry-comments", o_NO_VALUE,    o_NOT_NEGATABLE, 'c',  "add comments for each entry"},
1977 #ifdef VMS
1978     {"C",  "preserve-case", o_NO_VALUE,     o_NEGATABLE,     'C',  "Preserve (C-: down-) case all on VMS"},
1979     {"C2", "preserve-case-2", o_NO_VALUE,   o_NEGATABLE,     o_C2, "Preserve (C2-: down-) case ODS2 on VMS"},
1980     {"C5", "preserve-case-5", o_NO_VALUE,   o_NEGATABLE,     o_C5, "Preserve (C5-: down-) case ODS5 on VMS"},
1981 #endif /* VMS */
1982     {"d",  "delete",      o_NO_VALUE,       o_NOT_NEGATABLE, 'd',  "delete entries from archive"},
1983     {"db", "display-bytes", o_NO_VALUE,     o_NEGATABLE,     o_db, "display running bytes"},
1984     {"dc", "display-counts", o_NO_VALUE,    o_NEGATABLE,     o_dc, "display running file count"},
1985     {"dd", "display-dots", o_NO_VALUE,      o_NEGATABLE,     o_dd, "display dots as process each file"},
1986     {"dg", "display-globaldots",o_NO_VALUE, o_NEGATABLE,     o_dg, "display dots for archive instead of files"},
1987     {"ds", "dot-size",     o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_ds, "set progress dot size - default 10M bytes"},
1988     {"du", "display-usize", o_NO_VALUE,     o_NEGATABLE,     o_du, "display uncompressed size in bytes"},
1989     {"dv", "display-volume", o_NO_VALUE,    o_NEGATABLE,     o_dv, "display volume (disk) number"},
1990 #ifdef MACOS
1991     {"df", "datafork",    o_NO_VALUE,       o_NOT_NEGATABLE, o_df, "save datafork"},
1992 #endif /* MACOS */
1993     {"D",  "no-dir-entries", o_NO_VALUE,    o_NOT_NEGATABLE, 'D',  "no entries for dirs themselves (-x */)"},
1994     {"DF", "difference-archive",o_NO_VALUE, o_NOT_NEGATABLE, o_DF, "create diff archive with changed/new files"},
1995     {"e",  "encrypt",     o_NO_VALUE,       o_NOT_NEGATABLE, 'e',  "encrypt entries, ask for password"},
1996 #ifdef OS2
1997     {"E",  "longnames",   o_NO_VALUE,       o_NOT_NEGATABLE, 'E',  "use OS2 longnames"},
1998 #endif
1999     {"F",  "fix",         o_NO_VALUE,       o_NOT_NEGATABLE, 'F',  "fix mostly intact archive (try first)"},
2000     {"FF", "fixfix",      o_NO_VALUE,       o_NOT_NEGATABLE, o_FF, "try harder to fix archive (not as reliable)"},
2001     {"FI", "fifo",        o_NO_VALUE,       o_NEGATABLE,     o_FI, "read Unix FIFO (zip will wait on open pipe)"},
2002     {"FS", "filesync",    o_NO_VALUE,       o_NOT_NEGATABLE, o_FS, "add/delete entries to make archive match OS"},
2003     {"f",  "freshen",     o_NO_VALUE,       o_NOT_NEGATABLE, 'f',  "freshen existing archive entries"},
2004     {"fd", "force-descriptors", o_NO_VALUE, o_NOT_NEGATABLE, o_des,"force data descriptors as if streaming"},
2005 #ifdef ZIP64_SUPPORT
2006     {"fz", "force-zip64", o_NO_VALUE,       o_NEGATABLE,     o_z64,"force use of Zip64 format, negate prevents"},
2007 #endif
2008     {"g",  "grow",        o_NO_VALUE,       o_NOT_NEGATABLE, 'g',  "grow existing archive instead of replace"},
2009 #ifndef WINDLL
2010     {"h",  "help",        o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
2011     {"H",  "",            o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
2012     {"?",  "",            o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
2013     {"h2", "more-help",   o_NO_VALUE,       o_NOT_NEGATABLE, o_h2, "extended help"},
2014 #endif /* !WINDLL */
2015     {"i",  "include",     o_VALUE_LIST,     o_NOT_NEGATABLE, 'i',  "include only files matching patterns"},
2016 #if defined(VMS) || defined(WIN32)
2017     {"ic", "ignore-case", o_NO_VALUE,       o_NEGATABLE,     o_ic, "ignore case when matching archive entries"},
2018 #endif
2019 #ifdef RISCOS
2020     {"I",  "no-image",    o_NO_VALUE,       o_NOT_NEGATABLE, 'I',  "no image"},
2021 #endif
2022     {"j",  "junk-paths",  o_NO_VALUE,       o_NOT_NEGATABLE, 'j',  "strip paths and just store file names"},
2023 #ifdef MACOS
2024     {"jj", "absolute-path", o_NO_VALUE,     o_NOT_NEGATABLE, o_jj, "MAC absolute path"},
2025 #endif /* ?MACOS */
2026     {"J",  "junk-sfx",    o_NO_VALUE,       o_NOT_NEGATABLE, 'J',  "strip self extractor from archive"},
2027     {"k",  "DOS-names",   o_NO_VALUE,       o_NOT_NEGATABLE, 'k',  "force use of 8.3 DOS names"},
2028     {"l",  "to-crlf",     o_NO_VALUE,       o_NOT_NEGATABLE, 'l',  "convert text file line ends - LF->CRLF"},
2029     {"ll", "from-crlf",   o_NO_VALUE,       o_NOT_NEGATABLE, o_ll, "convert text file line ends - CRLF->LF"},
2030     {"lf", "logfile-path",o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_lf, "log to log file at path (default overwrite)"},
2031     {"la", "log-append",  o_NO_VALUE,       o_NEGATABLE,     o_la, "append to existing log file"},
2032     {"li", "log-info",    o_NO_VALUE,       o_NEGATABLE,     o_li, "include informational messages in log"},
2033 #ifndef WINDLL
2034     {"L",  "license",     o_NO_VALUE,       o_NOT_NEGATABLE, 'L',  "display license"},
2035 #endif
2036     {"m",  "move",        o_NO_VALUE,       o_NOT_NEGATABLE, 'm',  "add files to archive then delete files"},
2037     {"mm", "",            o_NO_VALUE,       o_NOT_NEGATABLE, o_mm, "not used"},
2038     {"MM", "must-match",  o_NO_VALUE,       o_NOT_NEGATABLE, o_MM, "error if in file not matched/not readable"},
2039     {"n",  "suffixes",    o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'n',  "suffixes to not compress: .gz:.zip"},
2040     {"nw", "no-wild",     o_NO_VALUE,       o_NOT_NEGATABLE, o_nw, "no wildcards during add or update"},
2041 #if defined(AMIGA) || defined(MACOS)
2042     {"N",  "notes",       o_NO_VALUE,       o_NOT_NEGATABLE, 'N',  "add notes as entry comments"},
2043 #endif
2044     {"o",  "latest-time", o_NO_VALUE,       o_NOT_NEGATABLE, 'o',  "use latest entry time as archive time"},
2045     {"O",  "output-file", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'O',  "set out zipfile different than in zipfile"},
2046     {"p",  "paths",       o_NO_VALUE,       o_NOT_NEGATABLE, 'p',  "store paths"},
2047     {"P",  "password",    o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'P',  "encrypt entries, option value is password"},
2048 #if defined(QDOS) || defined(QLZIP)
2049     {"Q",  "Q-flag",      o_NUMBER_VALUE,   o_NOT_NEGATABLE, 'Q',  "Q flag"},
2050 #endif
2051     {"q",  "quiet",       o_NO_VALUE,       o_NOT_NEGATABLE, 'q',  "quiet"},
2052     {"r",  "recurse-paths", o_NO_VALUE,     o_NOT_NEGATABLE, 'r',  "recurse down listed paths"},
2053     {"R",  "recurse-patterns", o_NO_VALUE,  o_NOT_NEGATABLE, 'R',  "recurse current dir and match patterns"},
2054     {"RE", "regex",       o_NO_VALUE,       o_NOT_NEGATABLE, o_RE, "allow [list] matching (regex)"},
2055     {"s",  "split-size",  o_REQUIRED_VALUE, o_NOT_NEGATABLE, 's',  "do splits, set split size (-s=0 no splits)"},
2056     {"sp", "split-pause", o_NO_VALUE,       o_NOT_NEGATABLE, o_sp, "pause while splitting to select destination"},
2057     {"sv", "split-verbose", o_NO_VALUE,     o_NOT_NEGATABLE, o_sv, "be verbose about creating splits"},
2058     {"sb", "split-bell",  o_NO_VALUE,       o_NOT_NEGATABLE, o_sb, "when pause for next split ring bell"},
2059     {"sc", "show-command",o_NO_VALUE,       o_NOT_NEGATABLE, o_sc, "show command line"},
2060 #ifdef UNICODE_TEST
2061     {"sC", "create-files",o_NO_VALUE,       o_NOT_NEGATABLE, o_sC, "create empty files using archive names"},
2062 #endif
2063     {"sd", "show-debug",  o_NO_VALUE,       o_NOT_NEGATABLE, o_sd, "show debug"},
2064     {"sf", "show-files",  o_NO_VALUE,       o_NEGATABLE,     o_sf, "show files to operate on and exit"},
2065     {"so", "show-options",o_NO_VALUE,       o_NOT_NEGATABLE, o_so, "show options"},
2066 #ifdef UNICODE_SUPPORT
2067     {"su", "show-unicode", o_NO_VALUE,      o_NEGATABLE,     o_su, "as -sf but also show escaped Unicode"},
2068     {"sU", "show-just-unicode", o_NO_VALUE, o_NEGATABLE,     o_sU, "as -sf but only show escaped Unicode"},
2069 #endif
2070 #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(ATARI)
2071     {"S",  "",            o_NO_VALUE,       o_NOT_NEGATABLE, 'S',  "include system and hidden"},
2072 #endif /* MSDOS || OS2 || WIN32 || ATARI */
2073     {"t",  "from-date",   o_REQUIRED_VALUE, o_NOT_NEGATABLE, 't',  "exclude before date"},
2074     {"tt", "before-date", o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_tt, "include before date"},
2075     {"T",  "test",        o_NO_VALUE,       o_NOT_NEGATABLE, 'T',  "test updates before replacing archive"},
2076     {"TT", "unzip-command", o_REQUIRED_VALUE,o_NOT_NEGATABLE,o_TT, "unzip command to use, name is added to end"},
2077     {"u",  "update",      o_NO_VALUE,       o_NOT_NEGATABLE, 'u',  "update existing entries and add new"},
2078     {"U",  "copy-entries", o_NO_VALUE,      o_NOT_NEGATABLE, 'U',  "select from archive instead of file system"},
2079 #ifdef UNICODE_SUPPORT
2080     {"UN", "unicode",     o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_UN, "UN=quit, warn, ignore, no, escape"},
2081 #endif
2082     {"v",  "verbose",     o_NO_VALUE,       o_NOT_NEGATABLE, 'v',  "display additional information"},
2083     {"",   "version",     o_NO_VALUE,       o_NOT_NEGATABLE, o_ve, "(if no other args) show version information"},
2084 #ifdef VMS
2085     {"V",  "VMS-portable", o_NO_VALUE,      o_NOT_NEGATABLE, 'V',  "Store VMS attributes, portable file format"},
2086     {"VV", "VMS-specific", o_NO_VALUE,      o_NOT_NEGATABLE, o_VV, "Store VMS attributes, VMS specific format"},
2087     {"w",  "VMS-versions", o_NO_VALUE,      o_NOT_NEGATABLE, 'w',  "store VMS versions"},
2088     {"ww", "VMS-dot-versions", o_NO_VALUE,  o_NOT_NEGATABLE, o_ww, "store VMS versions as \".nnn\""},
2089 #endif /* VMS */
2090     {"ws", "wild-stop-dirs", o_NO_VALUE,    o_NOT_NEGATABLE, o_ws,  "* stops at /, ** includes any /"},
2091     {"x",  "exclude",     o_VALUE_LIST,     o_NOT_NEGATABLE, 'x',  "exclude files matching patterns"},
2092 /*    {"X",  "no-extra",    o_NO_VALUE,       o_NOT_NEGATABLE, 'X',  "no extra"},
2093 */
2094     {"X",  "strip-extra", o_NO_VALUE,       o_NEGATABLE,     'X',  "-X- keep all ef, -X strip but critical ef"},
2095 #ifdef S_IFLNK
2096     {"y",  "symlinks",    o_NO_VALUE,       o_NOT_NEGATABLE, 'y',  "store symbolic links"},
2097 #endif /* S_IFLNK */
2098     {"z",  "archive-comment", o_NO_VALUE,   o_NOT_NEGATABLE, 'z',  "ask for archive comment"},
2099     {"Z",  "compression-method", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'Z', "compression method"},
2100 #if defined(MSDOS) || defined(OS2)
2101     {"$",  "volume-label", o_NO_VALUE,      o_NOT_NEGATABLE, '$',  "store volume label"},
2102 #endif
2103 #ifndef MACOS
2104     {"@",  "names-stdin", o_NO_VALUE,       o_NOT_NEGATABLE, '@',  "get file names from stdin, one per line"},
2105 #endif /* !MACOS */
2106 #ifdef NTSD_EAS
2107     {"!",  "use-privileges", o_NO_VALUE,    o_NOT_NEGATABLE, '!',  "use privileges"},
2108 #endif
2109 #ifdef RISCOS
2110     {"/",  "exts-to-swap", o_REQUIRED_VALUE, o_NOT_NEGATABLE, '/',  "override Zip$Exts"},
2111 #endif
2112     /* the end of the list */
2113     {NULL, NULL,          o_NO_VALUE,       o_NOT_NEGATABLE, 0,    NULL} /* end has option_ID = 0 */
2114   };
2115 
2116 
2117 
2118 #ifndef USE_ZIPMAIN
main(argc,argv)2119 int main(argc, argv)
2120 #else
2121 int zipmain(argc, argv)
2122 #endif
2123 int argc;               /* number of tokens in command line */
2124 char **argv;            /* command line tokens */
2125 /* Add, update, freshen, or delete zip entries in a zip file.  See the
2126    command help in help() above. */
2127 {
2128   int d;                /* true if just adding to a zip file */
2129   char *e;              /* malloc'd comment buffer */
2130   struct flist far *f;  /* steps through found linked list */
2131   int i;                /* arg counter, root directory flag */
2132   int kk;               /* next arg type (formerly another re-use of "k") */
2133 
2134   /* zip64 support 09/05/2003 R.Nausedat */
2135   uzoff_t c;            /* start of central directory */
2136   uzoff_t t;            /* length of central directory */
2137   zoff_t k;             /* marked counter, comment size, entry count */
2138   uzoff_t n;            /* total of entry len's */
2139 
2140   int o;                /* true if there were any ZE_OPEN errors */
2141   char *p;              /* steps through option arguments */
2142   char *pp;             /* temporary pointer */
2143   int r;                /* temporary variable */
2144   int s;                /* flag to read names from stdin */
2145   uzoff_t csize;        /* compressed file size for stats */
2146   uzoff_t usize;        /* uncompressed file size for stats */
2147   ulg tf;               /* file time */
2148   int first_listarg = 0;/* index of first arg of "process these files" list */
2149   struct zlist far *v;  /* temporary variable */
2150   struct zlist far * far *w;    /* pointer to last link in zfiles list */
2151   FILE *x /*, *y */;    /* input and output zip files (y global) */
2152   struct zlist far *z;  /* steps through zfiles linked list */
2153   int bad_open_is_error = 0; /* if read fails, 0=warning, 1=error */
2154 #if 0
2155   /* does not seem used */
2156 #ifdef WINDLL
2157   int retcode;          /* return code for dll */
2158 #endif /* WINDLL */
2159 #endif
2160 #if (!defined(VMS) && !defined(CMS_MVS))
2161   char *zipbuf;         /* stdio buffer for the zip file */
2162 #endif /* !VMS && !CMS_MVS */
2163   FILE *comment_stream; /* set to stderr if anything is read from stdin */
2164   int all_current;      /* used by File Sync to determine if all entries are current */
2165 
2166   struct filelist_struct *filearg;
2167 
2168 /* used by get_option */
2169   unsigned long option; /* option ID returned by get_option */
2170   int argcnt = 0;       /* current argcnt in args */
2171   int argnum = 0;       /* arg number */
2172   int optchar = 0;      /* option state */
2173   char *value = NULL;   /* non-option arg, option value or NULL */
2174   int negated = 0;      /* 1 = option negated */
2175   int fna = 0;          /* current first non-opt arg */
2176   int optnum = 0;       /* index in table */
2177 
2178   int show_options = 0; /* show options */
2179   int show_what_doing = 0; /* show what doing */
2180   int show_args = 0;    /* show command line */
2181   int seen_doubledash = 0; /* seen -- argument */
2182   int key_needed = 0;   /* prompt for encryption key */
2183   int have_out = 0;     /* if set in_path and out_path different archive */
2184 #ifdef UNICODE_TEST
2185   int create_files = 0;
2186 #endif
2187 
2188   char **args = NULL;  /* could be wide argv */
2189 
2190 
2191 #ifdef THEOS
2192   /* the argument expansion from the standard library is full of bugs */
2193   /* use mine instead */
2194   _setargv(&argc, &argv);
2195   setlocale(LC_CTYPE, "I");
2196 #else
2197   SETLOCALE(LC_CTYPE, "");
2198 #endif
2199 
2200 #ifdef UNICODE_SUPPORT
2201 # ifdef UNIX
2202   /* For Unix, set the locale to UTF-8.  Any UTF-8 locale is
2203      OK and they should all be the same.  This allows seeing,
2204      writing, and displaying (if the fonts are loaded) all
2205      characters in UTF-8. */
2206   {
2207     char *loc;
2208 
2209     /*
2210       loc = setlocale(LC_CTYPE, NULL);
2211       printf("  Initial language locale = '%s'\n", loc);
2212     */
2213 
2214     loc = setlocale(LC_CTYPE, "en_US.UTF-8");
2215 
2216     /*
2217       printf("langinfo %s\n", nl_langinfo(CODESET));
2218     */
2219 
2220     if (loc != NULL) {
2221       /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
2222       using_utf8 = 1;
2223       /*
2224         printf("  Locale set to %s\n", loc);
2225       */
2226     } else {
2227       /*
2228         printf("  Could not set Unicode UTF-8 locale\n");
2229       */
2230     }
2231   }
2232 # endif
2233 #endif
2234 
2235 #if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
2236   {
2237     extern void DebugMalloc(void);
2238     atexit(DebugMalloc);
2239   }
2240 #endif
2241 
2242 #ifdef QDOS
2243   {
2244     extern void QDOSexit(void);
2245     atexit(QDOSexit);
2246   }
2247 #endif
2248 
2249 #ifdef NLM
2250   {
2251     extern void NLMexit(void);
2252     atexit(NLMexit);
2253   }
2254 #endif
2255 
2256 #ifdef RISCOS
2257   set_prefix();
2258 #endif
2259 
2260 #ifdef __human68k__
2261   fflush(stderr);
2262   setbuf(stderr, NULL);
2263 #endif
2264 
2265 /* Re-initialize global variables to make the zip dll re-entrant. It is
2266  * possible that we could get away with not re-initializing all of these
2267  * but better safe than sorry.
2268  */
2269 #if defined(MACOS) || defined(WINDLL) || defined(USE_ZIPMAIN)
2270   action = ADD; /* one of ADD, UPDATE, FRESHEN, DELETE, or ARCHIVE */
2271   comadd = 0;   /* 1=add comments for new files */
2272   zipedit = 0;  /* 1=edit zip comment and all file comments */
2273   latest = 0;   /* 1=set zip file time to time of latest file */
2274   before = 0;   /* 0=ignore, else exclude files before this time */
2275   after = 0;    /* 0=ignore, else exclude files newer than this time */
2276   test = 0;     /* 1=test zip file with unzip -t */
2277   unzip_path = NULL; /* where to look for unzip command path */
2278   tempdir = 0;  /* 1=use temp directory (-b) */
2279   junk_sfx = 0; /* 1=junk the sfx prefix */
2280 #if defined(AMIGA) || defined(MACOS)
2281   filenotes = 0;/* 1=take comments from AmigaDOS/MACOS filenotes */
2282 #endif
2283 #ifndef USE_ZIPMAIN
2284   zipstate = -1;
2285 #endif
2286   tempzip = NULL;
2287   fcount = 0;
2288   recurse = 0;         /* 1=recurse into directories; 2=match filenames */
2289   dispose = 0;         /* 1=remove files after put in zip file */
2290   pathput = 1;         /* 1=store path with name */
2291   method = BEST;       /* one of BEST, DEFLATE (only), or STORE (only) */
2292   dosify = 0;          /* 1=make new entries look like MSDOS */
2293   verbose = 0;         /* 1=report oddities in zip file structure */
2294   fix = 0;             /* 1=fix the zip file */
2295   adjust = 0;          /* 1=adjust offsets for sfx'd file (keep preamble) */
2296   level = 6;           /* 0=fastest compression, 9=best compression */
2297   translate_eol = 0;   /* Translate end-of-line LF -> CR LF */
2298 #if defined(OS2) || defined(WIN32)
2299   use_longname_ea = 0; /* 1=use the .LONGNAME EA as the file's name */
2300 #endif
2301 #ifdef NTSD_EAS
2302   use_privileges = 0;     /* 1=use security privileges overrides */
2303 #endif
2304   no_wild = 0;            /* 1 = wildcards are disabled */
2305 #ifdef WILD_STOP_AT_DIR
2306    wild_stop_at_dir = 1;  /* default wildcards do not include / in matches */
2307 #else
2308    wild_stop_at_dir = 0;  /* default wildcards do include / in matches */
2309 #endif
2310 
2311   skip_this_disk = 0;
2312   des_good = 0;           /* Good data descriptor found */
2313   des_crc = 0;            /* Data descriptor CRC */
2314   des_csize = 0;          /* Data descriptor csize */
2315   des_usize = 0;          /* Data descriptor usize */
2316 
2317   dot_size = 0;           /* buffers processed in deflate per dot, 0 = no dots */
2318   dot_count = 0;          /* buffers seen, recyles at dot_size */
2319 
2320   display_counts = 0;     /* display running file count */
2321   display_bytes = 0;      /* display running bytes remaining */
2322   display_globaldots = 0; /* display dots for archive instead of each file */
2323   display_volume = 0;     /* display current input and output volume (disk) numbers */
2324   display_usize = 0;      /* display uncompressed bytes */
2325 
2326   files_so_far = 0;       /* files processed so far */
2327   bad_files_so_far = 0;   /* bad files skipped so far */
2328   files_total = 0;        /* files total to process */
2329   bytes_so_far = 0;       /* bytes processed so far (from initial scan) */
2330   good_bytes_so_far = 0;  /* good bytes read so far */
2331   bad_bytes_so_far = 0;   /* bad bytes skipped so far */
2332   bytes_total = 0;        /* total bytes to process (from initial scan) */
2333 
2334   logall = 0;             /* 0 = warnings/errors, 1 = all */
2335   logfile = NULL;         /* pointer to open logfile or NULL */
2336   logfile_append = 0;     /* append to existing logfile */
2337   logfile_path = NULL;    /* pointer to path of logfile */
2338 
2339   hidden_files = 0;       /* process hidden and system files */
2340   volume_label = 0;       /* add volume label */
2341   dirnames = 1;           /* include directory entries by default */
2342 #if defined(WIN32)
2343   only_archive_set = 0;   /* only include if DOS archive bit set */
2344   clear_archive_bits = 0; /* clear DOS archive bit of included files */
2345 #endif
2346   linkput = 0;            /* 1=store symbolic links as such */
2347   noisy = 1;              /* 0=quiet operation */
2348   extra_fields = 1;       /* 0=create minimum, 1=don't copy old, 2=keep old */
2349 
2350   use_descriptors = 0;    /* 1=use data descriptors 12/29/04 */
2351   zip_to_stdout = 0;      /* output zipfile to stdout 12/30/04 */
2352   allow_empty_archive = 0;/* if no files, create empty archive anyway 12/28/05 */
2353   copy_only = 0;          /* 1=copying archive entries only */
2354 
2355   output_seekable = 1;    /* 1 = output seekable 3/13/05 EG */
2356 
2357 #ifdef ZIP64_SUPPORT      /* zip64 support 10/4/03 */
2358   force_zip64 = -1;       /* if 1 force entries to be zip64 */
2359                           /* mainly for streaming from stdin */
2360   zip64_entry = 0;        /* current entry needs Zip64 */
2361   zip64_archive = 0;      /* if 1 then at least 1 entry needs zip64 */
2362 #endif
2363 
2364 #ifdef UNICODE_SUPPORT
2365   utf8_force = 0;         /* 1=force storing UTF-8 as standard per AppNote bit 11 */
2366 #endif
2367 
2368   unicode_escape_all = 0; /* 1=escape all non-ASCII characters in paths */
2369   unicode_mismatch = 1;   /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
2370 
2371   scan_delay = 5;         /* seconds before display Scanning files message */
2372   scan_dot_time = 2;      /* time in seconds between Scanning files dots */
2373   scan_start = 0;         /* start of scan */
2374   scan_last = 0;          /* time of last message */
2375   scan_started = 0;       /* scan has started */
2376   scan_count = 0;         /* Used for Scanning files ... message */
2377 
2378   before = 0;             /* 0=ignore, else exclude files before this time */
2379   after = 0;              /* 0=ignore, else exclude files newer than this time */
2380 
2381   special = ".Z:.zip:.zoo:.arc:.lzh:.arj"; /* List of special suffixes */
2382   key = NULL;             /* Scramble password if scrambling */
2383   key_needed = 0;         /* Need scramble password */
2384   tempath = NULL;         /* Path for temporary files */
2385   patterns = NULL;        /* List of patterns to be matched */
2386   pcount = 0;             /* number of patterns */
2387   icount = 0;             /* number of include only patterns */
2388   Rcount = 0;             /* number of -R include patterns */
2389 
2390   found = NULL;           /* List of names found, or new found entry */
2391   fnxt = &found;
2392 
2393   /* used by get_option */
2394   argcnt = 0;             /* size of args */
2395   argnum = 0;             /* current arg number */
2396   optchar = 0;            /* option state */
2397   value = NULL;           /* non-option arg, option value or NULL */
2398   negated = 0;            /* 1 = option negated */
2399   fna = 0;                /* current first nonopt arg */
2400   optnum = 0;             /* option index */
2401 
2402   show_options = 0;       /* 1 = show options */
2403   show_what_doing = 0;    /* 1 = show what zip doing */
2404   show_args = 0;          /* 1 = show command line */
2405   seen_doubledash = 0;    /* seen -- argument */
2406 
2407   zipfile = NULL;         /* path of usual in and out zipfile */
2408   tempzip = NULL;         /* name of temp file */
2409   y = NULL;               /* output file now global so can change in splits */
2410   in_file = NULL;         /* current input file for splits */
2411   in_split_path = NULL;   /* current in split path */
2412   in_path = NULL;         /* used by splits to track changing split locations */
2413   out_path = NULL;        /* if set, use -O out_path as output */
2414   have_out = 0;           /* if set, in_path and out_path not the same archive */
2415 
2416   total_disks = 0;        /* total disks in archive */
2417   current_in_disk = 0;    /* current read split disk */
2418   current_in_offset = 0;  /* current offset in current read disk */
2419   skip_current_disk = 0;  /* if != 0 and fix then skip entries on this disk */
2420 
2421   zip64_eocd_disk = 0;    /* disk with Zip64 End Of Central Directory Record */
2422   zip64_eocd_offset = 0;  /* offset for Zip64 EOCD Record */
2423 
2424   current_local_disk = 0; /* disk with current local header */
2425 
2426   current_disk = 0;           /* current disk number */
2427   cd_start_disk = (ulg)-1;    /* central directory start disk */
2428   cd_start_offset = 0;        /* offset of start of cd on cd start disk */
2429   cd_entries_this_disk = 0;   /* cd entries this disk */
2430   total_cd_entries = 0;       /* total cd entries in new/updated archive */
2431 
2432   /* for split method 1 (keep split with local header open and update) */
2433   current_local_tempname = NULL; /* name of temp file */
2434   current_local_file = NULL;  /* file pointer for current local header */
2435   current_local_offset = 0;   /* offset to start of current local header */
2436 
2437   /* global */
2438   bytes_this_split = 0;       /* bytes written to the current split */
2439   read_split_archive = 0;     /* 1=scanzipf_reg detected spanning signature */
2440   split_method = 0;           /* 0=no splits, 1=update LHs, 2=data descriptors */
2441   split_size = 0;             /* how big each split should be */
2442   split_bell = 0;             /* when pause for next split ring bell */
2443   bytes_prev_splits = 0;      /* total bytes written to all splits before this */
2444   bytes_this_entry = 0;       /* bytes written for this entry across all splits */
2445   noisy_splits = 0;           /* be verbose about creating splits */
2446   mesg_line_started = 0;      /* 1=started writing a line to mesg */
2447   logfile_line_started = 0;   /* 1=started writing a line to logfile */
2448 
2449   filelist = NULL;
2450   filearg_count = 0;
2451   allow_empty_archive = 0;    /* if no files, allow creation of empty archive anyway */
2452   bad_open_is_error = 0;      /* if read fails, 0=warning, 1=error */
2453   unicode_mismatch = 0;       /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
2454   show_files = 0;             /* show files to operate on and exit */
2455   scan_delay = 5;             /* seconds before display Scanning files message */
2456   scan_dot_time = 2;          /* time in seconds between Scanning files dots */
2457   scan_started = 0;           /* space at start of scan has been displayed */
2458   scan_last = 0;              /* Time last dot displayed for Scanning files message */
2459   scan_start = 0;             /* Time scanning started for Scanning files message */
2460 #ifdef UNICODE_SUPPORT
2461   use_wide_to_mb_default = 0;
2462 #endif
2463   filter_match_case = 1;      /* default is to match case when matching archive entries */
2464   allow_fifo = 0;             /* 1=allow reading Unix FIFOs, waiting if pipe open */
2465 
2466 #if !defined(MACOS) && !defined(USE_ZIPMAIN)
2467   retcode = setjmp(zipdll_error_return);
2468   if (retcode) {
2469     return retcode;
2470   }
2471 #endif /* !MACOS */
2472 #endif /* MACOS || WINDLL */
2473 
2474 #if !defined(ALLOW_REGEX) && (defined(MSDOS) || defined(WIN32))
2475   allow_regex = 0;        /* 1 = allow [list] matching (regex) */
2476 #else
2477   allow_regex = 1;
2478 #endif
2479 
2480   mesg = (FILE *) stdout; /* cannot be made at link time for VMS */
2481   comment_stream = (FILE *)stdin;
2482 
2483   init_upper();           /* build case map table */
2484 
2485 #ifdef LARGE_FILE_SUPPORT
2486   /* test if we can support large files - 9/29/04 */
2487   if (sizeof(zoff_t) < 8) {
2488     ZIPERR(ZE_COMPERR, "LARGE_FILE_SUPPORT enabled but OS not supporting it");
2489   }
2490 #endif
2491   /* test if sizes are the same - 12/30/04 */
2492   if (sizeof(uzoff_t) != sizeof(zoff_t)){
2493     ZIPERR(ZE_COMPERR, "uzoff_t not same size as zoff_t");
2494   }
2495 
2496 #if (defined(WIN32) && defined(USE_EF_UT_TIME))
2497   /* For the Win32 environment, we may have to "prepare" the environment
2498      prior to the tzset() call, to work around tzset() implementation bugs.
2499    */
2500   iz_w32_prepareTZenv();
2501 #endif
2502 
2503 #if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
2504 #  ifndef VALID_TIMEZONE
2505 #     define VALID_TIMEZONE(tmp) \
2506              (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0'))
2507 #  endif
2508   zp_tz_is_valid = VALID_TIMEZONE(p);
2509 #if (defined(AMIGA) || defined(DOS))
2510   if (!zp_tz_is_valid)
2511     extra_fields = 0;     /* disable storing "UT" time stamps */
2512 #endif /* AMIGA || DOS */
2513 #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
2514 
2515 /* For systems that do not have tzset() but supply this function using another
2516    name (_tzset() or something similar), an appropiate "#define tzset ..."
2517    should be added to the system specifc configuration section.  */
2518 #if (!defined(TOPS20) && !defined(VMS))
2519 #if (!defined(RISCOS) && !defined(MACOS) && !defined(QDOS))
2520 #if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM))
2521   tzset();
2522 #endif
2523 #endif
2524 #endif
2525 
2526 #ifdef VMSCLI
2527   {
2528       ulg status = vms_zip_cmdline(&argc, &argv);
2529       if (!(status & 1))
2530             return status;
2531   }
2532 #endif /* VMSCLI */
2533 
2534   /*    Substitutes the extended command line argument list produced by
2535    *    the MKS Korn Shell in place of the command line info from DOS.
2536    */
2537 
2538   /* extract extended argument list from environment */
2539   expand_args(&argc, &argv);
2540 
2541 #ifndef WINDLL
2542   /* Process arguments */
2543   diag("processing arguments");
2544   /* First, check if just the help or version screen should be displayed */
2545   if (argc == 1 && isatty(1))   /* no arguments, and output screen available */
2546   {                             /* show help screen */
2547 # ifdef VMSCLI
2548     VMSCLI_help();
2549 # else
2550     help();
2551 # endif
2552     EXIT(ZE_OK);
2553   }
2554   /* Check -v here as env arg can change argc.  Handle --version in main switch. */
2555   else if (argc == 2 && strcmp(argv[1], "-v") == 0 &&
2556            /* only "-v" as argument, and */
2557            (isatty(1) || isatty(0)))
2558            /* stdout or stdin is connected to console device */
2559   {                             /* show diagnostic version info */
2560     version_info();
2561     EXIT(ZE_OK);
2562   }
2563 # ifndef VMS
2564 #   ifndef RISCOS
2565   envargs(&argc, &argv, "ZIPOPT", "ZIP");  /* get options from environment */
2566 #   else /* RISCOS */
2567   envargs(&argc, &argv, "ZIPOPT", "Zip$Options");  /* get options from environment */
2568   getRISCOSexts("Zip$Exts");        /* get the extensions to swap from environment */
2569 #   endif /* ? RISCOS */
2570 # else /* VMS */
2571   envargs(&argc, &argv, "ZIPOPT", "ZIP_OPTS");  /* 4th arg for unzip compat. */
2572 # endif /* ?VMS */
2573 #endif /* !WINDLL */
2574 
2575   zipfile = tempzip = NULL;
2576   y = NULL;
2577   d = 0;                        /* disallow adding to a zip file */
2578 #if (!defined(MACOS) && !defined(WINDLL) && !defined(NLM))
2579   signal(SIGINT, handler);
2580 #ifdef SIGTERM                  /* AMIGADOS and others have no SIGTERM */
2581   signal(SIGTERM, handler);
2582 #endif
2583 # if defined(SIGABRT) && !(defined(AMIGA) && defined(__SASC))
2584    signal(SIGABRT, handler);
2585 # endif
2586 # ifdef SIGBREAK
2587    signal(SIGBREAK, handler);
2588 # endif
2589 # ifdef SIGBUS
2590    signal(SIGBUS, handler);
2591 # endif
2592 # ifdef SIGILL
2593    signal(SIGILL, handler);
2594 # endif
2595 # ifdef SIGSEGV
2596    signal(SIGSEGV, handler);
2597 # endif
2598 #endif /* !MACOS && !WINDLL && !NLM */
2599 #ifdef NLM
2600   NLMsignals();
2601 #endif
2602 
2603 
2604 #if defined(UNICODE_SUPPORT) && defined(WIN32)
2605   /* check if this Win32 OS has support for wide character calls */
2606   has_win32_wide();
2607 #endif
2608 
2609   /* make copy of args that can use with insert_arg() used by get_option() */
2610   args = copy_args(argv, 0);
2611 
2612   kk = 0;                       /* Next non-option argument type */
2613   s = 0;                        /* set by -@ */
2614 
2615   /*
2616   -------------------------------------------
2617   Process command line using get_option
2618   -------------------------------------------
2619 
2620   Each call to get_option() returns either a command
2621   line option and possible value or a non-option argument.
2622   Arguments are permuted so that all options (-r, -b temp)
2623   are returned before non-option arguments (zipfile).
2624   Returns 0 when nothing left to read.
2625   */
2626 
2627   /* set argnum = 0 on first call to init get_option */
2628   argnum = 0;
2629 
2630   /* get_option returns the option ID and updates parameters:
2631          args    - usually same as argv if no argument file support
2632          argcnt  - current argc for args
2633          value   - char* to value (free() when done with it) or NULL if no value
2634          negated - option was negated with trailing -
2635   */
2636 
2637   while ((option = get_option(&args, &argcnt, &argnum,
2638                               &optchar, &value, &negated,
2639                               &fna, &optnum, 0)))
2640   {
2641     switch (option)
2642     {
2643 #ifdef EBCDIC
2644       case 'a':
2645         aflag = ASCII;
2646         printf("Translating to ASCII...\n");
2647         break;
2648 #endif /* EBCDIC */
2649 #ifdef CMS_MVS
2650         case 'B':
2651           bflag = 1;
2652           printf("Using binary mode...\n");
2653           break;
2654 #endif /* CMS_MVS */
2655 #ifdef TANDEM
2656         case 'B':
2657           nskformatopt(value);
2658           free(value);
2659           break;
2660 #endif
2661 
2662         case '0':
2663           method = STORE; level = 0; break;
2664         case '1':  case '2':  case '3':  case '4':
2665         case '5':  case '6':  case '7':  case '8':  case '9':
2666           /* Set the compression efficacy */
2667           level = (int)option - '0';  break;
2668         case 'A':   /* Adjust unzipsfx'd zipfile:  adjust offsets only */
2669           adjust = 1; break;
2670 #if defined(WIN32)
2671         case o_AC:
2672           clear_archive_bits = 1; break;
2673         case o_AS:
2674           /* Since some directories could be empty if no archive bits are
2675              set for files in a directory, don't add directory entries (-D).
2676              Just files with the archive bit set are added, including paths
2677              (unless paths are excluded).  All major unzips should create
2678              directories for the paths as needed. */
2679           dirnames = 0;
2680           only_archive_set = 1; break;
2681 #endif /* MSDOS || OS2 || WIN32 */
2682         case 'b':   /* Specify path for temporary file */
2683           tempdir = 1;
2684           tempath = value;
2685           break;
2686         case 'c':   /* Add comments for new files in zip file */
2687           comadd = 1;  break;
2688 
2689         /* -C, -C2, and -C5 are with -V */
2690 
2691         case 'd':   /* Delete files from zip file */
2692           if (action != ADD) {
2693             ZIPERR(ZE_PARMS, "specify just one action");
2694           }
2695           action = DELETE;
2696           break;
2697 #ifdef MACOS
2698         case o_df:
2699           MacZip.DataForkOnly = true;
2700           break;
2701 #endif /* MACOS */
2702         case o_db:
2703           if (negated)
2704             display_bytes = 0;
2705           else
2706             display_bytes = 1;
2707           break;
2708         case o_dc:
2709           if (negated)
2710             display_counts = 0;
2711           else
2712             display_counts = 1;
2713           break;
2714         case o_dd:
2715           /* display dots */
2716           display_globaldots = 0;
2717           if (negated) {
2718             dot_count = 0;
2719           } else {
2720             /* set default dot size if dot_size not set (dot_count = 0) */
2721             if (dot_count == 0)
2722               /* default to 10 MB */
2723               dot_size = 10 * 0x100000;
2724             dot_count = -1;
2725           }
2726           break;
2727         case o_dg:
2728           /* display dots globally for archive instead of for each file */
2729           if (negated) {
2730             display_globaldots = 0;
2731           } else {
2732             display_globaldots = 1;
2733             /* set default dot size if dot_size not set (dot_count = 0) */
2734             if (dot_count == 0)
2735               dot_size = 10 * 0x100000;
2736             dot_count = -1;
2737           }
2738           break;
2739         case o_ds:
2740           /* input dot_size is now actual dot size to account for
2741              different buffer sizes */
2742           if (value == NULL)
2743             dot_size = 10 * 0x100000;
2744           else if (value[0] == '\0') {
2745             /* default to 10 MB */
2746             dot_size = 10 * 0x100000;
2747             free(value);
2748           } else {
2749             dot_size = ReadNumString(value);
2750             if (dot_size == (zoff_t)-1) {
2751               sprintf(errbuf, "option -ds (--dot-size) has bad size:  '%s'",
2752                       value);
2753               free(value);
2754               ZIPERR(ZE_PARMS, errbuf);
2755             }
2756             if (dot_size < 0x400) {
2757               /* < 1 KB so there is no multiplier, assume MB */
2758               dot_size *= 0x100000;
2759 
2760             } else if (dot_size < 0x400L * 32) {
2761               /* 1K <= dot_size < 32K */
2762               sprintf(errbuf, "dot size must be at least 32 KB:  '%s'", value);
2763               free(value);
2764               ZIPERR(ZE_PARMS, errbuf);
2765 
2766             } else {
2767               /* 32K <= dot_size */
2768             }
2769             free(value);
2770           }
2771           dot_count = -1;
2772           break;
2773         case o_du:
2774           if (negated)
2775             display_usize = 0;
2776           else
2777             display_usize = 1;
2778           break;
2779         case o_dv:
2780           if (negated)
2781             display_volume = 0;
2782           else
2783             display_volume = 1;
2784           break;
2785         case 'D':   /* Do not add directory entries */
2786           dirnames = 0; break;
2787         case o_DF:  /* Create a difference archive */
2788           diff_mode = 1;
2789           allow_empty_archive = 1;
2790           break;
2791         case 'e':   /* Encrypt */
2792 #if !CRYPT
2793           ZIPERR(ZE_PARMS, "encryption not supported");
2794 #else /* CRYPT */
2795           if (key)
2796             free(key);
2797           key_needed = 1;
2798 #endif /* !CRYPT */
2799           break;
2800         case 'F':   /* fix the zip file */
2801           fix = 1; break;
2802         case o_FF:  /* try harder to fix file */
2803           fix = 2; break;
2804         case o_FI:
2805           if (negated)
2806             allow_fifo = 0;
2807           else
2808             allow_fifo = 1;
2809           break;
2810         case o_FS:  /* delete exiting entries in archive where there is
2811                        no matching file on file system */
2812           filesync = 1; break;
2813         case 'f':   /* Freshen zip file--overwrite only */
2814           if (action != ADD) {
2815             ZIPERR(ZE_PARMS, "specify just one action");
2816           }
2817           action = FRESHEN;
2818           break;
2819         case 'g':   /* Allow appending to a zip file */
2820           d = 1;  break;
2821 #ifndef WINDLL
2822         case 'h': case 'H': case '?':  /* Help */
2823 #ifdef VMSCLI
2824           VMSCLI_help();
2825 #else
2826           help();
2827 #endif
2828           RETURN(finish(ZE_OK));
2829 #endif /* !WINDLL */
2830 
2831 #ifndef WINDLL
2832         case o_h2:  /* Extended Help */
2833           help_extended();
2834           RETURN(finish(ZE_OK));
2835 #endif /* !WINDLL */
2836 
2837         /* -i is with -x */
2838 #if defined(VMS) || defined(WIN32)
2839         case o_ic:  /* Ignore case (case-insensitive matching of archive entries) */
2840           if (negated)
2841             filter_match_case = 1;
2842           else
2843             filter_match_case = 0;
2844           break;
2845 #endif
2846 #ifdef RISCOS
2847         case 'I':   /* Don't scan through Image files */
2848           scanimage = 0;
2849           break;
2850 #endif
2851 #ifdef MACOS
2852         case o_jj:   /* store absolute path including volname */
2853             MacZip.StoreFullPath = true;
2854             break;
2855 #endif /* ?MACOS */
2856         case 'j':   /* Junk directory names */
2857           pathput = 0;  break;
2858         case 'J':   /* Junk sfx prefix */
2859           junk_sfx = 1;  break;
2860         case 'k':   /* Make entries using DOS names (k for Katz) */
2861           dosify = 1;  break;
2862         case 'l':   /* Translate end-of-line */
2863           translate_eol = 1; break;
2864         case o_ll:
2865           translate_eol = 2; break;
2866         case o_lf:
2867           /* open a logfile */
2868           /* allow multiple use of option but only last used */
2869           if (logfile_path) {
2870             free(logfile_path);
2871           }
2872           logfile_path = value;
2873           break;
2874         case o_la:
2875           /* append to existing logfile */
2876           if (negated)
2877             logfile_append = 0;
2878           else
2879             logfile_append = 1;
2880           break;
2881         case o_li:
2882           /* log all including informational messages */
2883           if (negated)
2884             logall = 0;
2885           else
2886             logall = 1;
2887           break;
2888 #ifndef WINDLL
2889         case 'L':   /* Show license */
2890           license();
2891           RETURN(finish(ZE_OK));
2892 #endif
2893         case 'm':   /* Delete files added or updated in zip file */
2894           dispose = 1;  break;
2895         case o_mm:  /* To prevent use of -mm for -MM */
2896           ZIPERR(ZE_PARMS, "-mm not supported, Must_Match is -MM");
2897           dispose = 1;  break;
2898         case o_MM:  /* Exit with error if input file can't be read */
2899           bad_open_is_error = 1; break;
2900         case 'n':   /* Don't compress files with a special suffix */
2901           special = value;
2902           /* special = NULL; */ /* will be set at next argument */
2903           break;
2904         case o_nw:  /* no wildcards - wildcards are handled like other characters */
2905           no_wild = 1;
2906           break;
2907 #if defined(AMIGA) || defined(MACOS)
2908         case 'N':   /* Get zipfile comments from AmigaDOS/MACOS filenotes */
2909           filenotes = 1; break;
2910 #endif
2911         case 'o':   /* Set zip file time to time of latest file in it */
2912           latest = 1;  break;
2913         case 'O':   /* Set output file different than input archive */
2914           out_path = ziptyp(value);
2915           free(value);
2916           have_out = 1;
2917           break;
2918         case 'p':   /* Store path with name */
2919           break;            /* (do nothing as annoyance avoidance) */
2920         case 'P':   /* password for encryption */
2921           if (key != NULL) {
2922             free(key);
2923           }
2924 #if CRYPT
2925           key = value;
2926           key_needed = 0;
2927 #else
2928           ZIPERR(ZE_PARMS, "encryption not supported");
2929 #endif /* CRYPT */
2930           break;
2931 #if defined(QDOS) || defined(QLZIP)
2932         case 'Q':
2933           qlflag  = strtol(value, NULL, 10);
2934        /* qlflag  = strtol((p+1), &p, 10); */
2935        /* p--; */
2936           if (qlflag == 0) qlflag = 4;
2937           free(value);
2938           break;
2939 #endif
2940         case 'q':   /* Quiet operation */
2941           noisy = 0;
2942 #ifdef MACOS
2943           MacZip.MacZip_Noisy = false;
2944 #endif  /* MACOS */
2945           if (verbose) verbose--;
2946           break;
2947         case 'r':   /* Recurse into subdirectories, match full path */
2948           if (recurse == 2) {
2949             ZIPERR(ZE_PARMS, "do not specify both -r and -R");
2950           }
2951           recurse = 1;  break;
2952         case 'R':   /* Recurse into subdirectories, match filename */
2953           if (recurse == 1) {
2954             ZIPERR(ZE_PARMS, "do not specify both -r and -R");
2955           }
2956           recurse = 2;  break;
2957 
2958         case o_RE:   /* Allow [list] matching (regex) */
2959           allow_regex = 1; break;
2960 
2961         case o_sc:  /* show command line args */
2962           show_args = 1; break;
2963 #ifdef UNICODE_TEST
2964         case o_sC:  /* create empty files from archive names */
2965           create_files = 1;
2966           show_files = 1; break;
2967 #endif
2968         case o_sd:  /* show debugging */
2969           show_what_doing = 1; break;
2970         case o_sf:  /* show files to operate on */
2971           if (!negated)
2972             show_files = 1;
2973           else
2974             show_files = 2;
2975           break;
2976         case o_so:  /* show all options */
2977           show_options = 1; break;
2978 #ifdef UNICODE_SUPPORT
2979         case o_su:  /* -sf but also show Unicode if exists */
2980           if (!negated)
2981             show_files = 3;
2982           else
2983             show_files = 4;
2984           break;
2985         case o_sU:  /* -sf but only show Unicode if exists or normal if not */
2986           if (!negated)
2987             show_files = 5;
2988           else
2989             show_files = 6;
2990           break;
2991 #endif
2992 
2993         case 's':   /* enable split archives */
2994           /* get the split size from value */
2995           if (strcmp(value, "-") == 0) {
2996             /* -s- do not allow splits */
2997             split_method = -1;
2998           } else {
2999             split_size = ReadNumString(value);
3000             if (split_size == (uzoff_t)-1) {
3001               sprintf(errbuf, "bad split size:  '%s'", value);
3002               ZIPERR(ZE_PARMS, errbuf);
3003             }
3004             if (split_size == 0) {
3005               /* do not allow splits */
3006               split_method = -1;
3007             } else {
3008               if (split_method == 0) {
3009                 split_method = 1;
3010               }
3011               if (split_size < 0x400) {
3012                 /* < 1 KB there is no multiplier, assume MB */
3013                 split_size *= 0x100000;
3014               }
3015               /* By setting the minimum split size to 64 KB we avoid
3016                  not having enough room to write a header unsplit
3017                  which is required */
3018               if (split_size < 0x400L * 64) {
3019                 /* split_size < 64K */
3020                 sprintf(errbuf, "minimum split size is 64 KB:  '%s'", value);
3021                 free(value);
3022                 ZIPERR(ZE_PARMS, errbuf);
3023               }
3024             }
3025           }
3026           free(value);
3027           break;
3028         case o_sb:  /* when pause for next split ring bell */
3029           split_bell = 1;
3030           break;
3031         case o_sp:  /* enable split select - pause splitting between splits */
3032           use_descriptors = 1;
3033           split_method = 2;
3034           break;
3035         case o_sv:  /* be verbose about creating splits */
3036           noisy_splits = 1;
3037           break;
3038 
3039 #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(ATARI)
3040         case 'S':
3041           hidden_files = 1; break;
3042 #endif /* MSDOS || OS2 || WIN32 || ATARI */
3043 #ifdef MACOS
3044         case 'S':
3045           MacZip.IncludeInvisible = true; break;
3046 #endif /* MACOS */
3047         case 't':   /* Exclude files earlier than specified date */
3048           {
3049             int yyyy, mm, dd;       /* results of sscanf() */
3050 
3051             /* Support ISO 8601 & American dates */
3052             if ((sscanf(value, "%4d-%2d-%2d", &yyyy, &mm, &dd) != 3 &&
3053                  sscanf(value, "%2d%2d%4d", &mm, &dd, &yyyy) != 3) ||
3054                 mm < 1 || mm > 12 || dd < 1 || dd > 31) {
3055               ZIPERR(ZE_PARMS,
3056                      "invalid date entered for -t option - use mmddyyyy or yyyy-mm-dd");
3057             }
3058             before = dostime(yyyy, mm, dd, 0, 0, 0);
3059           }
3060           free(value);
3061           break;
3062         case o_tt:  /* Exclude files at or after specified date */
3063           {
3064             int yyyy, mm, dd;       /* results of sscanf() */
3065 
3066             /* Support ISO 8601 & American dates */
3067             if ((sscanf(value, "%4d-%2d-%2d", &yyyy, &mm, &dd) != 3 &&
3068                  sscanf(value, "%2d%2d%4d", &mm, &dd, &yyyy) != 3) ||
3069                 mm < 1 || mm > 12 || dd < 1 || dd > 31) {
3070               ZIPERR(ZE_PARMS,
3071                      "invalid date entered for -tt option - use mmddyyyy or yyyy-mm-dd");
3072             }
3073             after = dostime(yyyy, mm, dd, 0, 0, 0);
3074           }
3075           free(value);
3076           break;
3077         case 'T':   /* test zip file */
3078           test = 1; break;
3079         case o_TT:  /* command path to use instead of 'unzip -t ' */
3080           if (unzip_path)
3081             free(unzip_path);
3082           unzip_path = value;
3083           break;
3084         case 'U':   /* Select archive entries to keep or operate on */
3085           if (action != ADD) {
3086             ZIPERR(ZE_PARMS, "specify just one action");
3087           }
3088           action = ARCHIVE;
3089           break;
3090 #ifdef UNICODE_SUPPORT
3091         case o_UN:   /* Unicode */
3092           if (abbrevmatch("quit", value, 0, 1)) {
3093             /* Unicode path mismatch is error */
3094             unicode_mismatch = 0;
3095           } else if (abbrevmatch("warn", value, 0, 1)) {
3096             /* warn of mismatches and continue */
3097             unicode_mismatch = 1;
3098           } else if (abbrevmatch("ignore", value, 0, 1)) {
3099             /* ignore mismatches and continue */
3100             unicode_mismatch = 2;
3101           } else if (abbrevmatch("no", value, 0, 1)) {
3102             /* no use Unicode path */
3103             unicode_mismatch = 3;
3104           } else if (abbrevmatch("escape", value, 0, 1)) {
3105             /* escape all non-ASCII characters */
3106             unicode_escape_all = 1;
3107 
3108           } else if (abbrevmatch("UTF8", value, 0, 1)) {
3109             /* force storing UTF-8 as standard per AppNote bit 11 */
3110             utf8_force = 1;
3111 
3112           } else {
3113             zipwarn("-UN must be Quit, Warn, Ignore, No, Escape, or UTF8: ", value);
3114 
3115             free(value);
3116             ZIPERR(ZE_PARMS, "-UN (unicode) bad value");
3117           }
3118           free(value);
3119           break;
3120 #endif
3121         case 'u':   /* Update zip file--overwrite only if newer */
3122           if (action != ADD) {
3123             ZIPERR(ZE_PARMS, "specify just one action");
3124           }
3125           action = UPDATE;
3126           break;
3127         case 'v':        /* Either display version information or */
3128         case o_ve:       /* Mention oddities in zip file structure */
3129           if (option == o_ve ||      /* --version */
3130               (argcnt == 2 && strlen(args[1]) == 2)) { /* -v only */
3131             /* display version */
3132 #ifndef WINDLL
3133             version_info();
3134 #else
3135             zipwarn("version information not supported for dll", "");
3136 #endif
3137             RETURN(finish(ZE_OK));
3138           } else {
3139             noisy = 1;
3140             verbose++;
3141           }
3142           break;
3143 #ifdef VMS
3144         case 'C':  /* Preserve case (- = down-case) all. */
3145           if (negated)
3146           { /* Down-case all. */
3147             if ((vms_case_2 > 0) || (vms_case_5 > 0))
3148             {
3149               ZIPERR( ZE_PARMS, "Conflicting case directives (-C-)");
3150             }
3151             vms_case_2 = -1;
3152             vms_case_5 = -1;
3153           }
3154           else
3155           { /* Not negated.  Preserve all. */
3156             if ((vms_case_2 < 0) || (vms_case_5 < 0))
3157             {
3158               ZIPERR( ZE_PARMS, "Conflicting case directives (-C)");
3159             }
3160             vms_case_2 = 1;
3161             vms_case_5 = 1;
3162           }
3163           break;
3164         case o_C2:  /* Preserve case (- = down-case) ODS2. */
3165           if (negated)
3166           { /* Down-case ODS2. */
3167             if (vms_case_2 > 0)
3168             {
3169               ZIPERR( ZE_PARMS, "Conflicting case directives (-C2-)");
3170             }
3171             vms_case_2 = -1;
3172           }
3173           else
3174           { /* Not negated.  Preserve ODS2. */
3175             if (vms_case_2 < 0)
3176             {
3177               ZIPERR( ZE_PARMS, "Conflicting case directives (-C2)");
3178             }
3179             vms_case_2 = 1;
3180           }
3181           break;
3182         case o_C5:  /* Preserve case (- = down-case) ODS5. */
3183           if (negated)
3184           { /* Down-case ODS5. */
3185             if (vms_case_5 > 0)
3186             {
3187               ZIPERR( ZE_PARMS, "Conflicting case directives (-C5-)");
3188             }
3189             vms_case_5 = -1;
3190           }
3191           else
3192           { /* Not negated.  Preserve ODS5. */
3193             if (vms_case_5 < 0)
3194             {
3195               ZIPERR( ZE_PARMS, "Conflicting case directives (-C5)");
3196             }
3197             vms_case_5 = 1;
3198           }
3199           break;
3200         case 'V':   /* Store in VMS format.  (Record multiples.) */
3201           vms_native = 1; break;
3202           /* below does work with new parser but doesn't allow tracking
3203              -VV separately, like adding a separate description */
3204           /* vms_native++; break; */
3205         case o_VV:  /* Store in VMS specific format */
3206           vms_native = 2; break;
3207         case 'w':   /* Append the VMS version number */
3208           vmsver |= 1;  break;
3209         case o_ww:   /* Append the VMS version number as ".nnn". */
3210           vmsver |= 3;  break;
3211 #endif /* VMS */
3212         case o_ws:  /* Wildcards do not include directory boundaries in matches */
3213           wild_stop_at_dir = 1;
3214           break;
3215 
3216         case 'i':   /* Include only the following files */
3217           /* if nothing matches include list then still create an empty archive */
3218           allow_empty_archive = 1;
3219         case 'x':   /* Exclude following files */
3220           add_filter((int) option, value);
3221           free(value);
3222           break;
3223 #ifdef S_IFLNK
3224         case 'y':   /* Store symbolic links as such */
3225           linkput = 1;  break;
3226 #endif /* S_IFLNK */
3227         case 'z':   /* Edit zip file comment */
3228           zipedit = 1;  break;
3229         case 'Z':   /* Compression method */
3230           if (abbrevmatch("deflate", value, 0, 1)) {
3231             /* deflate */
3232             method = DEFLATE;
3233           } else if (abbrevmatch("store", value, 0, 1)) {
3234             /* store */
3235             method = STORE;
3236           } else if (abbrevmatch("bzip2", value, 0, 1)) {
3237             /* bzip2 */
3238 #ifdef BZIP2_SUPPORT
3239             method = BZIP2;
3240 #else
3241             ZIPERR(ZE_COMPERR, "Compression method bzip2 not enabled");
3242 #endif
3243           } else {
3244 #ifdef BZIP2_SUPPORT
3245             zipwarn("valid compression methods are:  store, deflate, bzip2", "");
3246 #else
3247             zipwarn("valid compression methods are:  store, deflate)", "");
3248 #endif
3249             zipwarn("unknown compression method found:  ", value);
3250             free(value);
3251             ZIPERR(ZE_PARMS, "Option -Z (--compression-method):  unknown method");
3252           }
3253           free(value);
3254           break;
3255 #if defined(MSDOS) || defined(OS2)
3256         case '$':   /* Include volume label */
3257           volume_label = 1; break;
3258 #endif
3259 #ifndef MACOS
3260         case '@':   /* read file names from stdin */
3261           comment_stream = NULL;
3262           s = 1;          /* defer -@ until have zipfile name */
3263           break;
3264 #endif /* !MACOS */
3265         case 'X':
3266           if (negated)
3267             extra_fields = 2;
3268           else
3269             extra_fields = 0;
3270           break;
3271 #ifdef OS2
3272         case 'E':
3273           /* use the .LONGNAME EA (if any) as the file's name. */
3274           use_longname_ea = 1;
3275           break;
3276 #endif
3277 #ifdef NTSD_EAS
3278         case '!':
3279           /* use security privilege overrides */
3280           use_privileges = 1;
3281           break;
3282 #endif
3283 #ifdef RISCOS
3284         case '/':
3285           exts2swap = value; /* override Zip$Exts */
3286           break;
3287 #endif
3288         case o_des:
3289           use_descriptors = 1;
3290           break;
3291 
3292 #ifdef ZIP64_SUPPORT
3293         case o_z64:   /* Force creation of Zip64 entries */
3294           if (negated) {
3295             force_zip64 = 0;
3296           } else {
3297             force_zip64 = 1;
3298           }
3299           break;
3300 #endif
3301 
3302         case o_NON_OPTION_ARG:
3303           /* not an option */
3304           /* no more options as permuting */
3305           /* just dash also ends up here */
3306 
3307           if (recurse != 2 && kk == 0 && patterns == NULL) {
3308             /* have all filters so convert filterlist to patterns array
3309                as PROCNAME needs patterns array */
3310             filterlist_to_patterns();
3311           }
3312 
3313           /* "--" stops arg processing for remaining args */
3314           /* ignore only first -- */
3315           if (strcmp(value, "--") == 0 && seen_doubledash == 0) {
3316             /* -- */
3317             seen_doubledash = 1;
3318             if (kk == 0) {
3319               ZIPERR(ZE_PARMS, "can't use -- before archive name");
3320             }
3321 
3322             /* just ignore as just marks what follows as non-option arguments */
3323 
3324           } else if (kk == 6) {
3325             /* value is R pattern */
3326             add_filter((int)'R', value);
3327             free(value);
3328             if (first_listarg == 0) {
3329               first_listarg = argnum;
3330             }
3331           } else switch (kk)
3332           {
3333             case 0:
3334               /* first non-option arg is zipfile name */
3335 #if (!defined(MACOS) && !defined(WINDLL))
3336               if (strcmp(value, "-") == 0) {  /* output zipfile is dash */
3337                 /* just a dash */
3338                 zipstdout();
3339               } else
3340 #endif /* !MACOS && !WINDLL */
3341               {
3342                 /* name of zipfile */
3343                 if ((zipfile = ziptyp(value)) == NULL) {
3344                   ZIPERR(ZE_MEM, "was processing arguments");
3345                 }
3346                 /* read zipfile if exists */
3347                 /*
3348                 if ((r = readzipfile()) != ZE_OK) {
3349                   ZIPERR(r, zipfile);
3350                 }
3351                 */
3352                 free(value);
3353               }
3354               if (show_what_doing) {
3355                 fprintf(mesg, "sd: Zipfile name '%s'\n", zipfile);
3356                 fflush(mesg);
3357               }
3358               /* if in_path not set, use zipfile path as usual for input */
3359               /* in_path is used as the base path to find splits */
3360               if (in_path == NULL) {
3361                 if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
3362                   ZIPERR(ZE_MEM, "was processing arguments");
3363                 }
3364                 strcpy(in_path, zipfile);
3365               }
3366               /* if out_path not set, use zipfile path as usual for output */
3367               /* out_path is where the output archive is written */
3368               if (out_path == NULL) {
3369                 if ((out_path = malloc(strlen(zipfile) + 1)) == NULL) {
3370                   ZIPERR(ZE_MEM, "was processing arguments");
3371                 }
3372                 strcpy(out_path, zipfile);
3373               }
3374               kk = 3;
3375               if (s)
3376               {
3377                 /* do -@ and get names from stdin */
3378                 /* should be able to read names from
3379                    stdin and output to stdout, but
3380                    this was not allowed in old code.
3381                    This check moved to kk = 3 case to fix. */
3382                 /* if (strcmp(zipfile, "-") == 0) {
3383                   ZIPERR(ZE_PARMS, "can't use - and -@ together");
3384                 }
3385                 */
3386                 while ((pp = getnam(stdin)) != NULL)
3387                 {
3388                   kk = 4;
3389                   if (recurse == 2) {
3390                     /* reading patterns from stdin */
3391                     add_filter((int)'R', pp);
3392                   } else {
3393                     /* file argument now processed later */
3394                     add_name(pp);
3395                   }
3396                   /*
3397                   if ((r = PROCNAME(pp)) != ZE_OK) {
3398                     if (r == ZE_MISS)
3399                       zipwarn("name not matched: ", pp);
3400                     else {
3401                       ZIPERR(r, pp);
3402                     }
3403                   }
3404                   */
3405                   free(pp);
3406                 }
3407                 s = 0;
3408               }
3409               if (recurse == 2) {
3410                 /* rest are -R patterns */
3411                 kk = 6;
3412               }
3413               break;
3414 
3415             case 3:  case 4:
3416               /* no recurse and -r file names */
3417               /* can't read filenames -@ and input - from stdin at
3418                  same time */
3419               if (s == 1 && strcmp(value, "-") == 0) {
3420                 ZIPERR(ZE_PARMS, "can't read input (-) and filenames (-@) both from stdin");
3421               }
3422               /* add name to list for later processing */
3423               add_name(value);
3424               /*
3425               if ((r = PROCNAME(value)) != ZE_OK) {
3426                 if (r == ZE_MISS)
3427                   zipwarn("name not matched: ", value);
3428                 else {
3429                   ZIPERR(r, value);
3430                 }
3431               }
3432               */
3433               if (kk == 3) {
3434                 first_listarg = argnum;
3435                 kk = 4;
3436               }
3437               break;
3438 
3439             } /* switch kk */
3440             break;
3441 
3442         default:
3443           /* should never get here as get_option will exit if not in table */
3444           sprintf(errbuf, "no such option ID: %ld", option);
3445           ZIPERR(ZE_PARMS, errbuf);
3446 
3447      }  /* switch */
3448   }
3449 
3450 
3451   /* do processing of command line and one-time tasks */
3452 
3453   /* Key not yet specified.  If needed, get/verify it now. */
3454   if (key_needed) {
3455     if ((key = malloc(IZ_PWLEN+1)) == NULL) {
3456       ZIPERR(ZE_MEM, "was getting encryption password");
3457     }
3458     r = encr_passwd(ZP_PW_ENTER, key, IZ_PWLEN+1, zipfile);
3459     if (r != IZ_PW_ENTERED) {
3460       if (r < IZ_PW_ENTERED)
3461         r = ZE_PARMS;
3462       ZIPERR(r, "was getting encryption password");
3463     }
3464     if (*key == '\0') {
3465       ZIPERR(ZE_PARMS, "zero length password not allowed");
3466     }
3467     if ((e = malloc(IZ_PWLEN+1)) == NULL) {
3468       ZIPERR(ZE_MEM, "was verifying encryption password");
3469     }
3470     r = encr_passwd(ZP_PW_VERIFY, e, IZ_PWLEN+1, zipfile);
3471     if (r != IZ_PW_ENTERED && r != IZ_PW_SKIPVERIFY) {
3472       free((zvoid *)e);
3473       if (r < ZE_OK) r = ZE_PARMS;
3474       ZIPERR(r, "was verifying encryption password");
3475     }
3476     r = ((r == IZ_PW_SKIPVERIFY) ? 0 : strcmp(key, e));
3477     free((zvoid *)e);
3478     if (r) {
3479       ZIPERR(ZE_PARMS, "password verification failed");
3480     }
3481   }
3482   if (key) {
3483     /* if -P "" could get here */
3484     if (*key == '\0') {
3485       ZIPERR(ZE_PARMS, "zero length password not allowed");
3486     }
3487   }
3488 
3489   if (show_what_doing) {
3490     fprintf(mesg, "sd: Command line read\n");
3491     fflush(mesg);
3492   }
3493 
3494   /* show command line args */
3495   if (show_args) {
3496     fprintf(mesg, "command line:\n");
3497     for (i = 0; args[i]; i++) {
3498       fprintf(mesg, "'%s'  ", args[i]);
3499     }
3500     fprintf(mesg, "\n");
3501     ZIPERR(ZE_ABORT, "show command line");
3502   }
3503 
3504   /* show all options */
3505   if (show_options) {
3506     printf("available options:\n");
3507     printf(" %-2s  %-18s %-4s %-3s %-30s\n", "sh", "long", "val", "neg", "description");
3508     printf(" %-2s  %-18s %-4s %-3s %-30s\n", "--", "----", "---", "---", "-----------");
3509     for (i = 0; options[i].option_ID; i++) {
3510       printf(" %-2s  %-18s ", options[i].shortopt, options[i].longopt);
3511       switch (options[i].value_type) {
3512         case o_NO_VALUE:
3513           printf("%-4s ", "");
3514           break;
3515         case o_REQUIRED_VALUE:
3516           printf("%-4s ", "req");
3517           break;
3518         case o_OPTIONAL_VALUE:
3519           printf("%-4s ", "opt");
3520           break;
3521         case o_VALUE_LIST:
3522           printf("%-4s ", "list");
3523           break;
3524         case o_ONE_CHAR_VALUE:
3525           printf("%-4s ", "char");
3526           break;
3527         case o_NUMBER_VALUE:
3528           printf("%-4s ", "num");
3529           break;
3530         default:
3531           printf("%-4s ", "unk");
3532       }
3533       switch (options[i].negatable) {
3534         case o_NEGATABLE:
3535           printf("%-3s ", "neg");
3536           break;
3537         case o_NOT_NEGATABLE:
3538           printf("%-3s ", "");
3539           break;
3540         default:
3541           printf("%-3s ", "unk");
3542       }
3543       if (options[i].name)
3544         printf("%-30s\n", options[i].name);
3545       else
3546         printf("\n");
3547     }
3548     RETURN(finish(ZE_OK));
3549   }
3550 
3551 
3552   /* open log file */
3553   if (logfile_path) {
3554     char mode[10];
3555     char *p;
3556     char *lastp;
3557 
3558     /* if no extension add .log */
3559     p = logfile_path;
3560     /* find last / */
3561     lastp = NULL;
3562     for (p = logfile_path; (p = MBSRCHR(p, '/')) != NULL; p++) {
3563       lastp = p;
3564     }
3565     if (lastp == NULL)
3566       lastp = logfile_path;
3567     if (MBSRCHR(lastp, '.') == NULL) {
3568       /* add .log */
3569       if ((p = malloc(strlen(logfile_path) + 5)) == NULL) {
3570         ZIPERR(ZE_MEM, "logpath");
3571       }
3572       strcpy(p, logfile_path);
3573       strcat(p, ".log");
3574       free(logfile_path);
3575       logfile_path = p;
3576     }
3577 
3578     if (logfile_append) {
3579       sprintf(mode, "a");
3580     } else {
3581       sprintf(mode, "w");
3582     }
3583     if ((logfile = zfopen(logfile_path, mode)) == NULL) {
3584       sprintf(errbuf, "could not open logfile '%s'", logfile_path);
3585       ZIPERR(ZE_PARMS, errbuf);
3586     }
3587     {
3588       /* At top put start time and command line */
3589 
3590       /* get current time */
3591       struct tm *now;
3592       time_t clocktime;
3593 
3594       time(&clocktime);
3595       now = localtime(&clocktime);
3596 
3597       fprintf(logfile, "---------\n");
3598       fprintf(logfile, "Zip log opened %s", asctime(now));
3599       fprintf(logfile, "command line arguments:\n ");
3600       for (i = 1; args[i]; i++) {
3601         size_t j;
3602         int has_space = 0;
3603 
3604         for (j = 0; j < strlen(args[i]); j++) {
3605           if (isspace(args[i][j])) {
3606             has_space = 1;
3607             break;
3608           }
3609         }
3610         if (has_space)
3611           fprintf(logfile, "\"%s\" ", args[i]);
3612         else
3613           fprintf(logfile, "%s ", args[i]);
3614       }
3615       fprintf(logfile, "\n\n");
3616       fflush(logfile);
3617     }
3618   } else {
3619     /* only set logall if logfile open */
3620     logall = 0;
3621   }
3622 
3623 
3624   if (split_method && out_path) {
3625     /* if splitting, the archive name must have .zip extension */
3626     int plen = strlen(out_path);
3627     char *out_path_ext;
3628 
3629 #ifdef VMS
3630     /* On VMS, adjust plen (and out_path_ext) to avoid the file version. */
3631     plen -= strlen( vms_file_version( out_path));
3632 #endif /* def VMS */
3633     out_path_ext = out_path+ plen- 4;
3634 
3635     if (plen < 4 ||
3636         out_path_ext[0] != '.' ||
3637         toupper(out_path_ext[1]) != 'Z' ||
3638         toupper(out_path_ext[2]) != 'I' ||
3639         toupper(out_path_ext[3]) != 'P') {
3640       ZIPERR(ZE_PARMS, "archive name must end in .zip for splits");
3641     }
3642   }
3643 
3644 
3645   if (verbose && (dot_size == 0) && (dot_count == 0)) {
3646     /* now default to default 10 MB dot size */
3647     dot_size = 10 * 0x100000;
3648     /* show all dots as before if verbose set and dot_size not set (dot_count = 0) */
3649     /* maybe should turn off dots in default verbose mode */
3650     /* dot_size = -1; */
3651   }
3652 
3653   /* done getting -R filters so convert filterlist if not done */
3654   if (pcount && patterns == NULL) {
3655     filterlist_to_patterns();
3656   }
3657 
3658 #if (defined(MSDOS) || defined(OS2)) && !defined(WIN32)
3659   if ((kk == 3 || kk == 4) && volume_label == 1) {
3660     /* read volume label */
3661     PROCNAME(NULL);
3662     kk = 4;
3663   }
3664 #endif
3665 
3666   if (have_out && kk == 3) {
3667     copy_only = 1;
3668     action = ARCHIVE;
3669   }
3670 
3671   if (have_out && namecmp(in_path, out_path) == 0) {
3672     sprintf(errbuf, "--out path must be different than in path: %s", out_path);
3673     ZIPERR(ZE_PARMS, errbuf);
3674   }
3675 
3676   if (fix && diff_mode) {
3677     ZIPERR(ZE_PARMS, "can't use --diff (-DF) with fix (-F or -FF)");
3678   }
3679 
3680   if (action == ARCHIVE && !have_out && !show_files) {
3681     ZIPERR(ZE_PARMS, "-U (--copy) requires -O (--out)");
3682   }
3683 
3684   if (fix && !have_out) {
3685     zipwarn("fix options -F and -FF require --out:\n",
3686             "                     zip -F indamagedarchive --out outfixedarchive");
3687     ZIPERR(ZE_PARMS, "fix options require --out");
3688   }
3689 
3690   if (fix && !copy_only) {
3691     ZIPERR(ZE_PARMS, "no other actions allowed when fixing archive (-F or -FF)");
3692   }
3693 
3694   if (!have_out && diff_mode) {
3695     ZIPERR(ZE_PARMS, "-DF (--diff) requires -O (--out)");
3696   }
3697 
3698   if (diff_mode && (action == ARCHIVE || action == DELETE)) {
3699     ZIPERR(ZE_PARMS, "can't use --diff (-DF) with -d or -U");
3700   }
3701 
3702   if (action != ARCHIVE && (recurse == 2 || pcount) && first_listarg == 0 &&
3703       !filelist && (kk < 3 || (action != UPDATE && action != FRESHEN))) {
3704     ZIPERR(ZE_PARMS, "nothing to select from");
3705   }
3706 
3707 /*
3708   -------------------------------------
3709   end of new command line code
3710   -------------------------------------
3711 */
3712 
3713 #if (!defined(MACOS) && !defined(WINDLL))
3714   if (kk < 3) {               /* zip used as filter */
3715     zipstdout();
3716     comment_stream = NULL;
3717     if ((r = procname("-", 0)) != ZE_OK) {
3718       if (r == ZE_MISS) {
3719         if (bad_open_is_error) {
3720           zipwarn("name not matched: ", "-");
3721           ZIPERR(ZE_OPEN, "-");
3722         } else {
3723           zipwarn("name not matched: ", "-");
3724         }
3725       } else {
3726         ZIPERR(r, "-");
3727       }
3728     }
3729     kk = 4;
3730     if (s) {
3731       ZIPERR(ZE_PARMS, "can't use - and -@ together");
3732     }
3733   }
3734 #endif /* !MACOS && !WINDLL */
3735 
3736   if (zipfile && !strcmp(zipfile, "-")) {
3737     if (show_what_doing) {
3738       fprintf(mesg, "sd: Zipping to stdout\n");
3739       fflush(mesg);
3740     }
3741     zip_to_stdout = 1;
3742   }
3743 
3744   /* Check option combinations */
3745   if (special == NULL) {
3746     ZIPERR(ZE_PARMS, "missing suffix list");
3747   }
3748   if (level == 9 || !strcmp(special, ";") || !strcmp(special, ":"))
3749     special = NULL; /* compress everything */
3750 
3751   if (action == DELETE && (method != BEST || dispose || recurse ||
3752       key != NULL || comadd || zipedit)) {
3753     zipwarn("invalid option(s) used with -d; ignored.","");
3754     /* reset flags - needed? */
3755     method  = BEST;
3756     dispose = 0;
3757     recurse = 0;
3758     if (key != NULL) {
3759       free((zvoid *)key);
3760       key   = NULL;
3761     }
3762     comadd  = 0;
3763     zipedit = 0;
3764   }
3765   if (action == ARCHIVE && (method != BEST || dispose || recurse ||
3766       comadd || zipedit)) {
3767     zipwarn("can't set method, move, recurse, or comments with copy mode.","");
3768     /* reset flags - needed? */
3769     method  = BEST;
3770     dispose = 0;
3771     recurse = 0;
3772     comadd  = 0;
3773     zipedit = 0;
3774   }
3775   if (linkput && dosify)
3776     {
3777       zipwarn("can't use -y with -k, -y ignored", "");
3778       linkput = 0;
3779     }
3780   if (fix == 1 && adjust)
3781     {
3782       zipwarn("can't use -F with -A, -F ignored", "");
3783       fix = 0;
3784     }
3785   if (fix == 2 && adjust)
3786     {
3787       zipwarn("can't use -FF with -A, -FF ignored", "");
3788       fix = 0;
3789     }
3790   if (test && zip_to_stdout) {
3791     test = 0;
3792     zipwarn("can't use -T on stdout, -T ignored", "");
3793   }
3794   if (split_method && (fix || adjust)) {
3795     ZIPERR(ZE_PARMS, "can't create split archive while fixing or adjusting\n");
3796   }
3797   if (split_method && (d || zip_to_stdout)) {
3798     ZIPERR(ZE_PARMS, "can't create split archive with -d or -g or on stdout\n");
3799   }
3800   if ((action != ADD || d) && filesync) {
3801     ZIPERR(ZE_PARMS, "can't use -d, -f, -u, -U, or -g with filesync -FS\n");
3802   }
3803   if ((action != ADD || d) && zip_to_stdout) {
3804     ZIPERR(ZE_PARMS, "can't use -d, -f, -u, -U, or -g on stdout\n");
3805   }
3806 #if defined(EBCDIC)  && !defined(OS390)
3807   if (aflag==ASCII && !translate_eol) {
3808     /* Translation to ASCII implies EOL translation!
3809      * (on OS390, consistent EOL translation is controlled separately)
3810      * The default translation mode is "UNIX" mode (single LF terminators).
3811      */
3812     translate_eol = 2;
3813   }
3814 #endif
3815 #ifdef CMS_MVS
3816   if (aflag==ASCII && bflag)
3817     ZIPERR(ZE_PARMS, "can't use -a with -B");
3818 #endif
3819 #ifdef VMS
3820   if (!extra_fields && vms_native)
3821     {
3822       zipwarn("can't use -V with -X, -V ignored", "");
3823       vms_native = 0;
3824     }
3825   if (vms_native && translate_eol)
3826     ZIPERR(ZE_PARMS, "can't use -V with -l or -ll");
3827 #endif
3828 
3829   if (noisy) {
3830     if (fix == 1)
3831       zipmessage("Fix archive (-F) - assume mostly intact archive", "");
3832     else if (fix == 2)
3833       zipmessage("Fix archive (-FF) - salvage what can", "");
3834   }
3835 
3836   /* Read old archive */
3837 
3838   /* Now read the zip file here instead of when doing args above */
3839   /* Only read the central directory and build zlist */
3840   if (show_what_doing) {
3841     fprintf(mesg, "sd: Reading archive\n");
3842     fflush(mesg);
3843   }
3844 
3845 
3846 
3847 
3848   /* If -FF we do it all here */
3849   if (fix == 2) {
3850 
3851     /* Open zip file and temporary output file */
3852     if (show_what_doing) {
3853       fprintf(mesg, "sd: Open zip file and create temp file (-FF)\n");
3854       fflush(mesg);
3855     }
3856     diag("opening zip file and creating temporary zip file");
3857     x = NULL;
3858     tempzn = 0;
3859     if (show_what_doing) {
3860       fprintf(mesg, "sd: Creating new zip file (-FF)\n");
3861       fflush(mesg);
3862     }
3863 #if defined(UNIX) && !defined(NO_MKSTEMP)
3864     {
3865       int yd;
3866       int i;
3867 
3868       /* use mkstemp to avoid race condition and compiler warning */
3869 
3870       if (tempath != NULL)
3871       {
3872         /* if -b used to set temp file dir use that for split temp */
3873         if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
3874           ZIPERR(ZE_MEM, "allocating temp filename");
3875         }
3876         strcpy(tempzip, tempath);
3877         if (lastchar(tempzip) != '/')
3878           strcat(tempzip, "/");
3879       }
3880       else
3881       {
3882         /* create path by stripping name and appending template */
3883         if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
3884         ZIPERR(ZE_MEM, "allocating temp filename");
3885         }
3886         strcpy(tempzip, zipfile);
3887         for(i = strlen(tempzip); i > 0; i--) {
3888           if (tempzip[i - 1] == '/')
3889             break;
3890         }
3891         tempzip[i] = '\0';
3892       }
3893       strcat(tempzip, "ziXXXXXX");
3894 
3895       if ((yd = mkstemp(tempzip)) == EOF) {
3896         ZIPERR(ZE_TEMP, tempzip);
3897       }
3898       if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
3899         ZIPERR(ZE_TEMP, tempzip);
3900       }
3901     }
3902 #else
3903     if ((tempzip = tempname(zipfile)) == NULL) {
3904       ZIPERR(ZE_MEM, "allocating temp filename");
3905     }
3906     if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
3907       ZIPERR(ZE_TEMP, tempzip);
3908     }
3909 #endif
3910 
3911 #if (!defined(VMS) && !defined(CMS_MVS))
3912     /* Use large buffer to speed up stdio: */
3913 #if (defined(_IOFBF) || !defined(BUFSIZ))
3914     zipbuf = (char *)malloc(ZBSZ);
3915 #else
3916     zipbuf = (char *)malloc(BUFSIZ);
3917 #endif
3918     if (zipbuf == NULL) {
3919       ZIPERR(ZE_MEM, tempzip);
3920     }
3921 # ifdef _IOFBF
3922     setvbuf(y, zipbuf, _IOFBF, ZBSZ);
3923 # else
3924     setbuf(y, zipbuf);
3925 # endif /* _IOBUF */
3926 #endif /* !VMS  && !CMS_MVS */
3927 
3928 
3929     if ((r = readzipfile()) != ZE_OK) {
3930       ZIPERR(r, zipfile);
3931     }
3932 
3933     /* Write central directory and end header to temporary zip */
3934     if (show_what_doing) {
3935       fprintf(mesg, "sd: Writing central directory (-FF)\n");
3936       fflush(mesg);
3937     }
3938     diag("writing central directory");
3939     k = 0;                        /* keep count for end header */
3940     c = tempzn;                   /* get start of central */
3941     n = t = 0;
3942     for (z = zfiles; z != NULL; z = z->nxt)
3943     {
3944       if ((r = putcentral(z)) != ZE_OK) {
3945         ZIPERR(r, tempzip);
3946       }
3947       tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
3948       n += z->len;
3949       t += z->siz;
3950       k++;
3951     }
3952     if (zcount == 0)
3953       zipwarn("zip file empty", "");
3954     t = tempzn - c;               /* compute length of central */
3955     diag("writing end of central directory");
3956     if ((r = putend(k, t, c, zcomlen, zcomment)) != ZE_OK) {
3957       ZIPERR(r, tempzip);
3958     }
3959     if (fclose(y)) {
3960       ZIPERR(d ? ZE_WRITE : ZE_TEMP, tempzip);
3961     }
3962     if (in_file != NULL) {
3963       fclose(in_file);
3964       in_file = NULL;
3965     }
3966 
3967     /* Replace old zip file with new zip file, leaving only the new one */
3968     if (strcmp(zipfile, "-") && !d)
3969     {
3970       diag("replacing old zip file with new zip file");
3971       if ((r = replace(out_path, tempzip)) != ZE_OK)
3972       {
3973         zipwarn("new zip file left as: ", tempzip);
3974         free((zvoid *)tempzip);
3975         tempzip = NULL;
3976         ZIPERR(r, "was replacing the original zip file");
3977       }
3978       free((zvoid *)tempzip);
3979     }
3980     tempzip = NULL;
3981     if (zip_attributes && strcmp(zipfile, "-")) {
3982       setfileattr(out_path, zip_attributes);
3983 #ifdef VMS
3984       /* If the zip file existed previously, restore its record format: */
3985       if (x != NULL)
3986         (void)VMSmunch(out_path, RESTORE_RTYPE, NULL);
3987 #endif
3988     }
3989 
3990     set_filetype(out_path);
3991 
3992     /* finish logfile (it gets closed in freeup() called by finish()) */
3993     if (logfile) {
3994         struct tm *now;
3995         time_t clocktime;
3996 
3997         fprintf(logfile, "\nTotal %ld entries (", files_total);
3998         DisplayNumString(logfile, bytes_total);
3999         fprintf(logfile, " bytes)");
4000 
4001         /* get current time */
4002         time(&clocktime);
4003         now = localtime(&clocktime);
4004         fprintf(logfile, "\nDone %s", asctime(now));
4005         fflush(logfile);
4006     }
4007 
4008     RETURN(finish(ZE_OK));
4009   }
4010 
4011 
4012 
4013   /* read zipfile if exists */
4014   if ((r = readzipfile()) != ZE_OK) {
4015     ZIPERR(r, zipfile);
4016   }
4017 
4018 #ifndef UTIL
4019   if (split_method == -1) {
4020     split_method = 0;
4021   } else if (!fix && split_method == 0 && total_disks > 1) {
4022     /* if input archive is multi-disk and splitting has not been
4023        enabled or disabled (split_method == -1), then automatically
4024        set split size to same as first input split */
4025     zoff_t size = 0;
4026 
4027     in_split_path = get_in_split_path(in_path, 0);
4028 
4029     if (filetime(in_split_path, NULL, &size, NULL) == 0) {
4030       zipwarn("Could not get info for input split: ", in_split_path);
4031       return ZE_OPEN;
4032     }
4033     split_method = 1;
4034     split_size = (uzoff_t) size;
4035 
4036     free(in_split_path);
4037     in_split_path = NULL;
4038   }
4039 
4040   if (noisy_splits && split_size > 0)
4041     zipmessage("splitsize = ", zip_fuzofft(split_size, NULL, NULL));
4042 #endif
4043 
4044   /* so disk display starts at 1, will be updated when entries are read */
4045   current_in_disk = 0;
4046 
4047   /* no input zipfile and showing contents */
4048   if (!zipfile_exists && show_files && (kk == 3 || action == ARCHIVE)) {
4049     ZIPERR(ZE_OPEN, zipfile);
4050   }
4051 
4052   if (zcount == 0 && (action != ADD || d)) {
4053     zipwarn(zipfile, " not found or empty");
4054   }
4055 
4056   if (have_out && kk == 3) {
4057     /* no input paths so assume copy mode and match everything if --out */
4058     for (z = zfiles; z != NULL; z = z->nxt) {
4059       z->mark = pcount ? filter(z->zname, filter_match_case) : 1;
4060     }
4061   }
4062 
4063   /* Scan for new files */
4064 
4065   /* Process file arguments from command line */
4066   if (filelist) {
4067     if (action == ARCHIVE) {
4068       /* find in archive */
4069       if (show_what_doing) {
4070         fprintf(mesg, "sd: Scanning archive entries\n");
4071         fflush(mesg);
4072       }
4073       for (; filelist; ) {
4074         if ((r = proc_archive_name(filelist->name, filter_match_case)) != ZE_OK) {
4075           if (r == ZE_MISS) {
4076             char *n = NULL;
4077 #ifdef WIN32
4078             /* Win9x console always uses OEM character coding, and
4079                WinNT console is set to OEM charset by default, too */
4080             if ((n = malloc(strlen(filelist->name) + 1)) == NULL)
4081               ZIPERR(ZE_MEM, "name not matched error");
4082             INTERN_TO_OEM(filelist->name, n);
4083 #else
4084             n = filelist->name;
4085 #endif
4086             zipwarn("not in archive: ", n);
4087 #ifdef WIN32
4088             free(n);
4089 #endif
4090           }
4091           else {
4092             ZIPERR(r, filelist->name);
4093           }
4094         }
4095         free(filelist->name);
4096         filearg = filelist;
4097         filelist = filelist->next;
4098         free(filearg);
4099       }
4100     } else {
4101       /* try find matching files on OS first then try find entries in archive */
4102       if (show_what_doing) {
4103         fprintf(mesg, "sd: Scanning files\n");
4104         fflush(mesg);
4105       }
4106       for (; filelist; ) {
4107         if ((r = PROCNAME(filelist->name)) != ZE_OK) {
4108           if (r == ZE_MISS) {
4109             if (bad_open_is_error) {
4110               zipwarn("name not matched: ", filelist->name);
4111               ZIPERR(ZE_OPEN, filelist->name);
4112             } else {
4113               zipwarn("name not matched: ", filelist->name);
4114             }
4115           } else {
4116             ZIPERR(r, filelist->name);
4117           }
4118         }
4119         free(filelist->name);
4120         filearg = filelist;
4121         filelist = filelist->next;
4122         free(filearg);
4123       }
4124     }
4125   }
4126 
4127   /* recurse from current directory for -R */
4128   if (recurse == 2) {
4129 #ifdef AMIGA
4130     if ((r = PROCNAME("")) != ZE_OK)
4131 #else
4132     if ((r = PROCNAME(".")) != ZE_OK)
4133 #endif
4134     {
4135       if (r == ZE_MISS) {
4136         if (bad_open_is_error) {
4137           zipwarn("name not matched: ", "current directory for -R");
4138           ZIPERR(ZE_OPEN, "-R");
4139         } else {
4140           zipwarn("name not matched: ", "current directory for -R");
4141         }
4142       } else {
4143         ZIPERR(r, "-R");
4144       }
4145     }
4146   }
4147 
4148 
4149   if (show_what_doing) {
4150     fprintf(mesg, "sd: Applying filters\n");
4151     fflush(mesg);
4152   }
4153   /* Clean up selections ("3 <= kk <= 5" now) */
4154   if (kk != 4 && first_listarg == 0 &&
4155       (action == UPDATE || action == FRESHEN)) {
4156     /* if -u or -f with no args, do all, but, when present, apply filters */
4157     for (z = zfiles; z != NULL; z = z->nxt) {
4158       z->mark = pcount ? filter(z->zname, filter_match_case) : 1;
4159 #ifdef DOS
4160       if (z->mark) z->dosflag = 1;      /* force DOS attribs for incl. names */
4161 #endif
4162     }
4163   }
4164   if (show_what_doing) {
4165     fprintf(mesg, "sd: Checking dups\n");
4166     fflush(mesg);
4167   }
4168   if ((r = check_dup()) != ZE_OK) {     /* remove duplicates in found list */
4169     if (r == ZE_PARMS) {
4170       ZIPERR(r, "cannot repeat names in zip file");
4171     }
4172     else {
4173       ZIPERR(r, "was processing list of files");
4174     }
4175   }
4176 
4177   if (zcount)
4178     free((zvoid *)zsort);
4179 
4180 
4181 /*
4182  * XXX make some kind of mktemppath() function for each OS.
4183  */
4184 
4185 #ifndef VM_CMS
4186 /* For CMS, leave tempath NULL.  A-disk will be used as default. */
4187   /* If -b not specified, make temporary path the same as the zip file */
4188 #if defined(MSDOS) || defined(__human68k__) || defined(AMIGA)
4189   if (tempath == NULL && ((p = MBSRCHR(zipfile, '/')) != NULL ||
4190 #  ifdef MSDOS
4191                           (p = MBSRCHR(zipfile, '\\')) != NULL ||
4192 #  endif /* MSDOS */
4193                           (p = MBSRCHR(zipfile, ':')) != NULL))
4194   {
4195     if (*p == ':')
4196       p++;
4197 #else
4198 #ifdef RISCOS
4199   if (tempath == NULL && (p = MBSRCHR(zipfile, '.')) != NULL)
4200   {
4201 #else
4202 #ifdef QDOS
4203   if (tempath == NULL && (p = LastDir(zipfile)) != NULL)
4204   {
4205 #else
4206   if (tempath == NULL && (p = MBSRCHR(zipfile, '/')) != NULL)
4207   {
4208 #endif /* QDOS */
4209 #endif /* RISCOS */
4210 #endif /* MSDOS || __human68k__ || AMIGA */
4211     if ((tempath = (char *)malloc((int)(p - zipfile) + 1)) == NULL) {
4212       ZIPERR(ZE_MEM, "was processing arguments");
4213     }
4214     r = *p;  *p = 0;
4215     strcpy(tempath, zipfile);
4216     *p = (char)r;
4217   }
4218 #endif /* VM_CMS */
4219 
4220 #if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
4221   if (!zp_tz_is_valid) {
4222     zipwarn("TZ environment variable not found, cannot use UTC times!!","");
4223   }
4224 #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
4225 
4226   /* For each marked entry, if not deleting, check if it exists, and if
4227      updating or freshening, compare date with entry in old zip file.
4228      Unmark if it doesn't exist or is too old, else update marked count. */
4229   if (show_what_doing) {
4230     fprintf(mesg, "sd: Scanning files to update\n");
4231     fflush(mesg);
4232   }
4233 #ifdef MACOS
4234   PrintStatProgress("Getting file information ...");
4235 #endif
4236   diag("stating marked entries");
4237   k = 0;                        /* Initialize marked count */
4238   scan_started = 0;
4239   scan_count = 0;
4240   all_current = 1;
4241   for (z = zfiles; z != NULL; z = z->nxt) {
4242     /* if already displayed Scanning files in newname() then continue dots */
4243     if (noisy && scan_last) {
4244       scan_count++;
4245       if (scan_count % 100 == 0) {
4246         time_t current = time(NULL);
4247 
4248         if (current - scan_last > scan_dot_time) {
4249           if (scan_started == 0) {
4250             scan_started = 1;
4251             fprintf(mesg, " ");
4252             fflush(mesg);
4253           }
4254           scan_last = current;
4255           fprintf(mesg, ".");
4256           fflush(mesg);
4257         }
4258       }
4259     }
4260     z->current = 0;
4261     if (!(z->mark)) {
4262       /* if something excluded run through the list to catch deletions */
4263       all_current = 0;
4264     }
4265     if (z->mark) {
4266 #ifdef USE_EF_UT_TIME
4267       iztimes f_utim, z_utim;
4268       ulg z_tim;
4269 #endif /* USE_EF_UT_TIME */
4270       Trace((stderr, "zip diagnostics: marked file=%s\n", z->oname));
4271 
4272       csize = z->siz;
4273       usize = z->len;
4274       if (action == DELETE) {
4275         /* only delete files in date range */
4276 #ifdef USE_EF_UT_TIME
4277         z_tim = (get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
4278                 unix2dostime(&z_utim.mtime) : z->tim;
4279 #else /* !USE_EF_UT_TIME */
4280 #       define z_tim  z->tim
4281 #endif /* ?USE_EF_UT_TIME */
4282         if (z_tim < before || (after && z_tim >= after)) {
4283           /* include in archive */
4284           z->mark = 0;
4285         } else {
4286           /* delete file */
4287           files_total++;
4288           /* ignore len in old archive and update to current size */
4289           z->len = usize;
4290           if (csize != (uzoff_t) -1 && csize != (uzoff_t) -2)
4291             bytes_total += csize;
4292           k++;
4293         }
4294       } else if (action == ARCHIVE) {
4295         /* only keep files in date range */
4296 #ifdef USE_EF_UT_TIME
4297         z_tim = (get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
4298                 unix2dostime(&z_utim.mtime) : z->tim;
4299 #else /* !USE_EF_UT_TIME */
4300 #       define z_tim  z->tim
4301 #endif /* ?USE_EF_UT_TIME */
4302         if (z_tim < before || (after && z_tim >= after)) {
4303           /* exclude from archive */
4304           z->mark = 0;
4305         } else {
4306           /* keep file */
4307           files_total++;
4308           /* ignore len in old archive and update to current size */
4309           z->len = usize;
4310           if (csize != (uzoff_t) -1 && csize != (uzoff_t) -2)
4311             bytes_total += csize;
4312           k++;
4313         }
4314       } else {
4315         int isdirname = 0;
4316 
4317         if (z->name && (z->name)[strlen(z->name) - 1] == '/') {
4318           isdirname = 1;
4319         }
4320 
4321 # if defined(UNICODE_SUPPORT) && defined(WIN32)
4322         if (!no_win32_wide) {
4323           if (z->namew == NULL) {
4324             if (z->uname != NULL)
4325               z->namew = utf8_to_wchar_string(z->uname);
4326             else
4327               z->namew = local_to_wchar_string(z->name);
4328           }
4329         }
4330 # endif
4331 
4332 #ifdef USE_EF_UT_TIME
4333 # if defined(UNICODE_SUPPORT) && defined(WIN32)
4334         if (!no_win32_wide)
4335           tf = filetimew(z->namew, (ulg *)NULL, (zoff_t *)&usize, &f_utim);
4336         else
4337           tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, &f_utim);
4338 # else
4339         tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, &f_utim);
4340 # endif
4341 #else /* !USE_EF_UT_TIME */
4342 # if defined(UNICODE_SUPPORT) && defined(WIN32)
4343         if (!no_win32_wide)
4344           tf = filetimew(z->namew, (ulg *)NULL, (zoff_t *)&usize, NULL);
4345         else
4346           tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
4347 # else
4348         tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
4349 # endif
4350 #endif /* ?USE_EF_UT_TIME */
4351         if (tf == 0)
4352           /* entry that is not on OS */
4353           all_current = 0;
4354         if (tf == 0 ||
4355             tf < before || (after && tf >= after) ||
4356             ((action == UPDATE || action == FRESHEN) &&
4357 #ifdef USE_EF_UT_TIME
4358              ((get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
4359               f_utim.mtime <= ROUNDED_TIME(z_utim.mtime) : tf <= z->tim)
4360 #else /* !USE_EF_UT_TIME */
4361              tf <= z->tim
4362 #endif /* ?USE_EF_UT_TIME */
4363            ))
4364         {
4365           z->mark = comadd ? 2 : 0;
4366           z->trash = tf && tf >= before &&
4367                      (after ==0 || tf < after);   /* delete if -um or -fm */
4368           if (verbose)
4369             fprintf(mesg, "zip diagnostic: %s %s\n", z->oname,
4370                    z->trash ? "up to date" : "missing or early");
4371           if (logfile)
4372             fprintf(logfile, "zip diagnostic: %s %s\n", z->oname,
4373                    z->trash ? "up to date" : "missing or early");
4374         }
4375         else if (diff_mode && tf == z->tim &&
4376                  ((isdirname && (zoff_t)usize == -1) || (usize == z->len))) {
4377           /* if in diff mode only include if file time or size changed */
4378           /* usize is -1 for directories */
4379           z->mark = 0;
4380         }
4381         else {
4382           /* usize is -1 for directories and -2 for devices */
4383           if (tf == z->tim &&
4384               ((z->len == 0 && (zoff_t)usize == -1)
4385                || usize == z->len)) {
4386             /* FileSync uses the current flag */
4387             /* Consider an entry current if file time is the same
4388                and entry size is 0 and a directory on the OS
4389                or the entry size matches the OS size */
4390             z->current = 1;
4391           } else {
4392             all_current = 0;
4393           }
4394           files_total++;
4395           if (usize != (uzoff_t) -1 && usize != (uzoff_t) -2)
4396             /* ignore len in old archive and update to current size */
4397             z->len = usize;
4398           else
4399             z->len = 0;
4400           if (usize != (uzoff_t) -1 && usize != (uzoff_t) -2)
4401             bytes_total += usize;
4402           k++;
4403         }
4404       }
4405     }
4406   }
4407 
4408   /* Remove entries from found list that do not exist or are too old */
4409   if (show_what_doing) {
4410     fprintf(mesg, "sd: fcount = %u\n", (unsigned)fcount);
4411     fflush(mesg);
4412   }
4413 
4414   diag("stating new entries");
4415   scan_count = 0;
4416   scan_started = 0;
4417   Trace((stderr, "zip diagnostic: fcount=%u\n", (unsigned)fcount));
4418   for (f = found; f != NULL;) {
4419     Trace((stderr, "zip diagnostic: new file=%s\n", f->oname));
4420 
4421     if (noisy) {
4422       /* if updating archive and update was quick, scanning for new files
4423          can still take a long time */
4424       if (!zip_to_stdout && scan_last == 0 && scan_count % 100 == 0) {
4425         time_t current = time(NULL);
4426 
4427         if (current - scan_start > scan_delay) {
4428           fprintf(mesg, "Scanning files ");
4429           fflush(mesg);
4430           mesg_line_started = 1;
4431           scan_last = current;
4432         }
4433       }
4434       /* if already displayed Scanning files in newname() or above then continue dots */
4435       if (scan_last) {
4436         scan_count++;
4437         if (scan_count % 100 == 0) {
4438           time_t current = time(NULL);
4439 
4440           if (current - scan_last > scan_dot_time) {
4441             if (scan_started == 0) {
4442               scan_started = 1;
4443               fprintf(mesg, " ");
4444               fflush(mesg);
4445             }
4446             scan_last = current;
4447             fprintf(mesg, ".");
4448             fflush(mesg);
4449           }
4450         }
4451       }
4452     }
4453     tf = 0;
4454     if (action != DELETE && action != FRESHEN) {
4455 #if defined(UNICODE_SUPPORT) && defined(WIN32)
4456       if (!no_win32_wide)
4457         tf = filetimew(f->namew, (ulg *)NULL, (zoff_t *)&usize, NULL);
4458       else
4459         tf = filetime(f->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
4460 #else
4461       tf = filetime(f->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
4462 #endif
4463     }
4464 
4465     if (action == DELETE || action == FRESHEN ||
4466         tf == 0 ||
4467         tf < before || (after && tf >= after) ||
4468         (namecmp(f->zname, zipfile) == 0 && !zip_to_stdout)
4469        )
4470       f = fexpel(f);
4471     else {
4472       /* ??? */
4473       files_total++;
4474       f->usize = 0;
4475       if (usize != (uzoff_t) -1 && usize != (uzoff_t) -2) {
4476         bytes_total += usize;
4477         f->usize = usize;
4478       }
4479       f = f->nxt;
4480     }
4481   }
4482   if (mesg_line_started) {
4483     fprintf(mesg, "\n");
4484     mesg_line_started = 0;
4485   }
4486 #ifdef MACOS
4487   PrintStatProgress("done");
4488 #endif
4489 
4490   if (show_files) {
4491     uzoff_t count = 0;
4492     uzoff_t bytes = 0;
4493 
4494     if (noisy) {
4495       fflush(mesg);
4496     }
4497 
4498     if (noisy && (show_files == 1 || show_files == 3 || show_files == 5)) {
4499       /* sf, su, sU */
4500       if (mesg_line_started) {
4501         fprintf(mesg, "\n");
4502         mesg_line_started = 0;
4503       }
4504       if (kk == 3)
4505         /* -sf alone */
4506         fprintf(mesg, "Archive contains:\n");
4507       else if (action == DELETE)
4508         fprintf(mesg, "Would Delete:\n");
4509       else if (action == FRESHEN)
4510         fprintf(mesg, "Would Freshen:\n");
4511       else if (action == ARCHIVE)
4512         fprintf(mesg, "Would Copy:\n");
4513       else
4514         fprintf(mesg, "Would Add/Update:\n");
4515       fflush(mesg);
4516     }
4517 
4518     if (logfile) {
4519       if (logfile_line_started) {
4520         fprintf(logfile, "\n");
4521         logfile_line_started = 0;
4522       }
4523       if (kk == 3)
4524         /* -sf alone */
4525         fprintf(logfile, "Archive contains:\n");
4526       else if (action == DELETE)
4527         fprintf(logfile, "Would Delete:\n");
4528       else if (action == FRESHEN)
4529         fprintf(logfile, "Would Freshen:\n");
4530       else if (action == ARCHIVE)
4531         fprintf(logfile, "Would Copy:\n");
4532       else
4533         fprintf(logfile, "Would Add/Update:\n");
4534       fflush(logfile);
4535     }
4536 
4537     for (z = zfiles; z != NULL; z = z->nxt) {
4538       if (z->mark || kk == 3) {
4539         count++;
4540         if ((zoff_t)z->len > 0)
4541           bytes += z->len;
4542         if (noisy && (show_files == 1 || show_files == 3))
4543           /* sf, su */
4544           fprintf(mesg, "  %s\n", z->oname);
4545         if (logfile && !(show_files == 5 || show_files == 6))
4546           /* not sU or sU- show normal name in log */
4547           fprintf(logfile, "  %s\n", z->oname);
4548 
4549 #ifdef UNICODE_TEST
4550         if (create_files) {
4551           int r;
4552           int dir = 0;
4553           FILE *f;
4554 
4555 #if defined(UNICODE_SUPPORT) && defined(WIN32)
4556           char *fn = NULL;
4557           wchar_t *fnw = NULL;
4558 
4559           if (!no_win32_wide) {
4560             if ((fnw = malloc((wcslen(z->znamew) + 120) * sizeof(wchar_t))) == NULL)
4561               ZIPERR(ZE_MEM, "sC");
4562             wcscpy(fnw, L"testdir/");
4563             wcscat(fnw, z->znamew);
4564             if (fnw[wcslen(fnw) - 1] == '/')
4565               dir = 1;
4566             if (dir)
4567               r = _wmkdir(fnw);
4568             else
4569               f = _wfopen(fnw, L"w");
4570           } else {
4571             if ((fn = malloc(strlen(z->zname) + 120)) == NULL)
4572               ZIPERR(ZE_MEM, "sC");
4573             strcpy(fn, "testdir/");
4574             strcat(fn, z->zname);
4575             if (fn[strlen(fn) - 1] == '/')
4576               dir = 1;
4577             if (dir)
4578               r = mkdir(fn);
4579             else
4580               f = fopen(fn, "w");
4581           }
4582 #else
4583           char *fn = NULL;
4584           if ((fn = malloc(strlen(z->zname) + 120)) == NULL)
4585             ZIPERR(ZE_MEM, "sC");
4586           strcpy(fn, "testdir/");
4587           if (z->uname)
4588             strcat(fn, z->uname);
4589           else
4590             strcat(fn, z->zname);
4591 
4592           if (fn[strlen(fn) - 1] == '/')
4593             dir = 1;
4594           if (dir)
4595             r = mkdir(fn, 0777);
4596           else
4597             f = fopen(fn, "w");
4598 #endif
4599           if (dir) {
4600             if (r) {
4601               if (errno != 17) {
4602                 printf(" - could not create directory testdir/%s\n", z->oname);
4603                 perror("    dir");
4604               }
4605             } else {
4606               printf(" - created directory testdir/%s\n", z->oname);
4607             }
4608           } else {
4609             if (f == NULL) {
4610               printf(" - could not open testdir/%s\n", z->oname);
4611               perror("    file");
4612             } else {
4613               fclose(f);
4614               printf(" - created testdir/%s\n", z->oname);
4615               if (z->uname)
4616                 printf("   u - created testdir/%s\n", z->uname);
4617             }
4618           }
4619         }
4620 #endif
4621 #ifdef UNICODE_SUPPORT
4622         if (show_files == 3 || show_files == 4) {
4623           /* su, su- */
4624           /* Include escaped Unicode name if exists under standard name */
4625           if (z->ouname) {
4626             if (noisy && show_files == 3)
4627               fprintf(mesg, "     Escaped Unicode:  %s\n", z->ouname);
4628             if (logfile)
4629               fprintf(logfile, "     Escaped Unicode:  %s\n", z->ouname);
4630           }
4631         }
4632         if (show_files == 5 || show_files == 6) {
4633           /* sU, sU- */
4634           /* Display only escaped Unicode name if exists or standard name */
4635           if (z->ouname) {
4636             /* Unicode name */
4637             if (noisy && show_files == 5) {
4638               fprintf(mesg, "  %s\n", z->ouname);
4639             }
4640             if (logfile) {
4641               fprintf(logfile, "  %s\n", z->ouname);
4642             }
4643           } else {
4644             /* No Unicode name so use standard name */
4645             if (noisy && show_files == 5) {
4646               fprintf(mesg, "  %s\n", z->oname);
4647             }
4648             if (logfile) {
4649               fprintf(logfile, "  %s\n", z->oname);
4650             }
4651           }
4652         }
4653 #endif
4654       }
4655     }
4656     for (f = found; f != NULL; f = f->nxt) {
4657       count++;
4658       if ((zoff_t)f->usize > 0)
4659         bytes += f->usize;
4660 #ifdef UNICODE_SUPPORT
4661       if (unicode_escape_all) {
4662         char *escaped_unicode;
4663         escaped_unicode = local_to_escape_string(f->zname);
4664         if (noisy && (show_files == 1 || show_files == 3 || show_files == 5))
4665           /* sf, su, sU */
4666           fprintf(mesg, "  %s\n", escaped_unicode);
4667         if (logfile)
4668           fprintf(logfile, "  %s\n", escaped_unicode);
4669         free(escaped_unicode);
4670       } else {
4671 #endif
4672         if (noisy && (show_files == 1 || show_files == 3 || show_files == 5))
4673           /* sf, su, sU */
4674           fprintf(mesg, "  %s\n", f->oname);
4675         if (logfile)
4676           fprintf(logfile, "  %s\n", f->oname);
4677 #ifdef UNICODE_SUPPORT
4678       }
4679 #endif
4680     }
4681     if (noisy || logfile == NULL)
4682       fprintf(mesg, "Total %s entries (%s bytes)\n",
4683                                           zip_fuzofft(count, NULL, NULL),
4684                                           zip_fuzofft(bytes, NULL, NULL));
4685     if (logfile)
4686       fprintf(logfile, "Total %s entries (%s bytes)\n",
4687                                           zip_fuzofft(count, NULL, NULL),
4688                                           zip_fuzofft(bytes, NULL, NULL));
4689     RETURN(finish(ZE_OK));
4690   }
4691 
4692   /* Make sure there's something left to do */
4693   if (k == 0 && found == NULL && !diff_mode &&
4694       !(zfiles == NULL && allow_empty_archive) &&
4695       !(zfiles != NULL &&
4696         (latest || fix || adjust || junk_sfx || comadd || zipedit))) {
4697     if (test && (zfiles != NULL || zipbeg != 0)) {
4698 #ifndef WINDLL
4699       check_zipfile(zipfile, argv[0]);
4700 #endif
4701       RETURN(finish(ZE_OK));
4702     }
4703     if (action == UPDATE || action == FRESHEN) {
4704       RETURN(finish(ZE_NONE));
4705     }
4706     else if (zfiles == NULL && (latest || fix || adjust || junk_sfx)) {
4707       ZIPERR(ZE_NAME, zipfile);
4708     }
4709 #ifndef WINDLL
4710     else if (recurse && (pcount == 0) && (first_listarg > 0)) {
4711 #ifdef VMS
4712       strcpy(errbuf, "try: zip \"");
4713       for (i = 1; i < (first_listarg - 1); i++)
4714         strcat(strcat(errbuf, args[i]), "\" ");
4715       strcat(strcat(errbuf, args[i]), " *.* -i");
4716 #else /* !VMS */
4717       strcpy(errbuf, "try: zip");
4718       for (i = 1; i < first_listarg; i++)
4719         strcat(strcat(errbuf, " "), args[i]);
4720 #  ifdef AMIGA
4721       strcat(errbuf, " \"\" -i");
4722 #  else
4723       strcat(errbuf, " . -i");
4724 #  endif
4725 #endif /* ?VMS */
4726       for (i = first_listarg; i < argc; i++)
4727         strcat(strcat(errbuf, " "), args[i]);
4728       ZIPERR(ZE_NONE, errbuf);
4729     }
4730     else {
4731       ZIPERR(ZE_NONE, zipfile);
4732     }
4733 #endif /* !WINDLL */
4734   }
4735 
4736   if (filesync && all_current && fcount == 0) {
4737     zipmessage("Archive is current", "");
4738     RETURN(finish(ZE_OK));
4739   }
4740 
4741   d = (d && k == 0 && (zipbeg || zfiles != NULL)); /* d true if appending */
4742 
4743 #if CRYPT
4744   /* Initialize the crc_32_tab pointer, when encryption was requested. */
4745   if (key != NULL) {
4746     crc_32_tab = get_crc_table();
4747 #ifdef EBCDIC
4748     /* convert encryption key to ASCII (ISO variant for 8-bit ASCII chars) */
4749     strtoasc(key, key);
4750 #endif /* EBCDIC */
4751   }
4752 #endif /* CRYPT */
4753 
4754   /* Just ignore the spanning signature if a multi-disk archive */
4755   if (zfiles && total_disks != 1 && zipbeg == 4) {
4756     zipbeg = 0;
4757   }
4758 
4759   /* Before we get carried away, make sure zip file is writeable. This
4760    * has the undesired side effect of leaving one empty junk file on a WORM,
4761    * so when the zipfile does not exist already and when -b is specified,
4762    * the writability check is made in replace().
4763    */
4764   if (strcmp(zipfile, "-"))
4765   {
4766     if (tempdir && zfiles == NULL && zipbeg == 0) {
4767       zip_attributes = 0;
4768     } else {
4769       x = (have_out || (zfiles == NULL && zipbeg == 0)) ? zfopen(out_path, FOPW) :
4770                                                           zfopen(out_path, FOPM);
4771       /* Note: FOPW and FOPM expand to several parameters for VMS */
4772       if (x == NULL) {
4773         ZIPERR(ZE_CREAT, out_path);
4774       }
4775       fclose(x);
4776       zip_attributes = getfileattr(out_path);
4777       if (zfiles == NULL && zipbeg == 0)
4778         destroy(out_path);
4779     }
4780   }
4781   else
4782     zip_attributes = 0;
4783 
4784   /* Throw away the garbage in front of the zip file for -J */
4785   if (junk_sfx) zipbeg = 0;
4786 
4787   /* Open zip file and temporary output file */
4788   if (show_what_doing) {
4789     fprintf(mesg, "sd: Open zip file and create temp file\n");
4790     fflush(mesg);
4791   }
4792   diag("opening zip file and creating temporary zip file");
4793   x = NULL;
4794   tempzn = 0;
4795   if (strcmp(zipfile, "-") == 0)
4796   {
4797 #ifdef MSDOS
4798     /* It is nonsense to emit the binary data stream of a zipfile to
4799      * the (text mode) console.  This case should already have been caught
4800      * in a call to zipstdout() far above.  Therefore, if the following
4801      * failsafe check detects a console attached to stdout, zip is stopped
4802      * with an "internal logic error"!  */
4803     if (isatty(fileno(stdout)))
4804       ZIPERR(ZE_LOGIC, "tried to write binary zipfile data to console!");
4805     /* Set stdout mode to binary for MSDOS systems */
4806 #  ifdef __HIGHC__
4807     setmode(stdout, _BINARY);
4808 #  else
4809     setmode(fileno(stdout), O_BINARY);
4810 #  endif
4811     y = zfdopen(fileno(stdout), FOPW);
4812 #else
4813     y = stdout;
4814 #endif
4815     /* tempzip must be malloced so a later free won't barf */
4816     tempzip = malloc(4);
4817     if (tempzip == NULL) {
4818       ZIPERR(ZE_MEM, "allocating temp filename");
4819     }
4820     strcpy(tempzip, "-");
4821   }
4822   else if (d) /* d true if just appending (-g) */
4823   {
4824     if (total_disks > 1) {
4825       ZIPERR(ZE_PARMS, "cannot grow split archive");
4826     }
4827     if ((y = zfopen(zipfile, FOPM)) == NULL) {
4828       ZIPERR(ZE_NAME, zipfile);
4829     }
4830     tempzip = zipfile;
4831     /*
4832     tempzf = y;
4833     */
4834 
4835     if (zfseeko(y, cenbeg, SEEK_SET)) {
4836       ZIPERR(ferror(y) ? ZE_READ : ZE_EOF, zipfile);
4837     }
4838     bytes_this_split = cenbeg;
4839     tempzn = cenbeg;
4840   }
4841   else
4842   {
4843     if (show_what_doing) {
4844       fprintf(mesg, "sd: Creating new zip file\n");
4845       fflush(mesg);
4846     }
4847     /* See if there is something at beginning of disk 1 to copy.
4848        If not, do nothing as zipcopy() will open files to read
4849        as needed. */
4850     if (zipbeg) {
4851       in_split_path = get_in_split_path(in_path, 0);
4852 
4853       while ((in_file = zfopen(in_split_path, FOPR_EX)) == NULL) {
4854         /* could not open split */
4855 
4856         /* Ask for directory with split.  Updates in_path */
4857         if (ask_for_split_read_path(0) != ZE_OK) {
4858           ZIPERR(ZE_ABORT, "could not open archive to read");
4859         }
4860         free(in_split_path);
4861         in_split_path = get_in_split_path(in_path, 1);
4862       }
4863     }
4864 #if defined(UNIX) && !defined(NO_MKSTEMP)
4865     {
4866       int yd;
4867       int i;
4868 
4869       /* use mkstemp to avoid race condition and compiler warning */
4870 
4871       if (tempath != NULL)
4872       {
4873         /* if -b used to set temp file dir use that for split temp */
4874         if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
4875           ZIPERR(ZE_MEM, "allocating temp filename");
4876         }
4877         strcpy(tempzip, tempath);
4878         if (lastchar(tempzip) != '/')
4879           strcat(tempzip, "/");
4880       }
4881       else
4882       {
4883         /* create path by stripping name and appending template */
4884         if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
4885         ZIPERR(ZE_MEM, "allocating temp filename");
4886         }
4887         strcpy(tempzip, zipfile);
4888         for(i = strlen(tempzip); i > 0; i--) {
4889           if (tempzip[i - 1] == '/')
4890             break;
4891         }
4892         tempzip[i] = '\0';
4893       }
4894       strcat(tempzip, "ziXXXXXX");
4895 
4896       if ((yd = mkstemp(tempzip)) == EOF) {
4897         ZIPERR(ZE_TEMP, tempzip);
4898       }
4899       if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
4900         ZIPERR(ZE_TEMP, tempzip);
4901       }
4902     }
4903 #else
4904     if ((tempzip = tempname(zipfile)) == NULL) {
4905       ZIPERR(ZE_MEM, "allocating temp filename");
4906     }
4907     if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
4908       ZIPERR(ZE_TEMP, tempzip);
4909     }
4910 #endif
4911   }
4912 
4913 #if (!defined(VMS) && !defined(CMS_MVS))
4914   /* Use large buffer to speed up stdio: */
4915 #if (defined(_IOFBF) || !defined(BUFSIZ))
4916   zipbuf = (char *)malloc(ZBSZ);
4917 #else
4918   zipbuf = (char *)malloc(BUFSIZ);
4919 #endif
4920   if (zipbuf == NULL) {
4921     ZIPERR(ZE_MEM, tempzip);
4922   }
4923 # ifdef _IOFBF
4924   setvbuf(y, zipbuf, _IOFBF, ZBSZ);
4925 # else
4926   setbuf(y, zipbuf);
4927 # endif /* _IOBUF */
4928 #endif /* !VMS  && !CMS_MVS */
4929 
4930   /* If not seekable set some flags 3/14/05 EG */
4931   output_seekable = 1;
4932   if (!is_seekable(y)) {
4933     output_seekable = 0;
4934     use_descriptors = 1;
4935   }
4936 
4937   /* Not needed.  Only need Zip64 when input file is larger than 2 GB or reading
4938      stdin and writing stdout.  This is set in putlocal() for each file. */
4939 #if 0
4940   /* If using descriptors and Zip64 enabled force Zip64 3/13/05 EG */
4941 # ifdef ZIP64_SUPPORT
4942   if (use_descriptors && force_zip64 != 0) {
4943     force_zip64 = 1;
4944   }
4945 # endif
4946 #endif
4947 
4948   /* if archive exists, not streaming and not deleting or growing, copy
4949      any bytes at beginning */
4950   if (strcmp(zipfile, "-") != 0 && !d)  /* this must go *after* set[v]buf */
4951   {
4952     /* copy anything before archive */
4953     if (in_file && zipbeg && (r = bfcopy(zipbeg)) != ZE_OK) {
4954       ZIPERR(r, r == ZE_TEMP ? tempzip : zipfile);
4955     }
4956     if (in_file) {
4957       fclose(in_file);
4958       in_file = NULL;
4959       free(in_split_path);
4960     }
4961     tempzn = zipbeg;
4962     if (split_method) {
4963       /* add spanning signature */
4964       if (show_what_doing) {
4965         fprintf(mesg, "sd: Adding spanning/splitting signature at top of archive\n");
4966         fflush(mesg);
4967       }
4968       /* write the spanning signature at the top of the archive */
4969       errbuf[0] = 0x50 /*'P' except for EBCDIC*/;
4970       errbuf[1] = 0x4b /*'K' except for EBCDIC*/;
4971       errbuf[2] = 7;
4972       errbuf[3] = 8;
4973       bfwrite(errbuf, 1, 4, BFWRITE_DATA);
4974       /* tempzn updated below */
4975       tempzn += 4;
4976     }
4977   }
4978 
4979   o = 0;                                /* no ZE_OPEN errors yet */
4980 
4981 
4982   /* Process zip file, updating marked files */
4983 #ifdef DEBUG
4984   if (zfiles != NULL)
4985     diag("going through old zip file");
4986 #endif
4987   if (zfiles != NULL && show_what_doing) {
4988     fprintf(mesg, "sd: Going through old zip file\n");
4989     fflush(mesg);
4990   }
4991   w = &zfiles;
4992   while ((z = *w) != NULL) {
4993     if (z->mark == 1)
4994     {
4995       uzoff_t len;
4996       if ((zoff_t)z->len == -1)
4997         /* device */
4998         len = 0;
4999       else
5000         len = z->len;
5001 
5002       /* if not deleting, zip it up */
5003       if (action != ARCHIVE && action != DELETE)
5004       {
5005         struct zlist far *localz; /* local header */
5006 
5007         if (verbose || !(filesync && z->current))
5008           DisplayRunningStats();
5009         if (noisy)
5010         {
5011           if (action == FRESHEN) {
5012             fprintf(mesg, "freshening: %s", z->oname);
5013             mesg_line_started = 1;
5014             fflush(mesg);
5015           } else if (filesync && z->current) {
5016             if (verbose) {
5017               fprintf(mesg, "      ok: %s", z->oname);
5018               mesg_line_started = 1;
5019               fflush(mesg);
5020             }
5021           } else if (!(filesync && z->current)) {
5022             fprintf(mesg, "updating: %s", z->oname);
5023             mesg_line_started = 1;
5024             fflush(mesg);
5025           }
5026         }
5027         if (logall)
5028         {
5029           if (action == FRESHEN) {
5030             fprintf(logfile, "freshening: %s", z->oname);
5031             logfile_line_started = 1;
5032             fflush(logfile);
5033           } else if (filesync && z->current) {
5034             if (verbose) {
5035               fprintf(logfile, " current: %s", z->oname);
5036               logfile_line_started = 1;
5037               fflush(logfile);
5038             }
5039           } else {
5040             fprintf(logfile, "updating: %s", z->oname);
5041             logfile_line_started = 1;
5042             fflush(logfile);
5043           }
5044         }
5045 
5046         /* Get local header flags and extra fields */
5047         if (readlocal(&localz, z) != ZE_OK) {
5048           zipwarn("could not read local entry information: ", z->oname);
5049           z->lflg = z->flg;
5050           z->ext = 0;
5051         } else {
5052           z->lflg = localz->lflg;
5053           z->ext = localz->ext;
5054           z->extra = localz->extra;
5055           if (localz->nam) free(localz->iname);
5056           if (localz->nam) free(localz->name);
5057 #ifdef UNICODE_SUPPORT
5058           if (localz->uname) free(localz->uname);
5059 #endif
5060           free(localz);
5061         }
5062 
5063         if (!(filesync && z->current) &&
5064              (r = zipup(z)) != ZE_OK && r != ZE_OPEN && r != ZE_MISS)
5065         {
5066           zipmessage_nl("", 1);
5067           /*
5068           if (noisy)
5069           {
5070             if (mesg_line_started) {
5071 #if (!defined(MACOS) && !defined(WINDLL))
5072               putc('\n', mesg);
5073               fflush(mesg);
5074 #else
5075               fprintf(stdout, "\n");
5076               fflush(stdout);
5077 #endif
5078               mesg_line_started = 0;
5079             }
5080           }
5081           if (logall) {
5082             if (logfile_line_started) {
5083               fprintf(logfile, "\n");
5084               logfile_line_started = 0;
5085               fflush(logfile);
5086             }
5087           }
5088           */
5089           sprintf(errbuf, "was zipping %s", z->name);
5090           ZIPERR(r, errbuf);
5091         }
5092         if (filesync && z->current)
5093         {
5094           /* if filesync if entry matches OS just copy */
5095           if ((r = zipcopy(z)) != ZE_OK)
5096           {
5097             sprintf(errbuf, "was copying %s", z->oname);
5098             ZIPERR(r, errbuf);
5099           }
5100           zipmessage_nl("", 1);
5101           /*
5102           if (noisy)
5103           {
5104             if (mesg_line_started) {
5105 #if (!defined(MACOS) && !defined(WINDLL))
5106               putc('\n', mesg);
5107               fflush(mesg);
5108 #else
5109               fprintf(stdout, "\n");
5110               fflush(stdout);
5111 #endif
5112               mesg_line_started = 0;
5113             }
5114           }
5115           if (logall) {
5116             if (logfile_line_started) {
5117               fprintf(logfile, "\n");
5118               logfile_line_started = 0;
5119               fflush(logfile);
5120             }
5121           }
5122           */
5123         }
5124         if (r == ZE_OPEN || r == ZE_MISS)
5125         {
5126           o = 1;
5127           zipmessage_nl("", 1);
5128           /*
5129           if (noisy)
5130           {
5131 #if (!defined(MACOS) && !defined(WINDLL))
5132             putc('\n', mesg);
5133             fflush(mesg);
5134 #else
5135             fprintf(stdout, "\n");
5136 #endif
5137             mesg_line_started = 0;
5138           }
5139           if (logall) {
5140             fprintf(logfile, "\n");
5141             logfile_line_started = 0;
5142             fflush(logfile);
5143           }
5144           */
5145           if (r == ZE_OPEN) {
5146             perror(z->oname);
5147             zipwarn("could not open for reading: ", z->oname);
5148             if (bad_open_is_error) {
5149               sprintf(errbuf, "was zipping %s", z->name);
5150               ZIPERR(r, errbuf);
5151             }
5152           } else {
5153             zipwarn("file and directory with the same name: ", z->oname);
5154           }
5155           zipwarn("will just copy entry over: ", z->oname);
5156           if ((r = zipcopy(z)) != ZE_OK)
5157           {
5158             sprintf(errbuf, "was copying %s", z->oname);
5159             ZIPERR(r, errbuf);
5160           }
5161           z->mark = 0;
5162         }
5163         files_so_far++;
5164         good_bytes_so_far += z->len;
5165         bytes_so_far += len;
5166         w = &z->nxt;
5167       }
5168       else if (action == ARCHIVE)
5169       {
5170 #ifdef DEBUG
5171         zoff_t here = zftello(y);
5172 #endif
5173 
5174         DisplayRunningStats();
5175         if (skip_this_disk - 1 != z->dsk)
5176           /* moved to another disk so start copying again */
5177           skip_this_disk = 0;
5178         if (skip_this_disk - 1 == z->dsk) {
5179           /* skipping this disk */
5180           if (noisy) {
5181             fprintf(mesg, " skipping: %s", z->oname);
5182             mesg_line_started = 1;
5183             fflush(mesg);
5184           }
5185           if (logall) {
5186             fprintf(logfile, " skipping: %s", z->oname);
5187             logfile_line_started = 1;
5188             fflush(logfile);
5189           }
5190         } else {
5191           /* copying this entry */
5192           if (noisy) {
5193             fprintf(mesg, " copying: %s", z->oname);
5194             if (display_usize) {
5195               fprintf(mesg, " (");
5196               DisplayNumString(mesg, z->len );
5197               fprintf(mesg, ")");
5198             }
5199             mesg_line_started = 1;
5200             fflush(mesg);
5201           }
5202           if (logall)
5203           {
5204             fprintf(logfile, " copying: %s", z->oname);
5205             if (display_usize) {
5206               fprintf(logfile, " (");
5207               DisplayNumString(logfile, z->len );
5208               fprintf(logfile, ")");
5209             }
5210             logfile_line_started = 1;
5211             fflush(logfile);
5212           }
5213         }
5214 
5215         if (skip_this_disk - 1 == z->dsk)
5216           /* skip entries on this disk */
5217           z->mark = 0;
5218         else if ((r = zipcopy(z)) != ZE_OK)
5219         {
5220           if (r == ZE_ABORT) {
5221             ZIPERR(r, "user requested abort");
5222           } else if (fix != 1) {
5223             /* exit */
5224             sprintf(errbuf, "was copying %s", z->oname);
5225             zipwarn("(try -F to attempt to fix)", "");
5226             ZIPERR(r, errbuf);
5227           }
5228           else /* if (r == ZE_FORM) */ {
5229 #ifdef DEBUG
5230             zoff_t here = zftello(y);
5231 #endif
5232 
5233             /* seek back in output to start of this entry so can overwrite */
5234             if (zfseeko(y, current_local_offset, SEEK_SET) != 0){
5235               ZIPERR(r, "could not seek in output file");
5236             }
5237             zipwarn("bad - skipping: ", z->oname);
5238 #ifdef DEBUG
5239             here = zftello(y);
5240 #endif
5241             tempzn = current_local_offset;
5242             bytes_this_split = current_local_offset;
5243           }
5244         }
5245         if (skip_this_disk || !(fix == 1 && r != ZE_OK))
5246         {
5247           if (noisy && mesg_line_started) {
5248             fprintf(mesg, "\n");
5249             mesg_line_started = 0;
5250             fflush(mesg);
5251           }
5252           if (logall && logfile_line_started) {
5253             fprintf(logfile, "\n");
5254             logfile_line_started = 0;
5255             fflush(logfile);
5256           }
5257         }
5258         /* input counts */
5259         files_so_far++;
5260         if (r != ZE_OK)
5261           bad_bytes_so_far += z->siz;
5262         else
5263           good_bytes_so_far += z->siz;
5264         bytes_so_far += z->siz;
5265 
5266         if (r != ZE_OK && fix == 1) {
5267           /* remove bad entry from list */
5268           v = z->nxt;                     /* delete entry from list */
5269           free((zvoid *)(z->iname));
5270           free((zvoid *)(z->zname));
5271           free(z->oname);
5272 #ifdef UNICODE_SUPPORT
5273           if (z->uname) free(z->uname);
5274 #endif /* def UNICODE_SUPPORT */
5275           if (z->ext)
5276             /* don't have local extra until zipcopy reads it */
5277             if (z->extra) free((zvoid *)(z->extra));
5278           if (z->cext && z->cextra != z->extra)
5279             free((zvoid *)(z->cextra));
5280           if (z->com)
5281             free((zvoid *)(z->comment));
5282           farfree((zvoid far *)z);
5283           *w = v;
5284           zcount--;
5285         } else {
5286           w = &z->nxt;
5287         }
5288 
5289 #ifdef WINDLL
5290 #ifdef ZIP64_SUPPORT
5291         /* int64 support in caller */
5292         if (lpZipUserFunctions->ServiceApplication64 != NULL)
5293         {
5294           if ((*lpZipUserFunctions->ServiceApplication64)(z->zname, z->siz))
5295                     ZIPERR(ZE_ABORT, "User terminated operation");
5296         }
5297         else
5298         {
5299           /* no int64 support in caller */
5300           filesize64 = z->siz;
5301           low = (unsigned long)(filesize64 & 0x00000000FFFFFFFF);
5302           high = (unsigned long)((filesize64 >> 32) & 0x00000000FFFFFFFF);
5303           if (lpZipUserFunctions->ServiceApplication64_No_Int64 != NULL) {
5304             if ((*lpZipUserFunctions->ServiceApplication64_No_Int64)(z->zname, low, high))
5305                       ZIPERR(ZE_ABORT, "User terminated operation");
5306           }
5307         }
5308 #else
5309         if (lpZipUserFunctions->ServiceApplication != NULL) {
5310           if ((*lpZipUserFunctions->ServiceApplication)(z->zname, z->siz))
5311             ZIPERR(ZE_ABORT, "User terminated operation");
5312         }
5313 #endif /* ZIP64_SUPPORT - I added comments around // comments - does that help below? EG */
5314 /* strange but true: if I delete this and put these two endifs adjacent to
5315    each other, the Aztec Amiga compiler never sees the second endif!  WTF?? PK */
5316 #endif /* WINDLL */
5317       }
5318       else
5319       {
5320         DisplayRunningStats();
5321         if (noisy)
5322         {
5323           fprintf(mesg, "deleting: %s", z->oname);
5324           if (display_usize) {
5325             fprintf(mesg, " (");
5326             DisplayNumString(mesg, z->len );
5327             fprintf(mesg, ")");
5328           }
5329           fflush(mesg);
5330           fprintf(mesg, "\n");
5331         }
5332         if (logall)
5333         {
5334           fprintf(logfile, "deleting: %s", z->oname);
5335           if (display_usize) {
5336             fprintf(logfile, " (");
5337             DisplayNumString(logfile, z->len );
5338             fprintf(logfile, ")");
5339           }
5340           fprintf(logfile, "\n");
5341           fflush(logfile);
5342         }
5343         files_so_far++;
5344         good_bytes_so_far += z->siz;
5345         bytes_so_far += z->siz;
5346 #ifdef WINDLL
5347 #ifdef ZIP64_SUPPORT
5348         /* int64 support in caller */
5349         if (lpZipUserFunctions->ServiceApplication64 != NULL)
5350         {
5351           if ((*lpZipUserFunctions->ServiceApplication64)(z->zname, z->siz))
5352                     ZIPERR(ZE_ABORT, "User terminated operation");
5353         }
5354         else
5355         {
5356           /* no int64 support in caller */
5357           filesize64 = z->siz;
5358           low = (unsigned long)(filesize64 & 0x00000000FFFFFFFF);
5359           high = (unsigned long)((filesize64 >> 32) & 0x00000000FFFFFFFF);
5360           if (lpZipUserFunctions->ServiceApplication64_No_Int64 != NULL) {
5361             if ((*lpZipUserFunctions->ServiceApplication64_No_Int64)(z->zname, low, high))
5362                       ZIPERR(ZE_ABORT, "User terminated operation");
5363           }
5364         }
5365 #else
5366         if (lpZipUserFunctions->ServiceApplication != NULL) {
5367           if ((*lpZipUserFunctions->ServiceApplication)(z->zname, z->siz))
5368             ZIPERR(ZE_ABORT, "User terminated operation");
5369         }
5370 #endif /* ZIP64_SUPPORT - I added comments around // comments - does that help below? EG */
5371 /* strange but true: if I delete this and put these two endifs adjacent to
5372    each other, the Aztec Amiga compiler never sees the second endif!  WTF?? PK */
5373 #endif /* WINDLL */
5374 
5375         v = z->nxt;                     /* delete entry from list */
5376         free((zvoid *)(z->iname));
5377         free((zvoid *)(z->zname));
5378         free(z->oname);
5379 #ifdef UNICODE_SUPPORT
5380         if (z->uname) free(z->uname);
5381 #endif /* def UNICODE_SUPPORT */
5382         if (z->ext)
5383           /* don't have local extra until zipcopy reads it */
5384           if (z->extra) free((zvoid *)(z->extra));
5385         if (z->cext && z->cextra != z->extra)
5386           free((zvoid *)(z->cextra));
5387         if (z->com)
5388           free((zvoid *)(z->comment));
5389         farfree((zvoid far *)z);
5390         *w = v;
5391         zcount--;
5392       }
5393     }
5394     else
5395     {
5396       if (action == ARCHIVE) {
5397         v = z->nxt;                     /* delete entry from list */
5398         free((zvoid *)(z->iname));
5399         free((zvoid *)(z->zname));
5400         free(z->oname);
5401 #ifdef UNICODE_SUPPORT
5402         if (z->uname) free(z->uname);
5403 #endif /* def UNICODE_SUPPORT */
5404         if (z->ext)
5405           /* don't have local extra until zipcopy reads it */
5406           if (z->extra) free((zvoid *)(z->extra));
5407         if (z->cext && z->cextra != z->extra)
5408           free((zvoid *)(z->cextra));
5409         if (z->com)
5410           free((zvoid *)(z->comment));
5411         farfree((zvoid far *)z);
5412         *w = v;
5413         zcount--;
5414       }
5415       else
5416       {
5417         if (filesync) {
5418           /* Delete entries if don't match a file on OS */
5419           BlankRunningStats();
5420           if (noisy)
5421           {
5422             fprintf(mesg, "deleting: %s", z->oname);
5423             if (display_usize) {
5424               fprintf(mesg, " (");
5425               DisplayNumString(mesg, z->len );
5426               fprintf(mesg, ")");
5427             }
5428             fflush(mesg);
5429             fprintf(mesg, "\n");
5430             mesg_line_started = 0;
5431           }
5432           if (logall)
5433           {
5434             fprintf(logfile, "deleting: %s", z->oname);
5435             if (display_usize) {
5436               fprintf(logfile, " (");
5437               DisplayNumString(logfile, z->len );
5438               fprintf(logfile, ")");
5439             }
5440             fprintf(logfile, "\n");
5441             fflush(logfile);
5442             logfile_line_started = 0;
5443           }
5444         }
5445         /* copy the original entry */
5446         else if (!d && !diff_mode && (r = zipcopy(z)) != ZE_OK)
5447         {
5448           sprintf(errbuf, "was copying %s", z->oname);
5449           ZIPERR(r, errbuf);
5450         }
5451         w = &z->nxt;
5452       }
5453     }
5454   }
5455 
5456 
5457   /* Process the edited found list, adding them to the zip file */
5458   if (show_what_doing) {
5459     fprintf(mesg, "sd: Zipping up new entries\n");
5460     fflush(mesg);
5461   }
5462   diag("zipping up new entries, if any");
5463   Trace((stderr, "zip diagnostic: fcount=%u\n", (unsigned)fcount));
5464   for (f = found; f != NULL; f = fexpel(f))
5465   {
5466     uzoff_t len;
5467     /* add a new zfiles entry and set the name */
5468     if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
5469       ZIPERR(ZE_MEM, "was adding files to zip file");
5470     }
5471     z->nxt = NULL;
5472     z->name = f->name;
5473     f->name = NULL;
5474 #ifdef UNICODE_SUPPORT
5475     z->uname = NULL;          /* UTF-8 name for extra field */
5476     z->zuname = NULL;         /* externalized UTF-8 name for matching */
5477     z->ouname = NULL;         /* display version of UTF-8 name with OEM */
5478 
5479 #if 0
5480     /* New AppNote bit 11 allowing storing UTF-8 in path */
5481     if (utf8_force && f->uname) {
5482       if (f->iname)
5483         free(f->iname);
5484       if ((f->iname = malloc(strlen(f->uname) + 1)) == NULL)
5485         ZIPERR(ZE_MEM, "Unicode bit 11");
5486       strcpy(f->iname, f->uname);
5487 # ifdef WIN32
5488       if (f->inamew)
5489         free(f->inamew);
5490       f->inamew = utf8_to_wchar_string(f->iname);
5491 # endif
5492     }
5493 #endif
5494 
5495     /* Only set z->uname if have a non-ASCII Unicode name */
5496     /* The Unicode path extra field is created if z->uname is not NULL,
5497        unless on a UTF-8 system, then instead of creating the extra field
5498        set bit 11 in the General Purpose Bit Flag */
5499     {
5500       int is_ascii = 0;
5501 
5502 # ifdef WIN32
5503       if (!no_win32_wide)
5504         is_ascii = is_ascii_stringw(f->inamew);
5505       else
5506         is_ascii = is_ascii_string(f->uname);
5507 # else
5508       is_ascii = is_ascii_string(f->uname);
5509 # endif
5510 
5511       if (z->uname == NULL) {
5512         if (!is_ascii)
5513           z->uname = f->uname;
5514         else
5515           free(f->uname);
5516       } else {
5517         free(f->uname);
5518       }
5519     }
5520     f->uname = NULL;
5521 
5522 #endif
5523     z->iname = f->iname;
5524     f->iname = NULL;
5525     z->zname = f->zname;
5526     f->zname = NULL;
5527     z->oname = f->oname;
5528     f->oname = NULL;
5529 #if defined(UNICODE_SUPPORT) && defined(WIN32)
5530     z->namew = f->namew;
5531     f->namew = NULL;
5532     z->inamew = f->inamew;
5533     f->inamew = NULL;
5534     z->znamew = f->znamew;
5535     f->znamew = NULL;
5536 #endif
5537     z->ext = z->cext = z->com = 0;
5538     z->extra = z->cextra = NULL;
5539     z->mark = 1;
5540     z->dosflag = f->dosflag;
5541     /* zip it up */
5542     DisplayRunningStats();
5543     if (noisy)
5544     {
5545       fprintf(mesg, "  adding: %s", z->oname);
5546       mesg_line_started = 1;
5547       fflush(mesg);
5548     }
5549     if (logall)
5550     {
5551       fprintf(logfile, "  adding: %s", z->oname);
5552       logfile_line_started = 1;
5553       fflush(logfile);
5554     }
5555     /* initial scan */
5556     len = f->usize;
5557     if ((r = zipup(z)) != ZE_OK  && r != ZE_OPEN && r != ZE_MISS)
5558     {
5559       zipmessage_nl("", 1);
5560       /*
5561       if (noisy)
5562       {
5563 #if (!defined(MACOS) && !defined(WINDLL))
5564         putc('\n', mesg);
5565         fflush(mesg);
5566 #else
5567         fprintf(stdout, "\n");
5568 #endif
5569         mesg_line_started = 0;
5570         fflush(mesg);
5571       }
5572       if (logall) {
5573         fprintf(logfile, "\n");
5574         logfile_line_started = 0;
5575         fflush(logfile);
5576       }
5577       */
5578       sprintf(errbuf, "was zipping %s", z->oname);
5579       ZIPERR(r, errbuf);
5580     }
5581     if (r == ZE_OPEN || r == ZE_MISS)
5582     {
5583       o = 1;
5584       zipmessage_nl("", 1);
5585       /*
5586       if (noisy)
5587       {
5588 #if (!defined(MACOS) && !defined(WINDLL))
5589         putc('\n', mesg);
5590         fflush(mesg);
5591 #else
5592         fprintf(stdout, "\n");
5593 #endif
5594         mesg_line_started = 0;
5595         fflush(mesg);
5596       }
5597       if (logall) {
5598         fprintf(logfile, "\n");
5599         logfile_line_started = 0;
5600         fflush(logfile);
5601       }
5602       */
5603       if (r == ZE_OPEN) {
5604         perror("zip warning");
5605         if (logfile)
5606           fprintf(logfile, "zip warning: %s\n", strerror(errno));
5607         zipwarn("could not open for reading: ", z->oname);
5608         if (bad_open_is_error) {
5609           sprintf(errbuf, "was zipping %s", z->name);
5610           ZIPERR(r, errbuf);
5611         }
5612       } else {
5613         zipwarn("file and directory with the same name: ", z->oname);
5614       }
5615       files_so_far++;
5616       bytes_so_far += len;
5617       bad_files_so_far++;
5618       bad_bytes_so_far += len;
5619       free((zvoid *)(z->name));
5620       free((zvoid *)(z->iname));
5621       free((zvoid *)(z->zname));
5622       free(z->oname);
5623 #ifdef UNICODE_SUPPORT
5624       if (z->uname)
5625         free(z->uname);
5626 # ifdef WIN32
5627       if (z->namew)
5628         free((zvoid *)(z->namew));
5629       if (z->inamew)
5630         free((zvoid *)(z->inamew));
5631       if (z->znamew)
5632         free((zvoid *)(z->znamew));
5633 # endif
5634 #endif
5635       farfree((zvoid far *)z);
5636     }
5637     else
5638     {
5639       files_so_far++;
5640       /* current size of file (just before reading) */
5641       good_bytes_so_far += z->len;
5642       /* size of file on initial scan */
5643       bytes_so_far += len;
5644       *w = z;
5645       w = &z->nxt;
5646       zcount++;
5647     }
5648   }
5649   if (key != NULL)
5650   {
5651     free((zvoid *)key);
5652     key = NULL;
5653   }
5654 
5655   /* final status 3/17/05 EG */
5656   if (noisy && bad_files_so_far)
5657   {
5658     char tempstrg[100];
5659 
5660     fprintf(mesg, "\nzip warning: Not all files were readable\n");
5661     fprintf(mesg, "  files/entries read:  %lu", files_total - bad_files_so_far);
5662     WriteNumString(good_bytes_so_far, tempstrg);
5663     fprintf(mesg, " (%s bytes)", tempstrg);
5664     fprintf(mesg, "  skipped:  %lu", bad_files_so_far);
5665     WriteNumString(bad_bytes_so_far, tempstrg);
5666     fprintf(mesg, " (%s bytes)\n", tempstrg);
5667     fflush(mesg);
5668   }
5669   if (logfile && bad_files_so_far)
5670   {
5671     char tempstrg[100];
5672 
5673     fprintf(logfile, "\nzip warning: Not all files were readable\n");
5674     fprintf(logfile, "  files/entries read:  %lu", files_total - bad_files_so_far);
5675     WriteNumString(good_bytes_so_far, tempstrg);
5676     fprintf(logfile, " (%s bytes)", tempstrg);
5677     fprintf(logfile, "  skipped:  %lu", bad_files_so_far);
5678     WriteNumString(bad_bytes_so_far, tempstrg);
5679     fprintf(logfile, " (%s bytes)", tempstrg);
5680   }
5681 
5682   /* Get one line comment for each new entry */
5683   if (show_what_doing) {
5684     fprintf(mesg, "sd: Get comment if any\n");
5685     fflush(mesg);
5686   }
5687 #if defined(AMIGA) || defined(MACOS)
5688   if (comadd || filenotes)
5689   {
5690     if (comadd)
5691 #else
5692   if (comadd)
5693   {
5694 #endif
5695     {
5696       if (comment_stream == NULL) {
5697 #ifndef RISCOS
5698         comment_stream = (FILE*)fdopen(fileno(stderr), "r");
5699 #else
5700         comment_stream = stderr;
5701 #endif
5702       }
5703       if ((e = malloc(MAXCOM + 1)) == NULL) {
5704         ZIPERR(ZE_MEM, "was reading comment lines");
5705       }
5706     }
5707 #ifdef __human68k__
5708     setmode(fileno(comment_stream), O_TEXT);
5709 #endif
5710 #ifdef MACOS
5711     if (noisy) fprintf(mesg, "\nStart commenting files ...\n");
5712 #endif
5713     for (z = zfiles; z != NULL; z = z->nxt)
5714       if (z->mark)
5715 #if defined(AMIGA) || defined(MACOS)
5716         if (filenotes && (p = GetComment(z->zname)))
5717         {
5718           if (z->comment = malloc(k = strlen(p)+1))
5719           {
5720             z->com = k;
5721             strcpy(z->comment, p);
5722           }
5723           else
5724           {
5725             free((zvoid *)e);
5726             ZIPERR(ZE_MEM, "was reading filenotes");
5727           }
5728         }
5729         else if (comadd)
5730 #endif /* AMIGA || MACOS */
5731         {
5732           if (noisy)
5733             fprintf(mesg, "Enter comment for %s:\n", z->oname);
5734           if (fgets(e, MAXCOM+1, comment_stream) != NULL)
5735           {
5736             if ((p = malloc((extent)(k = strlen(e))+1)) == NULL)
5737             {
5738               free((zvoid *)e);
5739               ZIPERR(ZE_MEM, "was reading comment lines");
5740             }
5741             strcpy(p, e);
5742             if (p[k-1] == '\n')
5743               p[--k] = 0;
5744             z->comment = p;
5745             /* zip64 support 09/05/2003 R.Nausedat */
5746             z->com = (extent)k;
5747           }
5748         }
5749 #ifdef MACOS
5750     if (noisy) fprintf(mesg, "\n...done");
5751 #endif
5752 #if defined(AMIGA) || defined(MACOS)
5753     if (comadd)
5754       free((zvoid *)e);
5755     GetComment(NULL);           /* makes it free its internal storage */
5756 #else
5757     free((zvoid *)e);
5758 #endif
5759   }
5760 
5761   /* Get multi-line comment for the zip file */
5762   if (zipedit)
5763   {
5764 #ifndef WINDLL
5765     if (comment_stream == NULL) {
5766 #ifndef RISCOS
5767       comment_stream = (FILE*)fdopen(fileno(stderr), "r");
5768 #else
5769       comment_stream = stderr;
5770 #endif
5771     }
5772     if ((e = malloc(MAXCOM + 1)) == NULL) {
5773       ZIPERR(ZE_MEM, "was reading comment lines");
5774     }
5775     if (noisy && zcomlen)
5776     {
5777       fputs("current zip file comment is:\n", mesg);
5778       fwrite(zcomment, 1, zcomlen, mesg);
5779       if (zcomment[zcomlen-1] != '\n')
5780         putc('\n', mesg);
5781       free((zvoid *)zcomment);
5782     }
5783     if ((zcomment = malloc(1)) == NULL)
5784       ZIPERR(ZE_MEM, "was setting comments to null");
5785     zcomment[0] = '\0';
5786     if (noisy)
5787       fputs("enter new zip file comment (end with .):\n", mesg);
5788 #if (defined(AMIGA) && (defined(LATTICE)||defined(__SASC)))
5789     flushall();  /* tty input/output is out of sync here */
5790 #endif
5791 #ifdef __human68k__
5792     setmode(fileno(comment_stream), O_TEXT);
5793 #endif
5794 #ifdef MACOS
5795     printf("\n enter new zip file comment \n");
5796     if (fgets(e, MAXCOM+1, comment_stream) != NULL) {
5797         if ((p = malloc((k = strlen(e))+1)) == NULL) {
5798             free((zvoid *)e);
5799             ZIPERR(ZE_MEM, "was reading comment lines");
5800         }
5801         strcpy(p, e);
5802         if (p[k-1] == '\n') p[--k] = 0;
5803         zcomment = p;
5804     }
5805 #else /* !MACOS */
5806     while (fgets(e, MAXCOM+1, comment_stream) != NULL && strcmp(e, ".\n"))
5807     {
5808       if (e[(r = strlen(e)) - 1] == '\n')
5809         e[--r] = 0;
5810       if ((p = malloc((*zcomment ? strlen(zcomment) + 3 : 1) + r)) == NULL)
5811       {
5812         free((zvoid *)e);
5813         ZIPERR(ZE_MEM, "was reading comment lines");
5814       }
5815       if (*zcomment)
5816         strcat(strcat(strcpy(p, zcomment), "\r\n"), e);
5817       else
5818         strcpy(p, *e ? e : "\r\n");
5819       free((zvoid *)zcomment);
5820       zcomment = p;
5821     }
5822 #endif /* ?MACOS */
5823     free((zvoid *)e);
5824 #else /* WINDLL */
5825     comment(zcomlen);
5826     if ((p = malloc(strlen(szCommentBuf)+1)) == NULL) {
5827       ZIPERR(ZE_MEM, "was setting comments to null");
5828     }
5829     if (szCommentBuf[0] != '\0')
5830        lstrcpy(p, szCommentBuf);
5831     else
5832        p[0] = '\0';
5833     free((zvoid *)zcomment);
5834     GlobalUnlock(hStr);
5835     GlobalFree(hStr);
5836     zcomment = p;
5837 #endif /* WINDLL */
5838     zcomlen = strlen(zcomment);
5839   }
5840 
5841   if (display_globaldots) {
5842 #ifndef WINDLL
5843     putc('\n', mesg);
5844 #else
5845     fprintf(stdout,"%c",'\n');
5846 #endif
5847     mesg_line_started = 0;
5848   }
5849 
5850   /* Write central directory and end header to temporary zip */
5851   if (show_what_doing) {
5852     fprintf(mesg, "sd: Writing central directory\n");
5853     fflush(mesg);
5854   }
5855   diag("writing central directory");
5856   k = 0;                        /* keep count for end header */
5857   c = tempzn;                   /* get start of central */
5858   n = t = 0;
5859   for (z = zfiles; z != NULL; z = z->nxt)
5860   {
5861     if (z->mark || !(diff_mode || filesync)) {
5862       if ((r = putcentral(z)) != ZE_OK) {
5863         ZIPERR(r, tempzip);
5864       }
5865       tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
5866       n += z->len;
5867       t += z->siz;
5868       k++;
5869     }
5870   }
5871 
5872   if (k == 0)
5873     zipwarn("zip file empty", "");
5874   if (verbose) {
5875     fprintf(mesg, "total bytes=%s, compressed=%s -> %d%% savings\n",
5876             zip_fzofft(n, NULL, "u"), zip_fzofft(t, NULL, "u"), percent(n, t));
5877     fflush(mesg);
5878   }
5879   if (logall) {
5880     fprintf(logfile, "total bytes=%s, compressed=%s -> %d%% savings\n",
5881             zip_fzofft(n, NULL, "u"), zip_fzofft(t, NULL, "u"), percent(n, t));
5882     fflush(logfile);
5883   }
5884   t = tempzn - c;               /* compute length of central */
5885   diag("writing end of central directory");
5886   if (show_what_doing) {
5887     fprintf(mesg, "sd: Writing end of central directory\n");
5888     fflush(mesg);
5889   }
5890 
5891   if ((r = putend(k, t, c, zcomlen, zcomment)) != ZE_OK) {
5892     ZIPERR(r, tempzip);
5893   }
5894 
5895   /*
5896   tempzf = NULL;
5897   */
5898   if (fclose(y)) {
5899     ZIPERR(d ? ZE_WRITE : ZE_TEMP, tempzip);
5900   }
5901   y = NULL;
5902   if (in_file != NULL) {
5903     fclose(in_file);
5904     in_file = NULL;
5905   }
5906   /*
5907   if (x != NULL)
5908     fclose(x);
5909   */
5910 
5911   /* Free some memory before spawning unzip */
5912 #ifdef USE_ZLIB
5913   zl_deflate_free();
5914 #else
5915   lm_free();
5916 #endif
5917 #ifdef BZIP2_SUPPORT
5918   bz_compress_free();
5919 #endif
5920 
5921 #ifndef WINDLL
5922   /* Test new zip file before overwriting old one or removing input files */
5923   if (test)
5924     check_zipfile(tempzip, argv[0]);
5925 #endif
5926   /* Replace old zip file with new zip file, leaving only the new one */
5927   if (strcmp(zipfile, "-") && !d)
5928   {
5929     diag("replacing old zip file with new zip file");
5930     if (show_what_doing) {
5931       fprintf(mesg, "sd: Replacing old zip file\n");
5932       fflush(mesg);
5933     }
5934     if ((r = replace(out_path, tempzip)) != ZE_OK)
5935     {
5936       zipwarn("new zip file left as: ", tempzip);
5937       free((zvoid *)tempzip);
5938       tempzip = NULL;
5939       ZIPERR(r, "was replacing the original zip file");
5940     }
5941     free((zvoid *)tempzip);
5942   }
5943   tempzip = NULL;
5944   if (zip_attributes && strcmp(zipfile, "-")) {
5945     setfileattr(out_path, zip_attributes);
5946 #ifdef VMS
5947     /* If the zip file existed previously, restore its record format: */
5948     if (x != NULL)
5949       (void)VMSmunch(out_path, RESTORE_RTYPE, NULL);
5950 #endif
5951   }
5952   if (strcmp(zipfile, "-")) {
5953     if (show_what_doing) {
5954       fprintf(mesg, "sd: Setting file type\n");
5955       fflush(mesg);
5956     }
5957 
5958     set_filetype(out_path);
5959   }
5960 
5961 #if defined(WIN32)
5962   /* All looks good so, if requested, clear the DOS archive bits */
5963   if (clear_archive_bits) {
5964     if (noisy)
5965       zipmessage("Clearing archive bits...", "");
5966     for (z = zfiles; z != NULL; z = z->nxt)
5967     {
5968 # ifdef UNICODE_SUPPORT
5969       if (z->mark) {
5970         if (!no_win32_wide) {
5971           if (!ClearArchiveBitW(z->namew)){
5972             zipwarn("Could not clear archive bit for: ", z->oname);
5973           }
5974         } else {
5975           if (!ClearArchiveBit(z->name)){
5976             zipwarn("Could not clear archive bit for: ", z->oname);
5977           }
5978         }
5979       }
5980 # else
5981       if (!ClearArchiveBit(z->name)){
5982         zipwarn("Could not clear archive bit for: ", z->oname);
5983       }
5984 # endif
5985     }
5986   }
5987 #endif
5988 
5989   /* finish logfile (it gets closed in freeup() called by finish()) */
5990   if (logfile) {
5991       struct tm *now;
5992       time_t clocktime;
5993 
5994       fprintf(logfile, "\nTotal %ld entries (", files_total);
5995       if (good_bytes_so_far != bytes_total) {
5996         fprintf(logfile, "planned ");
5997         DisplayNumString(logfile, bytes_total);
5998         fprintf(logfile, " bytes, actual ");
5999         DisplayNumString(logfile, good_bytes_so_far);
6000         fprintf(logfile, " bytes)");
6001       } else {
6002         DisplayNumString(logfile, bytes_total);
6003         fprintf(logfile, " bytes)");
6004       }
6005 
6006       /* get current time */
6007 
6008       time(&clocktime);
6009       now = localtime(&clocktime);
6010       fprintf(logfile, "\nDone %s", asctime(now));
6011   }
6012 
6013   /* Finish up (process -o, -m, clean up).  Exit code depends on o. */
6014 #if (!defined(VMS) && !defined(CMS_MVS))
6015   free((zvoid *) zipbuf);
6016 #endif /* !VMS && !CMS_MVS */
6017   RETURN(finish(o ? ZE_OPEN : ZE_OK));
6018 }
6019