1/* 2 Copyright (c) 1990-2007 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2000-Apr-09 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 amiga.c 12 13 Amiga-specific routines for use with Info-ZIP's UnZip 5.1 and later. 14 See History.5xx for revision history. 15 16 Contents: do_wild() 17 mapattr() 18 mapname() 19 checkdir() 20 close_outfile() 21 stamp_file() 22 _abort() (Aztec C only) 23 [dateformat()] (currently not used) 24 screensize() 25 version() 26 27 ------------------------------------------------------------------------*/ 28 29 30#define UNZIP_INTERNAL 31#ifdef AZTEC_C 32# define NO_FCNTL_H 33#endif 34#include "unzip.h" 35#include "unzvers.h" 36 37/* Globular varibundus -- now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h */ 38 39/* static int created_dir; */ /* used in mapname(), checkdir() */ 40/* static int renamed_fullpath; */ /* ditto */ 41 42#define PERMS 0777 43#define MKDIR(path,mode) mkdir(path) 44 45#ifndef S_ISCRIPT /* not having one implies you have none */ 46# define S_IARCHIVE 0020 /* not modified since this bit was last set */ 47# define S_IREAD 0010 /* can be opened for reading */ 48# define S_IWRITE 0004 /* can be opened for writing */ 49# define S_IDELETE 0001 /* can be deleted */ 50#endif /* S_ISCRIPT */ 51 52#ifndef S_IRWD 53# define S_IRWD 0015 /* useful combo of Amiga privileges */ 54#endif /* !S_IRWD */ 55 56#ifndef S_IHIDDEN 57# define S_IHIDDEN 0200 /* hidden supported in future AmigaDOS (someday) */ 58#endif /* !S_HIDDEN */ 59 60#ifndef SFX 61/* Make sure the number here matches unzvers.h in the *EXACT* form */ 62/* UZ_MAJORVER "." UZ_MINORVER UZ_PATCHLEVEL vvvv No non-digits! */ 63const char version_id[] = "\0$VER: UnZip " UZ_VER_STRING " (" 64#include "env:VersionDate" 65 ")\r\n"; 66#endif /* SFX */ 67 68 69static int ispattern(ZCONST char *p) 70{ 71 register char c; 72 while (c = *p++) 73 if (c == '\\') { 74 if (!*++p) 75 return FALSE; 76 } else if (c == '?' || c == '*') 77 return TRUE; 78 else if (c == '[') { 79 for (;;) { 80 if (!(c = *p++)) 81 return FALSE; 82 else if (c == '\\') { 83 if (!*++p) 84 return FALSE; 85 } else if (c == ']') 86 return TRUE; 87 } 88 } 89 return FALSE; 90} 91 92/**********************/ 93/* Function do_wild() */ 94/**********************/ 95 96char *do_wild(__G__ wildspec) 97 __GDEF 98 ZCONST char *wildspec; /* only used first time on a given dir */ 99{ 100/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h: 101 static DIR *wild_dir = NULL; 102 static ZCONST char *wildname; 103 static char *dirname, matchname[FILNAMSIZ]; 104 static int notfirstcall = FALSE, dirnamelen; 105*/ 106 struct dirent *file; 107 BPTR lok = 0; 108 109 /* Even when we're just returning wildspec, we *always* do so in 110 * matchname[]--calling routine is allowed to append four characters 111 * to the returned string, and wildspec may be a pointer to argv[]. 112 */ 113 if (!G.notfirstcall) { /* first call: must initialize everything */ 114 G.notfirstcall = TRUE; 115 116 /* avoid needless readdir() scans: */ 117 if (!ispattern(wildspec) || 118 (lok = Lock((char *)wildspec, ACCESS_READ))) { 119 if (lok) UnLock(lok); /* ^^ we ignore wildcard chars if */ 120 G.dirnamelen = 0; /* the name matches a real file */ 121 strncpy(G.matchname, wildspec, FILNAMSIZ); 122 G.matchname[FILNAMSIZ-1] = '\0'; 123 return G.matchname; 124 } 125 126 /* break the wildspec into a directory part and a wildcard filename */ 127 if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL && 128 (G.wildname = (ZCONST char *)strrchr(wildspec, ':')) == NULL) { 129 G.dirname = ""; /* current dir */ 130 G.dirnamelen = 0; 131 G.wildname = wildspec; 132 } else { 133 ++G.wildname; /* point at character after '/' or ':' */ 134 G.dirnamelen = G.wildname - wildspec; 135 if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == NULL) { 136 Info(slide, 1, ((char *)slide, 137 "warning: cannot allocate wildcard buffers\n")); 138 strncpy(G.matchname, wildspec, FILNAMSIZ); 139 G.matchname[FILNAMSIZ-1] = '\0'; 140 return G.matchname; /* but maybe filespec was not a wildcard */ 141 } 142 strncpy(G.dirname, wildspec, G.dirnamelen); 143 G.dirname[G.dirnamelen] = '\0'; 144 } 145 146 if ((G.wild_dir = opendir(G.dirname)) != NULL) { 147 while ((file = readdir(G.wild_dir)) != NULL) { 148 if (match(file->d_name, G.wildname, 1 WISEP)) {/* ignore case */ 149 strcpy(G.matchname, G.dirname); 150 strcpy(G.matchname + G.dirnamelen, file->d_name); 151 return G.matchname; 152 } 153 } 154 /* if we get to here directory is exhausted, so close it */ 155 closedir(G.wild_dir); 156 G.wild_dir = NULL; 157 } 158 159 /* return the raw wildspec in case that works (e.g., directory not 160 * searchable, but filespec was not wild and file is readable) */ 161 strncpy(G.matchname, wildspec, FILNAMSIZ); 162 G.matchname[FILNAMSIZ-1] = '\0'; 163 return G.matchname; 164 } 165 166 /* last time through, might have failed opendir but returned raw wildspec */ 167 if (G.wild_dir == NULL) { 168 G.notfirstcall = FALSE; /* nothing left to try -- reset */ 169 if (G.dirnamelen > 0) 170 free(G.dirname); 171 return (char *)NULL; 172 } 173 174 /* If we've gotten this far, we've read and matched at least one entry 175 * successfully (in a previous call), so dirname has been copied into 176 * matchname already. 177 */ 178 while ((file = readdir(G.wild_dir)) != NULL) 179 if (match(file->d_name, G.wildname, 1 WISEP)) { /* 1 == ignore case */ 180 /* strcpy(G.matchname, dirname); */ 181 strcpy(G.matchname + G.dirnamelen, file->d_name); 182 return G.matchname; 183 } 184 185 closedir(G.wild_dir); /* have read at least one dir entry; nothing left */ 186 G.wild_dir = NULL; 187 G.notfirstcall = FALSE; /* reset for new wildspec */ 188 if (G.dirnamelen > 0) 189 free(G.dirname); 190 return (char *)NULL; 191 192} /* end function do_wild() */ 193 194 195 196 197/**********************/ 198/* Function mapattr() */ 199/**********************/ 200 201int mapattr(__G) /* Amiga version */ 202 __GDEF 203{ 204 ulg tmp = G.crec.external_file_attributes; 205 206 207 /* Amiga attributes = hsparwed = hidden, script, pure, archive, 208 * read, write, execute, delete */ 209 210 switch (G.pInfo->hostnum) { 211 case AMIGA_: 212 if ((tmp & 1) == (tmp>>18 & 1)) 213 tmp ^= 0x000F0000; /* PKAZip compatibility kluge */ 214 /* turn off archive bit for restored Amiga files */ 215 G.pInfo->file_attr = (unsigned)((tmp>>16) & (~S_IARCHIVE)); 216 break; 217 218 case UNIX_: /* preserve read, write, execute: use logical-OR of */ 219 case VMS_: /* user, group, and other; if writable, set delete bit */ 220 case ACORN_: 221 case ATARI_: 222 case ATHEOS_: 223 case BEOS_: 224 case QDOS_: 225 case TANDEM_: 226 { 227 unsigned uxattr = (unsigned)(tmp >> 16); 228 int r = FALSE; 229 230 if (uxattr == 0 && G.extra_field) { 231 /* Some (non-Info-ZIP) implementations of Zip for Unix and 232 VMS (and probably others ??) leave 0 in the upper 16-bit 233 part of the external_file_attributes field. Instead, they 234 store file permission attributes in some extra field. 235 As a work-around, we search for the presence of one of 236 these extra fields and fall back to the MSDOS compatible 237 part of external_file_attributes if one of the known 238 e.f. types has been detected. 239 Later, we might implement extraction of the permission 240 bits from the VMS extra field. But for now, the work-around 241 should be sufficient to provide "readable" extracted files. 242 (For ASI Unix e.f., an experimental remap of the e.f. 243 mode value IS already provided!) 244 */ 245 ush ebID; 246 unsigned ebLen; 247 uch *ef = G.extra_field; 248 unsigned ef_len = G.crec.extra_field_length; 249 250 while (!r && ef_len >= EB_HEADSIZE) { 251 ebID = makeword(ef); 252 ebLen = (unsigned)makeword(ef+EB_LEN); 253 if (ebLen > (ef_len - EB_HEADSIZE)) 254 /* discoverd some e.f. inconsistency! */ 255 break; 256 switch (ebID) { 257 case EF_ASIUNIX: 258 if (ebLen >= (EB_ASI_MODE+2)) { 259 uxattr = 260 (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE)); 261 /* force stop of loop: */ 262 ef_len = (ebLen + EB_HEADSIZE); 263 break; 264 } 265 /* else: fall through! */ 266 case EF_PKVMS: 267 /* "found nondecypherable e.f. with perm. attr" */ 268 r = TRUE; 269 default: 270 break; 271 } 272 ef_len -= (ebLen + EB_HEADSIZE); 273 ef += (ebLen + EB_HEADSIZE); 274 } 275 } 276 if (!r) { 277 uxattr = (( uxattr>>6 | uxattr>>3 | uxattr) & 07) << 1; 278 G.pInfo->file_attr = (unsigned)(uxattr&S_IWRITE ? 279 uxattr|S_IDELETE : uxattr); 280 break; 281 } 282 } 283 /* fall through! */ 284 285 /* all other platforms: assume read-only bit in DOS half of attribute 286 * word is set correctly ==> will become READ or READ+WRITE+DELETE */ 287 case FS_FAT_: 288 case FS_HPFS_: /* can add S_IHIDDEN check to MSDOS/OS2/NT eventually */ 289 case FS_NTFS_: 290 case MAC_: 291 case TOPS20_: 292 default: 293 G.pInfo->file_attr = (unsigned)(tmp&1? S_IREAD : S_IRWD); 294 break; 295 296 } /* end switch (host-OS-created-by) */ 297 298 G.pInfo->file_attr &= 0xff; /* mask off all but lower eight bits */ 299 return 0; 300 301} /* end function mapattr() */ 302 303 304 305 306/************************/ 307/* Function mapname() */ 308/************************/ 309 310int mapname(__G__ renamed) 311 __GDEF 312 int renamed; 313/* 314 * returns: 315 * MPN_OK - no problem detected 316 * MPN_INF_TRUNC - caution (truncated filename) 317 * MPN_INF_SKIP - info "skip entry" (dir doesn't exist) 318 * MPN_ERR_SKIP - error -> skip entry 319 * MPN_ERR_TOOLONG - error -> path is too long 320 * MPN_NOMEM - error (memory allocation failed) -> skip entry 321 * [also MPN_VOL_LABEL, MPN_CREATED_DIR] 322 */ 323{ 324 char pathcomp[FILNAMSIZ]; /* path-component buffer */ 325 char *pp, *cp=NULL; /* character pointers */ 326 char *lastsemi = NULL; /* pointer to last semi-colon in pathcomp */ 327 int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */ 328 int error = MPN_OK; 329 register unsigned workch; /* hold the character being tested */ 330 331 332/*--------------------------------------------------------------------------- 333 Initialize various pointers and counters and stuff. 334 ---------------------------------------------------------------------------*/ 335 336 if (G.pInfo->vollabel) 337 return MPN_VOL_LABEL; /* can't set disk volume labels in AmigaDOS */ 338 339 /* can create path as long as not just freshening, or if user told us */ 340 G.create_dirs = (!uO.fflag || renamed); 341 342 G.created_dir = FALSE; /* not yet */ 343 344 /* user gave full pathname: don't prepend G.rootpath */ 345#ifndef OLD_AMIGA_RENAMED 346 G.renamed_fullpath = (renamed && 347 (*G.filename == '/' || *G.filename == ':')); 348#else 349 /* supress G.rootpath even when user gave a relative pathname */ 350# if 1 351 G.renamed_fullpath = (renamed && strpbrk(G.filename, ":/"); 352# else 353 G.renamed_fullpath = (renamed && 354 (strchr(G.filename, ':') || strchr(G.filename, '/'))); 355# endif 356#endif 357 358 if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM) 359 return MPN_NOMEM; /* initialize path buffer, unless no memory */ 360 361 *pathcomp = '\0'; /* initialize translation buffer */ 362 pp = pathcomp; /* point to translation buffer */ 363 if (uO.jflag) /* junking directories */ 364 cp = (char *)strrchr(G.filename, '/'); 365 if (cp == (char *)NULL) /* no '/' or not junking dirs */ 366 cp = G.filename; /* point to internal zipfile-member pathname */ 367 else 368 ++cp; /* point to start of last component of path */ 369 370/*--------------------------------------------------------------------------- 371 Begin main loop through characters in filename. 372 ---------------------------------------------------------------------------*/ 373 374 while ((workch = (uch)*cp++) != 0) { 375 376 switch (workch) { 377 case '/': /* can assume -j flag not given */ 378 *pp = '\0'; 379 if (strcmp(pathcomp, ".") == 0) { 380 /* don't bother appending "./" to the path */ 381 *pathcomp = '\0'; 382 } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) { 383 /* "../" dir traversal detected, skip over it */ 384 *pathcomp = '\0'; 385 killed_ddot = TRUE; /* set "show message" flag */ 386 } 387 /* when path component is not empty, append it now */ 388 if (*pathcomp != '\0' && 389 ((error = checkdir(__G__ pathcomp, APPEND_DIR)) 390 & MPN_MASK) > MPN_INF_TRUNC) 391 return error; 392 pp = pathcomp; /* reset conversion buffer for next piece */ 393 lastsemi = (char *)NULL; /* leave direct. semi-colons alone */ 394 break; 395 396 case ';': /* VMS version (or DEC-20 attrib?) */ 397 lastsemi = pp; /* keep for now; remove VMS ";##" */ 398 *pp++ = (char)workch; /* later, if requested */ 399 break; 400 401 default: 402 /* allow ISO European characters in filenames: */ 403 if (isprint(workch) || (160 <= workch && workch <= 255)) 404 *pp++ = (char)workch; 405 } /* end switch */ 406 407 } /* end while loop */ 408 409 /* Show warning when stripping insecure "parent dir" path components */ 410 if (killed_ddot && QCOND2) { 411 Info(slide, 0, ((char *)slide, 412 "warning: skipped \"../\" path component(s) in %s\n", 413 FnFilter1(G.filename))); 414 if (!(error & ~MPN_MASK)) 415 error = (error & MPN_MASK) | PK_WARN; 416 } 417 418/*--------------------------------------------------------------------------- 419 Report if directory was created (and no file to create: filename ended 420 in '/'), check name to be sure it exists, and combine path and name be- 421 fore exiting. 422 ---------------------------------------------------------------------------*/ 423 424 if (G.filename[strlen(G.filename) - 1] == '/') { 425 checkdir(__G__ G.filename, GETPATH); 426 if (G.created_dir) { 427 if (QCOND2) { 428 Info(slide, 0, ((char *)slide, " creating: %s\n", 429 FnFilter1(G.filename))); 430 } 431 /* set dir time (note trailing '/') */ 432 return (error & ~MPN_MASK) | MPN_CREATED_DIR; 433 } 434 /* dir existed already; don't look for data to extract */ 435 return (error & ~MPN_MASK) | MPN_INF_SKIP; 436 } 437 438 *pp = '\0'; /* done with pathcomp: terminate it */ 439 440 /* if not saving them, remove VMS version numbers (appended ";###") */ 441 if (!uO.V_flag && lastsemi) { 442 pp = lastsemi + 1; 443 while (isdigit((uch)(*pp))) 444 ++pp; 445 if (*pp == '\0') /* only digits between ';' and end: nuke */ 446 *lastsemi = '\0'; 447 } 448 449 if (*pathcomp == '\0') { 450 Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n", 451 FnFilter1(G.filename))); 452 return (error & ~MPN_MASK) | MPN_ERR_SKIP; 453 } 454 455 error = (error & ~MPN_MASK) | checkdir(__G__ pathcomp, APPEND_NAME); 456 if ((error & MPN_MASK) == MPN_INF_TRUNC) { 457 /* GRR: OK if truncated here: warn and continue */ 458 /* (warn in checkdir?) */ 459 } 460 checkdir(__G__ G.filename, GETPATH); 461 462 return error; 463 464} /* end function mapname() */ 465 466 467 468 469/***********************/ 470/* Function checkdir() */ 471/***********************/ 472 473int checkdir(__G__ pathcomp, flag) 474 __GDEF 475 char *pathcomp; 476 int flag; 477/* 478 * returns: 479 * MPN_OK - no problem detected 480 * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename 481 * MPN_INF_SKIP - path doesn't exist, not allowed to create 482 * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path 483 * exists and is not a directory, but is supposed to be 484 * MPN_ERR_TOOLONG - path is too long 485 * MPN_NOMEM - can't allocate memory for filename buffers 486 */ 487{ 488/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h: */ 489/* static int rootlen = 0; */ /* length of rootpath */ 490/* static char *rootpath; */ /* user's "extract-to" directory */ 491/* static char *buildpath; */ /* full path (so far) to extracted file */ 492/* static char *end; */ /* pointer to end of buildpath ('\0') */ 493 494# define FN_MASK 7 495# define FUNCTION (flag & FN_MASK) 496 497 498/*--------------------------------------------------------------------------- 499 APPEND_DIR: append the path component to the path being built and check 500 for its existence. If doesn't exist and we are creating directories, do 501 so for this one; else signal success or error as appropriate. 502 ---------------------------------------------------------------------------*/ 503 504/* GRR: check path length after each segment: warn about truncation */ 505 506 if (FUNCTION == APPEND_DIR) { 507 int too_long = FALSE; 508 509 Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp))); 510 while ((*G.build_end = *pathcomp++) != '\0') 511 ++G.build_end; 512 /* Truncate components over 30 chars? Nah, the filesystem handles it. */ 513 if ((G.build_end-G.buildpath) > FILNAMSIZ-3) /* room for "/a\0" */ 514 too_long = TRUE; /* check if extracting dir? */ 515 if (SSTAT(G.buildpath, &G.statbuf)) { /* path doesn't exist */ 516 if (!G.create_dirs) { /* told not to create (freshening) */ 517 free(G.buildpath); 518 return MPN_INF_SKIP; /* path doesn't exist: nothing to do */ 519 } 520 if (too_long) { 521 Info(slide, 1, ((char *)slide, 522 "checkdir error: path too long: %s\n", 523 FnFilter1(G.buildpath))); 524 free(G.buildpath); 525 /* no room for filenames: fatal */ 526 return MPN_ERR_TOOLONG; 527 } 528 if (MKDIR(G.buildpath, 0777) == -1) { /* create the directory */ 529 Info(slide, 1, ((char *)slide, 530 "checkdir error: cannot create %s\n\ 531 unable to process %s.\n", 532 FnFilter2(G.buildpath), FnFilter1(G.filename))); 533 free(G.buildpath); 534 /* path didn't exist, tried to create, failed */ 535 return MPN_ERR_SKIP; 536 } 537 G.created_dir = TRUE; 538 } else if (!S_ISDIR(G.statbuf.st_mode)) { 539 Info(slide, 1, ((char *)slide, 540 "checkdir error: %s exists but is not directory\n\ 541 unable to process %s.\n", 542 FnFilter2(G.buildpath), FnFilter1(G.filename))); 543 free(G.buildpath); 544 /* path existed but wasn't dir */ 545 return MPN_ERR_SKIP; 546 } 547 if (too_long) { 548 Info(slide, 1, ((char *)slide, 549 "checkdir error: path too long: %s\n", FnFilter1(G.buildpath))); 550 free(G.buildpath); 551 /* no room for filenames: fatal */ 552 return MPN_ERR_TOOLONG; 553 } 554 *G.build_end++ = '/'; 555 *G.build_end = '\0'; 556 Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath))); 557 return MPN_OK; 558 559 } /* end if (FUNCTION == APPEND_DIR) */ 560 561/*--------------------------------------------------------------------------- 562 GETPATH: copy full path to the string pointed at by pathcomp, and free 563 G.buildpath. Not our responsibility to worry whether pathcomp has room. 564 ---------------------------------------------------------------------------*/ 565 566 if (FUNCTION == GETPATH) { 567 strcpy(pathcomp, G.buildpath); 568 Trace((stderr, "getting and freeing path [%s]\n", 569 FnFilter1(pathcomp))); 570 free(G.buildpath); 571 G.buildpath = G.build_end = (char *)NULL; 572 return MPN_OK; 573 } 574 575/*--------------------------------------------------------------------------- 576 APPEND_NAME: assume the path component is the filename; append it and 577 return without checking for existence. 578 ---------------------------------------------------------------------------*/ 579 580 if (FUNCTION == APPEND_NAME) { 581 Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp))); 582 while ((*G.build_end = *pathcomp++) != '\0') { 583 ++G.build_end; 584 if ((G.build_end-G.buildpath) >= FILNAMSIZ) { 585 *--G.build_end = '\0'; 586 Info(slide, 0x201, ((char *)slide, 587 "checkdir warning: path too long; truncating\n\ 588 %s\n -> %s\n", 589 FnFilter1(G.filename), FnFilter2(G.buildpath))); 590 return MPN_INF_TRUNC; /* filename truncated */ 591 } 592 } 593 Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath))); 594 /* could check for existence here, prompt for new name... */ 595 return MPN_OK; 596 } 597 598/*--------------------------------------------------------------------------- 599 INIT: allocate and initialize buffer space for the file currently being 600 extracted. If file was renamed with an absolute path, don't prepend the 601 extract-to path. 602 ---------------------------------------------------------------------------*/ 603 604 if (FUNCTION == INIT) { 605 Trace((stderr, "initializing buildpath to ")); 606 if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1)) 607 == (char *)NULL) 608 return MPN_NOMEM; 609 if ((G.rootlen > 0) && !G.renamed_fullpath) { 610 strcpy(G.buildpath, G.rootpath); 611 G.build_end = G.buildpath + G.rootlen; 612 } else { 613 *G.buildpath = '\0'; 614 G.build_end = G.buildpath; 615 } 616 Trace((stderr, "[%s]\n", FnFilter1(G.buildpath))); 617 return MPN_OK; 618 } 619 620/*--------------------------------------------------------------------------- 621 ROOT: if appropriate, store the path in G.rootpath and create it if 622 necessary; else assume it's a zipfile member and return. This path 623 segment gets used in extracting all members from every zipfile specified 624 on the command line. 625 ---------------------------------------------------------------------------*/ 626 627#if (!defined(SFX) || defined(SFX_EXDIR)) 628 if (FUNCTION == ROOT) { 629 Trace((stderr, "initializing root path to [%s]\n", 630 FnFilter1(pathcomp))); 631 if (pathcomp == (char *)NULL) { 632 G.rootlen = 0; 633 return MPN_OK; 634 } 635 if (G.rootlen > 0) /* rootpath was already set, nothing to do */ 636 return MPN_OK; 637 if ((G.rootlen = strlen(pathcomp)) > 0) { 638 if (stat(pathcomp, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) { 639 /* path does not exist */ 640 if (!G.create_dirs) { 641 G.rootlen = 0; 642 /* skip (or treat as stored file) */ 643 return MPN_INF_SKIP; 644 } 645 /* create the directory (could add loop here scanning pathcomp 646 * to create more than one level, but why really necessary?) */ 647 if (MKDIR(pathcomp, 0777) == -1) { 648 Info(slide, 1, ((char *)slide, 649 "checkdir: cannot create extraction directory: %s\n", 650 FnFilter1(pathcomp))); 651 G.rootlen = 0; 652 /* path didn't exist, tried to create, and failed: */ 653 /* file exists, or 2+ subdir levels required */ 654 return MPN_ERR_SKIP; 655 } 656 } 657 if ((G.rootpath = (char *)malloc(G.rootlen+2)) == NULL) { 658 G.rootlen = 0; 659 return MPN_NOMEM; 660 } 661 strcpy(G.rootpath, pathcomp); 662 if (G.rootpath[G.rootlen-1] != ':' && G.rootpath[G.rootlen-1] != '/') 663 G.rootpath[G.rootlen++] = '/'; 664 G.rootpath[G.rootlen] = '\0'; 665 Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath))); 666 } 667 return MPN_OK; 668 } 669#endif /* !SFX || SFX_EXDIR */ 670 671/*--------------------------------------------------------------------------- 672 END: free G.rootpath, immediately prior to program exit. 673 ---------------------------------------------------------------------------*/ 674 675 if (FUNCTION == END) { 676 Trace((stderr, "freeing rootpath\n")); 677 if (G.rootlen > 0) { 678 free(G.rootpath); 679 G.rootlen = 0; 680 } 681 return MPN_OK; 682 } 683 684 return MPN_INVALID; /* should never reach */ 685 686} /* end function checkdir() */ 687 688 689 690 691 692/**************************************/ 693/* Function close_outfile() */ 694/**************************************/ 695/* this part differs slightly with Zip */ 696/*-------------------------------------*/ 697 698void close_outfile(__G) 699 __GDEF 700{ 701 time_t m_time; 702#ifdef USE_EF_UT_TIME 703 iztimes z_utime; 704#endif 705 LONG FileDate(); 706 707 if (uO.cflag) /* can't set time or filenote on stdout */ 708 return; 709 710 /* close the file *before* setting its time under AmigaDOS */ 711 712 fclose(G.outfile); 713 714 /* skip restoring time stamps on user's request */ 715 if (uO.D_flag <= 1) { 716#ifdef USE_EF_UT_TIME 717 if (G.extra_field && 718#ifdef IZ_CHECK_TZ 719 G.tz_is_valid && 720#endif 721 (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0, 722 G.lrec.last_mod_dos_datetime, &z_utime, NULL) 723 & EB_UT_FL_MTIME)) 724 { 725 TTrace((stderr, "close_outfile: Unix e.f. modif. time = %ld\n", 726 z_utime.mtime)); 727 m_time = z_utime.mtime; 728 } else { 729 /* Convert DOS time to time_t format */ 730 m_time = dos_to_unix_time(G.lrec.last_mod_dos_datetime); 731 } 732#else /* !USE_EF_UT_TIME */ 733 /* Convert DOS time to time_t format */ 734 m_time = dos_to_unix_time(G.lrec.last_mod_dos_datetime); 735#endif /* ?USE_EF_UT_TIME */ 736 737#ifdef DEBUG 738 Info(slide, 1, ((char *)slide, "\nclose_outfile(): m_time=%s\n", 739 ctime(&m_time))); 740#endif 741 742 if (!FileDate(G.filename, &m_time)) 743 Info(slide, 1, ((char *)slide, 744 "warning: cannot set the time for %s\n", G.filename)); 745 } 746 747 /* set file perms after closing (not done at creation)--see mapattr() */ 748 749 chmod(G.filename, G.pInfo->file_attr); 750 751 /* give it a filenote from the zipfile comment, if appropriate */ 752 753 if (uO.N_flag && G.filenotes[G.filenote_slot]) { 754 SetComment(G.filename, G.filenotes[G.filenote_slot]); 755 free(G.filenotes[G.filenote_slot]); 756 G.filenotes[G.filenote_slot] = NULL; 757 } 758 759} /* end function close_outfile() */ 760 761 762#ifdef TIMESTAMP 763 764/*************************/ 765/* Function stamp_file() */ 766/*************************/ 767 768int stamp_file(fname, modtime) 769 ZCONST char *fname; 770 time_t modtime; 771{ 772 time_t m_time; 773 LONG FileDate(); 774 775 m_time = modtime; 776 return (FileDate((char *)fname, &m_time)); 777 778} /* end function stamp_file() */ 779 780#endif /* TIMESTAMP */ 781 782 783#ifndef __SASC 784/********************************************************************/ 785/* Load filedate as a separate external file; it's used by Zip, too.*/ 786/* */ 787# include "amiga/filedate.c" /* */ 788/* */ 789/********************************************************************/ 790 791/********************* do linewise with stat.c **********************/ 792 793# include "amiga/stat.c" 794/* this is the exact same stat.c used by Zip */ 795#endif /* !__SASC */ 796/* SAS/C makes separate object modules of these; there is less */ 797/* trouble that way when redefining standard library functions. */ 798 799#include <stdio.h> 800 801void _abort(void) /* called when ^C is pressed */ 802{ 803 /* echon(); */ 804 close_leftover_open_dirs(); 805 fflush(stdout); 806 fputs("\n^C\n", stderr); 807 exit(1); 808} 809 810 811/************************************************************/ 812/* function screensize() -- uses sendpkt() from filedate.c: */ 813/************************************************************/ 814 815#include <devices/conunit.h> 816#include <dos/dosextens.h> 817#include <exec/memory.h> 818#include <clib/exec_protos.h> 819 820extern long sendpkt(struct MsgPort *pid, long action, long *args, long nargs); 821 822int screensize(int *ttrows, int *ttcols) 823{ 824 BPTR fh = Output(); 825 if (fh && IsInteractive(fh)) { 826 struct ConUnit *conunit = NULL; 827 void *conp = ((struct FileHandle *) (fh << 2))->fh_Type; 828 struct InfoData *ind = AllocMem(sizeof(*ind), MEMF_PUBLIC); 829 long argp = ((unsigned long) ind) >> 2; 830 831 if (ind && conp && sendpkt(conp, ACTION_DISK_INFO, &argp, 1)) 832 conunit = (void *) ((struct IOStdReq *) ind->id_InUse)->io_Unit; 833 if (ind) 834 FreeMem(ind, sizeof(*ind)); 835 if (conunit) { 836 if (ttrows) *ttrows = conunit->cu_YMax + 1; 837 if (ttcols) *ttcols = conunit->cu_XMax + 1; 838 return 0; /* success */ 839 } 840 } 841 if (ttrows) *ttrows = INT_MAX; 842 if (ttcols) *ttcols = INT_MAX; 843 return 1; /* failure */ 844} 845 846 847#ifdef AMIGA_VOLUME_LABELS 848/* This function is for if we someday implement -$ on the Amiga. */ 849# include <dos/dosextens.h> 850# include <dos/filehandler.h> 851# include <clib/macros.h> 852 853BOOL is_floppy(ZCONST char *path) 854{ 855 BOOL okay = FALSE; 856 char devname[32], *debna; 857 ushort i; 858 BPTR lok = Lock((char *)path, ACCESS_READ), pok; 859 struct FileSysStartupMsg *fart; 860 struct DeviceNode *debb, devlist = (void *) BADDR((struct DosInfo *) 861 BADDR(DOSBase->dl_Root->rn_Info)->di_DevInfo); 862 if (!lok) 863 return FALSE; /* should not happen */ 864 if (pok = ParentDir((char *)path)) { 865 UnLock(lok); 866 UnLock(pok); 867 return FALSE; /* it's not a root directory path */ 868 } 869 Forbid(); 870 for (debb = devlist; debb; debb = BADDR(debb->dn_Next)) 871 if (debb->dn_Type == DLT_DEVICE && (debb->dn_Task == lick->fl_Task)) 872 if (fart = BADDR(debb->dn_Startup)) { 873 debna = (char *) BADDR(fart->fssm_Device) + 1; 874 if ((i = debna[-1]) > 31) i = 30; 875 strncpy(devname, debna, i); 876 devname[i] = 0; 877 okay = !strcmp(devname, "trackdisk.device") 878 || !strcmp(devname, "mfm.device") 879 || !strcmp(devname, "messydisk.device"); 880 break; /* We only support obvious floppy drives, not tricky */ 881 } /* things like removable cartrige hard drives, or */ 882 Permit(); /* any unusual kind of floppy device driver. */ 883 return okay; 884} 885#endif /* AMIGA_VOLUME_LABELS */ 886 887 888#ifndef SFX 889 890# if 0 891/* As far as I can tell, all the locales AmigaDOS 2.1 knows about all */ 892/* happen to use DF_MDY ordering, so there's no point in using this. */ 893 894/*************************/ 895/* Function dateformat() */ 896/*************************/ 897 898#include <clib/locale_protos.h> 899#ifdef AZTEC_C 900# include <pragmas/locale_lib.h> 901#endif 902 903int dateformat() 904{ 905/*--------------------------------------------------------------------------- 906 For those operating systems which support it, this function returns a 907 value which tells how national convention says that numeric dates are 908 displayed. Return values are DF_YMD, DF_DMY and DF_MDY (the meanings 909 should be fairly obvious). 910 ---------------------------------------------------------------------------*/ 911 struct Library *LocaleBase; 912 struct Locale *ll; 913 int result = DF_MDY; /* the default */ 914 915 if ((LocaleBase = OpenLibrary("locale.library", 0))) { 916 if (ll = OpenLocale(NULL)) { 917 uch *f = ll->loc_ShortDateFormat; 918 /* In this string, %y|%Y is year, %b|%B|%h|%m is month, */ 919 /* %d|%e is day day, and %D|%x is short for mo/da/yr. */ 920 if (!strstr(f, "%D") && !strstr(f, "%x")) { 921 uch *da, *mo, *yr; 922 if (!(mo = strstr(f, "%b")) && !(mo = strstr(f, "%B")) 923 && !(mo = strstr(f, "%h"))) 924 mo = strstr(f, "%m"); 925 if (!(da = strstr(f, "%d"))) 926 da = strstr(f, "%e"); 927 if (!(yr = strstr(f, "%y"))) 928 yr = strstr(f, "%Y"); 929 if (yr && yr < mo) 930 result = DF_YMD; 931 else if (da && da < mo) 932 result = DF_DMY; 933 } 934 CloseLocale(ll); 935 } 936 CloseLibrary(LocaleBase); 937 } 938 return result; 939} 940 941# endif /* 0 */ 942 943 944/************************/ 945/* Function version() */ 946/************************/ 947 948 949/* NOTE: the following include depends upon the environment 950 * variable $Workbench to be set correctly. (Set by 951 * default, by kickstart during startup) 952 */ 953int WBversion = (int) 954#include "ENV:Workbench" 955; 956 957void version(__G) 958 __GDEF 959{ 960/* Define buffers. */ 961 962 char buf1[16]; /* compiler name */ 963 char buf2[16]; /* revstamp */ 964 char buf3[16]; /* OS */ 965 char buf4[16]; /* Date */ 966/* char buf5[16]; /* Time */ 967 968/* format "with" name strings */ 969 970#ifdef AMIGA 971# ifdef __SASC 972 strcpy(buf1,"SAS/C "); 973# else 974# ifdef LATTICE 975 strcpy(buf1,"Lattice C "); 976# else 977# ifdef AZTEC_C 978 strcpy(buf1,"Manx Aztec C "); 979# else 980 strcpy(buf1,"UNKNOWN "); 981# endif 982# endif 983# endif 984/* "under" */ 985 sprintf(buf3,"AmigaDOS v%d",WBversion); 986#else 987 strcpy(buf1,"Unknown compiler "); 988 strcpy(buf3,"Unknown OS"); 989#endif 990 991/* Define revision, date, and time strings. 992 * NOTE: Do not calculate run time, be sure to use time compiled. 993 * Pass these strings via your makefile if undefined. 994 */ 995 996#if defined(__VERSION__) && defined(__REVISION__) 997 sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__); 998#else 999# ifdef __VERSION__ 1000 sprintf(buf2,"version %d",__VERSION__); 1001# else 1002 sprintf(buf2,"unknown version"); 1003# endif 1004#endif 1005 1006#ifdef __DATE__ 1007 sprintf(buf4," on %s",__DATE__); 1008#else 1009 strcpy(buf4," unknown date"); 1010#endif 1011 1012/****** 1013#ifdef __TIME__ 1014 sprintf(buf5," at %s",__TIME__); 1015#else 1016 strcpy(buf5," unknown time"); 1017#endif 1018******/ 1019 1020/* Print strings using "CompiledWith" mask defined in unzip.c (used by all). 1021 * ("Compiled with %s%s for %s%s%s%s.") 1022 */ 1023 1024 printf(LoadFarString(CompiledWith), 1025 buf1, 1026 buf2, 1027 buf3, 1028 buf4, 1029 "", /* buf5 not used */ 1030 "" ); /* buf6 not used */ 1031 1032} /* end function version() */ 1033 1034#endif /* !SFX */ 1035