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