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 */ 82int rmdir OF((const char *)); 83int utime OF((char *, ztimbuf *)); 84 85/* Local functions */ 86#ifndef GetFileMode 87int GetFileMode OF((char *name)); 88#endif /* !GetFileMode */ 89 90local int initDirSearch OF((char *name, ff_dir *ff_context_p)); 91local char *getVolumeLabel OF((int, ulg *, ulg *, time_t *)); 92local int wild_recurse OF((char *, char *)); 93local int procname_dos OF((char *n, int caseflag, unsigned attribs)); 94local 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 */ 100extern char *label; 101local ulg label_time = 0; 102local ulg label_mode = 0; 103local time_t label_utim = 0; 104 105/* Module level constants */ 106local ZCONST char wild_match_all[] = "*.*"; 107 108 109#ifndef GetFileMode 110int GetFileMode(char *name) 111{ 112 unsigned int attr = 0; 113 return (_dos_getfileattr(name, &attr) ? -1 : attr); 114} 115#endif /* !GetFileMode */ 116 117local 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 140local 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 183local int wild_recurse(whole, wildtail) 184char *whole; 185char *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 274int wild(w) 275char *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 324local int procname_dos(n, caseflag, attribs) 325char *n; /* name to process */ 326int caseflag; /* true to force case-sensitive match */ 327unsigned 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 455int procname(n, caseflag) 456char *n; /* name to process */ 457int caseflag; /* true to force case-sensitive match */ 458{ 459 return procname_dos(n, caseflag, MSDOS_INVALID_ATTR); 460} 461 462char *ex2in(x, isdir, pdosflag) 463char *x; /* external file name */ 464int isdir; /* input: x is a directory */ 465int *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 526char *in2ex(n) 527char *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 540void stamp(f, d) 541char *f; /* name of file to change */ 542ulg 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 564ulg filetime(f, a, n, t) 565char *f; /* name of file to get info on */ 566ulg *a; /* return value: file attributes */ 567long *n; /* return value: file size */ 568iztimes *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 637int deletedir(d) 638char *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 646int 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 695local int next_ptr = 0; 696 697typedef struct ptr_table_s { 698 zvoid far *org_ptr; 699 zvoid far *new_ptr; 700} ptr_table; 701 702local 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 710zvoid 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 731zvoid 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 759zvoid far *zcalloc (unsigned items, unsigned size) 760{ 761 return (zvoid far *)_halloc((long)items, size); 762} 763 764zvoid 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 [] 775void xit(void) 776{ 777 exit(20); 778} 779#endif 780 781local 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 807void 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 831static 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 834void 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> 972int volatile _doserrno; 973 974unsigned _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. */ 1013int _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 1022char **__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) 1032void __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 1059struct tm *localtime(const time_t *); 1060 1061struct 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 1071void __tzset(void); 1072int _isindst(struct tm *); 1073 1074extern 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 1082time_t _dtoxtime(year, month, mday, hour, min, sec) 1083int 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 1113int 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