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

  1. From: zip-bugs@wkuvx1.wku.edu (Info-ZIP group)
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i075:  unzip - Info-ZIP portable UnZip, version 5.12, Part10/20
  4. Date: 18 Sep 1994 23:15:39 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <35j39b$qoo@sparky.sterling.com>
  9. X-Md4-Signature: 12240212bb0bb59b8042f362e7312e91
  10.  
  11. Submitted-by: zip-bugs@wkuvx1.wku.edu (Info-ZIP group)
  12. Posting-number: Volume 44, Issue 75
  13. Archive-name: unzip/part10
  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/file_io.c unzip-5.12/tops20/make.mic
  22. #   unzip-5.12/unix/unix.c
  23. # Wrapped by kent@sparky on Sat Sep 17 23:33:41 1994
  24. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 10 (of 20)."'
  27. if test -f 'unzip-5.12/file_io.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'unzip-5.12/file_io.c'\"
  29. else
  30.   echo shar: Extracting \"'unzip-5.12/file_io.c'\" \(35360 characters\)
  31.   sed "s/^X//" >'unzip-5.12/file_io.c' <<'END_OF_FILE'
  32. X/*---------------------------------------------------------------------------
  33. X
  34. X  file_io.c
  35. X
  36. X  This file contains routines for doing direct but relatively generic input/
  37. X  output, file-related sorts of things, plus some miscellaneous stuff.  Most
  38. X  of the stuff has to do with opening, closing, reading and/or writing files.
  39. X
  40. X  Contains:  open_input_file()
  41. X             open_outfile()           (non-VMS)
  42. X             readbuf()
  43. X             readbyte()
  44. X             flush()                  (non-VMS)
  45. X             disk_error()             (non-VMS)
  46. X             handler()
  47. X             dos_to_unix_time()       (non-VMS, non-OS/2)
  48. X             check_for_newer()        (non-VMS, non-OS/2)
  49. X             find_ecrec()
  50. X             get_cdir_ent()
  51. X             do_string()
  52. X             makeword()
  53. X             makelong()
  54. X             memset()                 (ZMEM only)
  55. X             memcpy()                 (ZMEM only)
  56. X             zstrnicmp()
  57. X             zstat()                  (REGULUS only)
  58. X             LoadFarString()          (SMALL_MEM only)
  59. X             LoadFarStringSmall()     (SMALL_MEM only)
  60. X             LoadFarStringSmall2()    (SMALL_MEM only)
  61. X
  62. X  ---------------------------------------------------------------------------*/
  63. X
  64. X
  65. X#define FILE_IO_C
  66. X#include "unzip.h"
  67. X#include "crypt.h"
  68. X#include "tables.h"   /* definition/initialization of ebcdic[] */
  69. X
  70. X#ifdef USE_FWRITE
  71. X#  define WriteError(buf,len,strm) \
  72. X     ((extent)fwrite((char *)(buf),1,(extent)(len),strm) != (extent)(len))
  73. X#else
  74. X#  define WriteError(buf,len,strm) \
  75. X     ((extent)write(fileno(strm),(char *)(buf),(extent)(len)) != (extent)(len))
  76. X#endif
  77. X
  78. Xstatic int disk_error OF((void));
  79. X
  80. X
  81. X
  82. X/*****************************/
  83. X/* Strings used in file_io.c */
  84. X/*****************************/
  85. X
  86. X#ifdef UNIX
  87. X   static char Far CannotDeleteOldFile[] = "\nerror:  cannot delete old %s\n";
  88. X#endif
  89. X
  90. Xstatic char Far CantOpenZipfile[] = "error:  can't open zipfile [ %s ]\n";
  91. Xstatic char Far CannotCreateFile[] = "\nerror:  cannot create %s\n";
  92. Xstatic char Far ReadError[] = "error:  zipfile read error\n";
  93. Xstatic char Far DiskFull[] =
  94. X  "\n%s:  write error (disk full?).  Continue? (y/n/^C) ";
  95. Xstatic char Far ZipfileCorrupt[] = "error:  zipfile probably corrupt (%s)\n";
  96. Xstatic char Far CentDirEndSigNotFound[] = "\
  97. X  End-of-central-directory signature not found.  Either this file is not\n\
  98. X  a zipfile, or it constitutes one disk of a multi-part archive.  In the\n\
  99. X  latter case the central directory and zipfile comment will be found on\n\
  100. X  the last disk(s) of this archive.\n";
  101. Xstatic char Far FilenameTooLongTrunc[] =
  102. X  "warning:  filename too long--truncating.\n";
  103. Xstatic char Far ExtraFieldTooLong[] =
  104. X  "warning:  extra field too long (%d).  Ignoring...\n";
  105. X
  106. X
  107. X
  108. X
  109. X
  110. X/******************************/
  111. X/* Function open_input_file() */
  112. X/******************************/
  113. X
  114. Xint open_input_file()    /* return 1 if open failed */
  115. X{
  116. X    /*
  117. X     *  open the zipfile for reading and in BINARY mode to prevent cr/lf
  118. X     *  translation, which would corrupt the bitstreams
  119. X     */
  120. X
  121. X#if defined(UNIX) || defined(TOPS20) || defined(ATARI_ST)
  122. X    zipfd = open(zipfn, O_RDONLY);
  123. X#else /* !(UNIX || TOPS20) */
  124. X#ifdef VMS
  125. X    zipfd = open(zipfn, O_RDONLY, 0, "ctx=stm");
  126. X#else /* !VMS */
  127. X#ifdef MACOS
  128. X    zipfd = open(zipfn, 0);
  129. X#else /* !MACOS */
  130. X    zipfd = open(zipfn, O_RDONLY | O_BINARY);
  131. X#endif /* ?MACOS */
  132. X#endif /* ?VMS */
  133. X#endif /* ?(UNIX || TOPS20) */
  134. X    if (zipfd < 0) {
  135. X        FPRINTF(stderr, LoadFarString(CantOpenZipfile), zipfn);
  136. X        return 1;
  137. X    }
  138. X    return 0;
  139. X
  140. X} /* end function open_input_file() */
  141. X
  142. X
  143. X
  144. X
  145. X#ifndef VMS                      /* for VMS use code in vms.c */
  146. X
  147. X/***************************/
  148. X/* Function open_outfile() */
  149. X/***************************/
  150. X
  151. Xint open_outfile()         /* return 1 if fail */
  152. X{
  153. X#ifdef DOS_NT_OS2
  154. X    if (stat(filename, &statbuf) == 0 && !(statbuf.st_mode & S_IWRITE))
  155. X        chmod(filename, S_IREAD | S_IWRITE);
  156. X#endif
  157. X#ifdef UNIX
  158. X    if (stat(filename, &statbuf) == 0 && unlink(filename) < 0) {
  159. X        FPRINTF(stderr, LoadFarString(CannotDeleteOldFile), filename);
  160. X        return 1;
  161. X    }
  162. X#endif
  163. X#ifdef TOPS20
  164. X    char *tfilnam;
  165. X
  166. X    if ((tfilnam = (char *)malloc(2*strlen(filename)+1)) == (char *)NULL)
  167. X        return 1;
  168. X    strcpy(tfilnam, filename);
  169. X    upper(tfilnam);
  170. X    enquote(tfilnam);
  171. X    if ((outfile = fopen(tfilnam, FOPW)) == (FILE *)NULL) {
  172. X        FPRINTF(stderr, LoadFarString(CannotCreateFile), tfilnam);
  173. X        free(tfilnam);
  174. X        return 1;
  175. X    }
  176. X    free(tfilnam);
  177. X#else
  178. X#ifdef MTS
  179. X    if (aflag)
  180. X        outfile = fopen(filename, FOPWT);
  181. X    else
  182. X        outfile = fopen(filename, FOPW);
  183. X    if (outfile == (FILE *)NULL) {
  184. X        FPRINTF(stderr, LoadFarString(CannotCreateFile), filename);
  185. X        return 1;
  186. X    }
  187. X#else
  188. X    if ((outfile = fopen(filename, FOPW)) == (FILE *)NULL) {
  189. X        FPRINTF(stderr, LoadFarString(CannotCreateFile), filename);
  190. X        return 1;
  191. X    }
  192. X#endif
  193. X#endif
  194. X
  195. X#if 0      /* this SUCKS!  on Ultrix, it must be writing a byte at a time... */
  196. X    setbuf(outfile, (char *)NULL);   /* make output unbuffered */
  197. X#endif
  198. X
  199. X#ifdef USE_FWRITE
  200. X#ifdef DOS_NT_OS2
  201. X    /* 16-bit MSC: buffer size must be strictly LESS than 32K (WSIZE):  bogus */
  202. X    setbuf(outfile, (char *)NULL);   /* make output unbuffered */
  203. X#else /* !DOS_NT_OS2 */
  204. X#ifdef _IOFBF  /* make output fully buffered (works just about like write()) */
  205. X    setvbuf(outfile, (char *)slide, _IOFBF, WSIZE);
  206. X#else
  207. X    setbuf(outfile, (char *)slide);
  208. X#endif
  209. X#endif /* ?DOS_NT_OS2 */
  210. X#endif /* USE_FWRITE */
  211. X    return 0;
  212. X
  213. X} /* end function open_outfile() */
  214. X
  215. X#endif /* !VMS */
  216. X
  217. X
  218. X
  219. X
  220. X
  221. X/**********************/
  222. X/* Function readbuf() */
  223. X/**********************/
  224. X
  225. Xunsigned readbuf(buf, size)   /* return number of bytes read into buf */
  226. X    char *buf;
  227. X    register unsigned size;
  228. X{
  229. X    register unsigned count;
  230. X    unsigned n;
  231. X
  232. X    n = size;
  233. X    while (size) {
  234. X        if (incnt == 0) {
  235. X#ifdef OLD_READBUF
  236. X            if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) <= 0)
  237. X                return (n-size);
  238. X#else
  239. X            if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) == 0)
  240. X                return (n-size);
  241. X            else if (incnt < 0) {
  242. X                FPRINTF(stderr, LoadFarString(ReadError));
  243. X                return 0;  /* discarding some data; better than lock-up */
  244. X            }
  245. X#endif
  246. X            /* buffer ALWAYS starts on a block boundary:  */
  247. X            cur_zipfile_bufstart += INBUFSIZ;
  248. X            inptr = inbuf;
  249. X        }
  250. X        count = MIN(size, (unsigned)incnt);
  251. X        memcpy(buf, inptr, count);
  252. X        buf += count;
  253. X        inptr += count;
  254. X        incnt -= count;
  255. X        size -= count;
  256. X    }
  257. X    return n;
  258. X
  259. X} /* end function readbuf() */
  260. X
  261. X
  262. X
  263. X
  264. X
  265. X/***********************/
  266. X/* Function readbyte() */
  267. X/***********************/
  268. X
  269. Xint readbyte()   /* refill inbuf and return a byte if available, else EOF */
  270. X{
  271. X    if (mem_mode || (incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) <= 0)
  272. X        return EOF;
  273. X    cur_zipfile_bufstart += INBUFSIZ;   /* always starts on a block boundary */
  274. X    inptr = inbuf;
  275. X
  276. X#ifdef CRYPT
  277. X    if (pInfo->encrypted) {
  278. X        uch *p;
  279. X        int n;
  280. X
  281. X        for (n = (long)incnt > csize + 1 ? (int)csize + 1 : incnt,
  282. X             p = inptr;  n--;  p++)
  283. X            zdecode(*p);
  284. X    }
  285. X#endif /* CRYPT */
  286. X
  287. X    --incnt;
  288. X    return *inptr++;
  289. X
  290. X} /* end function readbyte() */
  291. X
  292. X
  293. X
  294. X
  295. X
  296. X#ifndef VMS                 /* for VMS use code in vms.c */
  297. X
  298. X/********************/
  299. X/* Function flush() */
  300. X/********************/
  301. X
  302. Xint flush(rawbuf, size, unshrink)   /* cflag => always 0; 50 if write error */
  303. X    uch *rawbuf;
  304. X    ulg size;
  305. X    int unshrink;
  306. X{
  307. X#ifdef ASM_CRC
  308. X    ulg CalcCRC(ulg *crc_table, ulg crcval, uch *rawbuf, ulg rawbufsize);
  309. X#else
  310. X    register ulg crcval = crc32val;
  311. X    register ulg n = size;
  312. X#endif
  313. X    register uch *p, *q;
  314. X    uch *transbuf;
  315. X    ulg transbufsiz;
  316. X    static int didCRlast = FALSE;
  317. X
  318. X
  319. X/*---------------------------------------------------------------------------
  320. X    Compute the CRC first; if testing or if disk is full, that's it.
  321. X  ---------------------------------------------------------------------------*/
  322. X
  323. X#ifdef ASM_CRC
  324. X    crc32val = CalcCRC(crc_32_tab, crc32val, rawbuf, size);
  325. X#else
  326. X    p = rawbuf;
  327. X    while (n--)
  328. X        crcval = crc_32_tab[((uch)crcval ^ (*p++)) & 0xff] ^ (crcval >> 8);
  329. X    crc32val = crcval;
  330. X#endif /* ?ASM_CRC */
  331. X
  332. X    if (tflag || size == 0L)   /* testing or nothing to write:  all done */
  333. X        return 0;
  334. X
  335. X    if (disk_full)
  336. X        return 50;            /* disk already full:  ignore rest of file */
  337. X
  338. X/*---------------------------------------------------------------------------
  339. X    Write the bytes rawbuf[0..size-1] to the output device, first converting
  340. X    end-of-lines and ASCII/EBCDIC as needed.  If SMALL_MEM or MED_MEM are NOT
  341. X    defined, outbuf is assumed to be at least as large as rawbuf and is not
  342. X    necessarily checked for overflow.
  343. X  ---------------------------------------------------------------------------*/
  344. X
  345. X    if (!pInfo->textmode) {
  346. X        /* GRR:  note that for standard MS-DOS compilers, size argument to
  347. X         * fwrite() can never be more than 65534, so WriteError macro will
  348. X         * have to be rewritten if size can ever be that large.  For now,
  349. X         * never more than 32K.  Also note that write() returns an int, which
  350. X         * doesn't necessarily limit size to 32767 bytes if write() is used
  351. X         * on 16-bit systems but does make it more of a pain; however, because
  352. X         * at least MSC 5.1 has a lousy implementation of fwrite() (as does
  353. X         * DEC Ultrix cc), write() is used anyway.
  354. X         */
  355. X        if (WriteError(rawbuf, size, outfile))  /* write raw binary data */
  356. X            return cflag? 0 : disk_error();
  357. X    } else {
  358. X        if (unshrink) {
  359. X            /* rawbuf = outbuf */
  360. X            transbuf = outbuf2;
  361. X            transbufsiz = TRANSBUFSIZ;
  362. X        } else {
  363. X            /* rawbuf = slide */
  364. X            transbuf = outbuf;
  365. X            transbufsiz = OUTBUFSIZ;
  366. X            Trace((stderr, "\ntransbufsiz = OUTBUFSIZ = %u\n", OUTBUFSIZ));
  367. X        }
  368. X        if (newfile) {
  369. X            didCRlast = FALSE;   /* no previous buffers written */
  370. X            newfile = FALSE;
  371. X        }
  372. X        p = rawbuf;
  373. X        if (*p == LF && didCRlast)
  374. X            ++p;
  375. X
  376. X    /*-----------------------------------------------------------------------
  377. X        Algorithm:  CR/LF => native; lone CR => native; lone LF => native.
  378. X        This routine is only for non-raw-VMS, non-raw-VM/CMS files (i.e.,
  379. X        stream-oriented files, not record-oriented).
  380. X      -----------------------------------------------------------------------*/
  381. X
  382. X        for (didCRlast = FALSE, q = transbuf;  p < rawbuf+size;  ++p) {
  383. X            if (*p == CR) {              /* lone CR or CR/LF: EOL either way */
  384. X                PutNativeEOL
  385. X                if (p == rawbuf+size-1)  /* last char in buffer */
  386. X                    didCRlast = TRUE;
  387. X                else if (p[1] == LF)     /* get rid of accompanying LF */
  388. X                    ++p;
  389. X            } else if (*p == LF)         /* lone LF */
  390. X                PutNativeEOL
  391. X            else
  392. X#ifndef DOS_NT_OS2
  393. X            if (*p != CTRLZ)             /* lose all ^Z's */
  394. X#endif
  395. X                *q++ = native(*p);
  396. X
  397. X#if (defined(SMALL_MEM) || defined(MED_MEM))
  398. X# if (lenEOL == 1)   /* don't check unshrink:  both buffers small but equal */
  399. X            if (!unshrink)
  400. X# endif
  401. X                /* check for danger of buffer overflow and flush */
  402. X                if (q > transbuf+transbufsiz-lenEOL) {
  403. X                    Trace((stderr,
  404. X                      "p - rawbuf = %u   q-transbuf = %u   size = %lu\n",
  405. X                      (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
  406. X                    if (WriteError(transbuf, (unsigned)(q-transbuf), outfile))
  407. X                        return cflag? 0 : disk_error();
  408. X                    q = transbuf;
  409. X                    continue;
  410. X                }
  411. X#endif /* SMALL_MEM || MED_MEM */
  412. X        }
  413. X
  414. X    /*-----------------------------------------------------------------------
  415. X        Done translating:  write whatever we've got to file.
  416. X      -----------------------------------------------------------------------*/
  417. X
  418. X        Trace((stderr, "p - rawbuf = %u   q-transbuf = %u   size = %lu\n",
  419. X          (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
  420. X        if (q > transbuf &&
  421. X            WriteError(transbuf, (unsigned)(q-transbuf), outfile))
  422. X            return cflag? 0 : disk_error();
  423. X    }
  424. X
  425. X    return 0;
  426. X
  427. X} /* end function flush() */
  428. X
  429. X
  430. X
  431. X
  432. X
  433. X/*************************/
  434. X/* Function disk_error() */
  435. X/*************************/
  436. X
  437. Xstatic int disk_error()
  438. X{
  439. X    FPRINTF(stderr, LoadFarString(DiskFull), filename);
  440. X    FFLUSH(stderr);
  441. X
  442. X#ifndef MSWIN
  443. X    fgets(answerbuf, 9, stdin);
  444. X    if (*answerbuf == 'y')   /* stop writing to this file */
  445. X        disk_full = 1;       /*  (outfile bad?), but new OK */
  446. X    else
  447. X#endif
  448. X        disk_full = 2;       /* no:  exit program */
  449. X
  450. X    return 50;               /* 50:  disk full */
  451. X
  452. X} /* end function disk_error() */
  453. X
  454. X#endif /* !VMS */
  455. X
  456. X
  457. X
  458. X
  459. X
  460. X/**********************/
  461. X/* Function handler() */
  462. X/**********************/
  463. X
  464. Xvoid handler(signal)   /* upon interrupt, turn on echo and exit cleanly */
  465. X    int signal;
  466. X{
  467. X#if defined(SIGBUS) || defined(SIGSEGV)
  468. X#  ifdef SMALL_MEM
  469. X    static char *corrupt;
  470. X    corrupt = LoadFarString(ZipfileCorrupt);
  471. X#  else
  472. X    static char *corrupt = LoadFarString(ZipfileCorrupt);
  473. X#  endif
  474. X#endif
  475. X
  476. X#if !defined(DOS_NT_OS2) && !defined(MACOS)
  477. X    echon();
  478. X    PUTC('\n', stderr);
  479. X#endif /* !DOS_NT_OS2 && !MACOS */
  480. X#ifdef SIGBUS
  481. X    if (signal == SIGBUS) {
  482. X        FPRINTF(stderr, corrupt, "bus error");
  483. X        exit(3);
  484. X    }
  485. X#endif /* SIGBUS */
  486. X#ifdef SIGSEGV
  487. X    if (signal == SIGSEGV) {
  488. X        FPRINTF(stderr, corrupt, "segmentation violation");
  489. X        exit(3);
  490. X    }
  491. X#endif /* SIGSEGV */
  492. X    exit(0);
  493. X}
  494. X
  495. X
  496. X
  497. X
  498. X
  499. X#ifdef DEBUG_TIME
  500. X#  define TTrace(x)  FPRINTF x
  501. X#else
  502. X#  define TTrace(x)
  503. X#endif
  504. X
  505. X#if !defined(VMS) && !defined(OS2)
  506. X
  507. X/*******************************/
  508. X/* Function dos_to_unix_time() */   /* only used for freshening/updating */
  509. X/*******************************/
  510. X
  511. Xtime_t dos_to_unix_time(ddate, dtime)
  512. X    unsigned ddate, dtime;
  513. X{
  514. X    int yr, mo, dy, hh, mm, ss;
  515. X#ifdef TOPS20
  516. X#   define YRBASE  1900
  517. X    struct tmx *tmx;
  518. X    char temp[20];
  519. X    time_t retval;
  520. X#else /* !TOPS20 */
  521. X#   define YRBASE  1970
  522. X    static short yday[]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  523. X    int leap;
  524. X    long m_time, days=0;
  525. X#if (!defined(MACOS) && !defined(MSC))
  526. X#if (defined(BSD) || defined(MTS) || defined(__GO32__))
  527. X#ifndef BSD4_4
  528. X    static struct timeb tbp;
  529. X#endif /* !BSD4_4 */
  530. X#else /* !(BSD || MTS || __GO32__) */
  531. X#ifdef ATARI_ST
  532. X    extern long _timezone;
  533. X#   define timezone _timezone;  /* a whoops in our library... */
  534. X#else /* !ATARI_ST */
  535. X    extern long timezone;       /* declared in <time.h> for MSC (& Borland?) */
  536. X#endif /* ?ATARI_ST */
  537. X#endif /* ?(BSD || MTS || __GO32__) */
  538. X#endif /* !MACOS && !MSC */
  539. X#endif /* ?TOPS20 */
  540. X
  541. X
  542. X    /* dissect date */
  543. X    yr = ((ddate >> 9) & 0x7f) + (1980 - YRBASE);
  544. X    mo = ((ddate >> 5) & 0x0f) - 1;
  545. X    dy = (ddate & 0x1f) - 1;
  546. X
  547. X    /* dissect time */
  548. X    hh = (dtime >> 11) & 0x1f;
  549. X    mm = (dtime >> 5) & 0x3f;
  550. X    ss = (dtime & 0x1f) * 2;
  551. X
  552. X#ifdef TOPS20
  553. X    tmx = (struct tmx *)malloc(sizeof(struct tmx));
  554. X    sprintf (temp, "%02d/%02d/%02d %02d:%02d:%02d", mo+1, dy+1, yr, hh, mm, ss);
  555. X    time_parse(temp, tmx, (char *)0);
  556. X    retval = time_make(tmx);
  557. X    free(tmx);
  558. X    return retval;
  559. X
  560. X#else /* !TOPS20 */
  561. X    /* leap = # of leap years from BASE up to but not including current year */
  562. X    leap = ((yr + YRBASE - 1) / 4);   /* leap year base factor */
  563. X
  564. X    /* calculate days from BASE to this year and add expired days this year */
  565. X    days = (yr * 365) + (leap - 492) + yday[mo];
  566. X
  567. X    /* if year is a leap year and month is after February, add another day */
  568. X    if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100))
  569. X        ++days;                 /* OK through 2199 */
  570. X
  571. X    /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */
  572. X    m_time = ((long)(days + dy) * 86400L) + ((long)hh * 3600) + (mm * 60) + ss;
  573. X      /* - 1;   MS-DOS times always rounded up to nearest even second */
  574. X    TTrace((stderr, "dos_to_unix_time:\n"));
  575. X    TTrace((stderr, "  m_time before timezone = %ld\n", m_time));
  576. X
  577. X#ifndef MACOS
  578. X#if (defined(BSD) || defined(MTS) || defined(__GO32__))
  579. X#ifndef BSD4_4
  580. X    ftime(&tbp);
  581. X    m_time += tbp.timezone * 60L;
  582. X#endif
  583. X#else /* !(BSD || MTS || __GO32__) */
  584. X#ifdef WIN32
  585. X    {
  586. X        TIME_ZONE_INFORMATION tzinfo;
  587. X        DWORD res;
  588. X
  589. X        /* account for timezone differences */
  590. X        res = GetTimeZoneInformation(&tzinfo);
  591. X        if (res == TIME_ZONE_ID_STANDARD)
  592. X            m_time += 60*(tzinfo.Bias + tzinfo.StandardBias);
  593. X        else if (res == TIME_ZONE_ID_DAYLIGHT)
  594. X            m_time += 60*(tzinfo.Bias + tzinfo.DaylightBias);
  595. X        /* GRR:  are other return-values possible? */
  596. X    }
  597. X#else /* !WIN32 */
  598. X    tzset();                    /* set `timezone' variable */
  599. X    m_time += timezone;
  600. X#endif /* ?WIN32 */
  601. X#endif /* ?(BSD || MTS || __GO32__) */
  602. X#endif /* !MACOS */
  603. X    TTrace((stderr, "  m_time after timezone =  %ld\n", m_time));
  604. X
  605. X#ifdef BSD4_4               /* see comments in unix.c */
  606. X    m_time -= localtime((time_t *) &m_time)->tm_gmtoff;
  607. X#else /* !BSD4_4 */
  608. X#ifndef WIN32
  609. X    if (localtime((time_t *)&m_time)->tm_isdst)
  610. X        m_time -= 60L * 60L;    /* adjust for daylight savings time */
  611. X#endif /* !WIN32 */
  612. X#endif /* ?BSD4_4 */
  613. X    TTrace((stderr, "  m_time after DST =       %ld\n", m_time));
  614. X
  615. X    return m_time;
  616. X#endif /* ?TOPS20 */
  617. X
  618. X} /* end function dos_to_unix_time() */
  619. X
  620. X
  621. X
  622. X
  623. X
  624. X/******************************/
  625. X/* Function check_for_newer() */   /* only used for freshening/updating */
  626. X/******************************/
  627. X
  628. Xint check_for_newer(filename)   /* return 1 if existing file newer or equal; */
  629. X    char *filename;             /*  0 if older; -1 if doesn't exist yet */
  630. X{
  631. X    time_t existing, archive;
  632. X
  633. X    if (stat(filename, &statbuf))
  634. X        return DOES_NOT_EXIST;
  635. X
  636. X    /* round up existing filetime to nearest 2 seconds for comparison */
  637. X    existing = (statbuf.st_mtime & 1) ? statbuf.st_mtime+1 : statbuf.st_mtime;
  638. X    archive  = dos_to_unix_time(lrec.last_mod_file_date,
  639. X                                lrec.last_mod_file_time);
  640. X
  641. X    TTrace((stderr, "check_for_newer:  existing %ld, archive %ld, e-a %ld\n",
  642. X      existing, archive, existing-archive));
  643. X
  644. X    return (existing >= archive);
  645. X
  646. X} /* end function check_for_newer() */
  647. X
  648. X#endif /* !VMS && !OS2 */
  649. X
  650. X
  651. X
  652. X
  653. X
  654. X/*************************/
  655. X/* Function find_ecrec() */
  656. X/*************************/
  657. X
  658. Xint find_ecrec(searchlen)   /* return PK-class error */
  659. X    long searchlen;
  660. X{
  661. X    int i, numblks, found=FALSE;
  662. X    LONGINT tail_len;
  663. X    ec_byte_rec byterec;
  664. X
  665. X
  666. X/*---------------------------------------------------------------------------
  667. X    Treat case of short zipfile separately.
  668. X  ---------------------------------------------------------------------------*/
  669. X
  670. X    if (ziplen <= INBUFSIZ) {
  671. X        lseek(zipfd, 0L, SEEK_SET);
  672. X        if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)ziplen)) ==
  673. X             (int)ziplen)
  674. X
  675. X            /* 'P' must be at least 22 bytes from end of zipfile */
  676. X            for (inptr = inbuf+(int)ziplen-22;  inptr >= inbuf;  --inptr)
  677. X                if ((native(*inptr) == 'P')  &&
  678. X                     !strncmp((char *)inptr, end_central_sig, 4)) {
  679. X                    incnt -= inptr - inbuf;
  680. X                    found = TRUE;
  681. X                    break;
  682. X                }
  683. X
  684. X/*---------------------------------------------------------------------------
  685. X    Zipfile is longer than INBUFSIZ:  may need to loop.  Start with short
  686. X    block at end of zipfile (if not TOO short).
  687. X  ---------------------------------------------------------------------------*/
  688. X
  689. X    } else {
  690. X        if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) {
  691. X            cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
  692. X            if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)tail_len)) !=
  693. X                 (int)tail_len)
  694. X                goto fail;      /* shut up; it's expedient */
  695. X
  696. X            /* 'P' must be at least 22 bytes from end of zipfile */
  697. X            for (inptr = inbuf+(int)tail_len-22;  inptr >= inbuf;  --inptr)
  698. X                if ((native(*inptr) == 'P')  &&
  699. X                     !strncmp((char *)inptr, end_central_sig, 4)) {
  700. X                    incnt -= inptr - inbuf;
  701. X                    found = TRUE;
  702. X                    break;
  703. X                }
  704. X            /* sig may span block boundary: */
  705. X            strncpy((char *)hold, (char *)inbuf, 3);
  706. X        } else
  707. X            cur_zipfile_bufstart = ziplen - tail_len;
  708. X
  709. X    /*-----------------------------------------------------------------------
  710. X        Loop through blocks of zipfile data, starting at the end and going
  711. X        toward the beginning.  In general, need not check whole zipfile for
  712. X        signature, but may want to do so if testing.
  713. X      -----------------------------------------------------------------------*/
  714. X
  715. X        numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
  716. X        /*               ==amount=   ==done==   ==rounding==    =blksiz=  */
  717. X
  718. X        for (i = 1;  !found && (i <= numblks);  ++i) {
  719. X            cur_zipfile_bufstart -= INBUFSIZ;
  720. X            lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
  721. X            if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) != INBUFSIZ)
  722. X                break;          /* fall through and fail */
  723. X
  724. X            for (inptr = inbuf+INBUFSIZ-1;  inptr >= inbuf;  --inptr)
  725. X                if ((native(*inptr) == 'P')  &&
  726. X                     !strncmp((char *)inptr, end_central_sig, 4)) {
  727. X                    incnt -= inptr - inbuf;
  728. X                    found = TRUE;
  729. X                    break;
  730. X                }
  731. X            /* sig may span block boundary: */
  732. X            strncpy((char *)hold, (char *)inbuf, 3);
  733. X        }
  734. X    } /* end if (ziplen > INBUFSIZ) */
  735. X
  736. X/*---------------------------------------------------------------------------
  737. X    Searched through whole region where signature should be without finding
  738. X    it.  Print informational message and die a horrible death.
  739. X  ---------------------------------------------------------------------------*/
  740. X
  741. Xfail:
  742. X    if (!found) {
  743. X#ifdef MSWIN
  744. X        MessageBeep(1);
  745. X#endif
  746. X        if (qflag || (zipinfo_mode && !hflag))
  747. X            FPRINTF(stderr, "[%s]\n", zipfn);
  748. X        FPRINTF(stderr, LoadFarString(CentDirEndSigNotFound));
  749. X        return PK_ERR;   /* failed */
  750. X    }
  751. X
  752. X/*---------------------------------------------------------------------------
  753. X    Found the signature, so get the end-central data before returning.  Do
  754. X    any necessary machine-type conversions (byte ordering, structure padding
  755. X    compensation) by reading data into character array and copying to struct.
  756. X  ---------------------------------------------------------------------------*/
  757. X
  758. X    real_ecrec_offset = cur_zipfile_bufstart + (inptr-inbuf);
  759. X#ifdef TEST
  760. X    printf("\n  found end-of-central-dir signature at offset %ld (%.8lXh)\n",
  761. X      real_ecrec_offset, real_ecrec_offset);
  762. X    printf("    from beginning of file; offset %d (%.4Xh) within block\n",
  763. X      inptr-inbuf, inptr-inbuf);
  764. X#endif
  765. X
  766. X    if (readbuf((char *)byterec, ECREC_SIZE+4) == 0)
  767. X        return PK_EOF;
  768. X
  769. X    ecrec.number_this_disk =
  770. X        makeword(&byterec[NUMBER_THIS_DISK]);
  771. X    ecrec.num_disk_with_start_central_dir =
  772. X        makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
  773. X    ecrec.num_entries_centrl_dir_ths_disk =
  774. X        makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
  775. X    ecrec.total_entries_central_dir =
  776. X        makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
  777. X    ecrec.size_central_directory =
  778. X        makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
  779. X    ecrec.offset_start_central_directory =
  780. X        makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
  781. X    ecrec.zipfile_comment_length =
  782. X        makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
  783. X
  784. X    expect_ecrec_offset = ecrec.offset_start_central_directory +
  785. X                          ecrec.size_central_directory;
  786. X    return PK_COOL;
  787. X
  788. X} /* end function find_ecrec() */
  789. X
  790. X
  791. X
  792. X
  793. X
  794. X/***************************/
  795. X/* Function get_cdir_ent() */
  796. X/***************************/
  797. X
  798. Xint get_cdir_ent()   /* return PK-type error code */
  799. X{
  800. X    cdir_byte_hdr byterec;
  801. X
  802. X
  803. X/*---------------------------------------------------------------------------
  804. X    Read the next central directory entry and do any necessary machine-type
  805. X    conversions (byte ordering, structure padding compensation--do so by
  806. X    copying the data from the array into which it was read (byterec) to the
  807. X    usable struct (crec)).
  808. X  ---------------------------------------------------------------------------*/
  809. X
  810. X    if (readbuf((char *)byterec, CREC_SIZE) == 0)
  811. X        return PK_EOF;
  812. X
  813. X    crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
  814. X    crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
  815. X    crec.version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
  816. X    crec.version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
  817. X
  818. X    crec.general_purpose_bit_flag =
  819. X        makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
  820. X    crec.compression_method =
  821. X        makeword(&byterec[C_COMPRESSION_METHOD]);
  822. X    crec.last_mod_file_time =
  823. X        makeword(&byterec[C_LAST_MOD_FILE_TIME]);
  824. X    crec.last_mod_file_date =
  825. X        makeword(&byterec[C_LAST_MOD_FILE_DATE]);
  826. X    crec.crc32 =
  827. X        makelong(&byterec[C_CRC32]);
  828. X    crec.csize =
  829. X        makelong(&byterec[C_COMPRESSED_SIZE]);
  830. X    crec.ucsize =
  831. X        makelong(&byterec[C_UNCOMPRESSED_SIZE]);
  832. X    crec.filename_length =
  833. X        makeword(&byterec[C_FILENAME_LENGTH]);
  834. X    crec.extra_field_length =
  835. X        makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
  836. X    crec.file_comment_length =
  837. X        makeword(&byterec[C_FILE_COMMENT_LENGTH]);
  838. X    crec.disk_number_start =
  839. X        makeword(&byterec[C_DISK_NUMBER_START]);
  840. X    crec.internal_file_attributes =
  841. X        makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
  842. X    crec.external_file_attributes =
  843. X        makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]);  /* LONG, not word! */
  844. X    crec.relative_offset_local_header =
  845. X        makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
  846. X
  847. X    return PK_COOL;
  848. X
  849. X} /* end function get_cdir_ent() */
  850. X
  851. X
  852. X
  853. X
  854. X
  855. X/************************/
  856. X/* Function do_string() */
  857. X/************************/
  858. X
  859. Xint do_string(len, option)      /* return PK-type error code */
  860. X    unsigned int len;           /* without prototype, ush converted to this */
  861. X    int option;
  862. X{
  863. X    long comment_bytes_left, block_length;
  864. X    int error=PK_OK;
  865. X    ush extra_len;
  866. X
  867. X
  868. X/*---------------------------------------------------------------------------
  869. X    This function processes arbitrary-length (well, usually) strings.  Three
  870. X    options are allowed:  SKIP, wherein the string is skipped (pretty logical,
  871. X    eh?); DISPLAY, wherein the string is printed to standard output after un-
  872. X    dergoing any necessary or unnecessary character conversions; and FILENAME,
  873. X    wherein the string is put into the filename[] array after undergoing ap-
  874. X    propriate conversions (including case-conversion, if that is indicated:
  875. X    see the global variable pInfo->lcflag).  The latter option should be OK,
  876. X    since filename is now dimensioned at 1025, but we check anyway.
  877. X
  878. X    The string, by the way, is assumed to start at the current file-pointer
  879. X    position; its length is given by len.  So start off by checking length
  880. X    of string:  if zero, we're already done.
  881. X  ---------------------------------------------------------------------------*/
  882. X
  883. X    if (!len)
  884. X        return PK_COOL;
  885. X
  886. X    switch (option) {
  887. X
  888. X    /*
  889. X     * First case:  print string on standard output.  First set loop vari-
  890. X     * ables, then loop through the comment in chunks of OUTBUFSIZ bytes,
  891. X     * converting formats and printing as we go.  The second half of the
  892. X     * loop conditional was added because the file might be truncated, in
  893. X     * which case comment_bytes_left will remain at some non-zero value for
  894. X     * all time.  outbuf and slide are used as scratch buffers because they
  895. X     * are available (we should be either before or in between any file pro-
  896. X     * cessing).
  897. X     */
  898. X
  899. X    case DISPLAY:
  900. X        comment_bytes_left = len;
  901. X        block_length = OUTBUFSIZ;    /* for the while statement, first time */
  902. X        while (comment_bytes_left > 0 && block_length > 0) {
  903. X#ifndef MSWIN
  904. X            register uch *p = outbuf;
  905. X            register uch *q = outbuf;
  906. X#endif
  907. X            if ((block_length = readbuf((char *)outbuf,
  908. X                   (unsigned) MIN((long)OUTBUFSIZ, comment_bytes_left))) == 0)
  909. X                return PK_EOF;
  910. X            comment_bytes_left -= block_length;
  911. X
  912. X            /* this is why we allocated an extra byte for outbuf: */
  913. X            outbuf[block_length] = '\0';   /* terminate w/zero:  ASCIIZ */
  914. X
  915. X            /* remove all ASCII carriage returns comment before printing
  916. X             * (since used before A_TO_N(), check for CR instead of '\r')
  917. X             */
  918. X            while (*p) {
  919. X                while (*p == CR)
  920. X                    ++p;
  921. X                *q++ = *p++;
  922. X            }
  923. X            /* could check whether (p - outbuf) == block_length here */
  924. X            *q = '\0';
  925. X
  926. X            A_TO_N(outbuf);   /* translate string to native */
  927. X
  928. X#ifdef MSWIN
  929. X            /* ran out of local mem -- had to cheat */
  930. X            WriteStringToMsgWin(outbuf, bRealTimeMsgUpdate);
  931. X#else /* !MSWIN */
  932. X#ifdef NATIVE
  933. X            PRINTF("%s", outbuf);   /* GRR:  can ANSI be used with EBCDIC? */
  934. X#else /* ASCII */
  935. X            p = outbuf - 1;
  936. X            q = slide;
  937. X            while (*++p) {
  938. X                if (*p == 0x1B) {   /* ASCII escape char */
  939. X                    *q++ = '^';
  940. X                    *q++ = '[';
  941. X                } else
  942. X                    *q++ = *p;
  943. X                if ((unsigned)(q-slide) > WSIZE-3) {   /* time to flush */
  944. X                    *q = '\0';
  945. X                    PRINTF("%s", slide);
  946. X                    q = slide;
  947. X                }
  948. X            }
  949. X            *q = '\0';
  950. X            PRINTF("%s", slide);
  951. X#endif /* ?NATIVE */
  952. X#endif /* ?MSWIN */
  953. X        }
  954. X        PRINTF("\n");   /* assume no newline at end */
  955. X        break;
  956. X
  957. X    /*
  958. X     * Second case:  read string into filename[] array.  The filename should
  959. X     * never ever be longer than FILNAMSIZ-1 (1024), but for now we'll check,
  960. X     * just to be sure.
  961. X     */
  962. X
  963. X    case FILENAME:
  964. X        extra_len = 0;
  965. X        if (len >= FILNAMSIZ) {
  966. X            FPRINTF(stderr, LoadFarString(FilenameTooLongTrunc));
  967. X            error = PK_WARN;
  968. X            extra_len = len - FILNAMSIZ + 1;
  969. X            len = FILNAMSIZ - 1;
  970. X        }
  971. X        if (readbuf(filename, len) == 0)
  972. X            return PK_EOF;
  973. X        filename[len] = '\0';   /* terminate w/zero:  ASCIIZ */
  974. X
  975. X        A_TO_N(filename);       /* translate string to native */
  976. X
  977. X        if (pInfo->lcflag)      /* replace with lowercase filename */
  978. X            TOLOWER(filename, filename);
  979. X
  980. X        if (pInfo->vollabel && len > 8 && filename[8] == '.') {
  981. X            char *p = filename+8;
  982. X            while (*p++)
  983. X                p[-1] = *p;  /* disk label, and 8th char is dot:  remove dot */
  984. X        }
  985. X
  986. X        if (!extra_len)         /* we're done here */
  987. X            break;
  988. X
  989. X        /*
  990. X         * We truncated the filename, so print what's left and then fall
  991. X         * through to the SKIP routine.
  992. X         */
  993. X        FPRINTF(stderr, "[ %s ]\n", filename);
  994. X        len = extra_len;
  995. X        /*  FALL THROUGH...  */
  996. X
  997. X    /*
  998. X     * Third case:  skip string, adjusting readbuf's internal variables
  999. X     * as necessary (and possibly skipping to and reading a new block of
  1000. X     * data).
  1001. X     */
  1002. X
  1003. X    case SKIP:
  1004. X        LSEEK(cur_zipfile_bufstart + (inptr-inbuf) + len)
  1005. X        break;
  1006. X
  1007. X    /*
  1008. X     * Fourth case:  assume we're at the start of an "extra field"; malloc
  1009. X     * storage for it and read data into the allocated space.
  1010. X     */
  1011. X
  1012. X    case EXTRA_FIELD:
  1013. X        if (extra_field != (uch *)NULL)
  1014. X            free(extra_field);
  1015. X        if ((extra_field = (uch *)malloc(len)) == (uch *)NULL) {
  1016. X            FPRINTF(stderr, LoadFarString(ExtraFieldTooLong), len);
  1017. X            LSEEK(cur_zipfile_bufstart + (inptr-inbuf) + len)
  1018. X        } else
  1019. X            if (readbuf((char *)extra_field, len) == 0)
  1020. X                return PK_EOF;
  1021. X        break;
  1022. X
  1023. X    } /* end switch (option) */
  1024. X    return error;
  1025. X
  1026. X} /* end function do_string() */
  1027. X
  1028. X
  1029. X
  1030. X
  1031. X
  1032. X/***********************/
  1033. X/* Function makeword() */
  1034. X/***********************/
  1035. X
  1036. Xush makeword(b)
  1037. X    uch *b;
  1038. X{
  1039. X    /*
  1040. X     * Convert Intel style 'short' integer to non-Intel non-16-bit
  1041. X     * host format.  This routine also takes care of byte-ordering.
  1042. X     */
  1043. X    return (ush)((b[1] << 8) | b[0]);
  1044. X}
  1045. X
  1046. X
  1047. X
  1048. X
  1049. X
  1050. X/***********************/
  1051. X/* Function makelong() */
  1052. X/***********************/
  1053. X
  1054. Xulg makelong(sig)
  1055. X    uch *sig;
  1056. X{
  1057. X    /*
  1058. X     * Convert intel style 'long' variable to non-Intel non-16-bit
  1059. X     * host format.  This routine also takes care of byte-ordering.
  1060. X     */
  1061. X    return (((ulg)sig[3]) << 24)
  1062. X        + (((ulg)sig[2]) << 16)
  1063. X        + (((ulg)sig[1]) << 8)
  1064. X        + ((ulg)sig[0]);
  1065. X}
  1066. X
  1067. X
  1068. X
  1069. X
  1070. X
  1071. X#ifdef ZMEM   /* memset, memcpy for systems without them */
  1072. X
  1073. X/*********************/
  1074. X/* Function memset() */
  1075. X/*********************/
  1076. X
  1077. Xchar *memset(buf, init, len)
  1078. X    register char *buf, init;   /* buffer loc and initializer */
  1079. X    register unsigned int len;  /* length of the buffer */
  1080. X{
  1081. X    char *start;
  1082. X
  1083. X    start = buf;
  1084. X    while (len--)
  1085. X        *(buf++) = init;
  1086. X    return start;
  1087. X}
  1088. X
  1089. X
  1090. X
  1091. X
  1092. X
  1093. X/*********************/
  1094. X/* Function memcpy() */
  1095. X/*********************/
  1096. X
  1097. Xchar *memcpy(dst, src, len)
  1098. X    register char *dst, *src;
  1099. X    register unsigned int len;
  1100. X{
  1101. X    char *start;
  1102. X
  1103. X    start = dst;
  1104. X    while (len-- > 0)
  1105. X        *dst++ = *src++;
  1106. X    return start;
  1107. X}
  1108. X
  1109. X#endif /* ZMEM */
  1110. X
  1111. X
  1112. X
  1113. X
  1114. X
  1115. X/************************/
  1116. X/* Function zstrnicmp() */
  1117. X/************************/
  1118. X
  1119. Xint zstrnicmp(s1, s2, n)
  1120. X    register char *s1, *s2;
  1121. X    register int n;
  1122. X{
  1123. X    for (; n > 0;  --n, ++s1, ++s2) {
  1124. X
  1125. X        if (ToLower(*s1) != ToLower(*s2))
  1126. X            /* test includes early termination of one string */
  1127. X            return (ToLower(*s1) < ToLower(*s2))? -1 : 1;
  1128. X
  1129. X        if (*s1 == '\0')   /* both strings terminate early */
  1130. X            return 0;
  1131. X    }
  1132. X    return 0;
  1133. X}
  1134. X
  1135. X
  1136. X
  1137. X
  1138. X
  1139. X#ifdef REGULUS  /* returns the inode number on success(!)...argh argh argh */
  1140. X#  undef stat
  1141. X
  1142. X/********************/
  1143. X/* Function zstat() */
  1144. X/********************/
  1145. X
  1146. Xint zstat(p, s)
  1147. X    char *p;
  1148. X    struct stat *s;
  1149. X{
  1150. X    return (stat(p,s) >= 0? 0 : (-1));
  1151. X}
  1152. X
  1153. X#endif /* REGULUS */
  1154. X
  1155. X
  1156. X
  1157. X
  1158. X
  1159. X#ifdef SMALL_MEM
  1160. X
  1161. Xchar rgchBigBuffer[512];
  1162. Xchar rgchSmallBuffer[96];
  1163. Xchar rgchSmallBuffer2[96];
  1164. X
  1165. X/******************************/
  1166. X/*  Function LoadFarString()  */   /* (and friends...) */
  1167. X/******************************/
  1168. X
  1169. Xchar *LoadFarString(char Far *sz)
  1170. X{
  1171. X    (void)zfstrcpy(rgchBigBuffer, sz);
  1172. X    return rgchBigBuffer;
  1173. X}
  1174. X
  1175. Xchar *LoadFarStringSmall(char Far *sz)
  1176. X{
  1177. X    (void)zfstrcpy(rgchSmallBuffer, sz);
  1178. X    return rgchSmallBuffer;
  1179. X}
  1180. X
  1181. Xchar *LoadFarStringSmall2(char Far *sz)
  1182. X{
  1183. X    (void)zfstrcpy(rgchSmallBuffer2, sz);
  1184. X    return rgchSmallBuffer2;
  1185. X}
  1186. X
  1187. X
  1188. X/*************************/
  1189. X/*  Function zfstrcpy()  */   /* portable clone of _fstrcpy() */
  1190. X/*************************/
  1191. X
  1192. Xchar Far * Far zfstrcpy(char Far *s1, const char Far *s2)
  1193. X{
  1194. X    char Far *p = s1;
  1195. X
  1196. X    while ((*s1++ = *s2++) != '\0');
  1197. X    return p;
  1198. X}
  1199. X
  1200. X#endif /* SMALL_MEM */
  1201. END_OF_FILE
  1202.   if test 35360 -ne `wc -c <'unzip-5.12/file_io.c'`; then
  1203.     echo shar: \"'unzip-5.12/file_io.c'\" unpacked with wrong size!
  1204.   fi
  1205.   # end of 'unzip-5.12/file_io.c'
  1206. fi
  1207. if test -f 'unzip-5.12/tops20/make.mic' -a "${1}" != "-c" ; then 
  1208.   echo shar: Will not clobber existing file \"'unzip-5.12/tops20/make.mic'\"
  1209. else
  1210.   echo shar: Extracting \"'unzip-5.12/tops20/make.mic'\" \(369 characters\)
  1211.   sed "s/^X//" >'unzip-5.12/tops20/make.mic' <<'END_OF_FILE'
  1212. X@te no pau e
  1213. X@cc -c -q unzip
  1214. X@cc -c -q crypt
  1215. X@cc -c -q envarg
  1216. X@cc -c -q explod
  1217. X@cc -c -q extrac
  1218. X@cc -c -q fileio
  1219. X@cc -c -q inflat
  1220. X@cc -c -q match
  1221. X@cc -c -q unredu
  1222. X@cc -c -q unshri
  1223. X@cc -c -q zipinf
  1224. X@cc -c -q tops20
  1225. X@cc -o unzip unzip.rel crypt.rel envarg.rel explod.rel extrac.rel fileio.rel inflat.rel match.rel unredu.rel unshri.rel zipinf.rel tops20.rel -ltmx 
  1226. X@kmic
  1227. END_OF_FILE
  1228.   if test 369 -ne `wc -c <'unzip-5.12/tops20/make.mic'`; then
  1229.     echo shar: \"'unzip-5.12/tops20/make.mic'\" unpacked with wrong size!
  1230.   fi
  1231.   # end of 'unzip-5.12/tops20/make.mic'
  1232. fi
  1233. if test -f 'unzip-5.12/unix/unix.c' -a "${1}" != "-c" ; then 
  1234.   echo shar: Will not clobber existing file \"'unzip-5.12/unix/unix.c'\"
  1235. else
  1236.   echo shar: Extracting \"'unzip-5.12/unix/unix.c'\" \(30753 characters\)
  1237.   sed "s/^X//" >'unzip-5.12/unix/unix.c' <<'END_OF_FILE'
  1238. X/*---------------------------------------------------------------------------
  1239. X
  1240. X  unix.c
  1241. X
  1242. X  Unix-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  1243. X
  1244. X  Contains:  readdir()
  1245. X             do_wild()           <-- generic enough to put in file_io.c?
  1246. X             mapattr()
  1247. X             mapname()
  1248. X             checkdir()
  1249. X             mkdir()
  1250. X             close_outfile()
  1251. X             version()
  1252. X
  1253. X  ---------------------------------------------------------------------------*/
  1254. X
  1255. X
  1256. X#include "unzip.h"
  1257. X
  1258. X/* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
  1259. X#if defined(__convexc__) || defined(SYSV) || defined(CRAY) || defined(BSD4_4)
  1260. X#  define DIRENT
  1261. X#endif
  1262. X#if defined(_AIX)
  1263. X#  define DIRENT
  1264. X#endif
  1265. X#ifdef COHERENT
  1266. X#  if defined(_I386) || (defined(__COHERENT__) && (__COHERENT__ >= 0x420))
  1267. X#    define DIRENT
  1268. X#  endif
  1269. X#endif
  1270. X
  1271. X/* GRR:  may need to uncomment one or both of these for the relevant systems */
  1272. X
  1273. X#if 0
  1274. X#if defined(_POSIX_VERSION)
  1275. X#  define DIRENT
  1276. X#endif
  1277. X#endif
  1278. X
  1279. X#if 0
  1280. X#if defined(M_XENIX)
  1281. X#  define SYSNDIR
  1282. X#endif
  1283. X#endif
  1284. X
  1285. X#ifdef DIRENT
  1286. X#  include <dirent.h>
  1287. X#else
  1288. X#  ifdef SYSV
  1289. X#    ifdef SYSNDIR
  1290. X#      include <sys/ndir.h>
  1291. X#    else
  1292. X#      include <ndir.h>
  1293. X#    endif
  1294. X#  else /* !SYSV */
  1295. X#    ifndef NO_SYSDIR
  1296. X#      include <sys/dir.h>
  1297. X#    endif
  1298. X#  endif /* ?SYSV */
  1299. X#  ifndef dirent
  1300. X#    define dirent direct
  1301. X#  endif
  1302. X#endif /* ?DIRENT */
  1303. X
  1304. Xstatic int created_dir;        /* used in mapname(), checkdir() */
  1305. Xstatic int renamed_fullpath;   /* ditto */
  1306. X
  1307. X
  1308. X#ifndef SFX
  1309. X#ifdef NO_DIR                    /* for AT&T 3B1 */
  1310. X
  1311. X#define opendir(path) fopen(path,"r")
  1312. X#define closedir(dir) fclose(dir)
  1313. Xtypedef FILE DIR;
  1314. X
  1315. X/*
  1316. X *  Apparently originally by Rich Salz.
  1317. X *  Cleaned up and modified by James W. Birdsall.
  1318. X */
  1319. Xstruct dirent *readdir(dirp)
  1320. X    DIR *dirp;
  1321. X{
  1322. X    static struct dirent entry;
  1323. X
  1324. X    if (dirp == NULL) 
  1325. X        return NULL;
  1326. X
  1327. X    for (;;)
  1328. X        if (fread(&entry, sizeof (struct dirent), 1, dirp) == 0) 
  1329. X            return (struct dirent *)NULL;
  1330. X        else if (entry.d_ino) 
  1331. X            return &entry;
  1332. X
  1333. X} /* end function readdir() */
  1334. X
  1335. X#endif /* NO_DIR */
  1336. X
  1337. X
  1338. X/**********************/
  1339. X/* Function do_wild() */   /* for porting:  dir separator; match(ignore_case) */
  1340. X/**********************/
  1341. X
  1342. Xchar *do_wild(wildspec)
  1343. X    char *wildspec;         /* only used first time on a given dir */
  1344. X{
  1345. X    static DIR *dir = (DIR *)NULL;
  1346. X    static char *dirname, *wildname, matchname[FILNAMSIZ];
  1347. X    static int firstcall=TRUE, have_dirname, dirnamelen;
  1348. X    struct dirent *file;
  1349. X
  1350. X
  1351. X    /* Even when we're just returning wildspec, we *always* do so in
  1352. X     * matchname[]--calling routine is allowed to append four characters
  1353. X     * to the returned string, and wildspec may be a pointer to argv[].
  1354. X     */
  1355. X    if (firstcall) {        /* first call:  must initialize everything */
  1356. X        firstcall = FALSE;
  1357. X
  1358. X        /* break the wildspec into a directory part and a wildcard filename */
  1359. X        if ((wildname = strrchr(wildspec, '/')) == (char *)NULL) {
  1360. X            dirname = ".";
  1361. X            dirnamelen = 1;
  1362. X            have_dirname = FALSE;
  1363. X            wildname = wildspec;
  1364. X        } else {
  1365. X            ++wildname;     /* point at character after '/' */
  1366. X            dirnamelen = wildname - wildspec;
  1367. X            if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  1368. X                FPRINTF(stderr, "warning:  can't allocate wildcard buffers\n");
  1369. X                strcpy(matchname, wildspec);
  1370. X                return matchname;   /* but maybe filespec was not a wildcard */
  1371. X            }
  1372. X            strncpy(dirname, wildspec, dirnamelen);
  1373. X            dirname[dirnamelen] = '\0';   /* terminate for strcpy below */
  1374. X            have_dirname = TRUE;
  1375. X        }
  1376. X
  1377. X        if ((dir = opendir(dirname)) != (DIR *)NULL) {
  1378. X            while ((file = readdir(dir)) != (struct dirent *)NULL) {
  1379. X                if (file->d_name[0] == '.' && wildname[0] != '.')
  1380. X                    continue;  /* Unix:  '*' and '?' do not match leading dot */
  1381. X                if (match(file->d_name, wildname, 0)) {  /* 0 == case sens. */
  1382. X                    if (have_dirname) {
  1383. X                        strcpy(matchname, dirname);
  1384. X                        strcpy(matchname+dirnamelen, file->d_name);
  1385. X                    } else
  1386. X                        strcpy(matchname, file->d_name);
  1387. X                    return matchname;
  1388. X                }
  1389. X            }
  1390. X            /* if we get to here directory is exhausted, so close it */
  1391. X            closedir(dir);
  1392. X            dir = (DIR *)NULL;
  1393. X        }
  1394. X
  1395. X        /* return the raw wildspec in case that works (e.g., directory not
  1396. X         * searchable, but filespec was not wild and file is readable) */
  1397. X        strcpy(matchname, wildspec);
  1398. X        return matchname;
  1399. X    }
  1400. X
  1401. X    /* last time through, might have failed opendir but returned raw wildspec */
  1402. X    if (dir == (DIR *)NULL) {
  1403. X        firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  1404. X        if (have_dirname)
  1405. X            free(dirname);
  1406. X        return (char *)NULL;
  1407. X    }
  1408. X
  1409. X    /* If we've gotten this far, we've read and matched at least one entry
  1410. X     * successfully (in a previous call), so dirname has been copied into
  1411. X     * matchname already.
  1412. X     */
  1413. X    while ((file = readdir(dir)) != (struct dirent *)NULL)
  1414. X        if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  1415. X            if (have_dirname) {
  1416. X                /* strcpy(matchname, dirname); */
  1417. X                strcpy(matchname+dirnamelen, file->d_name);
  1418. X            } else
  1419. X                strcpy(matchname, file->d_name);
  1420. X            return matchname;
  1421. X        }
  1422. X
  1423. X    closedir(dir);     /* have read at least one dir entry; nothing left */
  1424. X    dir = (DIR *)NULL;
  1425. X    firstcall = TRUE;  /* reset for new wildspec */
  1426. X    if (have_dirname)
  1427. X        free(dirname);
  1428. X    return (char *)NULL;
  1429. X
  1430. X} /* end function do_wild() */
  1431. X
  1432. X#endif /* !SFX */
  1433. X
  1434. X
  1435. X
  1436. X
  1437. X
  1438. X/**********************/
  1439. X/* Function mapattr() */
  1440. X/**********************/
  1441. X
  1442. Xint mapattr()
  1443. X{
  1444. X    ulg tmp = crec.external_file_attributes;
  1445. X
  1446. X    switch (pInfo->hostnum) {
  1447. X        case UNIX_:
  1448. X        case VMS_:
  1449. X            pInfo->file_attr = (unsigned)(tmp >> 16);
  1450. X            return 0;
  1451. X        case AMIGA_:
  1452. X            tmp = (unsigned)(tmp>>17 & 7);   /* Amiga RWE bits */
  1453. X            pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
  1454. X            break;
  1455. X        /* all remaining cases:  expand MSDOS read-only bit into write perms */
  1456. X        case FS_FAT_:
  1457. X        case FS_HPFS_:
  1458. X        case FS_NTFS_:
  1459. X        case MAC_:
  1460. X        case ATARI_:             /* (used to set = 0666) */
  1461. X        case TOPS20_:
  1462. X        default:
  1463. X            tmp = !(tmp & 1) << 1;   /* read-only bit --> write perms bits */
  1464. X            pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
  1465. X            break;
  1466. X    } /* end switch (host-OS-created-by) */
  1467. X
  1468. X    /* for originating systems with no concept of "group," "other," "system": */
  1469. X    umask( (int)(tmp=umask(0)) );    /* apply mask to expanded r/w(/x) perms */
  1470. X    pInfo->file_attr &= ~tmp;
  1471. X
  1472. X    return 0;
  1473. X
  1474. X} /* end function mapattr() */
  1475. X
  1476. X
  1477. X
  1478. X
  1479. X
  1480. X/************************/
  1481. X/*  Function mapname()  */
  1482. X/************************/
  1483. X
  1484. Xint mapname(renamed)  /* return 0 if no error, 1 if caution (filename trunc), */
  1485. X    int renamed;      /* 2 if warning (skip file because dir doesn't exist), */
  1486. X{                     /* 3 if error (skip file), 10 if no memory (skip file) */
  1487. X    char pathcomp[FILNAMSIZ];    /* path-component buffer */
  1488. X    char *pp, *cp=(char *)NULL;  /* character pointers */
  1489. X    char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  1490. X    int quote = FALSE;           /* flags */
  1491. X    int error = 0;
  1492. X    register unsigned workch;    /* hold the character being tested */
  1493. X
  1494. X
  1495. X/*---------------------------------------------------------------------------
  1496. X    Initialize various pointers and counters and stuff.
  1497. X  ---------------------------------------------------------------------------*/
  1498. X
  1499. X    if (pInfo->vollabel)
  1500. X        return IZ_VOL_LABEL;    /* can't set disk volume labels in Unix */
  1501. X
  1502. X    /* can create path as long as not just freshening, or if user told us */
  1503. X    create_dirs = (!fflag || renamed);
  1504. X
  1505. X    created_dir = FALSE;        /* not yet */
  1506. X
  1507. X    /* user gave full pathname:  don't prepend rootpath */
  1508. X    renamed_fullpath = (renamed && (*filename == '/'));
  1509. X
  1510. X    if (checkdir((char *)NULL, INIT) == 10)
  1511. X        return 10;              /* initialize path buffer, unless no memory */
  1512. X
  1513. X    *pathcomp = '\0';           /* initialize translation buffer */
  1514. X    pp = pathcomp;              /* point to translation buffer */
  1515. X    if (jflag)                  /* junking directories */
  1516. X        cp = (char *)strrchr(filename, '/');
  1517. X    if (cp == (char *)NULL)     /* no '/' or not junking dirs */
  1518. X        cp = filename;          /* point to internal zipfile-member pathname */
  1519. X    else
  1520. X        ++cp;                   /* point to start of last component of path */
  1521. X
  1522. X/*---------------------------------------------------------------------------
  1523. X    Begin main loop through characters in filename.
  1524. X  ---------------------------------------------------------------------------*/
  1525. X
  1526. X    while ((workch = (uch)*cp++) != 0) {
  1527. X
  1528. X        if (quote) {                 /* if character quoted, */
  1529. X            *pp++ = (char)workch;    /*  include it literally */
  1530. X            quote = FALSE;
  1531. X        } else
  1532. X            switch (workch) {
  1533. X            case '/':             /* can assume -j flag not given */
  1534. X                *pp = '\0';
  1535. X                if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
  1536. X                    return error;
  1537. X                pp = pathcomp;    /* reset conversion buffer for next piece */
  1538. X                lastsemi = (char *)NULL; /* leave directory semi-colons alone */
  1539. X                break;
  1540. X
  1541. X            case ';':             /* VMS version (or DEC-20 attrib?) */
  1542. X                lastsemi = pp;
  1543. X                *pp++ = ';';      /* keep for now; remove VMS ";##" */
  1544. X                break;            /*  later, if requested */
  1545. X
  1546. X            case '\026':          /* control-V quote for special chars */
  1547. X                quote = TRUE;     /* set flag for next character */
  1548. X                break;
  1549. X
  1550. X#ifdef MTS
  1551. X            case ' ':             /* change spaces to underscore under */
  1552. X                *pp++ = '_';      /*  MTS; leave as spaces under Unix */
  1553. X                break;
  1554. X#endif
  1555. X
  1556. X            default:
  1557. X                /* allow European characters in filenames: */
  1558. X                if (isprint(workch) || (128 <= workch && workch <= 254))
  1559. X                    *pp++ = (char)workch;
  1560. X            } /* end switch */
  1561. X
  1562. X    } /* end while loop */
  1563. X
  1564. X    *pp = '\0';                   /* done with pathcomp:  terminate it */
  1565. X
  1566. X    /* if not saving them, remove VMS version numbers (appended ";###") */
  1567. X    if (!V_flag && lastsemi) {
  1568. X        pp = lastsemi + 1;
  1569. X        while (isdigit((uch)(*pp)))
  1570. X            ++pp;
  1571. X        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  1572. X            *lastsemi = '\0';
  1573. X    }
  1574. X
  1575. X/*---------------------------------------------------------------------------
  1576. X    Report if directory was created (and no file to create:  filename ended
  1577. X    in '/'), check name to be sure it exists, and combine path and name be-
  1578. X    fore exiting.
  1579. X  ---------------------------------------------------------------------------*/
  1580. X
  1581. X    if (filename[strlen(filename) - 1] == '/') {
  1582. X        checkdir(filename, GETPATH);
  1583. X        if (created_dir && QCOND2) {
  1584. X            FPRINTF(stdout, "   creating: %s\n", filename);
  1585. X            return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  1586. X        }
  1587. X        return 2;   /* dir existed already; don't look for data to extract */
  1588. X    }
  1589. X
  1590. X    if (*pathcomp == '\0') {
  1591. X        FPRINTF(stderr, "mapname:  conversion of %s failed\n", filename);
  1592. X        return 3;
  1593. X    }
  1594. X
  1595. X    checkdir(pathcomp, APPEND_NAME);   /* returns 1 if truncated:  care? */
  1596. X    checkdir(filename, GETPATH);
  1597. X
  1598. X    return error;
  1599. X
  1600. X} /* end function mapname() */
  1601. X
  1602. X
  1603. X
  1604. X
  1605. X#if 0  /*========== NOTES ==========*/
  1606. X
  1607. X  extract-to dir:      a:path/
  1608. X  buildpath:           path1/path2/ ...   (NULL-terminated)
  1609. X  pathcomp:                filename 
  1610. X
  1611. X  mapname():
  1612. X    loop over chars in zipfile member name
  1613. X      checkdir(path component, COMPONENT | CREATEDIR) --> map as required?
  1614. X        (d:/tmp/unzip/)                    (disk:[tmp.unzip.)
  1615. X        (d:/tmp/unzip/jj/)                 (disk:[tmp.unzip.jj.)
  1616. X        (d:/tmp/unzip/jj/temp/)            (disk:[tmp.unzip.jj.temp.)
  1617. X    finally add filename itself and check for existence? (could use with rename)
  1618. X        (d:/tmp/unzip/jj/temp/msg.outdir)  (disk:[tmp.unzip.jj.temp]msg.outdir)
  1619. X    checkdir(name, COPYFREE)     -->  copy path to name and free space
  1620. X
  1621. X#endif /* 0 */
  1622. X
  1623. X
  1624. X
  1625. X
  1626. X/***********************/
  1627. X/* Function checkdir() */
  1628. X/***********************/
  1629. X
  1630. Xint checkdir(pathcomp, flag)
  1631. X    char *pathcomp;
  1632. X    int flag;
  1633. X/*
  1634. X * returns:  1 - (on APPEND_NAME) truncated filename
  1635. X *           2 - path doesn't exist, not allowed to create
  1636. X *           3 - path doesn't exist, tried to create and failed; or
  1637. X *               path exists and is not a directory, but is supposed to be
  1638. X *           4 - path is too long
  1639. X *          10 - can't allocate memory for filename buffers
  1640. X */
  1641. X{
  1642. X    static int rootlen = 0;   /* length of rootpath */
  1643. X    static char *rootpath;    /* user's "extract-to" directory */
  1644. X    static char *buildpath;   /* full path (so far) to extracted file */
  1645. X    static char *end;         /* pointer to end of buildpath ('\0') */
  1646. X
  1647. X#   define FN_MASK   7
  1648. X#   define FUNCTION  (flag & FN_MASK)
  1649. X
  1650. X
  1651. X
  1652. X/*---------------------------------------------------------------------------
  1653. X    APPEND_DIR:  append the path component to the path being built and check
  1654. X    for its existence.  If doesn't exist and we are creating directories, do
  1655. X    so for this one; else signal success or error as appropriate.
  1656. X  ---------------------------------------------------------------------------*/
  1657. X
  1658. X    if (FUNCTION == APPEND_DIR) {
  1659. X        int too_long = FALSE;
  1660. X#ifdef SHORT_NAMES
  1661. X        char *old_end = end;
  1662. X#endif
  1663. X
  1664. X        Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  1665. X        while ((*end = *pathcomp++) != '\0')
  1666. X            ++end;
  1667. X#ifdef SHORT_NAMES   /* path components restricted to 14 chars, typically */
  1668. X        if ((end-old_end) > FILENAME_MAX)  /* GRR:  proper constant? */
  1669. X            *(end = old_end + FILENAME_MAX) = '\0';
  1670. X#endif
  1671. X
  1672. X        /* GRR:  could do better check, see if overrunning buffer as we go:
  1673. X         * check end-buildpath after each append, set warning variable if
  1674. X         * within 20 of FILNAMSIZ; then if var set, do careful check when
  1675. X         * appending.  Clear variable when begin new path. */
  1676. X
  1677. X        if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '\0' */
  1678. X            too_long = TRUE;                /* check if extracting directory? */
  1679. X        if (stat(buildpath, &statbuf)) {    /* path doesn't exist */
  1680. X            if (!create_dirs) {   /* told not to create (freshening) */
  1681. X                free(buildpath);
  1682. X                return 2;         /* path doesn't exist:  nothing to do */
  1683. X            }
  1684. X            if (too_long) {
  1685. X                FPRINTF(stderr, "checkdir error:  path too long: %s\n",
  1686. X                  buildpath);
  1687. X                fflush(stderr);
  1688. X                free(buildpath);
  1689. X                return 4;         /* no room for filenames:  fatal */
  1690. X            }
  1691. X            if (mkdir(buildpath, 0777) == -1) {   /* create the directory */
  1692. X                FPRINTF(stderr, "checkdir error:  can't create %s\n\
  1693. X                 unable to process %s.\n", buildpath, filename);
  1694. X                fflush(stderr);
  1695. X                free(buildpath);
  1696. X                return 3;      /* path didn't exist, tried to create, failed */
  1697. X            }
  1698. X            created_dir = TRUE;
  1699. X        } else if (!S_ISDIR(statbuf.st_mode)) {
  1700. X            FPRINTF(stderr, "checkdir error:  %s exists but is not directory\n\
  1701. X                 unable to process %s.\n", buildpath, filename);
  1702. X            fflush(stderr);
  1703. X            free(buildpath);
  1704. X            return 3;          /* path existed but wasn't dir */
  1705. X        }
  1706. X        if (too_long) {
  1707. X            FPRINTF(stderr, "checkdir error:  path too long: %s\n", buildpath);
  1708. X            fflush(stderr);
  1709. X            free(buildpath);
  1710. X            return 4;         /* no room for filenames:  fatal */
  1711. X        }
  1712. X        *end++ = '/';
  1713. X        *end = '\0';
  1714. X        Trace((stderr, "buildpath now = [%s]\n", buildpath));
  1715. X        return 0;
  1716. X
  1717. X    } /* end if (FUNCTION == APPEND_DIR) */
  1718. X
  1719. X/*---------------------------------------------------------------------------
  1720. X    GETPATH:  copy full path to the string pointed at by pathcomp, and free
  1721. X    buildpath.
  1722. X  ---------------------------------------------------------------------------*/
  1723. X
  1724. X    if (FUNCTION == GETPATH) {
  1725. X        strcpy(pathcomp, buildpath);
  1726. X        Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  1727. X        free(buildpath);
  1728. X        buildpath = end = (char *)NULL;
  1729. X        return 0;
  1730. X    }
  1731. X
  1732. X/*---------------------------------------------------------------------------
  1733. X    APPEND_NAME:  assume the path component is the filename; append it and
  1734. X    return without checking for existence.
  1735. X  ---------------------------------------------------------------------------*/
  1736. X
  1737. X    if (FUNCTION == APPEND_NAME) {
  1738. X#ifdef SHORT_NAMES
  1739. X        char *old_end = end;
  1740. X#endif
  1741. X
  1742. X        Trace((stderr, "appending filename [%s]\n", pathcomp));
  1743. X        while ((*end = *pathcomp++) != '\0') {
  1744. X            ++end;
  1745. X#ifdef SHORT_NAMES  /* truncate name at 14 characters, typically */
  1746. X            if ((end-old_end) > FILENAME_MAX)      /* GRR:  proper constant? */
  1747. X                *(end = old_end + FILENAME_MAX) = '\0';
  1748. X#endif
  1749. X            if ((end-buildpath) >= FILNAMSIZ) {
  1750. X                *--end = '\0';
  1751. X                FPRINTF(stderr, "checkdir warning:  path too long; truncating\n\
  1752. Xcheckdir warning:  path too long; truncating\n\
  1753. X                   %s\n                -> %s\n", filename, buildpath);
  1754. X                fflush(stderr);
  1755. X                return 1;   /* filename truncated */
  1756. X            }
  1757. X        }
  1758. X        Trace((stderr, "buildpath now = [%s]\n", buildpath));
  1759. X        return 0;  /* could check for existence here, prompt for new name... */
  1760. X    }
  1761. X
  1762. X/*---------------------------------------------------------------------------
  1763. X    INIT:  allocate and initialize buffer space for the file currently being
  1764. X    extracted.  If file was renamed with an absolute path, don't prepend the
  1765. X    extract-to path.
  1766. X  ---------------------------------------------------------------------------*/
  1767. X
  1768. X/* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
  1769. X
  1770. X    if (FUNCTION == INIT) {
  1771. X        Trace((stderr, "initializing buildpath to "));
  1772. X        if ((buildpath = (char *)malloc(strlen(filename)+rootlen+1)) ==
  1773. X            (char *)NULL)
  1774. X            return 10;
  1775. X        if ((rootlen > 0) && !renamed_fullpath) {
  1776. X            strcpy(buildpath, rootpath);
  1777. X            end = buildpath + rootlen;
  1778. X        } else {
  1779. X            *buildpath = '\0';
  1780. X            end = buildpath;
  1781. X        }
  1782. X        Trace((stderr, "[%s]\n", buildpath));
  1783. X        return 0;
  1784. X    }
  1785. X
  1786. X/*---------------------------------------------------------------------------
  1787. X    ROOT:  if appropriate, store the path in rootpath and create it if neces-
  1788. X    sary; else assume it's a zipfile member and return.  This path segment
  1789. X    gets used in extracting all members from every zipfile specified on the
  1790. X    command line.
  1791. X  ---------------------------------------------------------------------------*/
  1792. X
  1793. X#if (!defined(SFX) || defined(SFX_EXDIR))
  1794. X    if (FUNCTION == ROOT) {
  1795. X        Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  1796. X        if (pathcomp == (char *)NULL) {
  1797. X            rootlen = 0;
  1798. X            return 0;
  1799. X        }
  1800. X        if ((rootlen = strlen(pathcomp)) > 0) {
  1801. X            int had_trailing_pathsep=FALSE;
  1802. X
  1803. X            if (pathcomp[rootlen-1] == '/') {
  1804. X                pathcomp[--rootlen] = '\0';
  1805. X                had_trailing_pathsep = TRUE;
  1806. X            }
  1807. X            if (rootlen > 0 && (stat(pathcomp, &statbuf) ||
  1808. X                !S_ISDIR(statbuf.st_mode)))          /* path does not exist */
  1809. X            {
  1810. X                if (!create_dirs                     /* || iswild(pathcomp) */
  1811. X#ifdef OLD_EXDIR
  1812. X                                 || !had_trailing_pathsep
  1813. X#endif
  1814. X                                                         ) {
  1815. X                    rootlen = 0;
  1816. X                    return 2;   /* skip (or treat as stored file) */
  1817. X                }
  1818. X                /* create the directory (could add loop here to scan pathcomp
  1819. X                 * and create more than one level, but why really necessary?) */
  1820. X                if (mkdir(pathcomp, 0777) == -1) {
  1821. X                    FPRINTF(stderr,
  1822. X                      "checkdir:  can't create extraction directory: %s\n",
  1823. X                      pathcomp);
  1824. X                    fflush(stderr);
  1825. X                    rootlen = 0;   /* path didn't exist, tried to create, and */
  1826. X                    return 3;  /* failed:  file exists, or 2+ levels required */
  1827. X                }
  1828. X            }
  1829. X            if ((rootpath = (char *)malloc(rootlen+2)) == (char *)NULL) {
  1830. X                rootlen = 0;
  1831. X                return 10;
  1832. X            }
  1833. X            strcpy(rootpath, pathcomp);
  1834. X            rootpath[rootlen++] = '/';
  1835. X            rootpath[rootlen] = '\0';
  1836. X        }
  1837. X        Trace((stderr, "rootpath now = [%s]\n", rootpath));
  1838. X        return 0;
  1839. X    }
  1840. X#endif /* !SFX || SFX_EXDIR */
  1841. X
  1842. X/*---------------------------------------------------------------------------
  1843. X    END:  free rootpath, immediately prior to program exit.
  1844. X  ---------------------------------------------------------------------------*/
  1845. X
  1846. X    if (FUNCTION == END) {
  1847. X        Trace((stderr, "freeing rootpath\n"));
  1848. X        if (rootlen > 0)
  1849. X            free(rootpath);
  1850. X        return 0;
  1851. X    }
  1852. X
  1853. X    return 99;  /* should never reach */
  1854. X
  1855. X} /* end function checkdir() */
  1856. X
  1857. X
  1858. X
  1859. X
  1860. X
  1861. X#ifdef NO_MKDIR
  1862. X
  1863. X/********************/
  1864. X/* Function mkdir() */
  1865. X/********************/
  1866. X
  1867. Xint mkdir(path, mode)
  1868. X    char *path;
  1869. X    int mode;   /* ignored */
  1870. X/*
  1871. X * returns:   0 - successful
  1872. X *           -1 - failed (errno not set, however)
  1873. X */
  1874. X{
  1875. X    char command[FILNAMSIZ+40]; /* buffer for system() call */
  1876. X
  1877. X    /* GRR 930416:  added single quotes around path to avoid bug with
  1878. X     * creating directories with ampersands in name; not yet tested */
  1879. X    sprintf(command, "IFS=\" \t\n\" /bin/mkdir '%s' 2>/dev/null", path);
  1880. X    if (system(command))
  1881. X        return -1;
  1882. X    return 0;
  1883. X}
  1884. X
  1885. X#endif /* NO_MKDIR */
  1886. X
  1887. X
  1888. X
  1889. X
  1890. X
  1891. X#ifndef MTS
  1892. X
  1893. X/****************************/
  1894. X/* Function close_outfile() */
  1895. X/****************************/
  1896. X
  1897. Xvoid close_outfile()
  1898. X{
  1899. X    static short yday[]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  1900. X    time_t m_time;
  1901. X    int yr, mo, dy, hh, mm, ss, leap, days;
  1902. X    struct utimbuf tp;
  1903. X#   define YRBASE  1970
  1904. X#ifndef BSD4_4
  1905. X#ifdef BSD
  1906. X    static struct timeb tbp;
  1907. X#else /* !BSD */
  1908. X    extern long timezone;
  1909. X#endif /* ?BSD */
  1910. X#endif /* !BSD4_4 */
  1911. X
  1912. X
  1913. X/*---------------------------------------------------------------------------
  1914. X    If symbolic links are supported, allocate a storage area, put the uncom-
  1915. X    pressed "data" in it, and create the link.  Since we know it's a symbolic
  1916. X    link to start with, we shouldn't have to worry about overflowing unsigned
  1917. X    ints with unsigned longs.
  1918. X  ---------------------------------------------------------------------------*/
  1919. X
  1920. X#ifdef SYMLINKS
  1921. X    if (symlnk) {
  1922. X        unsigned ucsize = (unsigned)lrec.ucsize;
  1923. X        char *linktarget = (char *)malloc((unsigned)lrec.ucsize+1);
  1924. X
  1925. X        fclose(outfile);                    /* close "data" file... */
  1926. X        outfile = fopen(filename, FOPR);    /* ...and reopen for reading */
  1927. X        if (!linktarget || (fread(linktarget, 1, ucsize, outfile) != ucsize)) {
  1928. X            FPRINTF(stderr, "\nwarning:  symbolic link (%s) failed\n",
  1929. X              filename);
  1930. X            if (linktarget)
  1931. X                free(linktarget);
  1932. X            fclose(outfile);
  1933. X            return;
  1934. X        }
  1935. X        fclose(outfile);                    /* close "data" file for good... */
  1936. X        unlink(filename);                   /* ...and delete it */
  1937. X        linktarget[ucsize] = '\0';
  1938. X        FPRINTF(stdout, "-> %s ", linktarget);
  1939. X        if (symlink(linktarget, filename))  /* create the real link */
  1940. X            perror("symlink error");
  1941. X        free(linktarget);
  1942. X        return;                             /* can't set time on symlinks */
  1943. X    }
  1944. X#endif /* SYMLINKS */
  1945. X
  1946. X    fclose(outfile);
  1947. X
  1948. X/*---------------------------------------------------------------------------
  1949. X    Change the file permissions from default ones to those stored in the
  1950. X    zipfile.
  1951. X  ---------------------------------------------------------------------------*/
  1952. X
  1953. X#ifndef NO_CHMOD
  1954. X    if (chmod(filename, 0xffff & pInfo->file_attr))
  1955. X            perror("chmod (file attributes) error");
  1956. X#endif
  1957. X
  1958. X/*---------------------------------------------------------------------------
  1959. X    Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
  1960. X    time:  adjust base year from 1980 to 1970, do usual conversions from
  1961. X    yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
  1962. X    light savings time differences.
  1963. X  ---------------------------------------------------------------------------*/
  1964. X
  1965. X    yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + (1980 - YRBASE);
  1966. X    mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1;
  1967. X    dy = (lrec.last_mod_file_date & 0x1f) - 1;
  1968. X    hh = (lrec.last_mod_file_time >> 11) & 0x1f;
  1969. X    mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  1970. X    ss = (lrec.last_mod_file_time & 0x1f) * 2;
  1971. X
  1972. X    /* leap = # of leap yrs from YRBASE up to but not including current year */
  1973. X    leap = ((yr + YRBASE - 1) / 4);   /* leap year base factor */
  1974. X
  1975. X    /* how many days from YRBASE to this year? (& add expired days this year) */
  1976. X    days = (yr * 365) + (leap - 492) + yday[mo];
  1977. X
  1978. X    /* if year is a leap year and month is after February, add another day */
  1979. X    if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100))
  1980. X        ++days;   /* OK through 2199 */
  1981. X
  1982. X    /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */
  1983. X    m_time = ((days + dy) * 86400) + (hh * 3600) + (mm * 60) + ss;
  1984. X
  1985. X    /* adjust for local timezone */
  1986. X#ifdef BSD
  1987. X#ifdef BSD4_4
  1988. X    m_time -= localtime(&m_time)->tm_gmtoff;  /* seconds EAST of GMT:  subtr. */
  1989. X#else
  1990. X    ftime(&tbp);                    /* get `timezone' */
  1991. X    m_time += tbp.timezone * 60L;   /* seconds WEST of GMT:  add */
  1992. X#endif /* ?BSD4_4 */
  1993. X#else /* !BSD */
  1994. X    tzset();              /* get `timezone' */
  1995. X    m_time += timezone;   /* seconds WEST of GMT:  add */
  1996. X#endif /* ?BSD */
  1997. X
  1998. X    /* adjust for daylight savings time (or local equivalent) */
  1999. X#ifndef BSD4_4  /* (DST already added to tm_gmtoff, so skip tm_isdst) */
  2000. X    if (localtime(&m_time)->tm_isdst)
  2001. X        m_time -= 60L * 60L;   /* adjust for daylight savings time */
  2002. X#endif
  2003. X
  2004. X    /* set the file's access and modification times */
  2005. X    tp.actime = tp.modtime = m_time;
  2006. X    if (utime(filename, &tp)) {
  2007. X#ifdef AOS_VS
  2008. X        FPRINTF(stderr, "... can't set time for %s", filename);
  2009. X#else
  2010. X        FPRINTF(stderr, "warning:  can't set the time for %s\n", filename);
  2011. X#endif
  2012. X        FFLUSH(stderr);
  2013. X    }
  2014. X
  2015. X} /* end function close_outfile() */
  2016. X
  2017. X#endif /* !MTS */
  2018. X
  2019. X
  2020. X
  2021. X
  2022. X#ifndef SFX
  2023. X
  2024. X/************************/
  2025. X/*  Function version()  */
  2026. X/************************/
  2027. X
  2028. Xvoid version()
  2029. X{
  2030. X    extern char Far  CompiledWith[];
  2031. X#if defined(CRAY) || defined(NetBSD)
  2032. X    char buf1[40];
  2033. X#if defined(CRAY)
  2034. X    char buf2[40];
  2035. X#endif
  2036. X#endif
  2037. X
  2038. X    PRINTF(LoadFarString(CompiledWith),
  2039. X
  2040. X#ifdef __GNUC__
  2041. X      "gcc ", __VERSION__,
  2042. X#else
  2043. X#  if defined(CRAY) && defined(_RELEASE)
  2044. X      "cc ", (sprintf(buf1, "version %d", _RELEASE), buf1),
  2045. X#  else
  2046. X#  ifdef __VERSION__
  2047. X      "cc ", __VERSION__,
  2048. X#  else
  2049. X      "cc", "",
  2050. X#  endif
  2051. X#  endif
  2052. X#endif
  2053. X
  2054. X      "Unix",
  2055. X
  2056. X#if defined(sgi) || defined(__sgi)
  2057. X      " (Silicon Graphics IRIX)",
  2058. X#else
  2059. X#ifdef sun
  2060. X#  ifdef sparc
  2061. X#    ifdef __SVR4
  2062. X      " (Sun Sparc/Solaris)",
  2063. X#    else /* may or may not be SunOS */
  2064. X      " (Sun Sparc)",
  2065. X#    endif
  2066. X#  else
  2067. X#  if defined(sun386) || defined(i386)
  2068. X      " (Sun 386i)",
  2069. X#  else
  2070. X#  if defined(mc68020) || defined(__mc68020__)
  2071. X      " (Sun 3)",
  2072. X#  else /* mc68010 or mc68000:  Sun 2 or earlier */
  2073. X      " (Sun 2)",
  2074. X#  endif
  2075. X#  endif
  2076. X#  endif
  2077. X#else
  2078. X#ifdef __hpux
  2079. X      " (HP/UX)",
  2080. X#else
  2081. X#ifdef __osf__
  2082. X      " (DEC OSF/1)",
  2083. X#else
  2084. X#ifdef _AIX
  2085. X      " (IBM AIX)",
  2086. X#else
  2087. X#ifdef aiws
  2088. X      " (IBM RT/AIX)",
  2089. X#else
  2090. X#if defined(CRAY) || defined(cray)
  2091. X#  ifdef _UNICOS
  2092. X      (sprintf(buf2, " (Cray UNICOS release %d)", _UNICOS), buf2),
  2093. X#  else
  2094. X      " (Cray UNICOS)",
  2095. X#  endif
  2096. X#else
  2097. X#if defined(uts) || defined(UTS)
  2098. X      " (Amdahl UTS)",
  2099. X#else
  2100. X#ifdef NeXT
  2101. X#  ifdef mc68000
  2102. X      " (NeXTStep/black)",
  2103. X#  else
  2104. X      " (NeXTStep for Intel)",
  2105. X#  endif
  2106. X#else              /* the next dozen or so are somewhat order-dependent */
  2107. X#ifdef LINUX
  2108. X      " (Linux)",
  2109. X#else
  2110. X#ifdef MINIX
  2111. X      " (Minix)",
  2112. X#else
  2113. X#ifdef M_UNIX
  2114. X      " (SCO Unix)",
  2115. X#else
  2116. X#ifdef M_XENIX
  2117. X      " (SCO Xenix)",
  2118. X#else
  2119. X#ifdef __NetBSD__
  2120. X#  ifdef NetBSD0_8
  2121. X      (sprintf(buf1, " (NetBSD 0.8%c)", (char)(NetBSD0_8 - 1 + 'A')), buf1),
  2122. X#  else
  2123. X#  ifdef NetBSD0_9
  2124. X      (sprintf(buf1, " (NetBSD 0.9%c)", (char)(NetBSD0_9 - 1 + 'A')), buf1),
  2125. X#  else
  2126. X#  ifdef NetBSD1_0
  2127. X      (sprintf(buf1, " (NetBSD 1.0%c)", (char)(NetBSD1_0 - 1 + 'A')), buf1),
  2128. X#  else
  2129. X      (BSD4_4 == 0.5)? " (NetBSD before 0.9)" : " (NetBSD 1.1 or later)",
  2130. X#  endif
  2131. X#  endif
  2132. X#  endif
  2133. X#else
  2134. X#ifdef __FreeBSD__
  2135. X      (BSD4_4 == 0.5)? " (FreeBSD 1.x)" : " (FreeBSD 2.0 or later)",
  2136. X#else
  2137. X#ifdef __bsdi__
  2138. X      (BSD4_4 == 0.5)? " (BSD/386 1.0)" : " (BSD/386 1.1 or later)",
  2139. X#else
  2140. X#ifdef __386BSD__
  2141. X      (BSD4_4 == 1)? " (386BSD, post-4.4 release)" : " (386BSD)",
  2142. X#else
  2143. X#if defined(i486) || defined(__i486) || defined(__i486__)
  2144. X      " (Intel 486)",
  2145. X#else
  2146. X#if defined(i386) || defined(__i386) || defined(__i386__)
  2147. X      " (Intel 386)",
  2148. X#else
  2149. X#ifdef pyr
  2150. X      " (Pyramid)",
  2151. X#else
  2152. X#ifdef ultrix
  2153. X#  ifdef mips
  2154. X      " (DEC/MIPS)",
  2155. X#  else
  2156. X#  ifdef vax
  2157. X      " (DEC/VAX)",
  2158. X#  else /* __alpha? */
  2159. X      " (DEC/Alpha)",
  2160. X#  endif
  2161. X#  endif
  2162. X#else
  2163. X#ifdef gould
  2164. X      " (Gould)",
  2165. X#else
  2166. X#ifdef MTS
  2167. X      " (MTS)",
  2168. X#else
  2169. X#ifdef __convexc__
  2170. X      " (Convex)",
  2171. X#else
  2172. X      "",
  2173. X#endif /* Convex */
  2174. X#endif /* MTS */
  2175. X#endif /* Gould */
  2176. X#endif /* DEC */
  2177. X#endif /* Pyramid */
  2178. X#endif /* 386 */
  2179. X#endif /* 486 */
  2180. X#endif /* 386BSD */
  2181. X#endif /* BSDI BSD/386 */
  2182. X#endif /* NetBSD */
  2183. X#endif /* FreeBSD */
  2184. X#endif /* SCO Xenix */
  2185. X#endif /* SCO Unix */
  2186. X#endif /* Minix */
  2187. X#endif /* Linux */
  2188. X#endif /* NeXT */
  2189. X#endif /* Amdahl */
  2190. X#endif /* Cray */
  2191. X#endif /* RT/AIX */
  2192. X#endif /* AIX */
  2193. X#endif /* OSF/1 */
  2194. X#endif /* HP/UX */
  2195. X#endif /* Sun */
  2196. X#endif /* SGI */
  2197. X
  2198. X#ifdef __DATE__
  2199. X      " on ", __DATE__
  2200. X#else
  2201. X      "", ""
  2202. X#endif
  2203. X      );
  2204. X
  2205. X} /* end function version() */
  2206. X
  2207. X#endif /* !SFX */
  2208. END_OF_FILE
  2209.   if test 30753 -ne `wc -c <'unzip-5.12/unix/unix.c'`; then
  2210.     echo shar: \"'unzip-5.12/unix/unix.c'\" unpacked with wrong size!
  2211.   fi
  2212.   # end of 'unzip-5.12/unix/unix.c'
  2213. fi
  2214. echo shar: End of archive 10 \(of 20\).
  2215. cp /dev/null ark10isdone
  2216. MISSING=""
  2217. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
  2218.     if test ! -f ark${I}isdone ; then
  2219.     MISSING="${MISSING} ${I}"
  2220.     fi
  2221. done
  2222. if test "${MISSING}" = "" ; then
  2223.     echo You have unpacked all 20 archives.
  2224.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2225. else
  2226.     echo You still must unpack the following archives:
  2227.     echo "        " ${MISSING}
  2228. fi
  2229. exit 0
  2230. exit 0 # Just in case...
  2231.