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/* 10 * fileio.c by Mark Adler 11 */ 12#define __FILEIO_C 13 14#include "zip.h" 15 16#ifdef MACOS 17# include "helpers.h" 18#endif 19 20#include <time.h> 21 22#ifdef NO_MKTIME 23time_t mktime OF((struct tm *)); 24#endif 25 26#ifdef OSF 27#define EXDEV 18 /* avoid a bug in the DEC OSF/1 header files. */ 28#else 29#include <errno.h> 30#endif 31 32#ifdef NO_ERRNO 33extern int errno; 34#endif 35 36#if defined(VMS) || defined(TOPS20) 37# define PAD 5 38#else 39# define PAD 0 40#endif 41 42#ifdef NO_RENAME 43int rename OF((ZCONST char *, ZCONST char *)); 44#endif 45 46 47#ifndef UTIL /* the companion #endif is a bit of ways down ... */ 48 49/* Local functions */ 50local int fqcmp OF((ZCONST zvoid *, ZCONST zvoid *)); 51local int fqcmpz OF((ZCONST zvoid *, ZCONST zvoid *)); 52 53/* Local module level variables. */ 54char *label = NULL; /* global, but only used in `system'.c */ 55local struct stat zipstatb; 56#if (!defined(MACOS) && !defined(WINDLL)) 57local int zipstate = -1; 58#else 59int zipstate; 60#endif 61/* -1 unknown, 0 old zip file exists, 1 new zip file */ 62 63char *getnam(n, fp) 64char *n; /* where to put name (must have >=FNMAX+1 bytes) */ 65FILE *fp; 66/* Read a \n or \r delimited name from stdin into n, and return 67 n. If EOF, then return NULL. Also, if the name read is too big, return 68 NULL. */ 69{ 70 int c; /* last character read */ 71 char *p; /* pointer into name area */ 72 73 p = n; 74 while ((c = getc(fp)) == '\n' || c == '\r') 75 ; 76 if (c == EOF) 77 return NULL; 78 do { 79 if (p - n >= FNMAX) 80 return NULL; 81 *p++ = (char) c; 82 c = getc(fp); 83 } while (c != EOF && (c != '\n' && c != '\r')); 84#ifdef WIN32 85/* 86 * WIN32 strips off trailing spaces and periods in filenames 87 * XXX what about a filename that only consists of spaces ? 88 * Answer: on WIN32, a filename must contain at least one non-space char 89 */ 90 while (p > n) { 91 if ((c = p[-1]) != ' ' && c != '.') 92 break; 93 --p; 94 } 95#endif 96 *p = 0; 97 return n; 98} 99 100struct flist far *fexpel(f) 101struct flist far *f; /* entry to delete */ 102/* Delete the entry *f in the doubly-linked found list. Return pointer to 103 next entry to allow stepping through list. */ 104{ 105 struct flist far *t; /* temporary variable */ 106 107 t = f->nxt; 108 *(f->lst) = t; /* point last to next, */ 109 if (t != NULL) 110 t->lst = f->lst; /* and next to last */ 111 if (f->name != NULL) /* free memory used */ 112 free((zvoid *)(f->name)); 113 if (f->zname != NULL) 114 free((zvoid *)(f->zname)); 115 if (f->iname != NULL) 116 free((zvoid *)(f->iname)); 117 farfree((zvoid far *)f); 118 fcount--; /* decrement count */ 119 return t; /* return pointer to next */ 120} 121 122 123local int fqcmp(a, b) 124ZCONST zvoid *a, *b; /* pointers to pointers to found entries */ 125/* Used by qsort() to compare entries in the found list by name. */ 126{ 127 return strcmp((*(struct flist far **)a)->name, 128 (*(struct flist far **)b)->name); 129} 130 131 132local int fqcmpz(a, b) 133ZCONST zvoid *a, *b; /* pointers to pointers to found entries */ 134/* Used by qsort() to compare entries in the found list by iname. */ 135{ 136 return strcmp((*(struct flist far **)a)->iname, 137 (*(struct flist far **)b)->iname); 138} 139 140 141char *last(p, c) 142char *p; /* sequence of path components */ 143int c; /* path components separator character */ 144/* Return a pointer to the start of the last path component. For a directory 145 * name terminated by the character in c, the return value is an empty string. 146 */ 147{ 148 char *t; /* temporary variable */ 149 150 if ((t = strrchr(p, c)) != NULL) 151 return t + 1; 152 else 153#ifndef AOS_VS 154 return p; 155#else 156/* We want to allow finding of end of path in either AOS/VS-style pathnames 157 * or Unix-style pathnames. This presents a few little problems ... 158 */ 159 { 160 if (*p == '=' || *p == '^') /* like ./ and ../ respectively */ 161 return p + 1; 162 else 163 return p; 164 } 165#endif 166} 167 168 169char *msname(n) 170char *n; 171/* Reduce all path components to MSDOS upper case 8.3 style names. */ 172{ 173 int c; /* current character */ 174 int f; /* characters in current component */ 175 char *p; /* source pointer */ 176 char *q; /* destination pointer */ 177 178 p = q = n; 179 f = 0; 180 while ((c = (unsigned char)*POSTINCSTR(p)) != 0) 181 if (c == ' ' || c == ':' || c == '"' || c == '*' || c == '+' || 182 c == ',' || c == ';' || c == '<' || c == '=' || c == '>' || 183 c == '?' || c == '[' || c == ']' || c == '|') 184 continue; /* char is discarded */ 185 else if (c == '/') 186 { 187 *POSTINCSTR(q) = (char)c; 188 f = 0; /* new component */ 189 } 190#ifdef __human68k__ 191 else if (ismbblead(c) && *p) 192 { 193 if (f == 7 || f == 11) 194 f++; 195 else if (*p && f < 12 && f != 8) 196 { 197 *q++ = c; 198 *q++ = *p++; 199 f += 2; 200 } 201 } 202#endif /* __human68k__ */ 203 else if (c == '.') 204 { 205 if (f == 0) 206 continue; /* leading dots are discarded */ 207 else if (f < 9) 208 { 209 *POSTINCSTR(q) = (char)c; 210 f = 9; /* now in file type */ 211 } 212 else 213 f = 12; /* now just excess characters */ 214 } 215 else 216 if (f < 12 && f != 8) 217 { 218 f += CLEN(p); /* do until end of name or type */ 219 *POSTINCSTR(q) = (char)(to_up(c)); 220 } 221 *q = 0; 222 return n; 223} 224 225int check_dup() 226/* Sort the found list and remove duplicates. 227 Return an error code in the ZE_ class. */ 228{ 229 struct flist far *f; /* steps through found linked list */ 230 extent j, k; /* indices for s */ 231 struct flist far **s; /* sorted table */ 232 struct flist far **nodup; /* sorted table without duplicates */ 233 234 /* sort found list, remove duplicates */ 235 if (fcount) 236 { 237 extent fl_size = fcount * sizeof(struct flist far *); 238 if ((fl_size / sizeof(struct flist far *)) != fcount || 239 (s = (struct flist far **)malloc(fl_size)) == NULL) 240 return ZE_MEM; 241 for (j = 0, f = found; f != NULL; f = f->nxt) 242 s[j++] = f; 243 /* Check names as given (f->name) */ 244 qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp); 245 for (k = j = fcount - 1; j > 0; j--) 246 if (strcmp(s[j - 1]->name, s[j]->name) == 0) 247 /* remove duplicate entry from list */ 248 fexpel(s[j]); /* fexpel() changes fcount */ 249 else 250 /* copy valid entry into destination position */ 251 s[k--] = s[j]; 252 s[k] = s[0]; /* First entry is always valid */ 253 nodup = &s[k]; /* Valid entries are at end of array s */ 254 255 /* sort only valid items and check for unique internal names (f->iname) */ 256 qsort((char *)nodup, fcount, sizeof(struct flist far *), fqcmpz); 257 for (j = 1; j < fcount; j++) 258 if (strcmp(nodup[j - 1]->iname, nodup[j]->iname) == 0) 259 { 260 zipwarn(" first full name: ", nodup[j - 1]->name); 261 zipwarn(" second full name: ", nodup[j]->name); 262#ifdef EBCDIC 263 strtoebc(nodup[j]->iname, nodup[j]->iname); 264#endif 265 zipwarn("name in zip file repeated: ", nodup[j]->iname); 266#ifdef EBCDIC 267 strtoasc(nodup[j]->iname, nodup[j]->iname); 268#endif 269 return ZE_PARMS; 270 } 271 free((zvoid *)s); 272 } 273 return ZE_OK; 274} 275 276int filter(name, casesensitive) 277 char *name; 278 int casesensitive; 279 /* Scan the -R, -i and -x lists for matches to the given name. 280 Return TRUE if the name must be included, FALSE otherwise. 281 Give precedence to -x over -i and -R. 282 Note that if both R and i patterns are given then must 283 have a match for both. 284 This routine relies on the following global variables: 285 patterns array of match pattern structures 286 pcount total number of patterns 287 icount number of -i patterns 288 Rcount number of -R patterns 289 These data are set up by the command line parsing code. 290 */ 291{ 292 unsigned int n; 293 int slashes; 294 char *p, *q; 295 /* without -i patterns, every name matches the "-i select rules" */ 296 int imatch = (icount == 0); 297 /* without -R patterns, every name matches the "-R select rules" */ 298 int Rmatch = (Rcount == 0); 299 300 if (pcount == 0) return TRUE; 301 302 for (n = 0; n < pcount; n++) { 303 if (!patterns[n].zname[0]) /* it can happen... */ 304 continue; 305 p = name; 306 switch (patterns[n].select) { 307 case 'R': 308 if (Rmatch) 309 /* one -R match is sufficient, skip this pattern */ 310 continue; 311 /* With -R patterns, if the pattern has N path components (that is, 312 N-1 slashes), then we test only the last N components of name. 313 */ 314 slashes = 0; 315 for (q = patterns[n].zname; (q = MBSCHR(q, '/')) != NULL; INCSTR(q)) 316 slashes++; 317 /* The name may have M path components (M-1 slashes) */ 318 for (q = p; (q = MBSCHR(q, '/')) != NULL; INCSTR(q)) 319 slashes--; 320 /* Now, "slashes" contains the difference "N-M" between the number 321 of path components in the pattern (N) and in the name (M). 322 */ 323 if (slashes < 0) 324 /* We found "M > N" 325 --> skip the first (M-N) path components of the name. 326 */ 327 for (q = p; (q = MBSCHR(q, '/')) != NULL; INCSTR(q)) 328 if (++slashes == 0) { 329 p = q + 1; /* q points at '/', mblen("/") is 1 */ 330 break; 331 } 332 break; 333 case 'i': 334 if (imatch) 335 /* one -i match is sufficient, skip this pattern */ 336 continue; 337 break; 338 } 339 if (MATCH(patterns[n].zname, p, casesensitive)) { 340 switch (patterns[n].select) { 341 case 'x': 342 /* The -x match takes precedence over everything else */ 343 return FALSE; 344 case 'R': 345 Rmatch = TRUE; 346 break; 347 default: 348 /* this must be a type -i match */ 349 imatch = TRUE; 350 break; 351 } 352 } 353 } 354 return imatch && Rmatch; 355} 356 357int newname(name, isdir, casesensitive) 358char *name; /* name to add (or exclude) */ 359int isdir; /* true for a directory */ 360int casesensitive; /* true for case-sensitive matching */ 361/* Add (or exclude) the name of an existing disk file. Return an error 362 code in the ZE_ class. */ 363{ 364 char *iname, *zname; /* internal name, external version of iname */ 365 char *undosm; /* zname version with "-j" and "-k" options disabled */ 366 struct flist far *f; /* where in found, or new found entry */ 367 struct zlist far *z; /* where in zfiles (if found) */ 368 int dosflag; 369 370 /* Search for name in zip file. If there, mark it, else add to 371 list of new names to do (or remove from that list). */ 372 if ((iname = ex2in(name, isdir, &dosflag)) == NULL) 373 return ZE_MEM; 374 375 /* Discard directory names with zip -rj */ 376 if (*iname == '\0') { 377#ifndef AMIGA 378/* A null string is a legitimate external directory name in AmigaDOS; also, 379 * a command like "zip -r zipfile FOO:" produces an empty internal name. 380 */ 381# ifndef RISCOS 382 /* If extensions needs to be swapped, we will have empty directory names 383 instead of the original directory. For example, zipping 'c.', 'c.main' 384 should zip only 'main.c' while 'c.' will be converted to '\0' by ex2in. */ 385 386 if (pathput && !recurse) error("empty name without -j or -r"); 387 388# endif /* !RISCOS */ 389#endif /* !AMIGA */ 390 free((zvoid *)iname); 391 return ZE_OK; 392 } 393 undosm = NULL; 394 if (dosflag || !pathput) { 395 int save_dosify = dosify, save_pathput = pathput; 396 dosify = 0; 397 pathput = 1; 398 /* zname is temporarly mis-used as "undosmode" iname pointer */ 399 if ((zname = ex2in(name, isdir, NULL)) != NULL) { 400 undosm = in2ex(zname); 401 free(zname); 402 } 403 dosify = save_dosify; 404 pathput = save_pathput; 405 } 406 if ((zname = in2ex(iname)) == NULL) 407 return ZE_MEM; 408 if (undosm == NULL) 409 undosm = zname; 410 if ((z = zsearch(zname)) != NULL) { 411 if (pcount && !filter(undosm, casesensitive)) { 412 /* Do not clear z->mark if "exclude", because, when "dosify || !pathput" 413 * is in effect, two files with different filter options may hit the 414 * same z entry. 415 */ 416 if (verbose) 417 fprintf(mesg, "excluding %s\n", zname); 418 free((zvoid *)iname); 419 free((zvoid *)zname); 420 } else { 421 z->mark = 1; 422 if ((z->name = malloc(strlen(name) + 1 + PAD)) == NULL) { 423 if (undosm != zname) 424 free((zvoid *)undosm); 425 free((zvoid *)iname); 426 free((zvoid *)zname); 427 return ZE_MEM; 428 } 429 strcpy(z->name, name); 430 z->dosflag = dosflag; 431 432#ifdef FORCE_NEWNAME 433 free((zvoid *)(z->iname)); 434 z->iname = iname; 435#else 436 /* Better keep the old name. Useful when updating on MSDOS a zip file 437 * made on Unix. 438 */ 439 free((zvoid *)iname); 440 free((zvoid *)zname); 441#endif /* ? FORCE_NEWNAME */ 442 } 443 if (name == label) { 444 label = z->name; 445 } 446 } else if (pcount == 0 || filter(undosm, casesensitive)) { 447 448 /* Check that we are not adding the zip file to itself. This 449 * catches cases like "zip -m foo ../dir/foo.zip". 450 */ 451#ifndef CMS_MVS 452/* Version of stat() for CMS/MVS isn't complete enough to see if */ 453/* files match. Just let ZIP.C compare the filenames. That's good */ 454/* enough for CMS anyway since there aren't paths to worry about. */ 455 struct stat statb; 456 457 if (zipstate == -1) 458 zipstate = strcmp(zipfile, "-") != 0 && 459 stat(zipfile, &zipstatb) == 0; 460 461 if (zipstate == 1 && (statb = zipstatb, stat(name, &statb) == 0 462 && zipstatb.st_mode == statb.st_mode 463#ifdef VMS 464 && memcmp(zipstatb.st_ino, statb.st_ino, sizeof(statb.st_ino)) == 0 465 && strcmp(zipstatb.st_dev, statb.st_dev) == 0 466 && zipstatb.st_uid == statb.st_uid 467#else /* !VMS */ 468 && zipstatb.st_ino == statb.st_ino 469 && zipstatb.st_dev == statb.st_dev 470 && zipstatb.st_uid == statb.st_uid 471 && zipstatb.st_gid == statb.st_gid 472#endif /* ?VMS */ 473 && zipstatb.st_size == statb.st_size 474 && zipstatb.st_mtime == statb.st_mtime 475 && zipstatb.st_ctime == statb.st_ctime)) { 476 /* Don't compare a_time since we are reading the file */ 477 if (verbose) 478 fprintf(mesg, "file matches zip file -- skipping\n"); 479 if (undosm != zname) 480 free((zvoid *)zname); 481 if (undosm != iname) 482 free((zvoid *)undosm); 483 free((zvoid *)iname); 484 return ZE_OK; 485 } 486#endif /* CMS_MVS */ 487 488 /* allocate space and add to list */ 489 if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL || 490 fcount + 1 < fcount || 491 (f->name = malloc(strlen(name) + 1 + PAD)) == NULL) 492 { 493 if (f != NULL) 494 farfree((zvoid far *)f); 495 if (undosm != zname) 496 free((zvoid *)undosm); 497 free((zvoid *)iname); 498 free((zvoid *)zname); 499 return ZE_MEM; 500 } 501 strcpy(f->name, name); 502 f->iname = iname; 503 f->zname = zname; 504 f->dosflag = dosflag; 505 *fnxt = f; 506 f->lst = fnxt; 507 f->nxt = NULL; 508 fnxt = &f->nxt; 509 fcount++; 510 if (name == label) { 511 label = f->name; 512 } 513 } 514 if (undosm != zname) 515 free((zvoid *)undosm); 516 return ZE_OK; 517} 518 519 520ulg dostime(y, n, d, h, m, s) 521int y; /* year */ 522int n; /* month */ 523int d; /* day */ 524int h; /* hour */ 525int m; /* minute */ 526int s; /* second */ 527/* Convert the date y/n/d and time h:m:s to a four byte DOS date and 528 time (date in high two bytes, time in low two bytes allowing magnitude 529 comparison). */ 530{ 531 return y < 1980 ? DOSTIME_MINIMUM /* dostime(1980, 1, 1, 0, 0, 0) */ : 532 (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) | 533 ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1); 534} 535 536 537ulg unix2dostime(t) 538time_t *t; /* unix time to convert */ 539/* Return the Unix time t in DOS format, rounded up to the next two 540 second boundary. */ 541{ 542 time_t t_even; 543 struct tm *s; /* result of localtime() */ 544 545 t_even = (time_t)(((unsigned long)(*t) + 1) & (~1)); 546 /* Round up to even seconds. */ 547 s = localtime(&t_even); /* Use local time since MSDOS does. */ 548 if (s == (struct tm *)NULL) { 549 /* time conversion error; use current time as emergency value 550 (assuming that localtime() does at least accept this value!) */ 551 t_even = (time_t)(((unsigned long)time(NULL) + 1) & (~1)); 552 s = localtime(&t_even); 553 } 554 return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday, 555 s->tm_hour, s->tm_min, s->tm_sec); 556} 557 558int issymlnk(a) 559ulg a; /* Attributes returned by filetime() */ 560/* Return true if the attributes are those of a symbolic link */ 561{ 562#ifndef QDOS 563#ifdef S_IFLNK 564#ifdef __human68k__ 565 int *_dos_importlnenv(void); 566 567 if (_dos_importlnenv() == NULL) 568 return 0; 569#endif 570 return ((a >> 16) & S_IFMT) == S_IFLNK; 571#else /* !S_IFLNK */ 572 return (int)a & 0; /* avoid warning on unused parameter */ 573#endif /* ?S_IFLNK */ 574#else 575 return 0; 576#endif 577} 578 579#endif /* !UTIL */ 580 581 582#if (!defined(UTIL) && !defined(ZP_NEED_GEN_D2U_TIME)) 583 /* There is no need for dos2unixtime() in the ZipUtils' code. */ 584# define ZP_NEED_GEN_D2U_TIME 585#endif 586#if ((defined(OS2) || defined(VMS)) && defined(ZP_NEED_GEN_D2U_TIME)) 587 /* OS/2 and VMS use a special solution to handle time-stams of files. */ 588# undef ZP_NEED_GEN_D2U_TIME 589#endif 590#if (defined(W32_STATROOT_FIX) && !defined(ZP_NEED_GEN_D2U_TIME)) 591 /* The Win32 stat()-bandaid to fix stat'ing root directories needs 592 * dos2unixtime() to calculate the time-stamps. */ 593# define ZP_NEED_GEN_D2U_TIME 594#endif 595 596#ifdef ZP_NEED_GEN_D2U_TIME 597 598time_t dos2unixtime(dostime) 599ulg dostime; /* DOS time to convert */ 600/* Return the Unix time_t value (GMT/UTC time) for the DOS format (local) 601 * time dostime, where dostime is a four byte value (date in most significant 602 * word, time in least significant word), see dostime() function. 603 */ 604{ 605 struct tm *t; /* argument for mktime() */ 606 ZCONST time_t clock = time(NULL); 607 608 t = localtime(&clock); 609 t->tm_isdst = -1; /* let mktime() determine if DST is in effect */ 610 /* Convert DOS time to UNIX time_t format */ 611 t->tm_sec = (((int)dostime) << 1) & 0x3e; 612 t->tm_min = (((int)dostime) >> 5) & 0x3f; 613 t->tm_hour = (((int)dostime) >> 11) & 0x1f; 614 t->tm_mday = (int)(dostime >> 16) & 0x1f; 615 t->tm_mon = ((int)(dostime >> 21) & 0x0f) - 1; 616 t->tm_year = ((int)(dostime >> 25) & 0x7f) + 80; 617 618 return mktime(t); 619} 620 621#undef ZP_NEED_GEN_D2U_TIME 622#endif /* ZP_NEED_GEN_D2U_TIME */ 623 624 625#ifndef MACOS 626int destroy(f) 627char *f; /* file to delete */ 628/* Delete the file *f, returning non-zero on failure. */ 629{ 630 return unlink(f); 631} 632 633 634int replace(d, s) 635char *d, *s; /* destination and source file names */ 636/* Replace file *d by file *s, removing the old *s. Return an error code 637 in the ZE_ class. This function need not preserve the file attributes, 638 this will be done by setfileattr() later. 639 */ 640{ 641 struct stat t; /* results of stat() */ 642#if defined(CMS_MVS) 643 /* cmsmvs.h defines FOPW_TEMP as memory(hiperspace). Since memory is 644 * lost at end of run, always do copy instead of rename. 645 */ 646 int copy = 1; 647#else 648 int copy = 0; 649#endif 650 int d_exists; 651 652#if defined(VMS) || defined(CMS_MVS) 653 /* stat() is broken on VMS remote files (accessed through Decnet). 654 * This patch allows creation of remote zip files, but is not sufficient 655 * to update them or compress remote files */ 656 unlink(d); 657#else /* !(VMS || CMS_MVS) */ 658 d_exists = (LSTAT(d, &t) == 0); 659 if (d_exists) 660 { 661 /* 662 * respect existing soft and hard links! 663 */ 664 if (t.st_nlink > 1 665# ifdef S_IFLNK 666 || (t.st_mode & S_IFMT) == S_IFLNK 667# endif 668 ) 669 copy = 1; 670 else if (unlink(d)) 671 return ZE_CREAT; /* Can't erase zip file--give up */ 672 } 673#endif /* ?(VMS || CMS_MVS) */ 674#ifndef CMS_MVS 675 if (!copy) { 676 if (rename(s, d)) { /* Just move s on top of d */ 677 copy = 1; /* failed ? */ 678#if !defined(VMS) && !defined(ATARI) && !defined(AZTEC_C) 679#if !defined(CMS_MVS) && !defined(RISCOS) && !defined(QDOS) 680 /* For VMS, ATARI, AMIGA Aztec, VM_CMS, MVS, RISCOS, 681 always assume that failure is EXDEV */ 682 if (errno != EXDEV 683# ifdef THEOS 684 && errno != EEXIST 685# else 686# ifdef ENOTSAM 687 && errno != ENOTSAM /* Used at least on Turbo C */ 688# endif 689# endif 690 ) return ZE_CREAT; 691#endif /* !CMS_MVS && !RISCOS */ 692#endif /* !VMS && !ATARI && !AZTEC_C */ 693 } 694 } 695#endif /* !CMS_MVS */ 696 697 if (copy) { 698 FILE *f, *g; /* source and destination files */ 699 int r; /* temporary variable */ 700 701#ifdef RISCOS 702 if (SWI_OS_FSControl_26(s,d,0xA1)!=NULL) { 703#endif 704 705 if ((f = fopen(s, FOPR)) == NULL) { 706 fprintf(stderr," replace: can't open %s\n", s); 707 return ZE_TEMP; 708 } 709 if ((g = fopen(d, FOPW)) == NULL) 710 { 711 fclose(f); 712 return ZE_CREAT; 713 } 714 r = fcopy(f, g, (ulg)-1L); 715 fclose(f); 716 if (fclose(g) || r != ZE_OK) 717 { 718 unlink(d); 719 return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE; 720 } 721 unlink(s); 722#ifdef RISCOS 723 } 724#endif 725 } 726 return ZE_OK; 727} 728#endif /* !MACOS */ 729 730 731int getfileattr(f) 732char *f; /* file path */ 733/* Return the file attributes for file f or 0 if failure */ 734{ 735#ifdef __human68k__ 736 struct _filbuf buf; 737 738 return _dos_files(&buf, f, 0xff) < 0 ? 0x20 : buf.atr; 739#else 740 struct stat s; 741 742 return SSTAT(f, &s) == 0 ? (int) s.st_mode : 0; 743#endif 744} 745 746 747int setfileattr(f, a) 748char *f; /* file path */ 749int a; /* attributes returned by getfileattr() */ 750/* Give the file f the attributes a, return non-zero on failure */ 751{ 752#if defined(TOPS20) || defined (CMS_MVS) 753 return 0; 754#else 755#ifdef __human68k__ 756 return _dos_chmod(f, a) < 0 ? -1 : 0; 757#else 758 return chmod(f, a); 759#endif 760#endif 761} 762 763#ifndef VMS /* VMS-specific function is in VMS.C. */ 764 765char *tempname(zip) 766char *zip; /* path name of zip file to generate temp name for */ 767 768/* Return a temporary file name in its own malloc'ed space, using tempath. */ 769{ 770 char *t = zip; /* malloc'ed space for name (use zip to avoid warning) */ 771 772#ifdef CMS_MVS 773 if ((t = malloc(strlen(tempath)+L_tmpnam+2)) == NULL) 774 return NULL; 775# ifdef VM_CMS 776 tmpnam(t); 777 /* Remove filemode and replace with tempath, if any. */ 778 /* Otherwise A-disk is used by default */ 779 *(strrchr(t, ' ')+1) = '\0'; 780 if (tempath!=NULL) 781 strcat(t, tempath); 782 return t; 783# else /* !VM_CMS */ 784 /* For MVS */ 785 tmpnam(t); 786 if (tempath != NULL) 787 { 788 int l1 = strlen(t); 789 char *dot; 790 if (*t == '\'' && *(t+l1-1) == '\'' && (dot = strchr(t, '.'))) 791 { 792 /* MVS and not OE. tmpnam() returns quoted string of 5 qualifiers. 793 * First is HLQ, rest are timestamps. User can only replace HLQ. 794 */ 795 int l2 = strlen(tempath); 796 if (strchr(tempath, '.') || l2 < 1 || l2 > 8) 797 ziperr(ZE_PARMS, "On MVS and not OE, tempath (-b) can only be HLQ"); 798 memmove(t+1+l2, dot, l1+1-(dot-t)); /* shift dot ready for new hlq */ 799 memcpy(t+1, tempath, l2); /* insert new hlq */ 800 } 801 else 802 { 803 /* MVS and probably OE. tmpnam() returns filename based on TMPDIR, 804 * no point in even attempting to change it. User should modify TMPDIR 805 * instead. 806 */ 807 zipwarn("MVS, assumed to be OE, change TMPDIR instead of option -b: ", 808 tempath); 809 } 810 } 811 return t; 812# endif /* !VM_CMS */ 813#else /* !CMS_MVS */ 814#ifdef TANDEM 815 char cur_subvol [FILENAME_MAX]; 816 char temp_subvol [FILENAME_MAX]; 817 char *zptr; 818 char *ptr; 819 char *cptr = &cur_subvol[0]; 820 char *tptr = &temp_subvol[0]; 821 short err; 822 FILE *tempf; 823 int attempts; 824 825 t = (char *)malloc(NAMELEN); /* malloc here as you cannot free */ 826 /* tmpnam allocated storage later */ 827 828 zptr = strrchr(zip, TANDEM_DELIMITER); 829 830 if (zptr != NULL) { 831 /* ZIP file specifies a Subvol so make temp file there so it can just 832 be renamed at end */ 833 834 *tptr = *cptr = '\0'; 835 strcat(cptr, getenv("DEFAULTS")); 836 837 strncat(tptr, zip, _min(FILENAME_MAX, (zptr - zip)) ); /* temp subvol */ 838 strncat(t, zip, _min(NAMELEN, ((zptr - zip) + 1)) ); /* temp stem */ 839 840 err = chvol(tptr); 841 ptr = t + strlen(t); /* point to end of stem */ 842 } 843 else 844 ptr = t; 845 846 /* If two zips are running in same subvol then we can get contention problems 847 with the temporary filename. As a work around we attempt to create 848 the file here, and if it already exists we get a new temporary name */ 849 850 attempts = 0; 851 do { 852 attempts++; 853 tmpnam(ptr); /* Add filename */ 854 tempf = fopen(ptr, FOPW_TMP); /* Attempt to create file */ 855 } while (tempf == NULL && attempts < 100); 856 857 if (attempts >= 100) { 858 ziperr(ZE_TEMP, "Could not get unique temp file name"); 859 } 860 fclose(tempf); 861 862 if (zptr != NULL) { 863 err = chvol(cptr); /* Put ourself back to where we came in */ 864 } 865 866 return t; 867 868#else /* !CMS_MVS && !TANDEM */ 869/* 870 * Do something with TMPDIR, TMP, TEMP ???? 871 */ 872 if (tempath != NULL) 873 { 874 if ((t = malloc(strlen(tempath)+12)) == NULL) 875 return NULL; 876 strcpy(t, tempath); 877#if (!defined(VMS) && !defined(TOPS20)) 878# ifdef MSDOS 879 { 880 char c = (char)lastchar(t); 881 if (c != '/' && c != ':' && c != '\\') 882 strcat(t, "/"); 883 } 884# else 885# ifdef AMIGA 886 { 887 char c = (char)lastchar(t); 888 if (c != '/' && c != ':') 889 strcat(t, "/"); 890 } 891# else /* !AMIGA */ 892# ifdef RISCOS 893 if (lastchar(t) != '.') 894 strcat(t, "."); 895# else /* !RISCOS */ 896# ifdef QDOS 897 if (lastchar(t) != '_') 898 strcat(t, "_"); 899# else 900 if (lastchar(t) != '/') 901 strcat(t, "/"); 902# endif /* ?QDOS */ 903# endif /* ?RISCOS */ 904# endif /* ?AMIGA */ 905# endif /* ?MSDOS */ 906#endif /* !VMS && !TOPS20 */ 907 } 908 else 909 { 910 if ((t = malloc(12)) == NULL) 911 return NULL; 912 *t = 0; 913 } 914#ifdef NO_MKTEMP 915 { 916 char *p = t + strlen(t); 917 sprintf(p, "%08lx", (ulg)time(NULL)); 918 return t; 919 } 920#else 921 strcat(t, "ziXXXXXX"); /* must use lowercase for Linux dos file system */ 922 return mktemp(t); 923#endif /* NO_MKTEMP */ 924#endif /* TANDEM */ 925#endif /* CMS_MVS */ 926} 927 928#endif /* !VMS */ 929 930int fcopy(f, g, n) 931FILE *f, *g; /* source and destination files */ 932ulg n; /* number of bytes to copy or -1 for all */ 933/* Copy n bytes from file *f to file *g, or until EOF if (long)n == -1. 934 Return an error code in the ZE_ class. */ 935{ 936 char *b; /* malloc'ed buffer for copying */ 937 extent k; /* result of fread() */ 938 ulg m; /* bytes copied so far */ 939 940 if ((b = malloc(CBSZ)) == NULL) 941 return ZE_MEM; 942 m = 0; 943 while (n == (ulg)(-1L) || m < n) 944 { 945 if ((k = fread(b, 1, n == (ulg)(-1) ? 946 CBSZ : (n - m < CBSZ ? (extent)(n - m) : CBSZ), f)) == 0) 947 { 948 if (ferror(f)) 949 { 950 free((zvoid *)b); 951 return ZE_READ; 952 } 953 else 954 break; 955 } 956 if (fwrite(b, 1, k, g) != k) 957 { 958 free((zvoid *)b); 959 fprintf(stderr," fcopy: write error\n"); 960 return ZE_TEMP; 961 } 962 m += k; 963 } 964 free((zvoid *)b); 965 return ZE_OK; 966} 967 968#ifdef NO_RENAME 969int rename(from, to) 970ZCONST char *from; 971ZCONST char *to; 972{ 973 unlink(to); 974 if (link(from, to) == -1) 975 return -1; 976 if (unlink(from) == -1) 977 return -1; 978 return 0; 979} 980 981#endif /* NO_RENAME */ 982 983 984#ifdef ZMEM 985 986/************************/ 987/* Function memset() */ 988/************************/ 989 990/* 991 * memset - for systems without it 992 * bill davidsen - March 1990 993 */ 994 995char * 996memset(buf, init, len) 997register char *buf; /* buffer loc */ 998register int init; /* initializer */ 999register unsigned int len; /* length of the buffer */ 1000{ 1001 char *start; 1002 1003 start = buf; 1004 while (len--) *(buf++) = init; 1005 return(start); 1006} 1007 1008 1009/************************/ 1010/* Function memcpy() */ 1011/************************/ 1012 1013char * 1014memcpy(dst,src,len) /* v2.0f */ 1015register char *dst, *src; 1016register unsigned int len; 1017{ 1018 char *start; 1019 1020 start = dst; 1021 while (len--) 1022 *dst++ = *src++; 1023 return(start); 1024} 1025 1026 1027/************************/ 1028/* Function memcmp() */ 1029/************************/ 1030 1031int 1032memcmp(b1,b2,len) /* jpd@usl.edu -- 11/16/90 */ 1033register char *b1, *b2; 1034register unsigned int len; 1035{ 1036 1037 if (len) do { /* examine each byte (if any) */ 1038 if (*b1++ != *b2++) 1039 return (*((uch *)b1-1) - *((uch *)b2-1)); /* exit when miscompare */ 1040 } while (--len); 1041 1042 return(0); /* no miscompares, yield 0 result */ 1043} 1044 1045#endif /* ZMEM */ 1046