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