1/* 2 Copyright (c) 1990-2009 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2009-Jan-02 or later 5 (the contents of which are also included in unzip.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 11 aosvs.c 12 13 AOS/VS-specific routines for use with Info-ZIP's UnZip 5.2 and later. 14[GRR: copied from unix.c -> undoubtedly has unnecessary stuff: delete at will] 15 16 Contains: readdir() 17 do_wild() 18 open_outfile() 19 mapattr() 20 mapname() 21 checkdir() 22 close_outfile() 23 version() <-- GRR: needs work! (Unix, not AOS/VS) 24 zvs_create() 25 zvs_credir() 26 ux_to_vs_name() 27 dgdate() 28 29 ---------------------------------------------------------------------------*/ 30 31 32#define UNZIP_INTERNAL 33#include "unzip.h" 34#include "aosvs/aosvs.h" 35#include <packets/create.h> 36#include <sys_calls.h> 37#include <paru.h> 38 39#define symlink(resname,linkname) \ 40 zvs_create(linkname,-1L,-1L,-1L,ux_to_vs_name(vs_resname,resname),$FLNK,-1,-1) 41 * file type */ 42 43#ifdef DIRENT 44# include <dirent.h> 45#else 46# ifdef SYSV 47# ifdef SYSNDIR 48# include <sys/ndir.h> 49# else 50# include <ndir.h> 51# endif 52# else /* !SYSV */ 53# ifndef NO_SYSDIR 54# include <sys/dir.h> 55# endif 56# endif /* ?SYSV */ 57# ifndef dirent 58# define dirent direct 59# endif 60#endif /* ?DIRENT */ 61 62static int created_dir; /* used in mapname(), checkdir() */ 63static int renamed_fullpath; /* ditto */ 64 65static ZEXTRAFLD zzextrafld; /* buffer for extra field containing 66 * ?FSTAT packet & ACL buffer */ 67static char vs_resname[2*$MXPL]; 68static char vs_path[2*$MXPL]; /* buf for AOS/VS pathname */ 69static char Vs_path[512]; /* should be big enough [GRR: ?] */ 70static P_CTIM zztimeblock; /* time block for file creation */ 71static ZVSCREATE_STRU zzcreatepacket; /* packet for sys_create(), any 72 73 74/***************************/ 75/* Strings used in aosvs.c */ 76/***************************/ 77 78static ZCONST char Far CannotDeleteOldFile[] = 79 "error: cannot delete old %s\n"; 80static ZCONST char Far CannotCreateFile[] = "error: cannot create %s\n"; 81 82 83#ifndef SFX 84#ifdef NO_DIR /* for AT&T 3B1 */ 85 86#define opendir(path) fopen(path,"r") 87#define closedir(dir) fclose(dir) 88typedef FILE DIR; 89 90/* 91 * Apparently originally by Rich Salz. 92 * Cleaned up and modified by James W. Birdsall. 93 */ 94struct dirent *readdir(dirp) 95 DIR *dirp; 96{ 97 static struct dirent entry; 98 99 if (dirp == NULL) 100 return NULL; 101 102 for (;;) 103 if (fread(&entry, sizeof (struct dirent), 1, dirp) == 0) 104 return (struct dirent *)NULL; 105 else if (entry.d_ino) 106 return &entry; 107 108} /* end function readdir() */ 109 110#endif /* NO_DIR */ 111 112 113/**********************/ 114/* Function do_wild() */ /* for porting: dir separator; match(ignore_case) */ 115/**********************/ 116 117char *do_wild(__G__ wildspec) 118 __GDEF 119 ZCONST char *wildspec; /* only used first time on a given dir */ 120{ 121 static DIR *wild_dir = (DIR *)NULL; 122 static ZCONST char *wildname; 123 static char *dirname, matchname[FILNAMSIZ]; 124 static int notfirstcall=FALSE, have_dirname, dirnamelen; 125 struct dirent *file; 126 127 /* Even when we're just returning wildspec, we *always* do so in 128 * matchname[]--calling routine is allowed to append four characters 129 * to the returned string, and wildspec may be a pointer to argv[]. 130 */ 131 if (!notfirstcall) { /* first call: must initialize everything */ 132 notfirstcall = TRUE; 133 134 if (!iswild(wildspec)) { 135 strncpy(matchname, wildspec, FILNAMSIZ); 136 matchname[FILNAMSIZ-1] = '\0'; 137 have_dirname = FALSE; 138 dir = NULL; 139 return matchname; 140 } 141 142 /* break the wildspec into a directory part and a wildcard filename */ 143 if ((wildname = strrchr(wildspec, '/')) == (ZCONST char *)NULL) { 144 dirname = "."; 145 dirnamelen = 1; 146 have_dirname = FALSE; 147 wildname = wildspec; 148 } else { 149 ++wildname; /* point at character after '/' */ 150 dirnamelen = wildname - wildspec; 151 if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) { 152 Info(slide, 0x201, ((char *)slide, 153 "warning: cannot allocate wildcard buffers\n")); 154 strncpy(matchname, wildspec, FILNAMSIZ); 155 matchname[FILNAMSIZ-1] = '\0'; 156 return matchname; /* but maybe filespec was not a wildcard */ 157 } 158 strncpy(dirname, wildspec, dirnamelen); 159 dirname[dirnamelen] = '\0'; /* terminate for strcpy below */ 160 have_dirname = TRUE; 161 } 162 163 if ((wild_dir = opendir(dirname)) != (DIR *)NULL) { 164 while ((file = readdir(wild_dir)) != (struct dirent *)NULL) { 165 Trace((stderr, "do_wild: readdir returns %s\n", 166 FnFilter1(file->d_name))); 167 if (file->d_name[0] == '.' && wildname[0] != '.') 168 continue; /* Unix: '*' and '?' do not match leading dot */ 169 if (match(file->d_name, wildname, 0 WISEP) && /* 0=case sens.*/ 170 /* skip "." and ".." directory entries */ 171 strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) { 172 Trace((stderr, "do_wild: match() succeeds\n")); 173 if (have_dirname) { 174 strcpy(matchname, dirname); 175 strcpy(matchname+dirnamelen, file->d_name); 176 } else 177 strcpy(matchname, file->d_name); 178 return matchname; 179 } 180 } 181 /* if we get to here directory is exhausted, so close it */ 182 closedir(wild_dir); 183 wild_dir = (DIR *)NULL; 184 } 185 186 /* return the raw wildspec in case that works (e.g., directory not 187 * searchable, but filespec was not wild and file is readable) */ 188 strncpy(matchname, wildspec, FILNAMSIZ); 189 matchname[FILNAMSIZ-1] = '\0'; 190 return matchname; 191 } 192 193 /* last time through, might have failed opendir but returned raw wildspec */ 194 if (wild_dir == (DIR *)NULL) { 195 notfirstcall = FALSE; /* nothing left to try--reset for new wildspec */ 196 if (have_dirname) 197 free(dirname); 198 return (char *)NULL; 199 } 200 201 /* If we've gotten this far, we've read and matched at least one entry 202 * successfully (in a previous call), so dirname has been copied into 203 * matchname already. 204 */ 205 while ((file = readdir(wild_dir)) != (struct dirent *)NULL) { 206 Trace((stderr, "do_wild: readdir returns %s\n", 207 FnFilter1(file->d_name))); 208 if (file->d_name[0] == '.' && wildname[0] != '.') 209 continue; /* Unix: '*' and '?' do not match leading dot */ 210 if (match(file->d_name, wildname, 0 WISEP)) { /* 0 == case sens. */ 211 Trace((stderr, "do_wild: match() succeeds\n")); 212 if (have_dirname) { 213 /* strcpy(matchname, dirname); */ 214 strcpy(matchname+dirnamelen, file->d_name); 215 } else 216 strcpy(matchname, file->d_name); 217 return matchname; 218 } 219 } 220 221 closedir(wild_dir); /* have read at least one entry; nothing left */ 222 wild_dir = (DIR *)NULL; 223 notfirstcall = FALSE; /* reset for new wildspec */ 224 if (have_dirname) 225 free(dirname); 226 return (char *)NULL; 227 228} /* end function do_wild() */ 229 230#endif /* !SFX */ 231 232 233 234 235 236/***************************/ 237/* Function open_outfile() */ 238/***************************/ 239 240int open_outfile(__G) /* return 1 if fail */ 241 __GDEF 242{ 243 int errc = 1; /* init to show no success with AOS/VS info */ 244 long dmm, ddd, dyy, dhh, dmin, dss; 245 246 247#ifdef DLL 248 if (G.redirect_data) 249 return redirect_outfile(__G)==FALSE; 250#endif 251 252 if (stat(G.filename, &G.statbuf) == 0 && unlink(G.filename) < 0) { 253 Info(slide, 0x401, ((char *)slide, LoadFarString(CannotDeleteOldFile), 254 FnFilter1(G.filename))); 255 return 1; 256 } 257 258/*--------------------------------------------------------------------------- 259 If the file didn't already exist, we created it earlier. But we just 260 deleted it, which we still had to do in case we are overwriting an exis- 261 ting file. So we must create it now, again, to set the creation time 262 properly. (The creation time is the best functional approximation of 263 the Unix mtime. Really!) 264 265 If we stored this with an AOS/VS Zip that set the extra field to contain 266 the ?FSTAT packet and the ACL, we should use info from the ?FSTAT call 267 now. Otherwise (or if that fails), we should create anyway as best we 268 can from the normal Zip info. 269 270 In theory, we should look through an entire series of extra fields that 271 might exist for the same file, but we're not going to bother. If we set 272 up other types of extra fields, or if other environments we run into may 273 add their own stuff to existing entries in Zip files, we'll have to. 274 275 Note that all the packet types for sys_fstat() are the same size & mostly 276 have the same structure, with some fields being unused, etc. Ditto for 277 sys_create(). Thus, we assume a normal one here, not a dir/cpd or device 278 or IPC file, & make little adjustments as necessary. We will set ACLs 279 later (to reduce the chance of lacking access to what we create now); note 280 that for links the resolution name should be stored in the ACL field (once 281 we get Zip recognizing links OK). 282 ---------------------------------------------------------------------------*/ 283 284 if (G.extra_field != NULL) { 285 memcpy((char *) &zzextrafld, G.extra_field, sizeof(zzextrafld)); 286 if (!memcmp(ZEXTRA_HEADID, zzextrafld.extra_header_id, 287 sizeof(zzextrafld.extra_header_id)) && 288 !memcmp(ZEXTRA_SENTINEL, zzextrafld.extra_sentinel), 289 sizeof(zzextrafld.extra_sentinel)) 290 { 291 zzcreatepacket.norm_create_packet.cftyp_format = 292 zzextrafld.fstat_packet.norm_fstat_packet.styp_format; 293 zzcreatepacket.norm_create_packet.cftyp_entry = 294 zzextrafld.fstat_packet.norm_fstat_packet.styp_type; 295 296 /* for DIRS/CPDs, the next one will give the hash frame size; for 297 * IPCs it will give the port number */ 298 zzcreatepacket.norm_create_packet.ccps = 299 zzextrafld.fstat_packet.norm_fstat_packet.scps; 300 301 zzcreatepacket.norm_create_packet.ctim = &zztimeblock; 302 zztimeblock.tcth = zzextrafld.fstat_packet.norm_fstat_packet.stch; 303 304 /* access & modification times default to current */ 305 zztimeblock.tath.long_time = zztimeblock.tmth.long_time = -1; 306 307 /* give it current process's ACL unless link; then give it 308 * resolution name */ 309 zzcreatepacket.norm_create_packet.cacp = (char *)(-1); 310 311 if (zzcreatepacket.norm_create_packet.cftyp_entry == $FLNK) 312 zzcreatepacket.norm_create_packet.cacp = zzextrafld.aclbuf; 313 314 zzcreatepacket.dir_create_packet.cmsh = 315 zzextrafld.fstat_packet.dir_fstat_packet.scsh; 316 if (zzcreatepacket.norm_create_packet.cftyp_entry != $FCPD) { 317 /* element size for normal files */ 318 zzcreatepacket.norm_create_packet.cdel = 319 zzextrafld.fstat_packet.norm_fstat_packet.sdeh; 320 } 321 zzcreatepacket.norm_create_packet.cmil = 322 zzextrafld.fstat_packet.norm_fstat_packet.smil; 323 324 if ((errc = sys_create(ux_to_vs_name(vs_path, G.filename), 325 &zzcreatepacket)) != 0) 326 Info(slide, 0x201, ((char *)slide, 327 "error creating %s with AOS/VS info -\n\ 328 will try again with ordinary Zip info\n", 329 FnFilter1(G.filename))); 330 } 331 } 332 333 /* do it the hard way if no AOS/VS info was stored or if we had problems */ 334 if (errc) { 335 /* skip restoring time stamps on user's request */ 336 if (uO.D_flag <= 1) { 337 dyy = (G.lrec.last_mod_dos_datetime >> 25) + 1980; 338 dmm = (G.lrec.last_mod_dos_datetime >> 21) & 0x0f; 339 ddd = (G.lrec.last_mod_dos_datetime >> 16) & 0x1f; 340 dhh = (G.lrec.last_mod_dos_datetime >> 11) & 0x1f; 341 dmin = (G.lrec.last_mod_dos_datetime >> 5) & 0x3f; 342 dss = (G.lrec.last_mod_dos_datetime << 1) & 0x3e; 343 } 344 345 if (zvs_create(G.filename, 346 (uO.D_flag <= 1 347 ? (((ulg)dgdate(dmm, ddd, dyy)) << 16) | 348 (dhh*1800L + dmin*30L + dss/2L) 349 : -1L), 350 -1L, -1L, (char *) -1, -1, -1, -1)) 351 { 352 Info(slide, 0x201, ((char *)slide, "error: %s: cannot create\n", 353 FnFilter1(G.filename))); 354 return 1; 355 } 356 } 357 358 Trace((stderr, "open_outfile: doing fopen(%s) for writing\n", 359 FnFilter1(G.filename))); 360 if ((G.outfile = fopen(G.filename, FOPW)) == (FILE *)NULL) { 361 Info(slide, 0x401, ((char *)slide, LoadFarString(CannotCreateFile), 362 FnFilter1(G.filename))); 363 return 1; 364 } 365 Trace((stderr, "open_outfile: fopen(%s) for writing succeeded\n", 366 FnFilter1(G.filename))); 367 368#ifdef USE_FWRITE 369#ifdef _IOFBF /* make output fully buffered (works just about like write()) */ 370 setvbuf(G.outfile, (char *)slide, _IOFBF, WSIZE); 371#else 372 setbuf(G.outfile, (char *)slide); 373#endif 374#endif /* USE_FWRITE */ 375 return 0; 376 377} /* end function open_outfile() */ 378 379 380 381 382 383/**********************/ 384/* Function mapattr() */ 385/**********************/ 386 387int mapattr(__G) 388 __GDEF 389{ 390 ulg tmp = G.crec.external_file_attributes; 391 392 G.pInfo->file_attr = 0; 393 /* initialized to 0 for check in "default" branch below... */ 394 395 switch (G.pInfo->hostnum) { 396 case AMIGA_: 397 tmp = (unsigned)(tmp>>17 & 7); /* Amiga RWE bits */ 398 G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp); 399 break; 400 case THEOS_: 401 tmp &= 0xF1FFFFFFL; 402 if ((tmp & 0xF0000000L) != 0x40000000L) 403 tmp &= 0x01FFFFFFL; /* not a dir, mask all ftype bits */ 404 else 405 tmp &= 0x41FFFFFFL; /* leave directory bit as set */ 406 /* fall through! */ 407 case UNIX_: 408 case VMS_: 409 case ACORN_: 410 case ATARI_: 411 case ATHEOS_: 412 case BEOS_: 413 case QDOS_: 414 case TANDEM_: 415 G.pInfo->file_attr = (unsigned)(tmp >> 16); 416 if (G.pInfo->file_attr != 0 || !G.extra_field) { 417 return 0; 418 } else { 419 /* Some (non-Info-ZIP) implementations of Zip for Unix and 420 * VMS (and probably others ??) leave 0 in the upper 16-bit 421 * part of the external_file_attributes field. Instead, they 422 * store file permission attributes in some extra field. 423 * As a work-around, we search for the presence of one of 424 * these extra fields and fall back to the MSDOS compatible 425 * part of external_file_attributes if one of the known 426 * e.f. types has been detected. 427 * Later, we might implement extraction of the permission 428 * bits from the VMS extra field. But for now, the work-around 429 * should be sufficient to provide "readable" extracted files. 430 * (For ASI Unix e.f., an experimental remap from the e.f. 431 * mode value IS already provided!) 432 */ 433 ush ebID; 434 unsigned ebLen; 435 uch *ef = G.extra_field; 436 unsigned ef_len = G.crec.extra_field_length; 437 int r = FALSE; 438 439 while (!r && ef_len >= EB_HEADSIZE) { 440 ebID = makeword(ef); 441 ebLen = (unsigned)makeword(ef+EB_LEN); 442 if (ebLen > (ef_len - EB_HEADSIZE)) 443 /* discoverd some e.f. inconsistency! */ 444 break; 445 switch (ebID) { 446 case EF_ASIUNIX: 447 if (ebLen >= (EB_ASI_MODE+2)) { 448 G.pInfo->file_attr = 449 (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE)); 450 /* force stop of loop: */ 451 ef_len = (ebLen + EB_HEADSIZE); 452 break; 453 } 454 /* else: fall through! */ 455 case EF_PKVMS: 456 /* "found nondecypherable e.f. with perm. attr" */ 457 r = TRUE; 458 default: 459 break; 460 } 461 ef_len -= (ebLen + EB_HEADSIZE); 462 ef += (ebLen + EB_HEADSIZE); 463 } 464 if (!r) 465 return 0; 466 } 467 /* fall through! */ 468 /* all remaining cases: expand MSDOS read-only bit into write perms */ 469 case FS_FAT_: 470 /* PKWARE's PKZip for Unix marks entries as FS_FAT_, but stores the 471 * Unix attributes in the upper 16 bits of the external attributes 472 * field, just like Info-ZIP's Zip for Unix. We try to use that 473 * value, after a check for consistency with the MSDOS attribute 474 * bits (see below). 475 */ 476 G.pInfo->file_attr = (unsigned)(tmp >> 16); 477 /* fall through! */ 478 case FS_HPFS_: 479 case FS_NTFS_: 480 case MAC_: 481 case TOPS20_: 482 default: 483 /* Ensure that DOS subdir bit is set when the entry's name ends 484 * in a '/'. Some third-party Zip programs fail to set the subdir 485 * bit for directory entries. 486 */ 487 if ((tmp & 0x10) == 0) { 488 extent fnlen = strlen(G.filename); 489 if (fnlen > 0 && G.filename[fnlen-1] == '/') 490 tmp |= 0x10; 491 } 492 /* read-only bit --> write perms; subdir bit --> dir exec bit */ 493 tmp = !(tmp & 1) << 1 | (tmp & 0x10) >> 4; 494 if ((G.pInfo->file_attr & 0700) == (unsigned)(0400 | tmp<<6)) 495 /* keep previous G.pInfo->file_attr setting, when its "owner" 496 * part appears to be consistent with DOS attribute flags! 497 */ 498 return 0; 499 G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp); 500 break; 501 } /* end switch (host-OS-created-by) */ 502 503 /* for originating systems with no concept of "group," "other," "system": */ 504 umask( (int)(tmp=umask(0)) ); /* apply mask to expanded r/w(/x) perms */ 505 G.pInfo->file_attr &= ~tmp; 506 507 return 0; 508 509} /* end function mapattr() */ 510 511 512 513 514 515/************************/ 516/* Function mapname() */ 517/************************/ 518 519int mapname(__G__ renamed) 520 __GDEF 521 int renamed; 522/* 523 * returns: 524 * MPN_OK - no problem detected 525 * MPN_INF_TRUNC - caution (truncated filename) 526 * MPN_INF_SKIP - info "skip entry" (dir doesn't exist) 527 * MPN_ERR_SKIP - error -> skip entry 528 * MPN_ERR_TOOLONG - error -> path is too long 529 * MPN_NOMEM - error (memory allocation failed) -> skip entry 530 * [also MPN_VOL_LABEL, MPN_CREATED_DIR] 531 */ 532{ 533 char pathcomp[FILNAMSIZ]; /* path-component buffer */ 534 char *pp, *cp=(char *)NULL; /* character pointers */ 535 char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */ 536#ifdef ACORN_FTYPE_NFS 537 char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */ 538 RO_extra_block *ef_spark; /* pointer Acorn FTYPE ef block */ 539#endif 540 int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */ 541 int error = MPN_OK; 542 register unsigned workch; /* hold the character being tested */ 543 544 545/*--------------------------------------------------------------------------- 546 Initialize various pointers and counters and stuff. 547 ---------------------------------------------------------------------------*/ 548 549 if (G.pInfo->vollabel) 550 return MPN_VOL_LABEL; /* can't set disk volume labels in Unix */ 551 552 /* can create path as long as not just freshening, or if user told us */ 553 G.create_dirs = (!uO.fflag || renamed); 554 555 created_dir = FALSE; /* not yet */ 556 557 /* user gave full pathname: don't prepend rootpath */ 558 renamed_fullpath = (renamed && (*G.filename == '/')); 559 560 if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM) 561 return MPN_NOMEM; /* initialize path buffer, unless no memory */ 562 563 *pathcomp = '\0'; /* initialize translation buffer */ 564 pp = pathcomp; /* point to translation buffer */ 565 if (uO.jflag) /* junking directories */ 566 cp = (char *)strrchr(G.filename, '/'); 567 if (cp == (char *)NULL) /* no '/' or not junking dirs */ 568 cp = G.filename; /* point to internal zipfile-member pathname */ 569 else 570 ++cp; /* point to start of last component of path */ 571 572/*--------------------------------------------------------------------------- 573 Begin main loop through characters in filename. 574 ---------------------------------------------------------------------------*/ 575 576 while ((workch = (uch)*cp++) != 0) { 577 578 switch (workch) { 579 case '/': /* can assume -j flag not given */ 580 *pp = '\0'; 581 if (strcmp(pathcomp, ".") == 0) { 582 /* don't bother appending "./" to the path */ 583 *pathcomp = '\0'; 584 } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) { 585 /* "../" dir traversal detected, skip over it */ 586 *pathcomp = '\0'; 587 killed_ddot = TRUE; /* set "show message" flag */ 588 } 589 /* when path component is not empty, append it now */ 590 if (*pathcomp != '\0' && 591 ((error = checkdir(__G__ pathcomp, APPEND_DIR)) 592 & MPN_MASK) > MPN_INF_TRUNC) 593 return error; 594 pp = pathcomp; /* reset conversion buffer for next piece */ 595 lastsemi = (char *)NULL; /* leave direct. semi-colons alone */ 596 break; 597 598 case ';': /* VMS version (or DEC-20 attrib?) */ 599 lastsemi = pp; 600 *pp++ = ';'; /* keep for now; remove VMS ";##" */ 601 break; /* later, if requested */ 602 603#ifdef ACORN_FTYPE_NFS 604 case ',': /* NFS filetype extension */ 605 lastcomma = pp; 606 *pp++ = ','; /* keep for now; may need to remove */ 607 break; /* later, if requested */ 608#endif 609 610#ifdef MTS 611 case ' ': /* change spaces to underscore under */ 612 *pp++ = '_'; /* MTS; leave as spaces under Unix */ 613 break; 614#endif 615 616 default: 617 /* allow European characters in filenames: */ 618 if (isprint(workch) || (128 <= workch && workch <= 254)) 619 *pp++ = (char)workch; 620 } /* end switch */ 621 622 } /* end while loop */ 623 624 /* Show warning when stripping insecure "parent dir" path components */ 625 if (killed_ddot && QCOND2) { 626 Info(slide, 0, ((char *)slide, 627 "warning: skipped \"../\" path component(s) in %s\n", 628 FnFilter1(G.filename))); 629 if (!(error & ~MPN_MASK)) 630 error = (error & MPN_MASK) | PK_WARN; 631 } 632 633/*--------------------------------------------------------------------------- 634 Report if directory was created (and no file to create: filename ended 635 in '/'), check name to be sure it exists, and combine path and name be- 636 fore exiting. 637 ---------------------------------------------------------------------------*/ 638 639 if (G.filename[strlen(G.filename) - 1] == '/') { 640 checkdir(__G__ G.filename, GETPATH); 641 if (created_dir) { 642 if (QCOND2) { 643 Info(slide, 0, ((char *)slide, " creating: %s\n", 644 FnFilter1(G.filename))); 645 } 646 /* set dir time (note trailing '/') */ 647 return (error & ~MPN_MASK) | MPN_CREATED_DIR; 648 } 649 /* dir existed already; don't look for data to extract */ 650 return (error & ~MPN_MASK) | MPN_INF_SKIP; 651 } 652 653 *pp = '\0'; /* done with pathcomp: terminate it */ 654 655 /* if not saving them, remove VMS version numbers (appended ";###") */ 656 if (!uO.V_flag && lastsemi) { 657 pp = lastsemi + 1; 658 while (isdigit((uch)(*pp))) 659 ++pp; 660 if (*pp == '\0') /* only digits between ';' and end: nuke */ 661 *lastsemi = '\0'; 662 } 663 664 /* On UNIX (and compatible systems), "." and ".." are reserved for 665 * directory navigation and cannot be used as regular file names. 666 * These reserved one-dot and two-dot names are mapped to "_" and "__". 667 */ 668 if (strcmp(pathcomp, ".") == 0) 669 *pathcomp = '_'; 670 else if (strcmp(pathcomp, "..") == 0) 671 strcpy(pathcomp, "__"); 672 673#ifdef ACORN_FTYPE_NFS 674 /* translate Acorn filetype information if asked to do so */ 675 if (uO.acorn_nfs_ext && 676 (ef_spark = (RO_extra_block *) 677 getRISCOSexfield(G.extra_field, G.lrec.extra_field_length)) 678 != (RO_extra_block *)NULL) 679 { 680 /* file *must* have a RISC OS extra field */ 681 long ft = (long)makelong(ef_spark->loadaddr); 682 /*32-bit*/ 683 if (lastcomma) { 684 pp = lastcomma + 1; 685 while (isxdigit((uch)(*pp))) ++pp; 686 if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */ 687 } 688 if ((ft & 1<<31)==0) ft=0x000FFD00; 689 sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF); 690 } 691#endif /* ACORN_FTYPE_NFS */ 692 693 if (*pathcomp == '\0') { 694 Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n", 695 FnFilter1(G.filename))); 696 return (error & ~MPN_MASK) | MPN_ERR_SKIP; 697 } 698 699 checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */ 700 checkdir(__G__ G.filename, GETPATH); 701 702 return error; 703 704} /* end function mapname() */ 705 706 707 708 709#if 0 /*========== NOTES ==========*/ 710 711 extract-to dir: a:path/ 712 buildpath: path1/path2/ ... (NULL-terminated) 713 pathcomp: filename 714 715 mapname(): 716 loop over chars in zipfile member name 717 checkdir(path component, COMPONENT | CREATEDIR) --> map as required? 718 (d:/tmp/unzip/) (disk:[tmp.unzip.) 719 (d:/tmp/unzip/jj/) (disk:[tmp.unzip.jj.) 720 (d:/tmp/unzip/jj/temp/) (disk:[tmp.unzip.jj.temp.) 721 finally add filename itself and check for existence? (could use with rename) 722 (d:/tmp/unzip/jj/temp/msg.outdir) (disk:[tmp.unzip.jj.temp]msg.outdir) 723 checkdir(name, GETPATH) --> copy path to name and free space 724 725#endif /* 0 */ 726 727 728 729 730/***********************/ 731/* Function checkdir() */ 732/***********************/ 733 734int checkdir(__G__ pathcomp, flag) 735 __GDEF 736 char *pathcomp; 737 int flag; 738/* 739 * returns: 740 * MPN_OK - no problem detected 741 * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename 742 * MPN_INF_SKIP - path doesn't exist, not allowed to create 743 * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path 744 * exists and is not a directory, but is supposed to be 745 * MPN_ERR_TOOLONG - path is too long 746 * MPN_NOMEM - can't allocate memory for filename buffers 747 */ 748{ 749 static int rootlen = 0; /* length of rootpath */ 750 static char *rootpath; /* user's "extract-to" directory */ 751 static char *buildpath; /* full path (so far) to extracted file */ 752 static char *end; /* pointer to end of buildpath ('\0') */ 753 754# define FN_MASK 7 755# define FUNCTION (flag & FN_MASK) 756 757 758 759/*--------------------------------------------------------------------------- 760 APPEND_DIR: append the path component to the path being built and check 761 for its existence. If doesn't exist and we are creating directories, do 762 so for this one; else signal success or error as appropriate. 763 ---------------------------------------------------------------------------*/ 764 765 if (FUNCTION == APPEND_DIR) { 766 int too_long = FALSE; 767#ifdef SHORT_NAMES 768 char *old_end = end; 769#endif 770 771 Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp))); 772 while ((*end = *pathcomp++) != '\0') 773 ++end; 774#ifdef SHORT_NAMES /* path components restricted to 14 chars, typically */ 775 if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */ 776 *(end = old_end + FILENAME_MAX) = '\0'; 777#endif 778 779 /* GRR: could do better check, see if overrunning buffer as we go: 780 * check end-buildpath after each append, set warning variable if 781 * within 20 of FILNAMSIZ; then if var set, do careful check when 782 * appending. Clear variable when begin new path. */ 783 784 /* next check: need to append '/', at least one-char name, '\0' */ 785 if ((end-buildpath) > FILNAMSIZ-3) 786 too_long = TRUE; /* check if extracting dir? */ 787 /* for AOS/VS, try to create so as to not use searchlist: */ 788 if ( /*SSTAT(buildpath, &G.statbuf)*/ 1) { 789 if (!G.create_dirs) { /* told not to create (freshening) */ 790 free(buildpath); 791 return MPN_INF_SKIP; /* path doesn't exist: nothing to do */ 792 } 793 if (too_long) { 794 Info(slide, 1, ((char *)slide, 795 "checkdir error: path too long: %s\n", 796 FnFilter1(buildpath))); 797 free(buildpath); 798 /* no room for filenames: fatal */ 799 return MPN_ERR_TOOLONG; 800 } 801 /* create the directory */ 802 if (zvs_credir(buildpath,-1L,-1L,-1L,(char *) -1,-1,0L,-1,-1) == -1) 803 { 804 Info(slide, 1, ((char *)slide, 805 "checkdir error: cannot create %s\n\ 806 %s\n\ 807 unable to process %s.\n", 808 FnFilter2(buildpath), 809 strerror(errno), 810 FnFilter1(G.filename))); 811 free(buildpath); 812 /* path didn't exist, tried to create, failed */ 813 return MPN_ERR_SKIP; 814 } 815 created_dir = TRUE; 816 } else if (!S_ISDIR(G.statbuf.st_mode)) { 817 Info(slide, 1, ((char *)slide, 818 "checkdir error: %s exists but is not directory\n\ 819 unable to process %s.\n", 820 FnFilter2(buildpath), FnFilter1(G.filename))); 821 free(buildpath); 822 /* path existed but wasn't dir */ 823 return MPN_ERR_SKIP; 824 } 825 if (too_long) { 826 Info(slide, 1, ((char *)slide, 827 "checkdir error: path too long: %s\n", FnFilter1(buildpath))); 828 free(buildpath); 829 /* no room for filenames: fatal */ 830 return MPN_ERR_TOOLONG; 831 } 832 *end++ = '/'; 833 *end = '\0'; 834 Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath))); 835 return MPN_OK; 836 837 } /* end if (FUNCTION == APPEND_DIR) */ 838 839/*--------------------------------------------------------------------------- 840 GETPATH: copy full path to the string pointed at by pathcomp, and free 841 buildpath. 842 ---------------------------------------------------------------------------*/ 843 844 if (FUNCTION == GETPATH) { 845 strcpy(pathcomp, buildpath); 846 Trace((stderr, "getting and freeing path [%s]\n", 847 FnFilter1(pathcomp))); 848 free(buildpath); 849 buildpath = end = (char *)NULL; 850 return MPN_OK; 851 } 852 853/*--------------------------------------------------------------------------- 854 APPEND_NAME: assume the path component is the filename; append it and 855 return without checking for existence. 856 ---------------------------------------------------------------------------*/ 857 858 if (FUNCTION == APPEND_NAME) { 859#ifdef SHORT_NAMES 860 char *old_end = end; 861#endif 862 863 Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp))); 864 while ((*end = *pathcomp++) != '\0') { 865 ++end; 866#ifdef SHORT_NAMES /* truncate name at 14 characters, typically */ 867 if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */ 868 *(end = old_end + FILENAME_MAX) = '\0'; 869#endif 870 if ((end-buildpath) >= FILNAMSIZ) { 871 *--end = '\0'; 872 Info(slide, 1, ((char *)slide, 873 "checkdir warning: path too long; truncating\n\ 874 %s\n -> %s\n", 875 FnFilter1(G.filename), FnFilter2(buildpath))); 876 return MPN_INF_TRUNC; /* filename truncated */ 877 } 878 } 879 Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath))); 880 /* could check for existence here, prompt for new name... */ 881 return MPN_OK; 882 } 883 884/*--------------------------------------------------------------------------- 885 INIT: allocate and initialize buffer space for the file currently being 886 extracted. If file was renamed with an absolute path, don't prepend the 887 extract-to path. 888 ---------------------------------------------------------------------------*/ 889 890/* GRR: for VMS and TOPS-20, add up to 13 to strlen */ 891 892 if (FUNCTION == INIT) { 893 Trace((stderr, "initializing buildpath to ")); 894 if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1)) 895 == (char *)NULL) 896 return MPN_NOMEM; 897 if ((rootlen > 0) && !renamed_fullpath) { 898 strcpy(buildpath, rootpath); 899 end = buildpath + rootlen; 900 } else { 901 *buildpath = '\0'; 902 end = buildpath; 903 } 904 Trace((stderr, "[%s]\n", FnFilter1(buildpath))); 905 return MPN_OK; 906 } 907 908/*--------------------------------------------------------------------------- 909 ROOT: if appropriate, store the path in rootpath and create it if 910 necessary; else assume it's a zipfile member and return. This path 911 segment gets used in extracting all members from every zipfile specified 912 on the command line. 913 ---------------------------------------------------------------------------*/ 914 915#if (!defined(SFX) || defined(SFX_EXDIR)) 916 if (FUNCTION == ROOT) { 917 Trace((stderr, "initializing root path to [%s]\n", 918 FnFilter1(pathcomp))); 919 if (pathcomp == (char *)NULL) { 920 rootlen = 0; 921 return MPN_OK; 922 } 923 if (rootlen > 0) /* rootpath was already set, nothing to do */ 924 return MPN_OK; 925 if ((rootlen = strlen(pathcomp)) > 0) { 926 char *tmproot; 927 928 if ((tmproot = (char *)malloc(rootlen+2)) == (char *)NULL) { 929 rootlen = 0; 930 return MPN_NOMEM; 931 } 932 strcpy(tmproot, pathcomp); 933 if (tmproot[rootlen-1] == '/') { 934 tmproot[--rootlen] = '\0'; 935 } 936 if (rootlen > 0 && (SSTAT(tmproot, &G.statbuf) || 937 !S_ISDIR(G.statbuf.st_mode))) 938 { /* path does not exist */ 939 if (!G.create_dirs /* || iswild(tmproot) */ ) { 940 free(tmproot); 941 rootlen = 0; 942 /* skip (or treat as stored file) */ 943 return MPN_INF_SKIP; 944 } 945 /* create the directory (could add loop here scanning tmproot 946 * to create more than one level, but why really necessary?) */ 947 if (zvs_credir(tmproot,-1L,-1L,-1L,(char *) -1,-1,0L,-1,-1) 948 == -1) 949 { 950 Info(slide, 1, ((char *)slide, 951 "checkdir: cannot create extraction directory: %s\n\ 952 %s\n", 953 FnFilter1(tmproot), strerror(errno))); 954 free(tmproot); 955 rootlen = 0; 956 /* path didn't exist, tried to create, and failed: */ 957 /* file exists, or 2+ subdir levels required */ 958 return MPN_ERR_SKIP; 959 } 960 } 961 tmproot[rootlen++] = '/'; 962 tmproot[rootlen] = '\0'; 963 if ((rootpath = (char *)realloc(tmproot, rootlen+1)) == NULL) { 964 free(tmproot); 965 rootlen = 0; 966 return MPN_NOMEM; 967 } 968 Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath))); 969 } 970 return MPN_OK; 971 } 972#endif /* !SFX || SFX_EXDIR */ 973 974/*--------------------------------------------------------------------------- 975 END: free rootpath, immediately prior to program exit. 976 ---------------------------------------------------------------------------*/ 977 978 if (FUNCTION == END) { 979 Trace((stderr, "freeing rootpath\n")); 980 if (rootlen > 0) { 981 free(rootpath); 982 rootlen = 0; 983 } 984 return MPN_OK; 985 } 986 987 return MPN_INVALID; /* should never reach */ 988 989} /* end function checkdir() */ 990 991 992 993 994 995/****************************/ 996/* Function close_outfile() */ 997/****************************/ 998 999void close_outfile(__G) /* GRR: change to return PK-style warning level */ 1000 __GDEF 1001{ 1002 1003/*--------------------------------------------------------------------------- 1004 If symbolic links are supported, allocate storage for a symlink control 1005 structure, put the uncompressed "data" and other required info in it, and 1006 add the structure to the "deferred symlinks" chain. Since we know it's a 1007 symbolic link to start with, we shouldn't have to worry about overflowing 1008 unsigned ints with unsigned longs. 1009 ---------------------------------------------------------------------------*/ 1010 1011#ifdef SYMLINKS 1012 if (G.symlnk) { 1013 extent ucsize = (extent)G.lrec.ucsize; 1014 /* size of the symlink entry is the sum of 1015 * (struct size (includes 1st '\0') + 1 additional trailing '\0'), 1016 * system specific attribute data size (might be 0), 1017 * and the lengths of name and link target. 1018 */ 1019 extent slnk_entrysize = (sizeof(slinkentry) + 1) + 1020 ucsize + strlen(G.filename); 1021 slinkentry *slnk_entry; 1022 1023 if (slnk_entrysize < ucsize) { 1024 Info(slide, 0x201, ((char *)slide, 1025 "warning: symbolic link (%s) failed: mem alloc overflow\n", 1026 FnFilter1(G.filename))); 1027 fclose(G.outfile); 1028 return; 1029 } 1030 1031 if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) { 1032 Info(slide, 0x201, ((char *)slide, 1033 "warning: symbolic link (%s) failed: no mem\n", 1034 FnFilter1(G.filename))); 1035 fclose(G.outfile); 1036 return; 1037 } 1038 slnk_entry->next = NULL; 1039 slnk_entry->targetlen = ucsize; 1040 slnk_entry->attriblen = 0; /* don't set attributes for symlinks */ 1041 slnk_entry->target = slnk_entry->buf; 1042 slnk_entry->fname = slnk_entry->target + ucsize + 1; 1043 strcpy(slnk_entry->fname, G.filename); 1044 1045 /* move back to the start of the file to re-read the "link data" */ 1046 rewind(G.outfile); 1047 1048 if (fread(slnk_entry->target, 1, ucsize, G.outfile) != ucsize) 1049 { 1050 Info(slide, 0x201, ((char *)slide, 1051 "warning: symbolic link (%s) failed\n", 1052 FnFilter1(G.filename))); 1053 free(slnk_entry); 1054 fclose(G.outfile); 1055 return; 1056 } 1057 fclose(G.outfile); /* close "link" file for good... */ 1058 slnk_entry->target[ucsize] = '\0'; 1059 if (QCOND2) 1060 Info(slide, 0, ((char *)slide, "-> %s ", 1061 FnFilter1(slnk_entry->target))); 1062 /* add this symlink record to the list of deferred symlinks */ 1063 if (G.slink_last != NULL) 1064 G.slink_last->next = slnk_entry; 1065 else 1066 G.slink_head = slnk_entry; 1067 G.slink_last = slnk_entry; 1068 return; 1069 } 1070#endif /* SYMLINKS */ 1071 1072 fclose(G.outfile); 1073 1074/*--------------------------------------------------------------------------- 1075 Change the file permissions from default ones to those stored in the 1076 zipfile. 1077 ---------------------------------------------------------------------------*/ 1078 1079#ifndef NO_CHMOD 1080 if (chmod(G.filename, 0xffff & G.pInfo->file_attr)) 1081 perror("chmod (file attributes) error"); 1082#endif 1083 1084/*--------------------------------------------------------------------------- 1085 AOS/VS only allows setting file times at creation but has its own permis- 1086 sions scheme which is better invoked here if the necessary information 1087 was in fact stored. In theory, we should look through an entire series 1088 of extra fields that might exist for the same file, but we're not going 1089 to bother. If we set up other types of extra fields, or if we run into 1090 other environments that add their own stuff to existing entries in ZIP 1091 files, we'll have to. NOTE: already copied extra-field stuff into 1092 zzextrafld structure when file was created. 1093 ---------------------------------------------------------------------------*/ 1094 1095 if (G.extra_field != NULL) { 1096 if (!memcmp(ZEXTRA_HEADID, zzextrafld.extra_header_id, 1097 sizeof(zzextrafld.extra_header_id)) && 1098 !memcmp(ZEXTRA_SENTINEL, zzextrafld.extra_sentinel, 1099 sizeof(zzextrafld.extra_sentinel)) && 1100 zzextrafld.fstat_packet.norm_fstat_packet.styp_type != $FLNK) 1101 /* (AOS/VS links don't have ACLs) */ 1102 { 1103 /* vs_path was set (in this case) when we created the file */ 1104 if (sys_sacl(vs_path, zzextrafld.aclbuf)) { 1105 Info(slide, 0x201, ((char *)slide, 1106 "error: cannot set ACL for %s\n", FnFilter1(G.filename))); 1107 perror("sys_sacl()"); 1108 } 1109 } 1110 } 1111} /* end function close_outfile() */ 1112 1113 1114 1115 1116#ifndef SFX 1117 1118/************************/ 1119/* Function version() */ 1120/************************/ 1121 1122void version(__G) 1123 __GDEF 1124{ 1125#if (defined(__GNUC__) && defined(NX_CURRENT_COMPILER_RELEASE)) 1126 char cc_namebuf[40]; 1127 char cc_versbuf[40]; 1128#else 1129#if (defined(CRAY) && defined(_RELEASE)) 1130 char cc_versbuf[40]; 1131#endif 1132#endif 1133#if ((defined(CRAY) || defined(cray)) && defined(_UNICOS)) 1134 char os_namebuf[40]; 1135#else 1136#if defined(__NetBSD__) 1137 char os_namebuf[40]; 1138#endif 1139#endif 1140 1141 /* Pyramid, NeXT have problems with huge macro expansion, too: no Info() */ 1142 sprintf((char *)slide, LoadFarString(CompiledWith), 1143 1144#ifdef __GNUC__ 1145# ifdef NX_CURRENT_COMPILER_RELEASE 1146 (sprintf(cc_namebuf, "NeXT DevKit %d.%02d ", 1147 NX_CURRENT_COMPILER_RELEASE/100, NX_CURRENT_COMPILER_RELEASE%100), 1148 cc_namebuf), 1149 (strlen(__VERSION__) > 8)? "(gcc)" : 1150 (sprintf(cc_versbuf, "(gcc %s)", __VERSION__), cc_versbuf), 1151# else 1152 "gcc ", __VERSION__, 1153# endif 1154#else 1155# if defined(CRAY) && defined(_RELEASE) 1156 "cc ", (sprintf(cc_versbuf, "version %d", _RELEASE), cc_versbuf), 1157# else 1158# ifdef __VERSION__ 1159# ifndef IZ_CC_NAME 1160# define IZ_CC_NAME "cc " 1161# endif 1162 IZ_CC_NAME, __VERSION__ 1163# else 1164# ifndef IZ_CC_NAME 1165# define IZ_CC_NAME "cc" 1166# endif 1167 IZ_CC_NAME, "", 1168# endif 1169# endif 1170#endif /* ?__GNUC__ */ 1171 1172#ifndef IZ_OS_NAME 1173# define IZ_OS_NAME "Unix" 1174#endif 1175 IZ_OS_NAME, 1176 1177#if defined(sgi) || defined(__sgi) 1178 " (Silicon Graphics IRIX)", 1179#else 1180#ifdef sun 1181# ifdef sparc 1182# ifdef __SVR4 1183 " (Sun SPARC/Solaris)", 1184# else /* may or may not be SunOS */ 1185 " (Sun SPARC)", 1186# endif 1187# else 1188# if defined(sun386) || defined(i386) 1189 " (Sun 386i)", 1190# else 1191# if defined(mc68020) || defined(__mc68020__) 1192 " (Sun 3)", 1193# else /* mc68010 or mc68000: Sun 2 or earlier */ 1194 " (Sun 2)", 1195# endif 1196# endif 1197# endif 1198#else 1199#ifdef __hpux 1200 " (HP/UX)", 1201#else 1202#ifdef __osf__ 1203 " (DEC OSF/1)", 1204#else 1205#ifdef _AIX 1206 " (IBM AIX)", 1207#else 1208#ifdef aiws 1209 " (IBM RT/AIX)", 1210#else 1211#if defined(CRAY) || defined(cray) 1212# ifdef _UNICOS 1213 (sprintf(os_namebuf, " (Cray UNICOS release %d)", _UNICOS), os_namebuf), 1214# else 1215 " (Cray UNICOS)", 1216# endif 1217#else 1218#if defined(uts) || defined(UTS) 1219 " (Amdahl UTS)", 1220#else 1221#ifdef NeXT 1222# ifdef mc68000 1223 " (NeXTStep/black)", 1224# else 1225 " (NeXTStep for Intel)", 1226# endif 1227#else /* the next dozen or so are somewhat order-dependent */ 1228#ifdef LINUX 1229# ifdef __ELF__ 1230 " (Linux ELF)", 1231# else 1232 " (Linux a.out)", 1233# endif 1234#else 1235#ifdef MINIX 1236 " (Minix)", 1237#else 1238#ifdef M_UNIX 1239 " (SCO Unix)", 1240#else 1241#ifdef M_XENIX 1242 " (SCO Xenix)", 1243#else 1244#ifdef __NetBSD__ 1245# ifdef NetBSD0_8 1246 (sprintf(os_namebuf, " (NetBSD 0.8%c)", (char)(NetBSD0_8 - 1 + 'A')), 1247 os_namebuf), 1248# else 1249# ifdef NetBSD0_9 1250 (sprintf(os_namebuf, " (NetBSD 0.9%c)", (char)(NetBSD0_9 - 1 + 'A')), 1251 os_namebuf), 1252# else 1253# ifdef NetBSD1_0 1254 (sprintf(os_namebuf, " (NetBSD 1.0%c)", (char)(NetBSD1_0 - 1 + 'A')), 1255 os_namebuf), 1256# else 1257 (BSD4_4 == 0.5)? " (NetBSD before 0.9)" : " (NetBSD 1.1 or later)", 1258# endif 1259# endif 1260# endif 1261#else 1262#ifdef __FreeBSD__ 1263 (BSD4_4 == 0.5)? " (FreeBSD 1.x)" : " (FreeBSD 2.0 or later)", 1264#else 1265#ifdef __bsdi__ 1266 (BSD4_4 == 0.5)? " (BSD/386 1.0)" : " (BSD/386 1.1 or later)", 1267#else 1268#ifdef __386BSD__ 1269 (BSD4_4 == 1)? " (386BSD, post-4.4 release)" : " (386BSD)", 1270#else 1271#if defined(i486) || defined(__i486) || defined(__i486__) 1272 " (Intel 486)", 1273#else 1274#if defined(i386) || defined(__i386) || defined(__i386__) 1275 " (Intel 386)", 1276#else 1277#ifdef pyr 1278 " (Pyramid)", 1279#else 1280#ifdef ultrix 1281# ifdef mips 1282 " (DEC/MIPS)", 1283# else 1284# ifdef vax 1285 " (DEC/VAX)", 1286# else /* __alpha? */ 1287 " (DEC/Alpha)", 1288# endif 1289# endif 1290#else 1291#ifdef gould 1292 " (Gould)", 1293#else 1294#ifdef MTS 1295 " (MTS)", 1296#else 1297#ifdef __convexc__ 1298 " (Convex)", 1299#else 1300 "", 1301#endif /* Convex */ 1302#endif /* MTS */ 1303#endif /* Gould */ 1304#endif /* DEC */ 1305#endif /* Pyramid */ 1306#endif /* 386 */ 1307#endif /* 486 */ 1308#endif /* 386BSD */ 1309#endif /* BSDI BSD/386 */ 1310#endif /* NetBSD */ 1311#endif /* FreeBSD */ 1312#endif /* SCO Xenix */ 1313#endif /* SCO Unix */ 1314#endif /* Minix */ 1315#endif /* Linux */ 1316#endif /* NeXT */ 1317#endif /* Amdahl */ 1318#endif /* Cray */ 1319#endif /* RT/AIX */ 1320#endif /* AIX */ 1321#endif /* OSF/1 */ 1322#endif /* HP/UX */ 1323#endif /* Sun */ 1324#endif /* SGI */ 1325 1326#ifdef __DATE__ 1327 " on ", __DATE__ 1328#else 1329 "", "" 1330#endif 1331 ); 1332 1333 (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0); 1334 1335} /* end function version() */ 1336 1337#endif /* !SFX */ 1338 1339 1340 1341 1342 1343/* =================================================================== 1344 * ZVS_CREATE() 1345 * Function to create a file with specified times. The times should be sent 1346 * as long ints in DG time format; use -1 to set to the current times. You 1347 * may also specify a pointer to the ACL, the file type (see PARU.H, and do 1348 * not specify dirs or links), the element size, and the max index level. 1349 * For all of these parameters you may use -1 to specify the default. 1350 * 1351 * Returns 0 if no error, or the error code returned by ?CREATE. 1352 * 1353 * HISTORY: 1354 * 15-dec-93 dbl 1355 * 31-may-94 dbl: added call to convert pathname to AOS/VS 1356 * 1357 * 1358 */ 1359 1360int zvs_create(ZCONST char *fname, long cretim, long modtim, long acctim, 1361 char *pacl, int ftyp, int eltsize, int maxindlev) 1362{ 1363 P_CREATE pcr_stru; 1364 P_CTIM pct_stru; 1365 1366 pcr_stru.cftyp_format = 0; /* unspecified record format */ 1367 if (ftyp == -1) /* default file type to UNX */ 1368 pcr_stru.cftyp_entry = $FUNX; 1369 else 1370 pcr_stru.cftyp_entry = ftyp; 1371 pcr_stru.ctim = &pct_stru; 1372 pcr_stru.cacp = pacl; 1373 pcr_stru.cdel = eltsize; 1374 pcr_stru.cmil = maxindlev; 1375 1376 pct_stru.tcth.long_time = cretim; 1377 pct_stru.tath.long_time = acctim; 1378 pct_stru.tmth.long_time = modtim; 1379 1380 return (sys_create(ux_to_vs_name(Vs_path, fname), &pcr_stru)); 1381 1382} /* end zvs_create() */ 1383 1384 1385 1386/* =================================================================== 1387 * ZVS_CREDIR() 1388 * Function to create a dir as specified. The times should be sent 1389 * as long ints in DG time format; use -1 to set to the current times. You 1390 * may also specify a pointer to the ACL, the file type (either $FDIR or $FCPD; see PARU.H), 1391 * the max # blocks (if a CPD), the hash frame size, and the max index level. 1392 * For all of these parameters (except for the CPD's maximum blocks), 1393 * you may use -1 to specify the default. 1394 * 1395 * (The System Call Dictionary says both that you may specify a 1396 * maximum-index-level value up to the maximum, with 0 for a contiguous 1397 * directory, and that 3 is always used for this whatever you specify.) 1398 * 1399 * If you specify anything other than CPD for the file type, DIR will 1400 * be used. 1401 * 1402 * Returns 0 if no error, or the error code returned by ?CREATE. 1403 * 1404 * HISTORY: 1405 * 1-jun-94 dbl 1406 * 1407 * 1408 */ 1409 1410int zvs_credir(ZCONST char *dname, long cretim, long modtim, long acctim, 1411 char *pacl, int ftyp, long maxblocks, int hashfsize, 1412 int maxindlev) 1413{ 1414 P_CREATE_DIR pcr_stru; 1415 P_CTIM pct_stru; 1416 1417 if (ftyp != $FCPD) /* default file type to UNX */ 1418 pcr_stru.cftyp_entry = $FDIR; 1419 else 1420 { 1421 pcr_stru.cftyp_entry = ftyp; 1422 pcr_stru.cmsh = maxblocks; 1423 } 1424 1425 pcr_stru.ctim = &pct_stru; 1426 pcr_stru.cacp = pacl; 1427 pcr_stru.chfs = hashfsize; 1428 pcr_stru.cmil = maxindlev; 1429 1430 pct_stru.tcth.long_time = cretim; 1431 pct_stru.tath.long_time = acctim; 1432 pct_stru.tmth.long_time = modtim; 1433 1434 return (sys_create(ux_to_vs_name(Vs_path, dname), &pcr_stru)); 1435 1436} /* end zvs_credir() */ 1437 1438 1439 1440/* =================================================================== 1441 * UX_TO_VS_NAME() - makes a somewhat dumb pass at converting a Unix 1442 * filename to an AOS/VS filename. This should 1443 * be just about adequate to handle the results 1444 * of similarly-simple AOS/VS-to-Unix conversions 1445 * in the ZIP program. It does not guarantee a 1446 * legal AOS/VS filename for every Unix filename; 1447 * conspicuous examples would be names with 1448 * embedded ./ and ../ (which will receive no 1449 * special treatment). 1450 * 1451 * RETURNS: pointer to the result (which is an input parameter) 1452 * 1453 * NOTE: calling code is responsible for making sure 1454 * the output buffer is big enough! 1455 * 1456 * HISTORY: 1457 * 31-may-94 dbl 1458 * 1459 */ 1460char *ux_to_vs_name(char *outname, ZCONST char *inname) 1461{ 1462 ZCONST char *ip=inname, *op=outname; 1463 1464 1465 if (ip[0] == '.') { 1466 if (ip[1] == '/') { 1467 *(op++) = '='; 1468 ip += 2; 1469 } else if (ip[1] == '.' && ip[2] == '/') { 1470 *(op++) = '^'; 1471 ip += 3; 1472 } 1473 } 1474 1475 do { 1476 if (*ip == '/') 1477 *(op++) = ':'; 1478 else if (strchr( 1479 "0123456789_$?.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 1480 *ip) != NULL) 1481 { 1482 *(op++) = *ip; 1483 } else 1484 *(op++) = '?'; 1485 1486 } while (*(ip++) != '\0'); 1487 1488 return outname; 1489 1490} /* end ux_to_vs_name() */ 1491 1492 1493 1494/* =================================================================== */ 1495 1496/* DGDATE 1497 Two functions do encode/decode dates in DG system format. 1498 1499 Usage: 1500 long value,year,month,day; 1501 1502 value=dgdate(month,day,year); 1503 undgdate(value,&month,&day,&year); [GRR: not used in UnZip: removed] 1504 1505 Notes: 1506 1507 1. DG date functions only work on dates within the range 1508 Jan 1, 1968 through Dec 31, 2099. I have tested these 1509 functions through the same range with exact agreement. 1510 For dates outside of that range, the DG system calls 1511 may return different values than these functions. 1512 1513 2. dgundate() accepts values between 0 and 48213 inclusive. 1514 These correspond to 12/31/1967 and 12/31/2099. 1515 1516 3. Both functions assume the data is in the native OS byte 1517 order. So if you're reading or writing these fields from 1518 a file that has been passed between AOS/VS and PC-DOS you 1519 will need to swap byte order. 1520 1521 4. With reference to byte order, the entire range of values 1522 supported by these functions will fit into an unsigned 1523 short int. In most cases the input or output will be 1524 in that variable type. You are better off casting the 1525 value to/from unsigned short so you only need to concern 1526 yourself with swapping two bytes instead of four. 1527 1528 Written by: Stanley J. Gula 1529 US&T, Inc. 1530 529 Main Street, Suite 1 1531 Indian Orchard, MA 01151 1532 (413)-543-3672 1533 Copyright (c) 1990 US&T, Inc. 1534 All rights reserved. 1535 1536 I hereby release these functions into the public 1537 domain. You may use these routines freely as long 1538 as the US&T copyright remains intact in the source 1539 code. 1540 1541 Stanley J. Gula July 24, 1990 1542*/ 1543 1544long motable[13]={0,31,59,90,120,151,181,212,243,273,304,334,365}; 1545 1546long yrtable[132]={ 1547 366, 731, 1096, 1461, 1827, 2192, 2557, 2922, 3288, 3653, 1548 4018, 4383, 4749, 5114, 5479, 5844, 6210, 6575, 6940, 7305, 1549 7671, 8036, 8401, 8766, 9132, 9497, 9862,10227,10593,10958, 1550 11323,11688,12054,12419,12784,13149,13515,13880,14245,14610, 1551 14976,15341,15706,16071,16437,16802,17167,17532,17898,18263, 1552 18628,18993,19359,19724,20089,20454,20820,21185,21550,21915, 1553 22281,22646,23011,23376,23742,24107,24472,24837,25203,25568, 1554 25933,26298,26664,27029,27394,27759,28125,28490,28855,29220, 1555 29586,29951,30316,30681,31047,31412,31777,32142,32508,32873, 1556 33238,33603,33969,34334,34699,35064,35430,35795,36160,36525, 1557 36891,37256,37621,37986,38352,38717,39082,39447,39813,40178, 1558 40543,40908,41274,41639,42004,42369,42735,43100,43465,43830, 1559 44196,44561,44926,45291,45657,46022,46387,46752,47118,47483, 1560 47848,48213}; 1561 1562/* Given y,m,d return # of days since 12/31/67 */ 1563long int dgdate(short mm, short dd, short yy) 1564{ 1565 long int temp; 1566 short ytmp; 1567 1568 if (mm<1 || mm>12 || dd<1 || dd>31 || yy<1968 || yy>2099) 1569 return 0L; 1570 1571 /* Figure in whole years since 1968 + whole months plus days */ 1572 temp=365L*(long)(yy-1968) + motable[mm-1] + (long)dd; 1573 1574 /* Adjust for leap years - note we don't account for skipped leap 1575 year in years divisible by 1000 but not by 4000. We're correct 1576 through the year 2099 */ 1577 temp+=(yy-1965)/4; 1578 1579 /* Correct for this year */ 1580 /* In leap years, if date is 3/1 or later, bump */ 1581 if ((yy%4==0) && (mm>2)) 1582 temp++; 1583 1584 return temp; 1585} 1586