home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / unzip / part08 < prev    next >
Internet Message Format  |  1994-09-19  |  71KB

  1. From: zip-bugs@wkuvx1.wku.edu (Info-ZIP group)
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i073:  unzip - Info-ZIP portable UnZip, version 5.12, Part08/20
  4. Date: 18 Sep 1994 23:15:22 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <35j38q$qo0@sparky.sterling.com>
  9. X-Md4-Signature: f330b237a5d9fd3100d029d904b846f7
  10.  
  11. Submitted-by: zip-bugs@wkuvx1.wku.edu (Info-ZIP group)
  12. Posting-number: Volume 44, Issue 73
  13. Archive-name: unzip/part08
  14. Environment: UNIX, VMS, OS/2, MS-DOS, MACINTOSH, WIN-NT, LINUX, MINIX, COHERENT, AMIGA?, ATARI TOS, SGI, DEC, Cray, Convex, Amdahl, Sun
  15. Supersedes: unzip50: Volume 31, Issue 104-117
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # Contents:  unzip-5.12/amiga/amiga.c unzip-5.12/nt/nt.c
  22. # Wrapped by kent@sparky on Sat Sep 17 23:33:40 1994
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 8 (of 20)."'
  26. if test -f 'unzip-5.12/amiga/amiga.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'unzip-5.12/amiga/amiga.c'\"
  28. else
  29.   echo shar: Extracting \"'unzip-5.12/amiga/amiga.c'\" \(25728 characters\)
  30.   sed "s/^X//" >'unzip-5.12/amiga/amiga.c' <<'END_OF_FILE'
  31. X/*------------------------------------------------------------------------
  32. X
  33. X  amiga.c
  34. X
  35. X  Amiga-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  36. X  See History.5xx for revision history.
  37. X
  38. X  Contents:   mapattr()
  39. X              mapname()
  40. X              do_wild()
  41. X              checkdir()
  42. X              cmptime()
  43. X              invlocal()
  44. X              close_outfile()
  45. X              _abort()         (Aztec C only)
  46. X              version()
  47. X
  48. X  ------------------------------------------------------------------------*/
  49. X
  50. X
  51. X#include "unzip.h"
  52. X
  53. X/* Globular varibundus */
  54. X
  55. Xstatic int created_dir;      /* used in mapname(), checkdir() */
  56. Xstatic int renamed_fullpath; /* ditto */
  57. X#define PERMS   0777
  58. X#define MKDIR(path,mode) mkdir(path)
  59. X
  60. X
  61. X#ifndef S_ISCRIPT          /* not having one implies you have none */
  62. X#  define S_IARCHIVE 0020  /* not modified since this bit was last set */
  63. X#  define S_IREAD    0010  /* can be opened for reading */
  64. X#  define S_IWRITE   0004  /* can be opened for writing */
  65. X#  define S_IDELETE  0001  /* can be deleted */
  66. X#endif /* S_ISCRIPT */
  67. X
  68. X#ifndef S_IRWD
  69. X#  define S_IRWD     0015  /* useful combo of Amiga privileges */
  70. X#endif /* !S_IRWD */
  71. X
  72. X#ifndef S_IHIDDEN
  73. X#  define S_IHIDDEN  0200  /* hidden supported in future AmigaDOS (someday) */
  74. X#endif /* !S_HIDDEN */
  75. X
  76. X
  77. X
  78. X/**********************/
  79. X/* Function mapattr() */
  80. X/**********************/
  81. X
  82. Xint mapattr(void)      /* Amiga version */
  83. X{
  84. X    ulg  tmp = crec.external_file_attributes;
  85. X
  86. X
  87. X    /* Amiga attributes = hsparwed = hidden, script, pure, archive,
  88. X     * read, write, execute, delete */
  89. X
  90. X    switch (pInfo->hostnum) {
  91. X        case AMIGA_:
  92. X            if ((tmp & 1) == (tmp>>18 & 1))
  93. X                tmp ^= 0x000F0000;      /* PKAZip compatibility kluge */
  94. X            /* turn off archive bit for restored Amiga files */
  95. X            pInfo->file_attr = (unsigned)((tmp>>16) & (~S_IARCHIVE));
  96. X            break;
  97. X
  98. X        case UNIX_:   /* preserve read, write, execute:  use logical-OR of */
  99. X        case VMS_:    /* user, group, and other; if writable, set delete bit */
  100. X            tmp >>= 16;
  101. X            tmp = (( tmp>>6 | tmp>>3 | tmp) & 07) << 1;
  102. X            pInfo->file_attr = (unsigned)(tmp&S_IWRITE? tmp|S_IDELETE : tmp);
  103. X            break;
  104. X
  105. X        /* all other platforms:  assume read-only bit in DOS half of attribute
  106. X         * word is set correctly ==> will become READ or READ+WRITE+DELETE */
  107. X        case FS_FAT_:
  108. X        case FS_HPFS_:  /* can add S_IHIDDEN check to MSDOS/OS2/NT eventually */
  109. X        case FS_NTFS_:
  110. X        case MAC_:
  111. X        case ATARI_:
  112. X        case TOPS20_:
  113. X        default:
  114. X            pInfo->file_attr = (unsigned)(tmp&1? S_IREAD : S_IRWD); 
  115. X            break;
  116. X
  117. X    } /* end switch (host-OS-created-by) */
  118. X
  119. X    pInfo->file_attr &= 0xff;   /* mask off all but lower eight bits */
  120. X    return 0;
  121. X
  122. X} /* end function mapattr() */
  123. X
  124. X
  125. X
  126. X
  127. X/************************/
  128. X/*  Function mapname()  */
  129. X/************************/
  130. X
  131. Xint mapname(renamed)  /* return 0 if no error, 1 if caution (filename trunc), */
  132. X    int renamed;      /* 2 if warning (skip file because dir doesn't exist), */
  133. X{                     /* 3 if error (skip file), 10 if no memory (skip file) */
  134. X    char pathcomp[FILNAMSIZ];   /* path-component buffer */
  135. X    char *pp, *cp=NULL;         /* character pointers */
  136. X    char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  137. X    int quote = FALSE;          /* flags */
  138. X    int error = 0;
  139. X    register unsigned workch;   /* hold the character being tested */
  140. X
  141. X
  142. X/*---------------------------------------------------------------------------
  143. X    Initialize various pointers and counters and stuff.
  144. X  ---------------------------------------------------------------------------*/
  145. X
  146. X    /* can create path as long as not just freshening, or if user told us */
  147. X    create_dirs = (!fflag || renamed);
  148. X
  149. X    created_dir = FALSE;        /* not yet */
  150. X
  151. X    /* user gave full pathname:  don't prepend rootpath */
  152. X    renamed_fullpath = (renamed && strchr(filename, ':'));
  153. X
  154. X    if (checkdir((char *)NULL, INIT) == 10)
  155. X        return 10;              /* initialize path buffer, unless no memory */
  156. X
  157. X    *pathcomp = '\0';           /* initialize translation buffer */
  158. X    pp = pathcomp;              /* point to translation buffer */
  159. X    if (jflag)                  /* junking directories */
  160. X        cp = (char *)strrchr(filename, '/');
  161. X    if (cp == NULL)             /* no '/' or not junking dirs */
  162. X        cp = filename;          /* point to internal zipfile-member pathname */
  163. X    else
  164. X        ++cp;                   /* point to start of last component of path */
  165. X
  166. X/*---------------------------------------------------------------------------
  167. X    Begin main loop through characters in filename.
  168. X  ---------------------------------------------------------------------------*/
  169. X
  170. X    while ((workch = (uch)*cp++) != 0) {
  171. X
  172. X        if (quote) {                 /* if character quoted, */
  173. X            *pp++ = (char)workch;    /*  include it literally */
  174. X            quote = FALSE;
  175. X        } else
  176. X            switch (workch) {
  177. X            case '/':             /* can assume -j flag not given */
  178. X                *pp = '\0';
  179. X                if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
  180. X                    return error;
  181. X                pp = pathcomp;    /* reset conversion buffer for next piece */
  182. X                lastsemi = NULL;  /* leave directory semi-colons alone */
  183. X                break;
  184. X
  185. X            case ';':             /* VMS version (or DEC-20 attrib?) */
  186. X                lastsemi = pp;         /* keep for now; remove VMS ";##" */
  187. X                *pp++ = (char)workch;  /*  later, if requested */
  188. X                break;
  189. X
  190. X            case '\026':          /* control-V quote for special chars */
  191. X                quote = TRUE;     /* set flag for next character */
  192. X                break;
  193. X
  194. X            default:
  195. X                /* allow European characters in filenames: */
  196. X                if (isprint(workch) || (128 <= workch && workch <= 255))
  197. X                    *pp++ = (char)workch;
  198. X            } /* end switch */
  199. X
  200. X    } /* end while loop */
  201. X
  202. X    *pp = '\0';                   /* done with pathcomp:  terminate it */
  203. X
  204. X    /* if not saving them, remove with VMS version numbers (appended ";###") */
  205. X    if (!V_flag && lastsemi) {
  206. X        pp = lastsemi + 1;
  207. X        while (isdigit((uch)(*pp)))
  208. X            ++pp;
  209. X        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  210. X            *lastsemi = '\0';
  211. X    }
  212. X
  213. X/*---------------------------------------------------------------------------
  214. X    Report if directory was created (and no file to create:  filename ended
  215. X    in '/'), check name to be sure it exists, and combine path and name be-
  216. X    fore exiting.
  217. X  ---------------------------------------------------------------------------*/
  218. X
  219. X    if (filename[strlen(filename) - 1] == '/') {
  220. X        if (checkdir(filename, GETPATH) == 1) {
  221. X            fprintf(stderr, "pathname too long:  truncat{ed/ing}\n");
  222. X            return 1;  /* GRR:  NEEDS WORK! (do checking only when appending) */
  223. X        }
  224. X        if (created_dir && QCOND2) {
  225. X            fprintf(stdout, "   creating: %s\n", filename);
  226. X            return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  227. X        }
  228. X        return 2;   /* dir existed already; don't look for data to extract */
  229. X    }
  230. X
  231. X    if (*pathcomp == '\0') {
  232. X        fprintf(stderr, "mapname:  conversion of %s failed\n", filename);
  233. X        return 3;
  234. X    }
  235. X
  236. X    if ((error = checkdir(pathcomp, APPEND_NAME)) == 1) {
  237. X        /* GRR:  OK if truncated here:  warn and continue */
  238. X        /* (warn in checkdir?) */
  239. X    }
  240. X    checkdir(filename, GETPATH);
  241. X
  242. X    return error;
  243. X
  244. X} /* end function mapname() */
  245. X
  246. X
  247. Xstatic int ispattern(char *p)
  248. X{
  249. X    register char c;
  250. X    while (c = *p++)
  251. X    if (c == '\\') {
  252. X        if (!*++p)
  253. X        return FALSE;
  254. X        } else if (c == '?' || c == '*')
  255. X            return TRUE;
  256. X        else if (c == '[') {
  257. X            for (;;) {
  258. X                if (!(c = *p++))
  259. X                    return FALSE;
  260. X                else if (c == '\\') {
  261. X                    if (!*++p)
  262. X            return FALSE;
  263. X                } else if (c == ']')
  264. X                    return TRUE;
  265. X            }
  266. X        }
  267. X    return FALSE;
  268. X}
  269. X
  270. X/**********************/
  271. X/* Function do_wild() */   /* for porting:  dir separator; match(ignore_case) */
  272. X/**********************/
  273. X
  274. Xchar *do_wild(wildspec)
  275. X    char *wildspec;         /* only used first time on a given dir */
  276. X{
  277. X    static DIR *dir = NULL;
  278. X    static char *dirname, *wildname, matchname[FILNAMSIZ];
  279. X    static int firstcall=TRUE, have_dirname, dirnamelen;
  280. X    struct dirent *file;
  281. X    BPTR lok = 0;
  282. X    /* Even when we're just returning wildspec, we *always* do so in
  283. X     * matchname[]--calling routine is allowed to append four characters
  284. X     * to the returned string, and wildspec may be a pointer to argv[].
  285. X     */
  286. X    if (firstcall) {        /* first call:  must initialize everything */
  287. X        firstcall = FALSE;
  288. X        /* avoid needless readdir() scans: */
  289. X        if (!ispattern(wildspec) || (lok = Lock(wildspec, ACCESS_READ))) {
  290. X            if (lok) UnLock(lok);
  291. X            have_dirname = FALSE;
  292. X            strcpy(matchname, wildspec);
  293. X            return matchname;
  294. X        }
  295. X
  296. X        /* break the wildspec into a directory part and a wildcard filename */
  297. X        if ((wildname = strrchr(wildspec, '/')) == NULL
  298. X                        && (wildname = strrchr(wildspec, ':')) == NULL) {
  299. X            dirname = "";               /* current dir */
  300. X            dirnamelen = 1;
  301. X            have_dirname = FALSE;
  302. X            wildname = wildspec;
  303. X        } else {
  304. X            ++wildname;     /* point at character after '/' or ':' */
  305. X            dirnamelen = wildname - wildspec;
  306. X            if ((dirname = (char *)malloc(dirnamelen+1)) == NULL) {
  307. X                fprintf(stderr, "warning:  can't allocate wildcard buffers\n");
  308. X                strcpy(matchname, wildspec);
  309. X                return matchname;   /* but maybe filespec was not a wildcard */
  310. X            }
  311. X            strncpy(dirname, wildspec, dirnamelen);
  312. X            dirname[dirnamelen] = 0;
  313. X            have_dirname = TRUE;
  314. X        }
  315. X
  316. X        if ((dir = opendir(dirname)) != NULL) {
  317. X            while ((file = readdir(dir)) != NULL) {
  318. X                if (match(file->d_name, wildname, 1)) {  /* case insensitive */
  319. X                    if (have_dirname) {
  320. X                        strcpy(matchname, dirname);
  321. X                        strcpy(matchname+dirnamelen, file->d_name);
  322. X                    } else
  323. X                        strcpy(matchname, file->d_name);
  324. X                    return matchname;
  325. X                }
  326. X            }
  327. X            /* if we get to here directory is exhausted, so close it */
  328. X            closedir(dir);
  329. X            dir = NULL;
  330. X        }
  331. X
  332. X        /* return the raw wildspec in case that works (e.g., directory not
  333. X         * searchable, but filespec was not wild and file is readable) */
  334. X        strcpy(matchname, wildspec);
  335. X        return matchname;
  336. X    }
  337. X
  338. X    /* last time through, might have failed opendir but returned raw wildspec */
  339. X    if (dir == NULL) {
  340. X        firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  341. X        if (have_dirname)
  342. X            free(dirname);
  343. X        return (char *)NULL;
  344. X    }
  345. X
  346. X    /* If we've gotten this far, we've read and matched at least one entry
  347. X     * successfully (in a previous call), so dirname has been copied into
  348. X     * matchname already.
  349. X     */
  350. X    while ((file = readdir(dir)) != NULL)
  351. X        if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  352. X            if (have_dirname) {
  353. X                /* strcpy(matchname, dirname); */
  354. X                strcpy(matchname+dirnamelen, file->d_name);
  355. X            } else
  356. X                strcpy(matchname, file->d_name);
  357. X            return matchname;
  358. X        }
  359. X
  360. X    closedir(dir);     /* have read at least one dir entry; nothing left */
  361. X    dir = NULL;
  362. X    firstcall = TRUE;  /* reset for new wildspec */
  363. X    if (have_dirname)
  364. X        free(dirname);
  365. X    return (char *)NULL;
  366. X
  367. X} /* end function do_wild() */
  368. X
  369. X
  370. X
  371. X/***********************/
  372. X/* Function checkdir() */
  373. X/***********************/
  374. X
  375. Xint checkdir(pathcomp, flag)
  376. X    char *pathcomp;
  377. X    int flag;
  378. X/*
  379. X * returns:  1 - (on APPEND_xxx) truncated path component
  380. X *           2 - path doesn't exist, not allowed to create
  381. X *           3 - path doesn't exist, tried to create and failed; or
  382. X *               path exists and is not a directory, but is supposed to be
  383. X *          10 - can't allocate memory for filename buffers
  384. X */
  385. X{
  386. X    static int rootlen = 0;   /* length of rootpath */
  387. X    static char *rootpath;    /* user's "extract-to" directory */
  388. X    static char *buildpath;   /* full path (so far) to extracted file */
  389. X    static char *end;         /* pointer to end of buildpath ('\0') */
  390. X
  391. X#   define FN_MASK   7
  392. X#   define FUNCTION  (flag & FN_MASK)
  393. X
  394. X
  395. X
  396. X/*---------------------------------------------------------------------------
  397. X    APPEND_DIR:  append the path component to the path being built and check
  398. X    for its existence.  If doesn't exist and we are creating directories, do
  399. X    so for this one; else signal success or error as appropriate.
  400. X  ---------------------------------------------------------------------------*/
  401. X
  402. X/* GRR:  check path length after each segment:  warn about truncation */
  403. X
  404. X    if (FUNCTION == APPEND_DIR) {
  405. X        Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  406. X        while ((*end = *pathcomp++))
  407. X            ++end;
  408. X        if (stat(buildpath, &statbuf)) {   /* path doesn't exist */
  409. X            if (!create_dirs) {   /* told not to create (freshening) */
  410. X                free(buildpath);
  411. X                return 2;         /* path doesn't exist:  nothing to do */
  412. X            }
  413. X            if (MKDIR(buildpath, 0777) == -1) {   /* create the directory */
  414. X                fprintf(stderr, 
  415. X                "checkdir:  can't create %s\n           unable to process %s.\n"
  416. X                  , buildpath, filename);
  417. X                fflush(stderr);
  418. X                free(buildpath);
  419. X                return 3;      /* path didn't exist, tried to create, failed */
  420. X            }
  421. X            created_dir = TRUE;
  422. X        } else if (!S_ISDIR(statbuf.st_mode)) {
  423. X            fprintf(stderr, "checkdir:  %s exists but is not a directory\n\
  424. X           unable to process %s.\n", buildpath, filename);
  425. X            fflush(stderr);
  426. X            free(buildpath);
  427. X            return 3;          /* path existed but wasn't dir */
  428. X        }
  429. X        *end++ = '/';
  430. X        *end = '\0';
  431. X        Trace((stderr, "buildpath now = [%s]\n", buildpath));
  432. X        return 0;
  433. X
  434. X    } /* end if (FUNCTION == APPEND_DIR) */
  435. X
  436. X/*---------------------------------------------------------------------------
  437. X    GETPATH:  copy full path to the string pointed at by pathcomp, and free
  438. X    buildpath.
  439. X  ---------------------------------------------------------------------------*/
  440. X
  441. X    if (FUNCTION == GETPATH) {
  442. X        strcpy(pathcomp, buildpath);  /* DO ERROR CHECKING:  TOO LONG? */
  443. X        Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  444. X        free(buildpath);
  445. X        buildpath = end = NULL;
  446. X        return 0;
  447. X    }
  448. X
  449. X/*---------------------------------------------------------------------------
  450. X    APPEND_NAME:  assume the path component is the filename; append it and
  451. X    return without checking for existence.
  452. X  ---------------------------------------------------------------------------*/
  453. X
  454. X    if (FUNCTION == APPEND_NAME) {                /* DO ERROR CHECKING */
  455. X        Trace((stderr, "appending filename [%s]\n", pathcomp));
  456. X        while ((*end = *pathcomp++))
  457. X            ++end;
  458. X        Trace((stderr, "buildpath now = [%s]\n", buildpath));
  459. X        return 0;  /* could check for existence here, prompt for new name... */
  460. X    }
  461. X
  462. X/*---------------------------------------------------------------------------
  463. X    INIT:  allocate and initialize buffer space for the file currently being
  464. X    extracted.  If file was renamed with an absolute path, don't prepend the
  465. X    extract-to path.
  466. X  ---------------------------------------------------------------------------*/
  467. X
  468. X    if (FUNCTION == INIT) {
  469. X        Trace((stderr, "initializing buildpath to "));
  470. X        if ((buildpath = (char *)malloc(strlen(filename)+rootlen+1)) == NULL)
  471. X            return 10;
  472. X        if ((rootlen > 0) && !renamed_fullpath) {
  473. X            strcpy(buildpath, rootpath);
  474. X            end = buildpath + rootlen;
  475. X        } else {
  476. X            *buildpath = '\0';
  477. X            end = buildpath;
  478. X        }
  479. X        Trace((stderr, "[%s]\n", buildpath));
  480. X        return 0;
  481. X    }
  482. X
  483. X/*---------------------------------------------------------------------------
  484. X    ROOT:  if appropriate, store the path in rootpath and create it if neces-
  485. X    sary; else assume it's a zipfile member and return.  This path segment
  486. X    gets used in extracting all members from every zipfile specified on the
  487. X    command line.
  488. X  ---------------------------------------------------------------------------*/
  489. X
  490. X#if (!defined(SFX) || defined(SFX_EXDIR))
  491. X    if (FUNCTION == ROOT) {
  492. X        Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  493. X        if (pathcomp == NULL) {
  494. X            rootlen = 0;
  495. X            return 0;
  496. X        }
  497. X        if ((rootlen = strlen(pathcomp)) > 0) {
  498. X            int had_trailing_pathsep=FALSE;
  499. X
  500. X            if (pathcomp[rootlen-1] == '/') {
  501. X                pathcomp[--rootlen] = '\0';
  502. X                had_trailing_pathsep = TRUE;
  503. X            }
  504. X            if (rootlen > 0 && (stat(pathcomp, &statbuf) ||
  505. X                !S_ISDIR(statbuf.st_mode)))      /* path does not exist */
  506. X            {
  507. X                if (!create_dirs                     /* || iswild(pathcomp) */
  508. X#ifdef OLD_EXDIR
  509. X                                 || !had_trailing_pathsep
  510. X#endif
  511. X                                                         ) {
  512. X                    rootlen = 0;
  513. X                    return 2;   /* treat as stored file */
  514. X                }
  515. X                /* create the directory (could add loop here to scan pathcomp
  516. X                 * and create more than one level, but why really necessary?) */
  517. X                if (MKDIR(pathcomp, 0777) == -1) {
  518. X                    fprintf(stderr,
  519. X                      "checkdir:  can't create extraction directory: %s\n",
  520. X                      pathcomp);
  521. X                    fflush(stderr);
  522. X                    rootlen = 0;   /* path didn't exist, tried to create, and */
  523. X                    return 3;  /* failed:  file exists, or 2+ levels required */
  524. X                }
  525. X            }
  526. X            if ((rootpath = (char *)malloc(rootlen+2)) == NULL) {
  527. X                rootlen = 0;
  528. X                return 10;
  529. X            }
  530. X            strcpy(rootpath, pathcomp);
  531. X            if (rootpath[rootlen - 1] != ':')
  532. X                rootpath[rootlen++] = '/';
  533. X            rootpath[rootlen] = '\0';
  534. X        }
  535. X        Trace((stderr, "rootpath now = [%s]\n", rootpath));
  536. X        return 0;
  537. X    }
  538. X#endif /* !SFX || SFX_EXDIR */
  539. X
  540. X/*---------------------------------------------------------------------------
  541. X    END:  free rootpath, immediately prior to program exit.
  542. X  ---------------------------------------------------------------------------*/
  543. X
  544. X    if (FUNCTION == END) {
  545. X        Trace((stderr, "freeing rootpath\n"));
  546. X        if (rootlen > 0)
  547. X            free(rootpath);
  548. X        return 0;
  549. X    }
  550. X
  551. X    return 99;  /* should never reach */
  552. X
  553. X} /* end function checkdir() */
  554. X
  555. X
  556. X/**********************/
  557. X/* Function cmptime() */
  558. X/**********************/
  559. X
  560. X/* cmptime() clone pinched from from Zip1.9h,
  561. X * by Mark Adler, Jean-loup Gailly, et al., circa 1991.  
  562. X * Incorporated into UnZip 5.1d by John Bush
  563. X */
  564. X
  565. Xint cmptime(p, q)
  566. Xstruct tm *p, *q;       /* times to compare */
  567. X/* Return negative if time p is before time q, positive if after, and
  568. X   zero if the same */
  569. X{
  570. X  int r;                /* temporary variable */
  571. X
  572. X  if (p == NULL)
  573. X    return -1;
  574. X  else if ((r = p->tm_year - q->tm_year) != 0)
  575. X    return r;
  576. X  else if ((r = p->tm_mon - q->tm_mon) != 0)
  577. X    return r;
  578. X  else if ((r = p->tm_mday - q->tm_mday) != 0)
  579. X    return r;
  580. X  else if ((r = p->tm_hour - q->tm_hour) != 0)
  581. X    return r;
  582. X  else if ((r = p->tm_min - q->tm_min) != 0)
  583. X    return r;
  584. X  else
  585. X    return p->tm_sec - q->tm_sec;
  586. X}
  587. X
  588. X
  589. X/***********************/
  590. X/* Function invlocal() */
  591. X/***********************/
  592. X
  593. X/* mktime() clone pinched from from Zip1.9h,
  594. X * by Mark Adler and Jean-loup Gailly, et.al, circa 1991.  
  595. X * Incorporated into UnZip 5.1d by John Bush
  596. X */
  597. Xtime_t invlocal(t)
  598. Xstruct tm *t;           /* time to convert */
  599. X/* Find inverse of localtime() using bisection.  This routine assumes that
  600. X   time_t is an integer type, either signed or unsigned.  The expectation
  601. X   is that sometime before the year 2038, time_t will be made a 64-bit
  602. X   integer, and this routine will still work. */
  603. X{
  604. X  time_t i;             /* midpoint of current root range */
  605. X  time_t l;             /* lower end of root range */
  606. X  time_t u;             /* upper end of root range */
  607. X
  608. X  /* Bracket the root [0,largest time_t].  Note: if time_t is a 32-bit signed
  609. X     integer, then the upper bound is GMT 1/19/2038 03:14:07, after which all
  610. X     the Unix systems in the world come to a grinding halt.  Either that, or
  611. X     all those systems will suddenly find themselves transported to December
  612. X     of 1901 ... */
  613. X  l = 0;
  614. X  u = 1;
  615. X  while (u < (u << 1))
  616. X    u = (u << 1) + 1;
  617. X
  618. X  /* Find the root */
  619. X  while (u - l > 1)
  620. X  {
  621. X    i = l + ((u - l) >> 1);
  622. X    if (cmptime(localtime(&i), t) <= 0)
  623. X      l = i;
  624. X    else
  625. X      u = i;
  626. X  }
  627. X  return l;
  628. X}
  629. X
  630. X
  631. X
  632. X/**************************************/
  633. X/* Function close_outfile() */
  634. X/**************************************/
  635. X/* this part differs slightly with Zip */
  636. X/*-------------------------------------*/
  637. X
  638. Xvoid close_outfile(void)
  639. X{
  640. X    struct tm t;                /* good ole time structure */
  641. X    time_t u[2];                /* mean ole time stamp */
  642. X    ulg dd,dt;                  /* DOS format time stamps */
  643. X    LONG FileDate();
  644. X    time_t invlocal();
  645. X
  646. X    if (cflag)                  /* can't set time on stdout */
  647. X        return;
  648. X
  649. X  /* close the file *before* setting its time under AmigaDos */
  650. X
  651. X    fclose(outfile);
  652. X
  653. X  /* assign date and time to local variables */
  654. X
  655. X    dd = lrec.last_mod_file_date;
  656. X    dt = lrec.last_mod_file_time;
  657. X
  658. X  /* Convert DOS time to time_t format in (time_t)u */
  659. X
  660. X    t.tm_sec =   (int) (dt <<  1) & 0x3e;
  661. X    t.tm_min =   (int) (dt >>  5) & 0x3f;
  662. X    t.tm_hour =  (int) (dt >> 11) & 0x1f;
  663. X
  664. X    t.tm_mday =  (int) (dd        & 0x1f);
  665. X    t.tm_mon =  ((int) (dd >>  5) & 0xf ) - 1;
  666. X    t.tm_year = ((int) (dd >>  9) & 0x7f) + 80;
  667. X
  668. X  /* invlocal() is equivalent to mktime() */
  669. X
  670. X    u[0] = u[1] = invlocal(&t); 
  671. X
  672. X#ifdef DEBUG
  673. X    fprintf (stderr,"\nclose_outfile(): u=%s\n",ctime(&u[0]));
  674. X#endif
  675. X
  676. X    if (!FileDate(filename, u))
  677. X        fprintf(stderr, "warning:  can't set the time for %s\n", filename);
  678. X
  679. X  /* set file perms after closing (not done at creation)--see mapattr() */
  680. X
  681. X    chmod(filename, pInfo->file_attr);
  682. X
  683. X} /* end function close_outfile() */
  684. X
  685. X
  686. X/********************************************************************/
  687. X/* Load filedate as a separate external file; it's used by Zip, too.*/
  688. X/*                                                                  */
  689. X#include "amiga/filedate.c"                                      /* */
  690. X/*                                                                  */
  691. X/********************************************************************/
  692. X
  693. X/**************** for Aztec, do linewise with stat.c ****************/
  694. X
  695. X#ifdef AZTEC_C
  696. X#  include "amiga/stat.c"
  697. X/* this is the exact same stat.c used for Aztec by Zip */
  698. X
  699. X#  include <stdio.h>
  700. X#  include "crypt.h"
  701. X
  702. Xvoid _abort(void)               /* called when ^C is pressed */
  703. X{
  704. X    echon();
  705. X    close_leftover_open_dirs();
  706. X    fflush(stdout);
  707. X    fputs("\n^C\n", stderr);
  708. X    exit(1);
  709. X}
  710. X#endif /* AZTEC_C */
  711. X
  712. X
  713. X#ifndef SFX
  714. X
  715. X/************************/
  716. X/*  Function version()  */
  717. X/************************/
  718. X
  719. X
  720. X/* NOTE:  the following include depends upon the environment 
  721. X *        variable $Workbench to be set correctly.  (Set by
  722. X *        default, by kickstart during startup)
  723. X */
  724. Xint WBversion = (int)
  725. X#include "ENV:Workbench"
  726. X;
  727. X
  728. Xvoid version()
  729. X{
  730. X   extern char Far  CompiledWith[];
  731. X
  732. X/* Define buffers. */
  733. X
  734. X   char buf1[16];  /* compiler name */
  735. X   char buf2[16];  /* revstamp */
  736. X   char buf3[16];  /* OS */
  737. X   char buf4[16];  /* Date */
  738. X/*   char buf5[16];  /* Time */
  739. X
  740. X/* format "with" name strings */
  741. X
  742. X#ifdef AMIGA
  743. X# ifdef __SASC
  744. X   strcpy(buf1,"SAS/C ");
  745. X# else
  746. X#  ifdef LATTICE
  747. X    strcpy(buf1,"Lattice C ");
  748. X#  else
  749. X#   ifdef AZTEC_C
  750. X     strcpy(buf1,"Manx Aztec C ");
  751. X#   else
  752. X     strcpy(buf1,"UNKNOWN ");
  753. X#   endif
  754. X#  endif
  755. X# endif
  756. X/* "under" */
  757. X  sprintf(buf3,"AmigaDOS v%d",WBversion);
  758. X#else
  759. X  strcpy(buf1,"Unknown compiler ");
  760. X  strcpy(buf3,"Unknown OS");
  761. X#endif
  762. X
  763. X/* Define revision, date, and time strings.  
  764. X * NOTE:  Do not calculate run time, be sure to use time compiled.
  765. X * Pass these strings via your makefile if undefined.
  766. X */
  767. X
  768. X#if defined(__VERSION__) && defined(__REVISION__)
  769. X  sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__);
  770. X#else
  771. X# ifdef __VERSION__
  772. X  sprintf(buf2,"version %d",__VERSION__);
  773. X# else
  774. X  sprintf(buf2,"unknown version");
  775. X# endif
  776. X#endif
  777. X
  778. X#ifdef __DATE__
  779. X  sprintf(buf4," on %s",__DATE__);
  780. X#else
  781. X  strcpy(buf4," unknown date");
  782. X#endif
  783. X
  784. X/******
  785. X#ifdef __TIME__
  786. X  sprintf(buf5," at %s",__TIME__);
  787. X#else
  788. X  strcpy(buf5," unknown time");
  789. X#endif
  790. X******/
  791. X
  792. X/* Print strings using "CompiledWith" mask defined in unzip.c (used by all).
  793. X *  ("Compiled with %s%s under %s%s%s%s.")
  794. X */
  795. X
  796. X   printf(LoadFarString(CompiledWith),
  797. X     buf1,
  798. X     buf2, 
  799. X     buf3,
  800. X     buf4,
  801. X     /* buf5, */ "",
  802. X     "" );  /* buf6 not used */
  803. X
  804. X} /* end function version() */
  805. X
  806. X#endif /* !SFX */
  807. END_OF_FILE
  808.   if test 25728 -ne `wc -c <'unzip-5.12/amiga/amiga.c'`; then
  809.     echo shar: \"'unzip-5.12/amiga/amiga.c'\" unpacked with wrong size!
  810.   fi
  811.   # end of 'unzip-5.12/amiga/amiga.c'
  812. fi
  813. if test -f 'unzip-5.12/nt/nt.c' -a "${1}" != "-c" ; then 
  814.   echo shar: Will not clobber existing file \"'unzip-5.12/nt/nt.c'\"
  815. else
  816.   echo shar: Extracting \"'unzip-5.12/nt/nt.c'\" \(40790 characters\)
  817.   sed "s/^X//" >'unzip-5.12/nt/nt.c' <<'END_OF_FILE'
  818. X/*---------------------------------------------------------------------------
  819. X
  820. X  nt.c                                              Last updated:  15 Aug 94
  821. X
  822. X  WinNT-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  823. X  (Borrowed, pilfered and plundered code from OS/2 and MS-DOS versions and
  824. X  from ZIP; modified as necessary.)
  825. X
  826. X  Contains:  GetLoadPath()
  827. X             opendir()
  828. X             readdir()
  829. X             closedir()
  830. X             mapattr()
  831. X             getNTfiletime()
  832. X             close_outfile()
  833. X             isfloppy()
  834. X             IsVolumeOldFAT()
  835. X             IsFileNameValid()
  836. X             map2fat()
  837. X             checkdir()
  838. X             do_wild()
  839. X             mapname()
  840. X             version()
  841. X
  842. X  ---------------------------------------------------------------------------*/
  843. X
  844. X#include <windows.h>
  845. X#include "unzip.h"
  846. X
  847. X
  848. X#define MKDIR(path,mode)   mkdir(path)
  849. X
  850. Xstruct direct
  851. X{
  852. X    char    reserved [21];
  853. X    char    ff_attrib;
  854. X    short   ff_ftime;
  855. X    short   ff_fdate;
  856. X    long    size;
  857. X    char    d_name[MAX_PATH];
  858. X    int     d_first;
  859. X    HANDLE  d_hFindFile;
  860. X};
  861. X
  862. X
  863. Xstatic int created_dir;         /* used by mapname(), checkdir() */
  864. Xstatic int renamed_fullpath;    /* ditto */
  865. Xstatic int fnlen;               /* ditto */
  866. Xstatic unsigned nLabelDrive;    /* ditto */
  867. X
  868. X
  869. X
  870. X#ifdef SFX
  871. X
  872. X/**************************/
  873. X/* Function GetLoadPath() */
  874. X/**************************/
  875. X
  876. Xchar *GetLoadPath(void) 
  877. X{
  878. X#ifdef MSC
  879. X    extern char *_pgmptr;
  880. X    return _pgmptr;
  881. X
  882. X#else    /* use generic API call */
  883. X    GetModuleFileName(NULL, filename, FILNAMSIZ);
  884. X    return filename;
  885. X#endif
  886. X
  887. X} /* end function GetLoadPath() */
  888. X
  889. X
  890. X
  891. X
  892. X
  893. X#else /* !SFX */
  894. X
  895. X/**********************/        /* Borrowed from ZIP 2.0 sources             */
  896. X/* Function opendir() */        /* Difference: no special handling for       */
  897. X/**********************/        /*             hidden or system files.       */
  898. X
  899. Xstatic struct direct *opendir(n)
  900. X    const char *n;  /* directory to open */
  901. X{
  902. X    struct direct *d;       /* malloc'd return value */
  903. X    char *p;                /* malloc'd temporary string */
  904. X    WIN32_FIND_DATA fd;
  905. X    int len = strlen(n);
  906. X
  907. X    /* Start searching for files in the MSDOS directory n */
  908. X
  909. X    if ((d = (struct direct *)malloc(sizeof(struct direct))) == NULL ||
  910. X        (p = malloc(strlen(n) + 5)) == NULL)
  911. X    {
  912. X        if (d != (struct direct *)NULL)
  913. X            free((void *)d);
  914. X        return (struct direct *)NULL;
  915. X    }
  916. X    strcpy(p, n);
  917. X    if (p[len-1] == ':')
  918. X        p[len++] = '.';   /* x: => x:. */
  919. X    else if (p[len-1] == '/' || p[len-1] == '\\')
  920. X        --len;            /* foo/ => foo */
  921. X    strcpy(p+len, "/*");
  922. X
  923. X    if (INVALID_HANDLE_VALUE == (d->d_hFindFile = FindFirstFile(p, &fd))) {
  924. X        free((voidp *)d);
  925. X        free((voidp *)p);
  926. X        return NULL;
  927. X    }
  928. X    strcpy(d->d_name, fd.cFileName);
  929. X
  930. X    free((voidp *)p);
  931. X    d->d_first = 1;
  932. X    return d;
  933. X
  934. X} /* end of function opendir() */
  935. X
  936. X
  937. X
  938. X
  939. X/**********************/        /* Borrowed from ZIP 2.0 sources             */
  940. X/* Function readdir() */        /* Difference: no special handling for       */
  941. X/**********************/        /*             hidden or system files.       */
  942. X
  943. Xstatic struct direct *readdir(d)
  944. X    struct direct *d;         /* directory stream from which to read */
  945. X{
  946. X    /* Return pointer to first or next directory entry, or NULL if end. */
  947. X
  948. X    if ( d->d_first )
  949. X        d->d_first = 0;
  950. X    else
  951. X    {
  952. X        WIN32_FIND_DATA fd;
  953. X
  954. X        if ( !FindNextFile(d->d_hFindFile, &fd) )
  955. X            return NULL;
  956. X
  957. X        strcpy(d->d_name, fd.cFileName);
  958. X    }
  959. X    return (struct direct *)d;
  960. X
  961. X} /* end of function readdir() */
  962. X
  963. X
  964. X
  965. X
  966. X/***********************/
  967. X/* Function closedir() */       /* Borrowed from ZIP 2.0 sources */
  968. X/***********************/
  969. X
  970. Xstatic void closedir(d)
  971. X    struct direct *d;         /* directory stream to close */
  972. X{
  973. X    FindClose(d->d_hFindFile);
  974. X    free(d);
  975. X}
  976. X
  977. X#endif /* ?SFX */
  978. X
  979. X
  980. X
  981. X
  982. X/**********************/
  983. X/* Function mapattr() */
  984. X/**********************/
  985. X
  986. X/* Identical to MS-DOS, OS/2 versions.                                       */
  987. X/* However, NT has a lot of extra permission stuff, so this function should  */
  988. X/*  probably be extended in the future.                                      */
  989. X
  990. Xint mapattr()
  991. X{
  992. X    /* set archive bit (file is not backed up): */
  993. X    pInfo->file_attr = (unsigned)(crec.external_file_attributes | 32) & 0xff;
  994. X    return 0;
  995. X
  996. X} /* end function mapattr() */
  997. X
  998. X
  999. X
  1000. X
  1001. X/****************************/      /* Get the file time in a format that */
  1002. X/* Function getNTfiletime() */      /* can be used by SetFileTime() in NT */
  1003. X/****************************/
  1004. X
  1005. Xint getNTfiletime(FILETIME *ft)
  1006. X{
  1007. X    FILETIME lft;      /* 64-bit value made up of two 32 bit [low & high] */
  1008. X    WORD wDOSDate;     /* for converting from DOS date to Windows NT      */
  1009. X    WORD wDOSTime;
  1010. X
  1011. X    /* Copy and/or convert time and date variables, if necessary;   */
  1012. X    /* then set the file time/date.                                 */
  1013. X    wDOSTime = (WORD)lrec.last_mod_file_time;
  1014. X    wDOSDate = (WORD)lrec.last_mod_file_date;
  1015. X
  1016. X    /* The DosDateTimeToFileTime() function converts a DOS date/time    */
  1017. X    /* into a 64 bit Windows NT file time                               */
  1018. X    if (!DosDateTimeToFileTime(wDOSDate, wDOSTime, &lft))
  1019. X    {
  1020. X        PRINTF("DosDateTime failed: %d\n", GetLastError());
  1021. X        return FALSE;
  1022. X    }
  1023. X    if (!LocalFileTimeToFileTime( &lft, ft))
  1024. X    {
  1025. X        PRINTF("LocalFileTime failed: %d\n", GetLastError());
  1026. X        *ft = lft;
  1027. X    }
  1028. X    return TRUE;
  1029. X}
  1030. X
  1031. X
  1032. X
  1033. X
  1034. X/****************************/
  1035. X/* Function close_outfile() */
  1036. X/****************************/
  1037. X
  1038. Xvoid close_outfile()
  1039. X{
  1040. X    FILETIME ft;       /* File time type defined in NT */
  1041. X    HANDLE hFile;      /* File handle defined in NT    */
  1042. X    int gotTime;
  1043. X
  1044. X    /* don't set the time stamp on standard output */
  1045. X    if (cflag) {
  1046. X        fclose(outfile);
  1047. X        return;
  1048. X    }
  1049. X
  1050. X    gotTime = getNTfiletime(&ft);
  1051. X
  1052. X    /* Close the file and then re-open it using the Win32
  1053. X     * CreateFile call, so that the file can be created
  1054. X     * with GENERIC_WRITE access, otherwise the SetFileTime
  1055. X     * call will fail. */
  1056. X    fclose(outfile);
  1057. X
  1058. X    hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
  1059. X         FILE_ATTRIBUTE_NORMAL, NULL);
  1060. X    if ( hFile == INVALID_HANDLE_VALUE ) {
  1061. X        FPRINTF(stderr, "\nCreateFile error %d when trying set file time\n",
  1062. X                GetLastError());
  1063. X    }
  1064. X    else {
  1065. X        if (gotTime)
  1066. X            if (!SetFileTime(hFile, NULL, NULL, &ft))
  1067. X                PRINTF("\nSetFileTime failed: %d\n", GetLastError());
  1068. X        CloseHandle(hFile);
  1069. X    }
  1070. X
  1071. X    /* HG: I think this could be done in the CreateFile call above - just  */
  1072. X    /*     replace 'FILE_ATTRIBUTE_NORMAL' with 'pInfo->file_attr & 0x7F'  */
  1073. X    if (!SetFileAttributes(filename, pInfo->file_attr & 0x7F))
  1074. X        FPRINTF(stderr, "\nwarning (%d): could not set file attributes\n",
  1075. X                GetLastError());
  1076. X
  1077. X    return;
  1078. X
  1079. X} /* end function close_outfile() */
  1080. X
  1081. X
  1082. X
  1083. X/* ============================================================================
  1084. X*/
  1085. X
  1086. X
  1087. X
  1088. X/***********************/
  1089. X/* Function isfloppy() */   /* more precisely, is it removable? */
  1090. X/***********************/
  1091. X
  1092. Xstatic int isfloppy(int nDrive)   /* 1 == A:, 2 == B:, etc. */
  1093. X{
  1094. X    char rootPathName[4];
  1095. X
  1096. X    rootPathName[0] = 'A' + nDrive - 1;   /* Build the root path name, */
  1097. X    rootPathName[1] = ':';                /* e.g. "A:/"                */
  1098. X    rootPathName[2] = '/';
  1099. X    rootPathName[3] = '\0';
  1100. X
  1101. X    return (GetDriveType(rootPathName) == DRIVE_REMOVABLE);
  1102. X
  1103. X} /* end function isfloppy() */
  1104. X
  1105. X
  1106. X
  1107. X
  1108. X/*****************************/
  1109. X/* Function IsVolumeOldFAT() */
  1110. X/*****************************/
  1111. X
  1112. X/*
  1113. X * Note:  8.3 limits on filenames apply only to old-style FAT filesystems.
  1114. X *        More recent versions of Windows (Windows NT 3.5 / Windows 4.0)
  1115. X *        can support long filenames (LFN) on FAT filesystems.  Check the
  1116. X *        filesystem maximum component length field to detect LFN support.
  1117. X *        [GRR:  this routine is only used to determine whether spaces in
  1118. X *        filenames are supported...]
  1119. X */
  1120. X
  1121. Xstatic int IsVolumeOldFAT(char *name)
  1122. X{
  1123. X    char     *tmp0;
  1124. X    char      rootPathName[4];
  1125. X    char      tmp1[MAX_PATH], tmp2[MAX_PATH];
  1126. X    unsigned  volSerNo, maxCompLen, fileSysFlags;
  1127. X
  1128. X    if (isalpha(name[0]) && (name[1] == ':'))
  1129. X        tmp0 = name;
  1130. X    else
  1131. X    {
  1132. X        GetFullPathName(name, MAX_PATH, tmp1, &tmp0);
  1133. X        tmp0 = &tmp1[0];
  1134. X    }
  1135. X    strncpy(rootPathName, tmp0, 3);   /* Build the root path name, */
  1136. X    rootPathName[3] = '\0';           /* e.g. "A:/"                */
  1137. X
  1138. X    GetVolumeInformation(rootPathName, tmp1, MAX_PATH, &volSerNo,
  1139. X                         &maxCompLen, &fileSysFlags, tmp2, MAX_PATH);
  1140. X
  1141. X    /* Long Filenames (LFNs) are available if the component length is > 12 */
  1142. X    return maxCompLen <= 12;
  1143. X/*  return !strncmp(strupr(tmp2), "FAT", 3);   old version */
  1144. X
  1145. X}
  1146. X
  1147. X
  1148. X
  1149. X
  1150. X/******************************/
  1151. X/* Function IsFileNameValid() */
  1152. X/******************************/
  1153. X
  1154. Xstatic int IsFileNameValid(char *name)
  1155. X{
  1156. X    HFILE    hf;
  1157. X    OFSTRUCT of;
  1158. X
  1159. X    hf = OpenFile(name, &of, OF_READ | OF_SHARE_DENY_NONE);
  1160. X    if (hf == HFILE_ERROR)
  1161. X        switch (GetLastError())
  1162. X        {
  1163. X            case ERROR_INVALID_NAME:
  1164. X            case ERROR_FILENAME_EXCED_RANGE:
  1165. X                return FALSE;
  1166. X            default:
  1167. X                return TRUE;
  1168. X        }
  1169. X    else
  1170. X        _lclose(hf);
  1171. X    return TRUE;
  1172. X}
  1173. X
  1174. X
  1175. X
  1176. X
  1177. X/**********************/
  1178. X/* Function map2fat() */        /* Identical to OS/2 version */
  1179. X/**********************/
  1180. X
  1181. Xvoid map2fat(pathcomp, pEndFAT)
  1182. X    char *pathcomp, **pEndFAT;
  1183. X{
  1184. X    char *ppc = pathcomp;       /* variable pointer to pathcomp */
  1185. X    char *pEnd = *pEndFAT;      /* variable pointer to buildpathFAT */
  1186. X    char *pBegin = *pEndFAT;    /* constant pointer to start of this comp. */
  1187. X    char *last_dot = NULL;      /* last dot not converted to underscore */
  1188. X    int dotname = FALSE;        /* flag:  path component begins with dot */
  1189. X                                /*  ("." and ".." don't count) */
  1190. X    register unsigned workch;   /* hold the character being tested */
  1191. X
  1192. X
  1193. X    /* Only need check those characters which are legal in HPFS but not
  1194. X     * in FAT:  to get here, must already have passed through mapname.
  1195. X     * (GRR:  oops, small bug--if char was quoted, no longer have any
  1196. X     * knowledge of that.)  Also must truncate path component to ensure
  1197. X     * 8.3 compliance...
  1198. X     */
  1199. X    while ((workch = (uch)*ppc++) != 0) {
  1200. X        switch (workch) {
  1201. X            case '[':
  1202. X            case ']':
  1203. X                *pEnd++ = '_';      /* convert brackets to underscores */
  1204. X                break;
  1205. X
  1206. X            case '.':
  1207. X                if (pEnd == *pEndFAT) {   /* nothing appended yet... */
  1208. X                    if (*ppc == '\0')     /* don't bother appending a */
  1209. X                        break;            /*  "./" component to the path */
  1210. X                    else if (*ppc == '.' && ppc[1] == '\0') {   /* "../" */
  1211. X                        *pEnd++ = '.';    /* add first dot, unchanged... */
  1212. X                        ++ppc;            /* skip second dot, since it will */
  1213. X                    } else {              /*  be "added" at end of if-block */
  1214. X                        *pEnd++ = '_';    /* FAT doesn't allow null filename */
  1215. X                        dotname = TRUE;   /*  bodies, so map .exrc -> _.exrc */
  1216. X                    }                     /*  (extra '_' now, "dot" below) */
  1217. X                } else if (dotname) {     /* found a second dot, but still */
  1218. X                    dotname = FALSE;      /*  have extra leading underscore: */
  1219. X                    *pEnd = '\0';         /*  remove it by shifting chars */
  1220. X                    pEnd = *pEndFAT + 1;  /*  left one space (e.g., .p1.p2: */
  1221. X                    while (pEnd[1]) {     /*  __p1 -> _p1_p2 -> _p1.p2 when */
  1222. X                        *pEnd = pEnd[1];  /*  finished) [opt.:  since first */
  1223. X                        ++pEnd;           /*  two chars are same, can start */
  1224. X                    }                     /*  shifting at second position] */
  1225. X                }
  1226. X                last_dot = pEnd;    /* point at last dot so far... */
  1227. X                *pEnd++ = '_';      /* convert dot to underscore for now */
  1228. X                break;
  1229. X
  1230. X            default:
  1231. X                *pEnd++ = (char)workch;
  1232. X
  1233. X        } /* end switch */
  1234. X    } /* end while loop */
  1235. X
  1236. X    *pEnd = '\0';                 /* terminate buildpathFAT */
  1237. X
  1238. X    /* NOTE:  keep in mind that pEnd points to the end of the path
  1239. X     * component, and *pEndFAT still points to the *beginning* of it...
  1240. X     * Also note that the algorithm does not try to get too fancy:
  1241. X     * if there are no dots already, the name either gets truncated
  1242. X     * at 8 characters or the last underscore is converted to a dot
  1243. X     * (only if more characters are saved that way).  In no case is
  1244. X     * a dot inserted between existing characters.
  1245. X     */
  1246. X    if (last_dot == NULL) {       /* no dots:  check for underscores... */
  1247. X        char *plu = strrchr(pBegin, '_');   /* pointer to last underscore */
  1248. X
  1249. X        if (plu == NULL) {   /* no dots, no underscores:  truncate at 8 chars */
  1250. X            *pEndFAT += 8;        /* (or could insert '.' and keep 11...?) */
  1251. X            if (*pEndFAT > pEnd)
  1252. X                *pEndFAT = pEnd;  /* oops...didn't have 8 chars to truncate */
  1253. X            else
  1254. X                **pEndFAT = '\0';
  1255. X        } else if (MIN(plu - pBegin, 8) + MIN(pEnd - plu - 1, 3) > 8) {
  1256. X            last_dot = plu;       /* be lazy:  drop through to next if-blk */
  1257. X        } else if ((pEnd - *pEndFAT) > 8) {
  1258. X            *pEndFAT += 8;        /* more fits into just basename than if */
  1259. X            **pEndFAT = '\0';     /*  convert last underscore to dot */
  1260. X        } else
  1261. X            *pEndFAT = pEnd;      /* whole thing fits into 8 chars or less */
  1262. X    }
  1263. X
  1264. X    if (last_dot != NULL) {       /* one dot (or two, in the case of */
  1265. X        *last_dot = '.';          /*  "..") is OK:  put it back in */
  1266. X
  1267. X        if ((last_dot - pBegin) > 8) {
  1268. X            char *p=last_dot, *q=pBegin+8;
  1269. X            int i;
  1270. X
  1271. X            for (i = 0;  (i < 4) && *p;  ++i)  /* too many chars in basename: */
  1272. X                *q++ = *p++;                   /*  shift .ext left and trun- */
  1273. X            *q = '\0';                         /*  cate/terminate it */
  1274. X            *pEndFAT = q;
  1275. X        } else if ((pEnd - last_dot) > 4) {    /* too many chars in extension */
  1276. X            *pEndFAT = last_dot + 4;
  1277. X            **pEndFAT = '\0';
  1278. X        } else
  1279. X            *pEndFAT = pEnd;   /* filename is fine; point at terminating zero */
  1280. X    }
  1281. X} /* end function map2fat() */
  1282. X
  1283. X
  1284. X
  1285. X
  1286. X/***********************/       /* Borrowed from os2.c for UnZip 5.1.        */
  1287. X/* Function checkdir() */       /* Difference: no EA stuff                   */
  1288. X/***********************/       /*             HPFS stuff works on NTFS too  */
  1289. X
  1290. Xint checkdir(pathcomp, flag)
  1291. X    char *pathcomp;
  1292. X    int flag;
  1293. X/*
  1294. X * returns:  1 - (on APPEND_NAME) truncated filename
  1295. X *           2 - path doesn't exist, not allowed to create
  1296. X *           3 - path doesn't exist, tried to create and failed; or
  1297. X *               path exists and is not a directory, but is supposed to be
  1298. X *           4 - path is too long
  1299. X *          10 - can't allocate memory for filename buffers
  1300. X */
  1301. X{
  1302. X    static int rootlen = 0;      /* length of rootpath */
  1303. X    static char *rootpath;       /* user's "extract-to" directory */
  1304. X    static char *buildpathHPFS;  /* full path (so far) to extracted file, */
  1305. X    static char *buildpathFAT;   /*  both HPFS/EA (main) and FAT versions */
  1306. X    static char *endHPFS;        /* corresponding pointers to end of */
  1307. X    static char *endFAT;         /*  buildpath ('\0') */
  1308. X
  1309. X#   define FN_MASK   7
  1310. X#   define FUNCTION  (flag & FN_MASK)
  1311. X
  1312. X
  1313. X
  1314. X/*---------------------------------------------------------------------------
  1315. X    APPEND_DIR:  append the path component to the path being built and check
  1316. X    for its existence.  If doesn't exist and we are creating directories, do
  1317. X    so for this one; else signal success or error as appropriate.
  1318. X  ---------------------------------------------------------------------------*/
  1319. X
  1320. X    if (FUNCTION == APPEND_DIR) {
  1321. X        char *p = pathcomp;
  1322. X        int too_long=FALSE;
  1323. X
  1324. X        Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  1325. X        while ((*endHPFS = *p++) != '\0')     /* copy to HPFS filename */
  1326. X            ++endHPFS;
  1327. X        if (IsFileNameValid(buildpathHPFS)) {
  1328. X            p = pathcomp;
  1329. X            while ((*endFAT = *p++) != '\0')  /* copy to FAT filename, too */
  1330. X                ++endFAT;
  1331. X        } else {
  1332. X/* GRR:  check error return? */
  1333. X            map2fat(pathcomp, &endFAT);  /* map, put in FAT fn, update endFAT */
  1334. X        }
  1335. X
  1336. X        /* GRR:  could do better check, see if overrunning buffer as we go:
  1337. X         * check endHPFS-buildpathHPFS after each append, set warning variable
  1338. X         * if within 20 of FILNAMSIZ; then if var set, do careful check when
  1339. X         * appending.  Clear variable when begin new path. */
  1340. X
  1341. X        /* next check:  need to append '/', at least one-char name, '\0' */
  1342. X        if ((endHPFS-buildpathHPFS) > FILNAMSIZ-3)
  1343. X            too_long = TRUE;                 /* check if extracting dir? */
  1344. X        if (stat(buildpathFAT, &statbuf))    /* path doesn't exist */
  1345. X        {
  1346. X            if (!create_dirs) {   /* told not to create (freshening) */
  1347. X                free(buildpathHPFS);
  1348. X                free(buildpathFAT);
  1349. X                return 2;         /* path doesn't exist:  nothing to do */
  1350. X            }
  1351. X            if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
  1352. X                FPRINTF(stderr, "checkdir error:  path too long: %s\n",
  1353. X                  buildpathHPFS);
  1354. X                fflush(stderr);
  1355. X                free(buildpathHPFS);
  1356. X                free(buildpathFAT);
  1357. X                return 4;         /* no room for filenames:  fatal */
  1358. X            }
  1359. X            if (MKDIR(buildpathFAT, 0777) == -1) {   /* create the directory */
  1360. X                FPRINTF(stderr, "checkdir error:  can't create %s\n\
  1361. X                 unable to process %s.\n", buildpathFAT, filename);
  1362. X                fflush(stderr);
  1363. X                free(buildpathHPFS);
  1364. X                free(buildpathFAT);
  1365. X                return 3;      /* path didn't exist, tried to create, failed */
  1366. X            }
  1367. X            created_dir = TRUE;
  1368. X        } else if (!S_ISDIR(statbuf.st_mode)) {
  1369. X            FPRINTF(stderr, "checkdir error:  %s exists but is not directory\n\
  1370. X                 unable to process %s.\n", buildpathFAT, filename);
  1371. X            fflush(stderr);
  1372. X            free(buildpathHPFS);
  1373. X            free(buildpathFAT);
  1374. X            return 3;          /* path existed but wasn't dir */
  1375. X        }
  1376. X        if (too_long) {
  1377. X            FPRINTF(stderr, "checkdir error:  path too long: %s\n",
  1378. X              buildpathHPFS);
  1379. X            fflush(stderr);
  1380. X            free(buildpathHPFS);
  1381. X            free(buildpathFAT);
  1382. X            return 4;         /* no room for filenames:  fatal */
  1383. X        }
  1384. X        *endHPFS++ = '/';
  1385. X        *endFAT++ = '/';
  1386. X        *endHPFS = *endFAT = '\0';
  1387. X        Trace((stderr, "buildpathHPFS now = [%s]\n", buildpathHPFS));
  1388. X        Trace((stderr, "buildpathFAT now =  [%s]\n", buildpathFAT));
  1389. X        return 0;
  1390. X
  1391. X    } /* end if (FUNCTION == APPEND_DIR) */
  1392. X
  1393. X/*---------------------------------------------------------------------------
  1394. X    GETPATH:  copy full FAT path to the string pointed at by pathcomp (want
  1395. X    filename to reflect name used on disk, not EAs; if full path is HPFS,
  1396. X    buildpathFAT and buildpathHPFS will be identical).  Also free both paths.
  1397. X  ---------------------------------------------------------------------------*/
  1398. X
  1399. X    if (FUNCTION == GETPATH) {
  1400. X        Trace((stderr, "getting and freeing FAT path [%s]\n", buildpathFAT));
  1401. X        Trace((stderr, "freeing HPFS path [%s]\n", buildpathHPFS));
  1402. X        strcpy(pathcomp, buildpathFAT);
  1403. X        free(buildpathFAT);
  1404. X        free(buildpathHPFS);
  1405. X        buildpathHPFS = buildpathFAT = endHPFS = endFAT = NULL;
  1406. X        return 0;
  1407. X    }
  1408. X
  1409. X/*---------------------------------------------------------------------------
  1410. X    APPEND_NAME:  assume the path component is the filename; append it and
  1411. X    return without checking for existence.
  1412. X  ---------------------------------------------------------------------------*/
  1413. X
  1414. X    if (FUNCTION == APPEND_NAME) {
  1415. X        char *p = pathcomp;
  1416. X        int error = 0;
  1417. X
  1418. X        Trace((stderr, "appending filename [%s]\n", pathcomp));
  1419. X        while ((*endHPFS = *p++) != '\0') {    /* copy to HPFS filename */
  1420. X            ++endHPFS;
  1421. X            if ((endHPFS-buildpathHPFS) >= FILNAMSIZ) {
  1422. X                *--endHPFS = '\0';
  1423. X                FPRINTF(stderr, "checkdir warning:  path too long; truncating\n\
  1424. X                   %s\n                -> %s\n", filename, buildpathHPFS);
  1425. X                fflush(stderr);
  1426. X                error = 1;   /* filename truncated */
  1427. X            }
  1428. X        }
  1429. X
  1430. X        if ( pInfo->vollabel || IsFileNameValid(buildpathHPFS)) {
  1431. X            p = pathcomp;
  1432. X            while ((*endFAT = *p++) != '\0')   /* copy to FAT filename, too */
  1433. X                ++endFAT;
  1434. X        } else {
  1435. X            map2fat(pathcomp, &endFAT);  /* map, put in FAT fn, update endFAT */
  1436. X        }
  1437. X        Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT:  %s\n",
  1438. X          buildpathHPFS, buildpathFAT));
  1439. X
  1440. X        return error;  /* could check for existence, prompt for new name... */
  1441. X
  1442. X    } /* end if (FUNCTION == APPEND_NAME) */
  1443. X
  1444. X/*---------------------------------------------------------------------------
  1445. X    INIT:  allocate and initialize buffer space for the file currently being
  1446. X    extracted.  If file was renamed with an absolute path, don't prepend the
  1447. X    extract-to path.
  1448. X  ---------------------------------------------------------------------------*/
  1449. X
  1450. X    if (FUNCTION == INIT) {
  1451. X
  1452. X/* HG: variable not used here */
  1453. X/*      char *p;              */
  1454. X
  1455. X        Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
  1456. X        if ((buildpathHPFS = (char *)malloc(fnlen+rootlen+1)) == NULL)
  1457. X            return 10;
  1458. X        if ((buildpathFAT = (char *)malloc(fnlen+rootlen+1)) == NULL) {
  1459. X            free(buildpathHPFS);
  1460. X            return 10;
  1461. X        }
  1462. X        if (pInfo->vollabel) {  /* use root or renamed path, but don't store */
  1463. X/* GRR:  for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
  1464. X            if (renamed_fullpath && pathcomp[1] == ':')
  1465. X                *buildpathHPFS = ToLower(*pathcomp);
  1466. X            else if (!renamed_fullpath && rootpath && rootpath[1] == ':')
  1467. X                *buildpathHPFS = ToLower(*rootpath);
  1468. X            else {
  1469. X                char tmpN[MAX_PATH], *tmpP;
  1470. X                if (GetFullPathName(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH)
  1471. X                { /* by definition of MAX_PATH we should never get here */
  1472. X                    FPRINTF(stderr,
  1473. X                            "checkdir warning: current dir path too long\n");
  1474. X                    return 1;   /* can't get drive letter */
  1475. X                }
  1476. X                nLabelDrive = *tmpN - 'a' + 1;
  1477. X                *buildpathHPFS = (char)(nLabelDrive - 1 + 'a');
  1478. X            }
  1479. X            nLabelDrive = *buildpathHPFS - 'a' + 1;     /* save for mapname() */
  1480. X            if (volflag == 0 || *buildpathHPFS < 'a' ||   /* no labels/bogus? */
  1481. X                (volflag == 1 && !isfloppy(nLabelDrive))) {  /* -$:  no fixed */
  1482. X                free(buildpathHPFS);
  1483. X                free(buildpathFAT);
  1484. X                return IZ_VOL_LABEL;   /* skipping with message */
  1485. X            }
  1486. X            *buildpathHPFS = '\0';
  1487. X        } else if (renamed_fullpath)   /* pathcomp = valid data */
  1488. X            strcpy(buildpathHPFS, pathcomp);
  1489. X        else if (rootlen > 0)
  1490. X            strcpy(buildpathHPFS, rootpath);
  1491. X        else
  1492. X            *buildpathHPFS = '\0';
  1493. X        endHPFS = buildpathHPFS;
  1494. X        endFAT = buildpathFAT;
  1495. X        while ((*endFAT = *endHPFS) != '\0') {
  1496. X            ++endFAT;
  1497. X            ++endHPFS;
  1498. X        }
  1499. X        Trace((stderr, "[%s]\n", buildpathHPFS));
  1500. X        return 0;
  1501. X    }
  1502. X
  1503. X/*---------------------------------------------------------------------------
  1504. X    ROOT:  if appropriate, store the path in rootpath and create it if neces-
  1505. X    sary; else assume it's a zipfile member and return.  This path segment
  1506. X    gets used in extracting all members from every zipfile specified on the
  1507. X    command line.  Note that under OS/2 and MS-DOS, if a candidate extract-to
  1508. X    directory specification includes a drive letter (leading "x:"), it is
  1509. X    treated just as if it had a trailing '/'--that is, one directory level
  1510. X    will be created if the path doesn't exist, unless this is otherwise pro-
  1511. X    hibited (e.g., freshening).
  1512. X  ---------------------------------------------------------------------------*/
  1513. X
  1514. X#if (!defined(SFX) || defined(SFX_EXDIR))
  1515. X    if (FUNCTION == ROOT) {
  1516. X        Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  1517. X        if (pathcomp == NULL) {
  1518. X            rootlen = 0;
  1519. X            return 0;
  1520. X        }
  1521. X        if ((rootlen = strlen(pathcomp)) > 0) {
  1522. X            int had_trailing_pathsep=FALSE, has_drive=FALSE, xtra=2;
  1523. X
  1524. X            if (isalpha(pathcomp[0]) && pathcomp[1] == ':')
  1525. X                has_drive = TRUE;   /* drive designator */
  1526. X            if (pathcomp[rootlen-1] == '/') {
  1527. X                pathcomp[--rootlen] = '\0';
  1528. X                had_trailing_pathsep = TRUE;
  1529. X            }
  1530. X            if (has_drive && (rootlen == 2)) {
  1531. X                if (!had_trailing_pathsep)   /* i.e., original wasn't "x:/" */
  1532. X                    xtra = 3;      /* room for '.' + '/' + 0 at end of "x:" */
  1533. X            } else if (rootlen > 0) {     /* need not check "x:." and "x:/" */
  1534. X                if (SSTAT(pathcomp, &statbuf) || !S_ISDIR(statbuf.st_mode)) {
  1535. X                    /* path does not exist */
  1536. X                    if (!create_dirs                 /* || iswild(pathcomp) */
  1537. X#ifdef OLD_EXDIR
  1538. X                                     || (!has_drive && !had_trailing_pathsep)
  1539. X#endif
  1540. X                                                                             ) {
  1541. X                        rootlen = 0;
  1542. X                        return 2;   /* treat as stored file */
  1543. X                    }
  1544. X                    /* create directory (could add loop here to scan pathcomp
  1545. X                     * and create more than one level, but really necessary?) */
  1546. X                    if (MKDIR(pathcomp, 0777) == -1) {
  1547. X                        FPRINTF(stderr,
  1548. X                          "checkdir:  can't create extraction directory: %s\n",
  1549. X                          pathcomp);
  1550. X                        fflush(stderr);
  1551. X                        rootlen = 0;   /* path didn't exist, tried to create, */
  1552. X                        return 3;  /* failed:  file exists, or need 2+ levels */
  1553. X                    }
  1554. X                }
  1555. X            }
  1556. X            if ((rootpath = (char *)malloc(rootlen+xtra)) == NULL) {
  1557. X                rootlen = 0;
  1558. X                return 10;
  1559. X            }
  1560. X            strcpy(rootpath, pathcomp);
  1561. X            if (xtra == 3)                  /* had just "x:", make "x:." */
  1562. X                rootpath[rootlen++] = '.';
  1563. X            rootpath[rootlen++] = '/';
  1564. X            rootpath[rootlen] = '\0';
  1565. X        }
  1566. X        Trace((stderr, "rootpath now = [%s]\n", rootpath));
  1567. X        return 0;
  1568. X    }
  1569. X#endif /* !SFX || SFX_EXDIR */
  1570. X
  1571. X/*---------------------------------------------------------------------------
  1572. X    END:  free rootpath, immediately prior to program exit.
  1573. X  ---------------------------------------------------------------------------*/
  1574. X
  1575. X    if (FUNCTION == END) {
  1576. X        Trace((stderr, "freeing rootpath\n"));
  1577. X        if (rootlen > 0)
  1578. X            free(rootpath);
  1579. X        return 0;
  1580. X    }
  1581. X
  1582. X    return 99;  /* should never reach */
  1583. X
  1584. X} /* end function checkdir() */
  1585. X
  1586. X
  1587. X
  1588. X
  1589. X#ifndef SFX
  1590. X
  1591. X/************************/
  1592. X/*  Function do_wild()  */   /* identical to OS/2 version */
  1593. X/************************/
  1594. X
  1595. Xchar *do_wild(wildspec)
  1596. X    char *wildspec;         /* only used first time on a given dir */
  1597. X{
  1598. X    static struct direct *dir = NULL;
  1599. X    static char *dirname, *wildname, matchname[FILNAMSIZ];
  1600. X    static int firstcall=TRUE, have_dirname, dirnamelen;
  1601. X    struct direct *file;
  1602. X
  1603. X
  1604. X    /* Even when we're just returning wildspec, we *always* do so in
  1605. X     * matchname[]--calling routine is allowed to append four characters
  1606. X     * to the returned string, and wildspec may be a pointer to argv[].
  1607. X     */
  1608. X    if (firstcall) {        /* first call:  must initialize everything */
  1609. X        firstcall = FALSE;
  1610. X
  1611. X        /* break the wildspec into a directory part and a wildcard filename */
  1612. X        if ((wildname = strrchr(wildspec, '/')) == NULL &&
  1613. X            (wildname = strrchr(wildspec, ':')) == NULL) {
  1614. X            dirname = ".";
  1615. X            dirnamelen = 1;
  1616. X            have_dirname = FALSE;
  1617. X            wildname = wildspec;
  1618. X        } else {
  1619. X            ++wildname;     /* point at character after '/' or ':' */
  1620. X            dirnamelen = wildname - wildspec;
  1621. X            if ((dirname = (char *)malloc(dirnamelen+1)) == NULL) {
  1622. X                FPRINTF(stderr, "warning:  can't allocate wildcard buffers\n");
  1623. X                strcpy(matchname, wildspec);
  1624. X                return matchname;   /* but maybe filespec was not a wildcard */
  1625. X            }
  1626. X            strncpy(dirname, wildspec, dirnamelen);
  1627. X            dirname[dirnamelen] = '\0';   /* terminate for strcpy below */
  1628. X            have_dirname = TRUE;
  1629. X        }
  1630. X        Trace((stderr, "do_wild:  dirname = [%s]\n", dirname));
  1631. X
  1632. X        if ((dir = opendir(dirname)) != NULL) {
  1633. X            while ((file = readdir(dir)) != NULL) {
  1634. X                Trace((stderr, "do_wild:  readdir returns %s\n", file->d_name));
  1635. X                if (match(file->d_name, wildname, 1)) {  /* 1 == ignore case */
  1636. X                    Trace((stderr, "do_wild:  match() succeeds\n"));
  1637. X                    if (have_dirname) {
  1638. X                        strcpy(matchname, dirname);
  1639. X                        strcpy(matchname+dirnamelen, file->d_name);
  1640. X                    } else
  1641. X                        strcpy(matchname, file->d_name);
  1642. X                    return matchname;
  1643. X                }
  1644. X            }
  1645. X            /* if we get to here directory is exhausted, so close it */
  1646. X            closedir(dir);
  1647. X            dir = NULL;
  1648. X        }
  1649. X        Trace((stderr, "do_wild:  opendir(%s) returns NULL\n", dirname));
  1650. X
  1651. X        /* return the raw wildspec in case that works (e.g., directory not
  1652. X         * searchable, but filespec was not wild and file is readable) */
  1653. X        strcpy(matchname, wildspec);
  1654. X        return matchname;
  1655. X    }
  1656. X
  1657. X    /* last time through, might have failed opendir but returned raw wildspec */
  1658. X    if (dir == NULL) {
  1659. X        firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  1660. X        if (have_dirname)
  1661. X            free(dirname);
  1662. X        return (char *)NULL;
  1663. X    }
  1664. X
  1665. X    /* If we've gotten this far, we've read and matched at least one entry
  1666. X     * successfully (in a previous call), so dirname has been copied into
  1667. X     * matchname already.
  1668. X     */
  1669. X    while ((file = readdir(dir)) != NULL)
  1670. X        if (match(file->d_name, wildname, 1)) {   /* 1 == ignore case */
  1671. X            if (have_dirname) {
  1672. X                /* strcpy(matchname, dirname); */
  1673. X                strcpy(matchname+dirnamelen, file->d_name);
  1674. X            } else
  1675. X                strcpy(matchname, file->d_name);
  1676. X            return matchname;
  1677. X        }
  1678. X
  1679. X    closedir(dir);     /* have read at least one dir entry; nothing left */
  1680. X    dir = NULL;
  1681. X    firstcall = TRUE;  /* reset for new wildspec */
  1682. X    if (have_dirname)
  1683. X        free(dirname);
  1684. X    return (char *)NULL;
  1685. X
  1686. X} /* end function do_wild() */
  1687. X
  1688. X#endif /* !SFX */
  1689. X
  1690. X
  1691. X
  1692. X
  1693. X/************************/
  1694. X/*  Function mapname()  */
  1695. X/************************/
  1696. X
  1697. X/*
  1698. X * There are presently two possibilities in OS/2:  the output filesystem is
  1699. X * FAT, or it is HPFS.  If the former, we need to map to FAT, obviously, but
  1700. X * we *also* must map to HPFS and store that version of the name in extended
  1701. X * attributes.  Either way, we need to map to HPFS, so the main mapname
  1702. X * routine does that.  In the case that the output file system is FAT, an
  1703. X * extra filename-mapping routine is called in checkdir().  While it should
  1704. X * be possible to determine the filesystem immediately upon entry to mapname(),
  1705. X * it is conceivable that the DOS APPEND utility could be added to OS/2 some-
  1706. X * day, allowing a FAT directory to be APPENDed to an HPFS drive/path.  There-
  1707. X * fore we simply check the filesystem at each path component.
  1708. X *
  1709. X * Note that when alternative IFS's become available/popular, everything will
  1710. X * become immensely more complicated.  For example, a Minix filesystem would
  1711. X * have limited filename lengths like FAT but no extended attributes in which
  1712. X * to store the longer versions of the names.  A BSD Unix filesystem would
  1713. X * support paths of length 1024 bytes or more, but it is not clear that FAT
  1714. X * EAs would allow such long .LONGNAME fields or that OS/2 would properly
  1715. X * restore such fields when moving files from FAT to the new filesystem.
  1716. X *
  1717. X * GRR:  some or all of the following chars should be checked in either
  1718. X *       mapname (HPFS) or map2fat (FAT), depending:  ,=^+'"[]<>|\t&
  1719. X */
  1720. X
  1721. Xint mapname(renamed)  /* return 0 if no error, 1 if caution (filename trunc), */
  1722. X    int renamed;      /* 2 if warning (skip file because dir doesn't exist), */
  1723. X{                     /* 3 if error (skip file), 10 if no memory (skip file), */
  1724. X                      /* IZ_VOL_LABEL if can't do vol label, IZ_CREATED_DIR */
  1725. X    char pathcomp[FILNAMSIZ];   /* path-component buffer */
  1726. X    char *pp, *cp=NULL;         /* character pointers */
  1727. X    char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  1728. X    int quote = FALSE;          /* flag:  next char is literal */
  1729. X    int error = 0;
  1730. X    register unsigned workch;   /* hold the character being tested */
  1731. X
  1732. X
  1733. X/*---------------------------------------------------------------------------
  1734. X    Initialize various pointers and counters and stuff.
  1735. X  ---------------------------------------------------------------------------*/
  1736. X
  1737. X    /* can create path as long as not just freshening, or if user told us */
  1738. X    create_dirs = (!fflag || renamed);
  1739. X
  1740. X    created_dir = FALSE;        /* not yet */
  1741. X    renamed_fullpath = FALSE;
  1742. X    fnlen = strlen(filename);
  1743. X
  1744. X    if (renamed) {
  1745. X        cp = filename - 1;      /* point to beginning of renamed name... */
  1746. X        while (*++cp)
  1747. X            if (*cp == '\\')    /* convert backslashes to forward */
  1748. X                *cp = '/';
  1749. X        cp = filename;
  1750. X        /* use temporary rootpath if user gave full pathname */
  1751. X        if (filename[0] == '/') {
  1752. X            renamed_fullpath = TRUE;
  1753. X            pathcomp[0] = '/';  /* copy the '/' and terminate */
  1754. X            pathcomp[1] = '\0';
  1755. X            ++cp;
  1756. X        } else if (isalpha(filename[0]) && filename[1] == ':') {
  1757. X            renamed_fullpath = TRUE;
  1758. X            pp = pathcomp;
  1759. X            *pp++ = *cp++;      /* copy the "d:" (+ '/', possibly) */
  1760. X            *pp++ = *cp++;
  1761. X            if (*cp == '/')
  1762. X                *pp++ = *cp++;  /* otherwise add "./"? */
  1763. X            *pp = '\0';
  1764. X        }
  1765. X    }
  1766. X
  1767. X    /* pathcomp is ignored unless renamed_fullpath is TRUE: */
  1768. X    if ((error = checkdir(pathcomp, INIT)) != 0)    /* initialize path buffer */
  1769. X        return error;           /* ...unless no mem or vol label on hard disk */
  1770. X
  1771. X    *pathcomp = '\0';           /* initialize translation buffer */
  1772. X    pp = pathcomp;              /* point to translation buffer */
  1773. X    if (!renamed) {             /* cp already set if renamed */
  1774. X        if (jflag)              /* junking directories */
  1775. X            cp = (char *)strrchr(filename, '/');
  1776. X        if (cp == NULL)             /* no '/' or not junking dirs */
  1777. X            cp = filename;          /* point to internal zipfile-member pathname */
  1778. X        else
  1779. X            ++cp;                   /* point to start of last component of path */
  1780. X    }
  1781. X
  1782. X/*---------------------------------------------------------------------------
  1783. X    Begin main loop through characters in filename.
  1784. X  ---------------------------------------------------------------------------*/
  1785. X
  1786. X    while ((workch = (uch)*cp++) != 0) {
  1787. X
  1788. X        if (quote) {              /* if character quoted, */
  1789. X            *pp++ = (char)workch; /*  include it literally */
  1790. X            quote = FALSE;
  1791. X        } else
  1792. X            switch (workch) {
  1793. X            case '/':             /* can assume -j flag not given */
  1794. X                *pp = '\0';
  1795. X                if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
  1796. X                    return error;
  1797. X                pp = pathcomp;    /* reset conversion buffer for next piece */
  1798. X                lastsemi = NULL;  /* leave directory semi-colons alone */
  1799. X                break;
  1800. X
  1801. X            case ':':
  1802. X                *pp++ = '_';      /* drive names not stored in zipfile, */
  1803. X                break;            /*  so no colons allowed */
  1804. X
  1805. X            case ';':             /* start of VMS version? */
  1806. X                lastsemi = pp;    /* remove VMS version later... */
  1807. X                *pp++ = ';';      /*  but keep semicolon for now */
  1808. X                break;
  1809. X
  1810. X            case '\026':          /* control-V quote for special chars */
  1811. X                quote = TRUE;     /* set flag for next character */
  1812. X                break;
  1813. X
  1814. X            case ' ':             /* keep spaces unless specifically */
  1815. X                /* NT cannot create filenames with spaces on FAT volumes */
  1816. X                if (sflag || IsVolumeOldFAT(filename))
  1817. X                    *pp++ = '_';
  1818. X                else
  1819. X                    *pp++ = ' ';
  1820. X                break;
  1821. X
  1822. X            default:
  1823. X                /* allow European characters in filenames: */
  1824. X                if (isprint(workch) || (128 <= workch && workch <= 254))
  1825. X                    *pp++ = (char)workch;
  1826. X            } /* end switch */
  1827. X
  1828. X    } /* end while loop */
  1829. X
  1830. X    *pp = '\0';                   /* done with pathcomp:  terminate it */
  1831. X
  1832. X    /* if not saving them, remove VMS version numbers (appended "###") */
  1833. X    if (!V_flag && lastsemi) {
  1834. X        pp = lastsemi + 1;        /* semi-colon was kept:  expect #'s after */
  1835. X        while (isdigit((uch)(*pp)))
  1836. X            ++pp;
  1837. X        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  1838. X            *lastsemi = '\0';
  1839. X    }
  1840. X
  1841. X/*---------------------------------------------------------------------------
  1842. X    Report if directory was created (and no file to create:  filename ended
  1843. X    in '/'), check name to be sure it exists, and combine path and name be-
  1844. X    fore exiting.
  1845. X  ---------------------------------------------------------------------------*/
  1846. X
  1847. X    if (filename[fnlen-1] == '/') {
  1848. X        checkdir(filename, GETPATH);
  1849. X        if (created_dir && QCOND2) {
  1850. X/* GRR:  trailing '/'?  need to strip or not? */
  1851. X            FPRINTF(stdout, "   creating: %-22s\n", filename);
  1852. X            /* HG: are we setting the date&time on a newly created dir?  */
  1853. X            /*     Not quite sure how to do this. It does not seem to    */
  1854. X            /*     be done in the MS-DOS version of mapname().           */
  1855. X            return IZ_CREATED_DIR;   /* dir time already set */
  1856. X        }
  1857. X        return 2;   /* dir existed already; don't look for data to extract */
  1858. X    }
  1859. X
  1860. X    if (*pathcomp == '\0') {
  1861. X        FPRINTF(stderr, "mapname:  conversion of %s failed\n", filename);
  1862. X        return 3;
  1863. X    }
  1864. X
  1865. X    checkdir(pathcomp, APPEND_NAME);   /* returns 1 if truncated:  care? */
  1866. X    checkdir(filename, GETPATH);
  1867. X    Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n",
  1868. X      filename, error));
  1869. X
  1870. X    if (pInfo->vollabel) {   /* set the volume label now */
  1871. X        char drive[3];
  1872. X
  1873. X        /* Build a drive string, e.g. "b:" */
  1874. X        drive[0] = 'a' + nLabelDrive - 1;
  1875. X        drive[1] = ':';
  1876. X        drive[2] = '\0';
  1877. X        if (QCOND2)
  1878. X            FPRINTF(stdout, "labelling %s %-22s\n", drive, filename);
  1879. X        if (!SetVolumeLabel(drive, filename)) {
  1880. X            FPRINTF(stderr, "mapname:  error setting volume label\n");
  1881. X            return 3;
  1882. X        }
  1883. X        return 2;   /* success:  skip the "extraction" quietly */
  1884. X    }
  1885. X
  1886. X    return error;
  1887. X
  1888. X} /* end function mapname() */
  1889. X
  1890. X
  1891. X
  1892. X
  1893. X
  1894. X#ifndef SFX
  1895. X
  1896. X/************************/
  1897. X/*  Function version()  */
  1898. X/************************/
  1899. X
  1900. Xvoid version()
  1901. X{
  1902. X    extern char Far  CompiledWith[];
  1903. X#if defined(_MSC_VER)
  1904. X    char buf[80];
  1905. X#endif
  1906. X
  1907. X    PRINTF(LoadFarString(CompiledWith),
  1908. X
  1909. X#ifdef _MSC_VER  /* MSC == VC++, but what about SDK compiler? */
  1910. X      (sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100), buf),
  1911. X#  if (_MSC_VER >= 800)
  1912. X        "(Visual C++)",
  1913. X#  else
  1914. X        "(bad version)",
  1915. X#  endif
  1916. X#else
  1917. X      "unknown compiler (SDK?)", "",
  1918. X#endif
  1919. X
  1920. X      "Windows NT", " (32-bit)",
  1921. X
  1922. X#ifdef __DATE__
  1923. X      " on ", __DATE__
  1924. X#else
  1925. X      "", ""
  1926. X#endif
  1927. X      );
  1928. X
  1929. X    return;
  1930. X
  1931. X} /* end function version() */
  1932. X
  1933. X#endif /* !SFX */
  1934. END_OF_FILE
  1935.   if test 40790 -ne `wc -c <'unzip-5.12/nt/nt.c'`; then
  1936.     echo shar: \"'unzip-5.12/nt/nt.c'\" unpacked with wrong size!
  1937.   fi
  1938.   # end of 'unzip-5.12/nt/nt.c'
  1939. fi
  1940. echo shar: End of archive 8 \(of 20\).
  1941. cp /dev/null ark8isdone
  1942. MISSING=""
  1943. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
  1944.     if test ! -f ark${I}isdone ; then
  1945.     MISSING="${MISSING} ${I}"
  1946.     fi
  1947. done
  1948. if test "${MISSING}" = "" ; then
  1949.     echo You have unpacked all 20 archives.
  1950.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1951. else
  1952.     echo You still must unpack the following archives:
  1953.     echo "        " ${MISSING}
  1954. fi
  1955. exit 0
  1956. exit 0 # Just in case...
  1957.