1 /*
2   Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
3 
4   See the accompanying file LICENSE, version 2005-Feb-10 or later
5   (the contents of which are also included in zip.h) for terms of use.
6   If, for some reason, all these files are missing, the Info-ZIP license
7   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 #include "zip.h"
10 
11 #ifndef UTIL    /* little or no material in this file is used by UTIL */
12 
13 #include <dos.h>
14 #include <time.h>
15 
16 
17 #if defined(__GO32__) || defined(__TURBOC__)
18 #  include <dir.h> /* prototypes of find*() */
19    typedef struct ffblk   ff_dir;
20 #  define FATTR (hidden_files ? FA_HIDDEN+FA_SYSTEM+FA_DIREC : FA_DIREC)
21 #  define FFIRST(n,d,a)   findfirst(n,(struct ffblk *)d,a)
22 #  define FNEXT(d)        findnext((struct ffblk *)d)
23 #  if (defined(__TURBOC__) || (defined(__DJGPP__) && (__DJGPP__ >=2)))
24 #    if (defined(__DJGPP__) && (__DJGPP__ == 2) && (__DJGPP_MINOR__ == 0))
25 #      include <libc/dosio.h>
26 #    endif
27 #    define GetFileMode(name) _chmod(name, 0)
28 #    define SetFileMode(name, attr) _chmod(name, 1, attr)
29 #  else /* DJGPP v1.x */
30 #    define GetFileMode(name) bdosptr(0x43, (name), 0)
31 #  endif
32 #endif /* __GO32__ || __TURBOC__ */
33 
34 #if defined(MSC) || defined(__WATCOMC__)
35    typedef struct find_t  ff_dir;
36 #  define FATTR (hidden_files ? _A_HIDDEN+_A_SYSTEM+_A_SUBDIR : _A_SUBDIR)
37 #  ifndef FA_LABEL
38 #    define FA_LABEL      _A_VOLID
39 #  endif
40 #  define FFIRST(n,d,a)   _dos_findfirst(n,a,(struct find_t *)d)
41 #  define FNEXT(d)        _dos_findnext((struct find_t *)d)
42 #  define ff_name         name
43 #  define ff_fdate        wr_date
44 #  define ff_ftime        wr_time
45 #  define ff_attrib       attrib
46 #endif /* MSC || __WATCOMC__ */
47 
48 #ifdef __EMX__
49 #  ifdef EMX_OBSOLETE           /* emx 0.9b or earlier */
50 #    define size_t xxx_size_t
51 #    define wchar_t xxx_wchar_t
52 #    define tm xxx_tm
53 #    include <sys/emx.h>
54 #    undef size_t
55 #    undef wchar_t
56 #    undef tm
57 #  else /* !EMX_OBSOLETE */     /* emx 0.9c or newer */
58 #    include <emx/syscalls.h>
59 #  endif /* ?EMX_OBSOLETE */
60    typedef struct _find   ff_dir;
61 #  define FATTR (hidden_files ? _A_HIDDEN+_A_SYSTEM+_A_SUBDIR : _A_SUBDIR)
62 #  define FA_LABEL        _A_VOLID
63 #  define FFIRST(n,d,a)   __findfirst(n,a,d)
64 #  define FNEXT(d)        __findnext(d)
65 #  define ff_name         name
66 #  define ff_fdate        date
67 #  define ff_ftime        time
68 #  define ff_attrib       attr
69 #  define GetFileMode(name) __chmod(name, 0, 0)
70 #  define SetFileMode(name, attr) __chmod(name, 1, attr)
71 #endif /* __EMX__ */
72 
73 #ifndef SetFileMode
74 #  define SetFileMode(name, attr) _dos_setfileattr(name, attr)
75 #endif
76 
77 
78 #define PAD  0
79 #define PATH_END '/'
80 
81 /* Library functions not in (most) header files */
82 int rmdir OF((const char *));
83 int utime OF((char *, ztimbuf *));
84 
85 /* Local functions */
86 #ifndef GetFileMode
87 int GetFileMode OF((char *name));
88 #endif /* !GetFileMode */
89 
90 local int  initDirSearch OF((char *name, ff_dir *ff_context_p));
91 local char *getVolumeLabel OF((int, ulg *, ulg *, time_t *));
92 local int  wild_recurse OF((char *, char *));
93 local int procname_dos OF((char *n, int caseflag, unsigned attribs));
94 local int is_running_on_windows OF((void));
95 
96 #define MSDOS_INVALID_ATTR      0xFF
97 #define getDirEntryAttr(d)      ((d)->ff_attrib)
98 
99 /* Module level variables */
100 extern char *label;
101 local ulg label_time = 0;
102 local ulg label_mode = 0;
103 local time_t label_utim = 0;
104 
105 /* Module level constants */
106 local ZCONST char wild_match_all[] = "*.*";
107 
108 
109 #ifndef GetFileMode
GetFileMode(char * name)110 int GetFileMode(char *name)
111 {
112   unsigned int attr = 0;
113   return (_dos_getfileattr(name, &attr) ? -1 : attr);
114 }
115 #endif /* !GetFileMode */
116 
initDirSearch(name,ff_context_p)117 local int initDirSearch(name, ff_context_p)
118   char *name;                   /* name of directory to scan */
119   ff_dir *ff_context_p;         /* pointer to FFIRST/FNEXT context structure */
120 {
121   int r;                        /* FFIRST return value */
122   char *p, *q;                  /* temporary copy of name, and aux pointer */
123 
124   if ((p = malloc(strlen(name) + (2 + sizeof(wild_match_all)))) == NULL)
125     return ZE_MEM;
126 
127   strcpy(p, name);
128   q = p + strlen(p);
129   if (q[-1] == ':')
130     *q++ = '.';
131   if ((q - p) > 0 && *(q - 1) != '/')
132     *q++ = '/';
133   strcpy(q, wild_match_all);
134   r = FFIRST(p, ff_context_p, FATTR);
135   free((zvoid *)p);
136 
137   return (r ? ZE_MISS : ZE_OK);
138 }
139 
getVolumeLabel(drive,vtime,vmode,vutim)140 local char *getVolumeLabel(drive, vtime, vmode, vutim)
141   int drive;    /* drive name: 'A' .. 'Z' or '\0' for current drive */
142   ulg *vtime;   /* volume label creation time (DOS format) */
143   ulg *vmode;   /* volume label file mode */
144   time_t *vutim;/* volume label creation time (UNIX format) */
145 
146 /* If a volume label exists for the given drive, return its name and
147    set its time and mode. The returned name must be static data. */
148 {
149   static char vol[14];
150   ff_dir d;
151   char *p;
152 
153   if (drive) {
154     vol[0] = (char)drive;
155     strcpy(vol+1, ":/");
156   } else {
157     strcpy(vol, "/");
158   }
159   strcat(vol, wild_match_all);
160   if (FFIRST(vol, &d, FA_LABEL) == 0) {
161     strncpy(vol, d.ff_name, sizeof(vol)-1);
162     vol[sizeof(vol)-1] = '\0';   /* just in case */
163     if ((p = strchr(vol, '.')) != NULL) /* remove dot, though PKZIP doesn't */
164       strcpy(p, p + 1);
165     *vtime = ((ulg)d.ff_fdate << 16) | ((ulg)d.ff_ftime & 0xffff);
166     *vmode = (ulg)d.ff_attrib;
167     *vutim = dos2unixtime(*vtime);
168     return vol;
169   }
170   return NULL;
171 }
172 
173 
174 #ifdef MSDOS16
175 #define ONENAMELEN 12   /* no 16-bit compilers supports LFN */
176 #else
177 #define ONENAMELEN 255
178 #endif
179 
180 /* whole is a pathname with wildcards, wildtail points somewhere in the  */
181 /* middle of it.  All wildcards to be expanded must come AFTER wildtail. */
182 
wild_recurse(whole,wildtail)183 local int wild_recurse(whole, wildtail)
184 char *whole;
185 char *wildtail;
186 {
187     ff_dir dir;
188     char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
189     ush newlen, amatch = 0;
190     int e = ZE_MISS;
191 
192     if (!isshexp(wildtail)) {
193         struct stat s;                          /* dummy buffer for stat() */
194 
195         if (!LSSTAT(whole, &s))                 /* file exists ? */
196             return procname(whole, 0);
197         else
198             return ZE_MISS;                     /* woops, no wildcards! */
199     }
200 
201     /* back up thru path components till existing dir found */
202     do {
203         name = wildtail + strlen(wildtail) - 1;
204         for (;;)
205             if (name-- <= wildtail || *name == PATH_END) {
206                 subwild = name + 1;
207                 plug2 = *subwild;
208                 *subwild = 0;
209                 break;
210             }
211         if (glue)
212             *glue = plug;
213         glue = subwild;
214         plug = plug2;
215         e = initDirSearch(whole, &dir);
216     } while (e == ZE_MISS && subwild > wildtail);
217     wildtail = subwild;                 /* skip past non-wild components */
218     if (e != ZE_OK) {
219         if (glue)
220             *glue = plug;
221         goto ohforgetit;
222     }
223     subwild = strchr(wildtail + 1, PATH_END);
224     /* this "+ 1" dodges the  ^^^ hole left by *glue == 0 */
225     if (subwild != NULL) {
226         *(subwild++) = 0;               /* wildtail = one component pattern */
227         newlen = strlen(whole) + strlen(subwild) + (ONENAMELEN + 2);
228     } else
229         newlen = strlen(whole) + (ONENAMELEN + 1);
230     if ((newwhole = malloc(newlen)) == NULL) {
231         if (glue)
232             *glue = plug;
233         e = ZE_MEM;
234         goto ohforgetit;
235     }
236     strcpy(newwhole, whole);
237     newlen = strlen(newwhole);
238     if (glue)
239         *glue = plug;                           /* repair damage to whole */
240     if (!isshexp(wildtail)) {
241         e = ZE_MISS;                            /* non-wild name not found */
242         goto ohforgetit;
243     }
244 
245     do {
246         if (strcmp(dir.ff_name, ".") && strcmp(dir.ff_name, "..")
247                                   && MATCH(wildtail, dir.ff_name, 0)) {
248             strcpy(newwhole + newlen, dir.ff_name);
249             if (subwild) {
250                 name = newwhole + strlen(newwhole);
251                 *(name++) = PATH_END;
252                 strcpy(name, subwild);
253                 e = wild_recurse(newwhole, name);
254             } else
255                 e = procname_dos(newwhole, 0, getDirEntryAttr(&dir));
256             newwhole[newlen] = 0;
257             if (e == ZE_OK)
258                 amatch = 1;
259             else if (e != ZE_MISS)
260                 break;
261         }
262     } while (FNEXT(&dir) == 0);
263 
264   ohforgetit:
265     if (subwild)
266         *--subwild = PATH_END;
267     if (newwhole)
268         free(newwhole);
269     if (e == ZE_MISS && amatch)
270         e = ZE_OK;
271     return e;
272 }
273 
wild(w)274 int wild(w)
275 char *w;                /* path/pattern to match */
276 /* If not in exclude mode, expand the pattern based on the contents of the
277    file system.  Return an error code in the ZE_ class. */
278 {
279     char *p;            /* path */
280     char *q;            /* diskless path */
281     int e;              /* result */
282 
283     if (volume_label == 1) {
284       volume_label = 2;
285       label = getVolumeLabel((w != NULL && w[1] == ':') ? to_up(w[0]) : '\0',
286                              &label_time, &label_mode, &label_utim);
287       if (label != NULL)
288         (void)newname(label, 0, 0);
289       if (w == NULL || (w[1] == ':' && w[2] == '\0')) return ZE_OK;
290       /* "zip -$ foo a:" can be used to force drive name */
291     }
292     /* special handling of stdin request */
293     if (strcmp(w, "-") == 0)   /* if compressing stdin */
294         return newname(w, 0, 0);
295 
296     /* Allocate and copy pattern, leaving room to add "." if needed */
297     if ((p = malloc(strlen(w) + 2)) == NULL)
298         return ZE_MEM;
299     strcpy(p, w);
300 
301     /* Normalize path delimiter as '/' */
302     for (q = p; *q; q++)                  /* use / consistently */
303         if (*q == '\\')
304             *q = '/';
305 
306     /* Separate the disk part of the path */
307     q = strchr(p, ':');
308     if (q != NULL) {
309         if (strchr(++q, ':'))     /* sanity check for safety of wild_recurse */
310             return ZE_MISS;
311     } else
312         q = p;
313 
314     /* Normalize bare disk names */
315     if (q > p && !*q)
316         strcpy(q, ".");
317 
318     /* Here we go */
319     e = wild_recurse(p, q);
320     free((zvoid *)p);
321     return e;
322 }
323 
procname_dos(n,caseflag,attribs)324 local int procname_dos(n, caseflag, attribs)
325 char *n;                /* name to process */
326 int caseflag;           /* true to force case-sensitive match */
327 unsigned attribs;       /* file attributes, if available */
328 /* Process a name or sh expression to operate on (or exclude).  Return
329    an error code in the ZE_ class. */
330 {
331   char *a;              /* path and name for recursion */
332   ff_dir *d;            /* control structure for FFIRST/FNEXT */
333   char *e;              /* pointer to name from readd() */
334   int m;                /* matched flag */
335   int ff_status;        /* return value of FFIRST/FNEXT */
336   char *p;              /* path for recursion */
337   struct stat s;        /* result of stat() */
338   struct zlist far *z;  /* steps through zfiles list */
339 
340   if (n == NULL)        /* volume_label request in freshen|delete mode ?? */
341     return ZE_OK;
342 
343   if (strcmp(n, "-") == 0)   /* if compressing stdin */
344     return newname(n, 0, caseflag);
345   else if (*n == '\0') return ZE_MISS;
346   else if (attribs != MSDOS_INVALID_ATTR)
347   {
348     /* Avoid calling stat() for performance reasons when it is already known
349        (from a previous directory scan) that the passed name corresponds to
350        a "real existing" file.  The only information needed further down in
351        this function is the distinction between directory entries and other
352        (typically normal file) entries.  This distinction can be derived from
353        the file's attributes that the directory lookup has already provided
354        "for free".
355      */
356     s.st_mode = ((attribs & MSDOS_DIR_ATTR) ? S_IFDIR : S_IFREG);
357   }
358   else if (LSSTAT(n, &s)
359 #ifdef __TURBOC__
360            /* For this compiler, stat() succeeds on wild card names! */
361            || isshexp(n)
362 #endif
363           )
364   {
365     /* Not a file or directory--search for shell expression in zip file */
366     if (caseflag) {
367       p = malloc(strlen(n) + 1);
368       if (p != NULL)
369         strcpy(p, n);
370     } else
371       p = ex2in(n, 0, (int *)NULL);     /* shouldn't affect matching chars */
372     m = 1;
373     for (z = zfiles; z != NULL; z = z->nxt) {
374       if (MATCH(p, z->iname, caseflag))
375       {
376         z->mark = pcount ? filter(z->zname, caseflag) : 1;
377         if (z->mark) z->dosflag = 1;    /* force DOS attribs for incl. names */
378         if (verbose)
379             fprintf(mesg, "zip diagnostic: %scluding %s\n",
380                z->mark ? "in" : "ex", z->name);
381         m = 0;
382       }
383     }
384     free((zvoid *)p);
385     return m ? ZE_MISS : ZE_OK;
386   }
387 
388   /* Live name--use if file, recurse if directory */
389   for (p = n; *p; p++)          /* use / consistently */
390     if (*p == '\\')
391       *p = '/';
392   if ((s.st_mode & S_IFDIR) == 0)
393   {
394     /* add or remove name of file */
395     if ((m = newname(n, 0, caseflag)) != ZE_OK)
396       return m;
397   } else {
398     /* Add trailing / to the directory name */
399     if ((p = malloc(strlen(n)+2)) == NULL)
400       return ZE_MEM;
401     if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
402       *p = '\0';  /* avoid "./" prefix and do not create zip entry */
403     } else {
404       strcpy(p, n);
405       a = p + strlen(p);
406       if (a[-1] != '/')
407         strcpy(a, "/");
408       if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
409         free((zvoid *)p);
410         return m;
411       }
412     }
413     /* recurse into directory */
414     if (recurse)
415     {
416       if ((d = malloc(sizeof(ff_dir))) == NULL ||
417           (m = initDirSearch(n, d)) == ZE_MEM)
418       {
419         if (d != NULL)
420           free((zvoid *)d);
421         free((zvoid *)p);
422         return ZE_MEM;
423       }
424       for (e = d->ff_name, ff_status = m;
425            ff_status == 0;
426            ff_status = FNEXT(d))
427       {
428         if (strcmp(e, ".") && strcmp(e, ".."))
429         {
430           if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
431           {
432             free((zvoid *)d);
433             free((zvoid *)p);
434             return ZE_MEM;
435           }
436           strcat(strcpy(a, p), e);
437           if ((m = procname_dos(a, caseflag, getDirEntryAttr(d)))
438               != ZE_OK)         /* recurse on name */
439           {
440             if (m == ZE_MISS)
441               zipwarn("name not matched: ", a);
442             else
443               ziperr(m, a);
444           }
445           free((zvoid *)a);
446         }
447       }
448       free((zvoid *)d);
449     }
450     free((zvoid *)p);
451   } /* (s.st_mode & S_IFDIR) == 0) */
452   return ZE_OK;
453 }
454 
procname(n,caseflag)455 int procname(n, caseflag)
456 char *n;                /* name to process */
457 int caseflag;           /* true to force case-sensitive match */
458 {
459   return procname_dos(n, caseflag, MSDOS_INVALID_ATTR);
460 }
461 
ex2in(x,isdir,pdosflag)462 char *ex2in(x, isdir, pdosflag)
463 char *x;                /* external file name */
464 int isdir;              /* input: x is a directory */
465 int *pdosflag;          /* output: force MSDOS file attributes? */
466 /* Convert the external file name to a zip file name, returning the malloc'ed
467    string or NULL if not enough memory. */
468 {
469   char *n;              /* internal file name (malloc'ed) */
470   char *t;              /* shortened name */
471   int dosflag;
472 
473   dosflag = 1;
474 
475   /* Find starting point in name before doing malloc */
476   /* Strip drive specification */
477   t = *x && *(x + 1) == ':' ? x + 2 : x;
478   /* Strip "//host/share/" part of a UNC name */
479   if ((!strncmp(x,"//",2) || !strncmp(x,"\\\\",2)) &&
480       (x[2] != '\0' && x[2] != '/' && x[2] != '\\')) {
481     n = x + 2;
482     while (*n != '\0' && *n != '/' && *n != '\\')
483       n++;              /* strip host name */
484     if (*n != '\0') {
485       n++;
486       while (*n != '\0' && *n != '/' && *n != '\\')
487         n++;            /* strip `share' name */
488     }
489     if (*n != '\0')
490       t = n + 1;
491   }
492   /* Strip leading "/" to convert an absolute path into a relative path */
493   while (*t == '/' || *t == '\\')
494     t++;
495   /* Skip leading "./" as well */
496   while (*t == '.' && (t[1] == '/' || t[1] == '\\'))
497     t += 2;
498 
499   /* Make changes, if any, to the copied name (leave original intact) */
500   for (n = t; *n; n++)
501     if (*n == '\\')
502       *n = '/';
503 
504   if (!pathput)
505     t = last(t, PATH_END);
506 
507   /* Malloc space for internal name and copy it */
508   if ((n = malloc(strlen(t) + 1)) == NULL)
509     return NULL;
510   strcpy(n, t);
511 
512   if (isdir == 42) return n;      /* avoid warning on unused variable */
513 
514   if (dosify)
515     msname(n);
516   else
517 #if defined(__DJGPP__) && __DJGPP__ >= 2
518     if (_USE_LFN == 0)
519 #endif
520       strlwr(n);
521   if (pdosflag)
522     *pdosflag = dosflag;
523   return n;
524 }
525 
in2ex(n)526 char *in2ex(n)
527 char *n;                /* internal file name */
528 /* Convert the zip file name to an external file name, returning the malloc'ed
529    string or NULL if not enough memory. */
530 {
531   char *x;              /* external file name */
532 
533   if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
534       return NULL;
535   strcpy(x, n);
536 
537   return x;
538 }
539 
stamp(f,d)540 void stamp(f, d)
541 char *f;                /* name of file to change */
542 ulg d;                  /* dos-style time to change it to */
543 /* Set last updated and accessed time of file f to the DOS time d. */
544 {
545 #if defined(__TURBOC__) || defined(__GO32__)
546   int h;                /* file handle */
547 
548   if ((h = open(f, 0)) != -1)
549   {
550     setftime(h, (struct ftime *)(void *)&d);
551     close(h);
552   }
553 #else /* !__TURBOC__ && !__GO32__ */
554   ztimbuf u;            /* argument for utime() */
555 
556   /* Convert DOS time to time_t format in u.actime and u.modtime */
557   u.actime = u.modtime = dos2unixtime(d);
558 
559   /* Set updated and accessed times of f */
560   utime(f, &u);
561 #endif /* ?(__TURBOC__ || __GO32__) */
562 }
563 
filetime(f,a,n,t)564 ulg filetime(f, a, n, t)
565 char *f;                /* name of file to get info on */
566 ulg *a;                 /* return value: file attributes */
567 long *n;                /* return value: file size */
568 iztimes *t;             /* return value: access, modific. and creation times */
569 /* If file *f does not exist, return 0.  Else, return the file's last
570    modified date and time as an MSDOS date and time.  The date and
571    time is returned in a long with the date most significant to allow
572    unsigned integer comparison of absolute times.  Also, if a is not
573    a NULL pointer, store the file attributes there, with the high two
574    bytes being the Unix attributes, and the low byte being a mapping
575    of that to DOS attributes.  If n is not NULL, store the file size
576    there.  If t is not NULL, the file's access, modification and creation
577    times are stored there as UNIX time_t values.
578    If f is "-", use standard input as the file. If f is a device, return
579    a file size of -1 */
580 {
581   struct stat s;        /* results of stat() */
582   /* convert FNMAX to malloc - 11/8/04 EG */
583   char *name;
584   int len = strlen(f);
585   int isstdin = !strcmp(f, "-");
586 
587   if (f == label) {
588     if (a != NULL)
589       *a = label_mode;
590     if (n != NULL)
591       *n = -2L; /* convention for a label name */
592     if (t != NULL)
593       t->atime = t->mtime = t->ctime = label_utim;
594     return label_time;
595   }
596   if ((name = malloc(len + 1)) == NULL) {
597     ZIPERR(ZE_MEM, "filetime");
598   }
599   strcpy(name, f);
600   if (name[len - 1] == '/')
601     name[len - 1] = '\0';
602   /* not all systems allow stat'ing a file with / appended */
603 
604   if (isstdin) {
605     if (fstat(fileno(stdin), &s) != 0) {
606       free(name);
607       error("fstat(stdin)");
608     }
609     time((time_t *)&s.st_mtime);       /* some fstat()s return time zero */
610   } else if (LSSTAT(name, &s) != 0) {
611              /* Accept about any file kind including directories
612               * (stored with trailing / with -r option)
613               */
614     free(name);
615     return 0;
616   }
617 
618   if (a != NULL) {
619     *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
620 #if (S_IFREG != 0x8000)
621     /* kludge to work around non-standard S_IFREG flag used in DJGPP V2.x */
622     if ((s.st_mode & S_IFMT) == S_IFREG) *a |= 0x80000000L;
623 #endif
624   }
625   free(name);
626   if (n != NULL)
627     *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
628   if (t != NULL) {
629     t->atime = s.st_atime;
630     t->mtime = s.st_mtime;
631     t->ctime = s.st_ctime;
632   }
633 
634   return unix2dostime((time_t *)&s.st_mtime);
635 }
636 
deletedir(d)637 int deletedir(d)
638 char *d;                /* directory to delete */
639 /* Delete the directory *d if it is empty, do nothing otherwise.
640    Return the result of rmdir(), delete(), or system().
641  */
642 {
643     return rmdir(d);
644 }
645 
set_extra_field(z,z_utim)646 int set_extra_field(z, z_utim)
647   struct zlist far *z;
648   iztimes *z_utim;
649   /* create extra field and change z->att if desired */
650 {
651 #ifdef USE_EF_UT_TIME
652 #ifdef IZ_CHECK_TZ
653   if (!zp_tz_is_valid) return ZE_OK;    /* skip silently if no valid TZ info */
654 #endif
655 
656   if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
657     return ZE_MEM;
658 
659   z->extra[0]  = 'U';
660   z->extra[1]  = 'T';
661   z->extra[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
662   z->extra[3]  = 0;
663   z->extra[4]  = EB_UT_FL_MTIME;
664   z->extra[5]  = (char)(z_utim->mtime);
665   z->extra[6]  = (char)(z_utim->mtime >> 8);
666   z->extra[7]  = (char)(z_utim->mtime >> 16);
667   z->extra[8]  = (char)(z_utim->mtime >> 24);
668 
669   z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
670   z->cextra = z->extra;
671 
672   return ZE_OK;
673 #else /* !USE_EF_UT_TIME */
674   return (int)(z-z);
675 #endif /* ?USE_EF_UT_TIME */
676 }
677 
678 
679 #ifdef MY_ZCALLOC       /* Special zcalloc function for MEMORY16 (MSDOS/OS2) */
680 
681 #if defined(__TURBOC__) && !defined(OS2)
682 /* Small and medium model are for now limited to near allocation with
683  * reduced MAX_WBITS and MAX_MEM_LEVEL
684  */
685 
686 /* Turbo C malloc() does not allow dynamic allocation of 64K bytes
687  * and farmalloc(64K) returns a pointer with an offset of 8, so we
688  * must fix the pointer. Warning: the pointer must be put back to its
689  * original form in order to free it, use zcfree().
690  */
691 
692 #define MAX_PTR 10
693 /* 10*64K = 640K */
694 
695 local int next_ptr = 0;
696 
697 typedef struct ptr_table_s {
698     zvoid far *org_ptr;
699     zvoid far *new_ptr;
700 } ptr_table;
701 
702 local ptr_table table[MAX_PTR];
703 /* This table is used to remember the original form of pointers
704  * to large buffers (64K). Such pointers are normalized with a zero offset.
705  * Since MSDOS is not a preemptive multitasking OS, this table is not
706  * protected from concurrent access. This hack doesn't work anyway on
707  * a protected system like OS/2. Use Microsoft C instead.
708  */
709 
zcalloc(unsigned items,unsigned size)710 zvoid far *zcalloc (unsigned items, unsigned size)
711 {
712     zvoid far *buf;
713     ulg bsize = (ulg)items*size;
714 
715     if (bsize < (65536L-16L)) {
716         buf = farmalloc(bsize);
717         if (*(ush*)&buf != 0) return buf;
718     } else {
719         buf = farmalloc(bsize + 16L);
720     }
721     if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
722     table[next_ptr].org_ptr = buf;
723 
724     /* Normalize the pointer to seg:0 */
725     *((ush*)&buf+1) += ((ush)((uch*)buf-NULL) + 15) >> 4;
726     *(ush*)&buf = 0;
727     table[next_ptr++].new_ptr = buf;
728     return buf;
729 }
730 
zcfree(zvoid far * ptr)731 zvoid zcfree (zvoid far *ptr)
732 {
733     int n;
734     if (*(ush*)&ptr != 0) { /* object < 64K */
735         farfree(ptr);
736         return;
737     }
738     /* Find the original pointer */
739     for (n = next_ptr - 1; n >= 0; n--) {
740         if (ptr != table[n].new_ptr) continue;
741 
742         farfree(table[n].org_ptr);
743         while (++n < next_ptr) {
744             table[n-1] = table[n];
745         }
746         next_ptr--;
747         return;
748     }
749     ziperr(ZE_MEM, "zcfree: ptr not found");
750 }
751 #endif /* __TURBOC__ */
752 
753 #if defined(MSC) || defined(__WATCOMC__)
754 #if (!defined(_MSC_VER) || (_MSC_VER < 700))
755 #  define _halloc  halloc
756 #  define _hfree   hfree
757 #endif
758 
zcalloc(unsigned items,unsigned size)759 zvoid far *zcalloc (unsigned items, unsigned size)
760 {
761     return (zvoid far *)_halloc((long)items, size);
762 }
763 
zcfree(zvoid far * ptr)764 zvoid zcfree (zvoid far *ptr)
765 {
766     _hfree((void huge *)ptr);
767 }
768 #endif /* MSC || __WATCOMC__ */
769 
770 #endif /* MY_ZCALLOC */
771 
772 #if (defined(__WATCOMC__) && defined(ASMV) && !defined(__386__))
773 /* This is a hack to connect "call _exit" in match.asm to exit() */
774 #pragma aux xit "_exit" parm caller []
xit(void)775 void xit(void)
776 {
777     exit(20);
778 }
779 #endif
780 
is_running_on_windows(void)781 local int is_running_on_windows(void)
782 {
783     char * var = getenv("OS");
784 
785     /* if the OS env.var says 'Windows_NT' then */
786     /* we're likely running on a variant of WinNT */
787 
788     if ((NULL != var) && (0 == strcmp("Windows_NT", var)))
789     {
790         return 1;
791     }
792 
793     /* if the windir env.var is non-null then */
794     /* we're likely running on a variant of Win9x */
795     /* DOS mode of Win9x doesn't define windir, only winbootdir */
796     /* NT's command.com can't see lowercase env. vars */
797 
798     var = getenv("windir");
799     if ((NULL != var) && (0 != var[0]))
800     {
801         return 1;
802     }
803 
804     return 0;
805 }
806 
check_for_windows(char * app)807 void check_for_windows(char *app)
808 {
809     /* Print a warning for users running under Windows */
810     /* to reduce bug reports due to running DOS version */
811     /* under Windows, when Windows version usually works correctly */
812 
813     /* This is only called from the DOS version */
814 
815     if (is_running_on_windows())
816     {
817         printf("\nzip warning:  You are running MSDOS %s on Windows.\n"
818                "Try the Windows version before reporting any problems.\n",
819                app);
820     }
821 }
822 
823 #endif /* !UTIL */
824 
825 
826 #ifndef WINDLL
827 /******************************/
828 /*  Function version_local()  */
829 /******************************/
830 
831 static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s.\n\n";
832                         /* At module level to keep Turbo C++ 1.0 happy !! */
833 
version_local()834 void version_local()
835 {
836 #if defined(__DJGPP__) || defined(__WATCOMC__) || \
837     (defined(_MSC_VER) && (_MSC_VER != 800))
838     char buf[80];
839 #endif
840 
841 /* Define the compiler name and version strings */
842 #if defined(__GNUC__)
843 #  if defined(__DJGPP__)
844     sprintf(buf, "djgpp v%d.%02d / gcc ", __DJGPP__, __DJGPP_MINOR__);
845 #    define COMPILER_NAME1      buf
846 #  elif defined(__GO32__)         /* __GO32__ is defined as "1" only (sigh) */
847 #    define COMPILER_NAME1      "djgpp v1.x / gcc "
848 #  elif defined(__EMX__)          /* ...so is __EMX__ (double sigh) */
849 #    define COMPILER_NAME1      "emx+gcc "
850 #  else
851 #    define COMPILER_NAME1      "gcc "
852 #  endif
853 #  define COMPILER_NAME2        __VERSION__
854 #elif defined(__WATCOMC__)
855 #  if (__WATCOMC__ % 10 > 0)
856 /* We do this silly test because __WATCOMC__ gives two digits for the  */
857 /* minor version, but Watcom packaging prefers to show only one digit. */
858     sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
859             __WATCOMC__ % 100);
860 #  else
861     sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
862             (__WATCOMC__ % 100) / 10);
863 #  endif
864 #  define COMPILER_NAME1        buf
865 #  define COMPILER_NAME2        ""
866 #elif defined(__TURBOC__)
867 #  ifdef __BORLANDC__
868 #    define COMPILER_NAME1      "Borland C++"
869 #    if (__BORLANDC__ < 0x0200)
870 #      define COMPILER_NAME2    " 1.0"
871 #    elif (__BORLANDC__ == 0x0200)   /* James:  __TURBOC__ = 0x0297 */
872 #      define COMPILER_NAME2    " 2.0"
873 #    elif (__BORLANDC__ == 0x0400)
874 #      define COMPILER_NAME2    " 3.0"
875 #    elif (__BORLANDC__ == 0x0410)   /* __BCPLUSPLUS__ = 0x0310 */
876 #      define COMPILER_NAME2    " 3.1"
877 #    elif (__BORLANDC__ == 0x0452)   /* __BCPLUSPLUS__ = 0x0320 */
878 #      define COMPILER_NAME2    " 4.0 or 4.02"
879 #    elif (__BORLANDC__ == 0x0460)   /* __BCPLUSPLUS__ = 0x0340 */
880 #      define COMPILER_NAME2    " 4.5"
881 #    elif (__BORLANDC__ == 0x0500)   /* __TURBOC__ = 0x0500 */
882 #      define COMPILER_NAME2    " 5.0"
883 #    else
884 #      define COMPILER_NAME2    " later than 5.0"
885 #    endif
886 #  else
887 #    define COMPILER_NAME1      "Turbo C"
888 #    if (__TURBOC__ > 0x0401)
889 #      define COMPILER_NAME2    "++ later than 3.0"
890 #    elif (__TURBOC__ == 0x0401)     /* Kevin:  3.0 -> 0x0401 */
891 #      define COMPILER_NAME2    "++ 3.0"
892 #    elif (__TURBOC__ == 0x0296)     /* [662] checked by SPC */
893 #      define COMPILER_NAME2    "++ 1.01"
894 #    elif (__TURBOC__ == 0x0295)     /* [661] vfy'd by Kevin */
895 #      define COMPILER_NAME2    "++ 1.0"
896 #    elif (__TURBOC__ == 0x0201)     /* Brian:  2.01 -> 0x0201 */
897 #      define COMPILER_NAME2    " 2.01"
898 #    elif ((__TURBOC__ >= 0x018d) && (__TURBOC__ <= 0x0200)) /* James: 0x0200 */
899 #      define COMPILER_NAME2    " 2.0"
900 #    elif (__TURBOC__ > 0x0100)
901 #      define COMPILER_NAME2    " 1.5"          /* James:  0x0105? */
902 #    else
903 #      define COMPILER_NAME2    " 1.0"          /* James:  0x0100 */
904 #    endif
905 #  endif
906 #elif defined(MSC)
907 #  if defined(_QC) && !defined(_MSC_VER)
908 #    define COMPILER_NAME1      "Microsoft Quick C"
909 #    define COMPILER_NAME2      ""      /* _QC is defined as 1 */
910 #  else
911 #    define COMPILER_NAME1      "Microsoft C "
912 #    ifdef _MSC_VER
913 #      if (_MSC_VER == 800)
914 #        define COMPILER_NAME2  "8.0/8.0c (Visual C++ 1.0/1.5)"
915 #      else
916 #        define COMPILER_NAME2 \
917            (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf)
918 #      endif
919 #    else
920 #      define COMPILER_NAME2    "5.1 or earlier"
921 #    endif
922 #  endif
923 #else
924 #    define COMPILER_NAME1      "unknown compiler"
925 #    define COMPILER_NAME2      ""
926 #endif
927 
928 /* Define the OS name and memory environment strings */
929 #if defined(__WATCOMC__) || defined(__TURBOC__) || defined(MSC) || \
930     defined(__GNUC__)
931 #  define OS_NAME1      "\nMS-DOS"
932 #else
933 #  define OS_NAME1      "MS-DOS"
934 #endif
935 
936 #if (defined(__GNUC__) || (defined(__WATCOMC__) && defined(__386__)))
937 #  define OS_NAME2      " (32-bit)"
938 #elif defined(M_I86HM) || defined(__HUGE__)
939 #  define OS_NAME2      " (16-bit, huge)"
940 #elif defined(M_I86LM) || defined(__LARGE__)
941 #  define OS_NAME2      " (16-bit, large)"
942 #elif defined(M_I86MM) || defined(__MEDIUM__)
943 #  define OS_NAME2      " (16-bit, medium)"
944 #elif defined(M_I86CM) || defined(__COMPACT__)
945 #  define OS_NAME2      " (16-bit, compact)"
946 #elif defined(M_I86SM) || defined(__SMALL__)
947 #  define OS_NAME2      " (16-bit, small)"
948 #elif defined(M_I86TM) || defined(__TINY__)
949 #  define OS_NAME2      " (16-bit, tiny)"
950 #else
951 #  define OS_NAME2      " (16-bit)"
952 #endif
953 
954 /* Define the compile date string */
955 #ifdef __DATE__
956 #  define COMPILE_DATE " on " __DATE__
957 #else
958 #  define COMPILE_DATE ""
959 #endif
960 
961     printf(CompiledWith, COMPILER_NAME1, COMPILER_NAME2,
962            OS_NAME1, OS_NAME2, COMPILE_DATE);
963 
964 } /* end function version_local() */
965 #endif /* !WINDLL */
966 
967 
968 #if 0 /* inserted here for future use (clearing of archive bits) */
969 #if (defined(__GO32__) && (!defined(__DJGPP__) || (__DJGPP__ < 2)))
970 
971 #include <errno.h>
972 int volatile _doserrno;
973 
974 unsigned _dos_setfileattr(char *name, unsigned attr)
975 {
976 #if 0   /* stripping of trailing '/' is not needed for zip-internal use */
977     unsigned namlen = strlen(name);
978     char *i_name = alloca(namlen + 1);
979 
980     strcpy(i_name, name);
981     if (namlen > 1 && i_name[namlen-1] == '/' && i_name[namlen-2] != ':')
982         i_name[namlen-1] = '\0';
983     asm("movl %0, %%edx": : "g" (i_name));
984 #else
985     asm("movl %0, %%edx": : "g" (name));
986 #endif
987     asm("movl %0, %%ecx": : "g" (attr));
988     asm("movl $0x4301, %eax");
989     asm("int $0x21": : : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi");
990     _doserrno = 0;
991     asm("jnc 1f");
992     asm("movl %%eax, %0": "=m" (_doserrno));
993     switch (_doserrno) {
994     case 2:
995     case 3:
996            errno = ENOENT;
997            break;
998     case 5:
999            errno = EACCES;
1000            break;
1001     }
1002     asm("1:");
1003     return (unsigned)_doserrno;
1004 }
1005 
1006 #endif /* DJGPP v1.x */
1007 #endif /* never (not yet used) */
1008 
1009 
1010 #if (defined(__DJGPP__) && (__DJGPP__ >= 2))
1011 
1012 /* Disable determination of "x" bit in st_mode field for [f]stat() calls. */
_is_executable(const char * path,int fhandle,const char * ext)1013 int _is_executable (const char *path, int fhandle, const char *ext)
1014 {
1015     return 0;
1016 }
1017 
1018 /* Prevent globbing of filenames.  This gives the same functionality as
1019  * "stubedit <program> globbing=no" did with DJGPP v1.
1020  */
1021 #ifndef USE_DJGPP_GLOB
__crt0_glob_function(char * _arg)1022 char **__crt0_glob_function(char *_arg)
1023 {
1024     return NULL;
1025 }
1026 #endif
1027 
1028 /* Reduce the size of the executable and remove the functionality to read
1029  * the program's environment from whatever $DJGPP points to.
1030  */
1031 #if !defined(USE_DJGPP_ENV) || defined(UTIL)
__crt0_load_environment_file(char * _app_name)1032 void __crt0_load_environment_file(char *_app_name)
1033 {
1034 }
1035 #endif
1036 
1037 #endif /* __DJGPP__ >= 2 */
1038 
1039 
1040 #if defined(_MSC_VER) && _MSC_VER == 700
1041 
1042 /*
1043  * ARGH.  MSC 7.0 libraries think times are based on 1899 Dec 31 00:00, not
1044  *  1970 Jan 1 00:00.  So we have to diddle time_t's appropriately:  add
1045  *  70 years' worth of seconds for localtime() wrapper function;
1046  *  (70*365 regular days + 17 leap days + 1 1899 day) * 86400 ==
1047  *  (25550 + 17 + 1) * 86400 == 2209075200 seconds.
1048  *  Let time() and stat() return seconds since 1970 by using our own
1049  *  _dtoxtime() which is the routine that is called by these two functions.
1050  */
1051 
1052 
1053 #ifdef UTIL
1054 #  include <time.h>
1055 #endif
1056 
1057 #ifndef UTIL
1058 #undef localtime
1059 struct tm *localtime(const time_t *);
1060 
msc7_localtime(const time_t * clock)1061 struct tm *msc7_localtime(const time_t *clock)
1062 {
1063    time_t t = *clock;
1064 
1065    t += 2209075200L;
1066    return localtime(&t);
1067 }
1068 #endif /* !UTIL */
1069 
1070 
1071 void __tzset(void);
1072 int _isindst(struct tm *);
1073 
1074 extern int _days[];
1075 
1076 /* Nonzero if `y' is a leap year, else zero. */
1077 #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
1078 
1079 /* Number of leap years from 1970 to `y' (not including `y' itself). */
1080 #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
1081 
_dtoxtime(year,month,mday,hour,min,sec)1082 time_t _dtoxtime(year, month, mday, hour, min, sec)
1083 int year, month, mday, year, hour, min, sec;
1084 {
1085    struct tm tm;
1086    time_t t;
1087    int days;
1088 
1089    days = _days[month - 1] + mday;
1090    year += 1980;
1091    if (leap(year) && month > 2)
1092      ++days;
1093    tm.tm_yday = days;
1094    tm.tm_mon = month - 1;
1095    tm.tm_year = year - 1900;
1096    tm.tm_hour = hour;
1097    __tzset();
1098    days += 365 * (year - 1970) + nleap (year);
1099    t = 86400L * days + 3600L * hour + 60 * min + sec + _timezone;
1100    if (_daylight && _isindst(&tm))
1101       t -= 3600;
1102    return t;
1103 }
1104 
1105 #endif /* _MSC_VER && _MSC_VER == 700 */
1106 
1107 
1108 #ifdef __WATCOMC__
1109 
1110 /* This papers over a bug in Watcom 10.6's standard library... sigh */
1111 /* Apparently it applies to both the DOS and Win32 stat()s.         */
1112 
stat_bandaid(const char * path,struct stat * buf)1113 int stat_bandaid(const char *path, struct stat *buf)
1114 {
1115   char newname[4];
1116   if (!stat(path, buf))
1117     return 0;
1118   else if (!strcmp(path, ".") || (path[0] && !strcmp(path + 1, ":."))) {
1119     strcpy(newname, path);
1120     newname[strlen(path) - 1] = '\\';   /* stat(".") fails for root! */
1121     return stat(newname, buf);
1122   } else
1123     return -1;
1124 }
1125 
1126 #endif
1127