home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / UNZP50P1.ZIP / file_io.c < prev    next >
C/C++ Source or Header  |  1993-01-23  |  34KB  |  1,166 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   file_io.c
  4.  
  5.   This file contains routines for doing direct input/output, file-related
  6.   sorts of things.  Most of the system-specific code for unzip is contained
  7.   here, including the non-echoing password code for decryption (bottom).
  8.  
  9.   ---------------------------------------------------------------------------*/
  10.  
  11.  
  12. #ifndef __GO32__
  13. #  define const
  14. #endif
  15.  
  16. #define FILE_IO_C
  17. #include "unzip.h"
  18.  
  19. #ifdef  MSWIN
  20. #  include "wizunzip.h"
  21. #endif
  22.  
  23.  
  24. /************************************/
  25. /*  File_IO Local Prototypes, etc.  */
  26. /************************************/
  27.  
  28. #if (!defined(DOS_OS2) || defined(MSWIN))
  29.    static int dos2unix __((unsigned char *buf, int len));
  30.    int CR_flag = 0;      /* when last char of buffer == CR (for dos2unix()) */
  31. #endif
  32.  
  33. #ifdef OS2
  34.    extern int   longname;          /* set in mapname.c */
  35.    extern char  longfilename[];
  36. #endif
  37.  
  38. #ifdef CRYPT
  39. #  if (defined(DOS_OS2) || defined(VMS))
  40. #    define MSVMS
  41. #    ifdef DOS_OS2
  42. #      ifdef __EMX__
  43. #        define getch() _read_kbd(0, 1, 0)
  44. #      else
  45. #        ifdef __GO32__
  46. #          include <pc.h>
  47. #          define getch() getkey()
  48. #        else /* !__GO32__ */
  49. #          include <conio.h>
  50. #        endif /* ?__GO32__ */
  51. #      endif
  52. #    else /* !DOS_OS2 */
  53. #      define getch() getc(stderr)
  54. #      define OFF 0   /* for echo control */
  55. #      define ON 1
  56. #      define echoff(f) echo(OFF)
  57. #      define echon()   echo(ON)
  58. #      include <descrip.h>
  59. #      include <iodef.h>
  60. #      include <ttdef.h>
  61. #      if !defined(SS$_NORMAL)
  62. #        define SS$_NORMAL 1   /* only thing we need from <ssdef.h> */
  63. #      endif
  64. #    endif /* ?DOS_OS2 */
  65. #  else /* !(DOS_OS2 || VMS) */
  66. #    ifdef TERMIO       /* Amdahl, Cray, all SysV? */
  67. #      ifdef CONVEX
  68. #        include <sys/termios.h>
  69. #        include <sgtty.h>
  70. #      else /* !CONVEX */
  71. #        ifdef LINUX
  72. #          include <termios.h>
  73. #        else /* !LINUX */
  74. #          include <sys/termio.h>
  75. #        endif /* ?LINUX */
  76. #        define sgttyb termio
  77. #        define sg_flags c_lflag
  78. #      endif /* ?CONVEX */
  79.        int ioctl OF((int, int, voidp *));
  80. #      define GTTY(f,s) ioctl(f,TCGETA,(voidp *)s)
  81. #      define STTY(f,s) ioctl(f,TCSETAW,(voidp *)s)
  82. #    else /* !TERMIO */
  83. #      if (!defined(MINIX) && !defined(__386BSD__))
  84. #        include <sys/ioctl.h>
  85. #      endif /* !MINIX && !__386BSD__ */
  86. #      include <sgtty.h>
  87. #      ifdef __386BSD__
  88. #        define GTTY(f, s) ioctl(f, TIOCGETP, (voidp *) s)
  89. #        define STTY(f, s) ioctl(f, TIOCSETP, (voidp *) s)
  90. #      else /* !__386BSD__ */
  91. #        define GTTY gtty
  92. #        define STTY stty
  93.          int gtty OF((int, struct sgttyb *));
  94.          int stty OF((int, struct sgttyb *));
  95. #      endif /* ?__386BSD__ */
  96. #    endif /* ?TERMIO */
  97.      int isatty OF((int));
  98.      char *ttyname OF((int));
  99. #    if (defined(PROTO) && !defined(__GNUC__) && !defined(_AIX))
  100.        int open (char *, int, ...);
  101. #    endif
  102.      int close OF((int));
  103.      int read OF((int, voidp *, int));
  104. #  endif /* ?(DOS_OS2 || VMS) */
  105. #endif /* CRYPT */
  106.  
  107.  
  108.  
  109.  
  110.  
  111. /******************************/
  112. /* Function open_input_file() */
  113. /******************************/
  114.  
  115. int open_input_file()    /* return non-zero if open failed */
  116. {
  117.     /*
  118.      *  open the zipfile for reading and in BINARY mode to prevent cr/lf
  119.      *  translation, which would corrupt the bitstreams
  120.      */
  121.  
  122. #ifdef VMS
  123.     zipfd = open(zipfn, O_RDONLY, 0, "ctx=stm");
  124. #else /* !VMS */
  125. #ifdef UNIX
  126.     zipfd = open(zipfn, O_RDONLY);
  127. #else /* !UNIX */
  128. #ifdef MACOS
  129.     zipfd = open(zipfn, 0);
  130. #else /* !MACOS */
  131.     zipfd = open(zipfn, O_RDONLY | O_BINARY);
  132. #endif /* ?MACOS */
  133. #endif /* ?UNIX */
  134. #endif /* ?VMS */
  135.     if (zipfd < 1) {
  136.         fprintf(stderr, "error:  can't open zipfile [ %s ]\n", zipfn);
  137.         return (1);
  138.     }
  139.     return 0;
  140. }
  141.  
  142.  
  143.  
  144.  
  145.  
  146. /**********************/
  147. /* Function readbuf() */
  148. /**********************/
  149.  
  150. int readbuf(buf, size)
  151.     char *buf;
  152.     register unsigned size;
  153. {                               /* return number of bytes read into buf */
  154.     register int count;
  155.     int n;
  156.  
  157.     n = size;
  158.     while (size) {
  159.         if (incnt == 0) {
  160.             if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) <= 0)
  161.                 return (n-size);
  162.             /* buffer ALWAYS starts on a block boundary:  */
  163.             cur_zipfile_bufstart += INBUFSIZ;
  164.             inptr = inbuf;
  165.         }
  166.         count = MIN(size, (unsigned)incnt);
  167.         memcpy(buf, inptr, count);
  168.         buf += count;
  169.         inptr += count;
  170.         incnt -= count;
  171.         size -= count;
  172.     }
  173.     return (n);
  174. }
  175.  
  176.  
  177.  
  178.  
  179.  
  180. #ifndef VMS   /* for VMS use code in vms.c (old VMS code below is retained
  181.                * in case of problems...will be removed in a later release) */
  182.  
  183. /*********************************/
  184. /* Function create_output_file() */
  185. /*********************************/
  186.  
  187. int create_output_file()         /* return non-0 if creat failed */
  188. {
  189. /*---------------------------------------------------------------------------
  190.     Create the output file with appropriate permissions.  If we've gotten to
  191.     this point and the file still exists, we have permission to blow it away.
  192.   ---------------------------------------------------------------------------*/
  193.  
  194. #if (!defined(DOS_OS2) || defined(MSWIN))
  195.     CR_flag = 0;   /* hack to get CR at end of buffer working */
  196. #endif
  197.  
  198. #if (defined(UNIX) && !defined(AMIGA))
  199.     {
  200.         int mask;
  201.  
  202. #ifndef VMS
  203.         if (!stat(filename, &statbuf) && (unlink(filename) < 0)) {
  204.             fprintf(stderr, "\n%s:  cannot delete old copy\n", filename);
  205.             return 1;
  206.         }
  207. #       define EXTRA_ARGS
  208. #else /* VMS */
  209. #       define EXTRA_ARGS   ,"rfm=stmlf","rat=cr"
  210. #endif /* ?VMS */
  211.  
  212.         mask = umask(0);   /* now know that we own it */
  213.         outfd = creat(filename, 0xffff & pInfo->unix_attr  EXTRA_ARGS);
  214.         umask(mask);                                            /* VMS, Unix */
  215.     }
  216. #else /* !UNIX || AMIGA */  /* file permissions set after file closed */
  217. #ifndef MACOS
  218.     outfd = creat(filename, S_IWRITE | S_IREAD);     /* DOS, OS2, Mac, Amiga */
  219. #else /* MACOS */
  220.     {
  221.         short fDataFork=TRUE;
  222.         MACINFO mi;
  223.         OSErr err;
  224.  
  225.         fMacZipped = FALSE;
  226.         CtoPstr(filename);
  227.         if (extra_field &&
  228.             (lrec.extra_field_length > sizeof(MACINFOMIN)) &&
  229.             (lrec.extra_field_length <= sizeof(MACINFO))) {
  230.             BlockMove(extra_field, &mi, lrec.extra_field_length);
  231.             if ((makeword((byte *)&mi.header) == 1992) &&
  232.                 (makeword((byte *)&mi.data) ==
  233.                   lrec.extra_field_length-sizeof(ZIP_EXTRA_HEADER)) &&
  234.                 (mi.signature == 'JLEE')) {
  235.                 gostCreator = mi.finfo.fdCreator;
  236.                 gostType = mi.finfo.fdType;
  237.                 fDataFork = (mi.flags & 1) ? TRUE : FALSE;
  238.                 fMacZipped = true;
  239.                 /* If it was Zipped w/Mac version, the filename has either */
  240.                 /* a 'd' or 'r' appended.  Remove the d/r when unzipping */
  241.                 filename[0]-=1;
  242.             }
  243.         }
  244.         if (!fMacZipped) {
  245.             if (!aflag)
  246.                 gostType = gostCreator = '\?\?\?\?';
  247.             else {
  248. #ifdef THINK_C
  249.                 gostCreator = 'KAHL';
  250. #else
  251. #ifdef MCH_MACINTOSH
  252.                 gostCreator = 'Manx';
  253. #else
  254.                 gostCreator = 'MPS ';
  255. #endif
  256. #endif
  257.                 gostType = 'TEXT';
  258.             }
  259.         }
  260.         PtoCstr(filename);
  261.  
  262.         outfd = creat(filename, 0);
  263.         if (fMacZipped) {
  264.             CtoPstr(filename);
  265.             if (hfsflag) {
  266.                 HParamBlockRec   hpbr;
  267.     
  268.                 hpbr.fileParam.ioNamePtr = (StringPtr)filename;
  269.                 hpbr.fileParam.ioVRefNum = gnVRefNum;
  270.                 hpbr.fileParam.ioDirID = glDirID;
  271.                 hpbr.fileParam.ioFlFndrInfo = mi.finfo;
  272.                 hpbr.fileParam.ioFlCrDat = mi.lCrDat;
  273.                 hpbr.fileParam.ioFlMdDat = mi.lMdDat;
  274.                 err = PBHSetFInfo(&hpbr, 0);
  275.             } else {
  276.                 err = SetFInfo((StringPtr)filename , 0, &mi.finfo);
  277.             }
  278.             PtoCstr(filename);
  279.         }
  280.         if (outfd != -1)
  281.             outfd = open(filename, (fDataFork)? 1 : 2);
  282.     }
  283. #endif /* ?MACOS */
  284. #endif /* ?(UNIX && !AMIGA) */
  285.  
  286.     if (outfd < 1) {
  287.         fprintf(stderr, "\n%s:  cannot create\n", filename);
  288.         return 1;
  289.     }
  290.  
  291. /*---------------------------------------------------------------------------
  292.     If newly created file is in text mode and should be binary (to disable
  293.     automatic CR/LF translations), either close it and reopen as binary or
  294.     else change the mode to binary (DOS, OS/2).
  295.   ---------------------------------------------------------------------------*/
  296.  
  297. #if (!defined(UNIX) && !defined(MACOS))
  298.     if (!aflag) {
  299. #ifdef DOS_OS2
  300.         if (setmode(outfd, O_BINARY) == -1) {
  301. #else /* !DOS_OS2 */
  302.         close(outfd);
  303.         if ((outfd = open(filename, O_RDWR | O_BINARY)) < 1) {
  304. #endif /* ?DOS_OS2 */
  305.             fprintf(stderr, "Can't make output file binary:  %s\n", filename);
  306.             return 1;
  307.         }
  308.     }
  309. #endif /* !UNIX && !MACOS */
  310.  
  311.     return 0;
  312. }
  313.  
  314. #endif /* !VMS */
  315.  
  316.  
  317.  
  318.  
  319.  
  320. /****************************/
  321. /* Function FillBitBuffer() */
  322. /****************************/
  323.  
  324. int FillBitBuffer()
  325. {
  326.     /*
  327.      * Fill bitbuf, which is 32 bits.  This function is only used by the
  328.      * READBIT and PEEKBIT macros (which are used by all of the uncompression
  329.      * routines).
  330.      */
  331.     UWORD temp;
  332.  
  333.     zipeof = 1;
  334.     while (bits_left < 25 && ReadByte(&temp) == 8)
  335.     {
  336.       bitbuf |= (ULONG)temp << bits_left;
  337.       bits_left += 8;
  338.       zipeof = 0;
  339.     }
  340.     return 0;
  341. }
  342.  
  343.  
  344.  
  345.  
  346.  
  347. /***********************/
  348. /* Function ReadByte() */
  349. /***********************/
  350.  
  351. int ReadByte(x)
  352.     UWORD *x;
  353. {
  354.     /*
  355.      * read a byte; return 8 if byte available, 0 if not
  356.      */
  357.  
  358.     if (mem_mode)
  359.         return ReadMemoryByte(x);
  360.  
  361.     if (csize-- <= 0)
  362.         return 0;
  363.  
  364.     if (incnt == 0) {
  365.         if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) <= 0)
  366.             return 0;
  367.         /* buffer ALWAYS starts on a block boundary:  */
  368.         cur_zipfile_bufstart += INBUFSIZ;
  369.         inptr = inbuf;
  370. #ifdef CRYPT
  371.         if (pInfo->encrypted) {
  372.             byte *p;
  373.             int n, t;
  374.  
  375.             for (n = (longint)incnt > csize + 1 ? (int)csize + 1 : incnt,
  376.                  p = inptr; n--; p++)
  377.                 *p = (byte) DECRYPT(*p);
  378.         }
  379. #endif /* CRYPT */
  380.     }
  381.     *x = *inptr++;
  382.     --incnt;
  383.     return 8;
  384. }
  385.  
  386.  
  387.  
  388.  
  389.  
  390. #ifndef VMS   /* for VMS use code in vms.c */
  391.  
  392. /**************************/
  393. /* Function FlushOutput() */
  394. /**************************/
  395.  
  396. int FlushOutput()
  397. {
  398.     /*
  399.      * flush contents of output buffer; return PK-type error code
  400.      */
  401. #if (!defined(DOS_OS2) || defined(MSWIN))
  402.     int saved_ctrlZ = FALSE;
  403. #endif
  404.     int len;
  405.  
  406.  
  407.     if (mem_mode) {
  408.         int rc = FlushMemory();
  409.         outpos += outcnt;
  410.         outcnt = 0;
  411.         outptr = outbuf;
  412.         return rc;
  413.     }
  414.  
  415.     if (disk_full) {
  416.         outpos += outcnt;   /* fake emptied buffer */
  417.         outcnt = 0;
  418.         outptr = outbuf;
  419.         return 50;          /* ignore rest of this file */
  420.     }
  421.  
  422.     if (outcnt) {
  423.         UpdateCRC(outbuf, outcnt);
  424.  
  425.         if (!tflag) {
  426. #if (!defined(DOS_OS2) || defined(MSWIN))
  427.             if (aflag) {
  428.                 if (outbuf[outcnt-1] == CTRLZ) {
  429.                     --outcnt;
  430.                     saved_ctrlZ = TRUE;
  431.                 }
  432.                 len = dos2unix(outbuf, outcnt);
  433.             } else
  434. #endif /* !DOS_OS2 || MSWIN */
  435.                 len = outcnt;
  436. #ifdef MACOS
  437.             if ((giCursor+1) >> 2 != (giCursor>>2))
  438.                 SetCursor( *rghCursor[((giCursor+1)>>2)&0x03] );
  439.             giCursor = (giCursor+1) & 15;
  440. #endif /* MACOS */
  441. #ifdef MSWIN
  442.             /* if writing to console vs. actual file, write to Msg Window */
  443.             if (cflag)
  444.                 WriteBufferToMsgWin(outout, len, FALSE);
  445.             else if (_lwrite(outfd, outout, len) != (UINT)len)
  446. #else /* !MSWIN */
  447.             if (write(outfd, (char *)outout, len) != len)
  448. #endif /* ?MSWIN */
  449. #ifdef DOS_OS2
  450.                 if (!cflag)           /* ^Z treated as EOF, removed with -c */
  451. #else /* !DOS_OS2 */
  452. #ifdef MINIX
  453.                 if (errno == EFBIG)
  454.                     if (write(fd, outout, len/2) != len/2  ||
  455.                         write(fd, outout+len/2, len/2) != len/2)
  456. #endif /* MINIX */
  457. #endif /* ?DOS_OS2 */
  458.                 {
  459.                     /* GRR: add test for force_flag when has its own switch */
  460.                     fprintf(stderr,
  461.                       "\n%s:  write error (disk full?).  Continue? (y/n/^C) ",
  462.                       filename);
  463.                     FFLUSH   /* for Amiga and Mac MPW */
  464. #ifdef MSWIN
  465.                     disk_full = 2;
  466. #else /* !MSWIN */
  467.                     fgets(answerbuf, 9, stdin);
  468.                     if (*answerbuf == 'y')   /* stop writing to this file */
  469.                         disk_full = 1;       /*  (outfd bad?), but new OK */
  470.                     else
  471.                         disk_full = 2;       /* no:  exit program */
  472. #endif /* ?MSWIN */
  473.                     return 50;    /* 50:  disk full */
  474.                 }
  475.         }
  476.         outpos += outcnt;
  477.         outcnt = 0;
  478.         outptr = outbuf;
  479. #if (!defined(DOS_OS2) || defined(MSWIN))
  480.         if (saved_ctrlZ) {
  481.             *outptr++ = CTRLZ;
  482.             ++outcnt;
  483.         }
  484. #endif /* !DOS_OS2 || MSWIN */
  485.     }
  486.     return 0;                   /* 0:  no error */
  487. }
  488.  
  489. #endif /* !VMS */
  490.  
  491.  
  492.  
  493.  
  494.  
  495. #if (!defined(DOS_OS2) || defined(MSWIN))
  496.  
  497. /***********************/
  498. /* Function dos2unix() */
  499. /***********************/
  500.  
  501. static int dos2unix(buf, len)   /* GRR:  rewrite for generic text conversions */
  502.     unsigned char *buf;
  503.     int len;
  504. {
  505.     int new_len;
  506.     int i;
  507. #ifdef MSWIN
  508.     unsigned char __far *walker;
  509. #else /* !MSWIN */
  510.     unsigned char *walker;
  511. #endif /* ?MSWIN */
  512.  
  513.     new_len = len;
  514.     walker = outout;
  515. #ifdef MACOS
  516.     /*
  517.      * Mac wants to strip LFs instead CRs from CRLF pairs
  518.      */
  519.     if (CR_flag && *buf == LF) {
  520.         buf++;
  521.         new_len--;
  522.         len--;
  523.         CR_flag = buf[len] == CR;
  524.     }
  525.     else
  526.         CR_flag = buf[len - 1] == CR;
  527.     for (i = 0; i < len; i += 1) {
  528.         *walker++ = ascii_to_native(*buf);
  529.         if (*buf == LF) walker[-1] = CR;
  530.         if (*buf++ == CR && *buf == LF) {
  531.             new_len--;
  532.             buf++;
  533.             i++;
  534.         }
  535.     }
  536. #else /* !MACOS */
  537.     if (CR_flag && *buf != LF)
  538.         *walker++ = ascii_to_native(CR);
  539.     CR_flag = buf[len - 1] == CR;
  540.     for (i = 0; i < len; i += 1) {
  541.         *walker++ = ascii_to_native(*buf);
  542.         if (*buf++ == CR && *buf == LF) {
  543.             new_len--;
  544.             walker[-1] = ascii_to_native(*buf++);
  545.             i++;
  546.         }
  547.     }
  548.     /*
  549.      * If the last character is a CR, then "ignore it" for now...
  550.      */
  551.     if (walker[-1] == ascii_to_native(CR))
  552.         new_len--;
  553. #endif /* ?MACOS */
  554.     return new_len;
  555. }
  556.  
  557. #endif /* !DOS_OS2 || MSWIN */
  558.  
  559.  
  560.  
  561.  
  562.  
  563. #ifdef __GO32__
  564.  
  565. void _dos_setftime(int fd, UWORD dosdate, UWORD dostime)
  566. {
  567.     asm("pushl %ebx");
  568.     asm("movl %0, %%ebx": : "g" (fd));
  569.     asm("movl %0, %%ecx": : "g" (dostime));
  570.     asm("movl %0, %%edx": : "g" (dosdate));
  571.     asm("movl $0x5701, %eax");
  572.     asm("int $0x21");
  573.     asm("popl %ebx");
  574. }
  575.  
  576. void _dos_setfileattr(char *name, int attr)
  577. {
  578.     asm("movl %0, %%edx": : "g" (name));
  579.     asm("movl %0, %%ecx": : "g" (attr));
  580.     asm("movl $0x4301, %eax");
  581.     asm("int $0x21");
  582. }
  583.  
  584. #endif /* __GO32__ */
  585.  
  586.  
  587.  
  588.  
  589.  
  590. #ifdef DOS_OS2
  591.  
  592. /**************************************/
  593. /* Function set_file_time_and_close() */
  594. /**************************************/
  595.  
  596. void set_file_time_and_close()
  597.  /*
  598.   * MS-DOS AND OS/2 VERSION (Mac, Unix/VMS versions are below)
  599.   *
  600.   * Set the output file date/time stamp according to information from the
  601.   * zipfile directory record for this member, then close the file and set
  602.   * its permissions (archive, hidden, read-only, system).  Aside from closing
  603.   * the file, this routine is optional (but most compilers support it).
  604.   */
  605. {
  606. /*---------------------------------------------------------------------------
  607.     Allocate local variables needed by OS/2 and Turbo C.
  608.   ---------------------------------------------------------------------------*/
  609.  
  610. #ifdef __TURBOC__
  611.  
  612.     union {
  613.         struct ftime ft;        /* system file time record */
  614.         struct {
  615.             UWORD ztime;        /* date and time words */
  616.             UWORD zdate;        /* .. same format as in .ZIP file */
  617.         } zt;
  618.     } td;
  619.  
  620. #endif                          /* __TURBOC__ */
  621.  
  622. /*---------------------------------------------------------------------------
  623.      Do not attempt to set the time stamp on standard output.
  624.   ---------------------------------------------------------------------------*/
  625.  
  626.     if (cflag) {
  627.         close(outfd);
  628.         return;
  629.     }
  630.  
  631. /*---------------------------------------------------------------------------
  632.     Copy and/or convert time and date variables, if necessary; then set the
  633.     file time/date.
  634.   ---------------------------------------------------------------------------*/
  635.  
  636. #ifndef OS2
  637. #ifdef __TURBOC__
  638.     td.zt.ztime = lrec.last_mod_file_time;
  639.     td.zt.zdate = lrec.last_mod_file_date;
  640.     setftime(outfd, &td.ft);
  641. #else /* !__TURBOC__ */
  642. #ifdef WIN32
  643.     {
  644.         FILETIME ft;     /* 64-bit value made up of two 32 bit [low & high] */
  645.         WORD wDOSDate;   /* for vconvertin from DOS date to Windows NT */
  646.         WORD wDOSTime;
  647.         HANDLE hFile;    /* file handle (defined in Windows NT) */
  648.  
  649.         wDOSTime = (WORD) lrec.last_mod_file_time;
  650.         wDOSDate = (WORD) lrec.last_mod_file_date;
  651.  
  652.         /* The DosDateTimeToFileTime() function converts a DOS date/time
  653.          * into a 64 bit Windows NT file time */
  654.         DosDateTimeToFileTime(wDOSDate, wDOSTime, &ft);
  655.  
  656.         /* Close the file and then re-open it using the Win32
  657.          * CreateFile call, so that the file can be created
  658.          * with GENERIC_WRITE access, otherwise the SetFileTime
  659.          * call will fail. */
  660.         close(outfd);
  661.  
  662.         hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
  663.              FILE_ATTRIBUTE_NORMAL, NULL);
  664.  
  665.         if (!SetFileTime(hFile, NULL, NULL, &ft))
  666.             printf("\nSetFileTime failed: %d\n", GetLastError());
  667.         CloseHandle(hFile);
  668.         return;
  669.     }
  670. #else /* !WIN32 */
  671.     _dos_setftime(outfd, lrec.last_mod_file_date, lrec.last_mod_file_time);
  672. #endif /* ?WIN32 */
  673. #endif /* ?__TURBOC__ */
  674. #endif /* ?OS2 */
  675.  
  676. /*---------------------------------------------------------------------------
  677.     And finally we can close the file...at least everybody agrees on how to
  678.     do *this*.  I think...  Oh yeah, also change the mode according to the
  679.     stored file attributes, since we didn't do that when we opened the dude.
  680.   ---------------------------------------------------------------------------*/
  681.  
  682.     close(outfd);
  683.  
  684. #ifdef OS2
  685.     SetPathInfo(filename, lrec.last_mod_file_date,
  686.                           lrec.last_mod_file_time, pInfo->dos_attr);
  687.     if (extra_field)
  688.         SetEAs(filename, extra_field);
  689.     if (longname)
  690.         SetLongNameEA(filename, longfilename);
  691. #else /* !OS2 */
  692. #ifdef __TURBOC__
  693.     if (_chmod(filename, 1, pInfo->dos_attr) != pInfo->dos_attr)
  694.         fprintf(stderr, "\nwarning:  file attributes may not be correct\n");
  695. #else /* !__TURBOC__ */
  696. #ifdef WIN32
  697.     /* Attempt to set the file attributes.  SetFileAttributes returns
  698.      * FALSE (0) if unsucessful, in which case print an error message,
  699.      * with error value returned from GetLastError call. */
  700.     pInfo->dos_attr = pInfo->dos_attr & 0x7F;
  701.  
  702.     if (!(SetFileAttributes(filename, pInfo->dos_attr)))
  703.         fprintf(stderr, "\nwarning (%d): could not set file attributes\n",
  704.           GetLastError());
  705. #else /* !WIN32 */
  706.     _dos_setfileattr(filename, pInfo->dos_attr);
  707. #endif /* ?WIN32 */
  708. #endif /* ?__TURBOC__ */
  709. #endif /* ?OS2 */
  710.  
  711. } /* end function set_file_time_and_close() (DOS, OS/2) */
  712.  
  713.  
  714.  
  715.  
  716.  
  717. #else                           /* !DOS_OS2 */
  718. #ifdef MACOS                    /* Mac */
  719.  
  720. /**************************************/
  721. /* Function set_file_time_and_close() */
  722. /**************************************/
  723.  
  724. void set_file_time_and_close()
  725.  /*
  726.   * MAC VERSION
  727.   */
  728. {
  729.     long m_time;
  730.     DateTimeRec dtr;
  731.     ParamBlockRec pbr;
  732.     HParamBlockRec hpbr;
  733.     OSErr err;
  734.  
  735.     if (outfd != 1) {
  736.         close(outfd);
  737.  
  738.         /*
  739.          * Macintosh bases all file modification times on the number of seconds
  740.          * elapsed since Jan 1, 1904, 00:00:00.  Therefore, to maintain
  741.          * compatibility with MS-DOS archives, which date from Jan 1, 1980,
  742.          * with NO relation to GMT, the following conversions must be made:
  743.          *      the Year (yr) must be incremented by 1980;
  744.          *      and converted to seconds using the Mac routine Date2Secs(),
  745.          *      almost similar in complexity to the Unix version :-)
  746.          *                                     J. Lee
  747.          */
  748.  
  749.         dtr.year = (((lrec.last_mod_file_date >> 9) & 0x7f) + 1980);
  750.         dtr.month = ((lrec.last_mod_file_date >> 5) & 0x0f);
  751.         dtr.day = (lrec.last_mod_file_date & 0x1f);
  752.  
  753.         dtr.hour = ((lrec.last_mod_file_time >> 11) & 0x1f);
  754.         dtr.minute = ((lrec.last_mod_file_time >> 5) & 0x3f);
  755.         dtr.second = ((lrec.last_mod_file_time & 0x1f) * 2);
  756.  
  757.         Date2Secs(&dtr, (unsigned long *)&m_time);
  758.         CtoPstr(filename);
  759.         if (hfsflag) {
  760.             hpbr.fileParam.ioNamePtr = (StringPtr)filename;
  761.             hpbr.fileParam.ioVRefNum = gnVRefNum;
  762.             hpbr.fileParam.ioDirID = glDirID;
  763.             hpbr.fileParam.ioFDirIndex = 0;
  764.             err = PBHGetFInfo(&hpbr, 0L);
  765.             hpbr.fileParam.ioFlMdDat = m_time;
  766.             if ( !fMacZipped )
  767.                 hpbr.fileParam.ioFlCrDat = m_time;
  768.             hpbr.fileParam.ioDirID = glDirID;
  769.             if (err == noErr)
  770.                 err = PBHSetFInfo(&hpbr, 0L);
  771.             if (err != noErr)
  772.                 printf("error:  can't set the time for %s\n", filename);
  773.         } else {
  774.             pbr.fileParam.ioNamePtr = (StringPtr)filename;
  775.             pbr.fileParam.ioVRefNum = pbr.fileParam.ioFVersNum =
  776.               pbr.fileParam.ioFDirIndex = 0;
  777.             err = PBGetFInfo(&pbr, 0L);
  778.             pbr.fileParam.ioFlMdDat = pbr.fileParam.ioFlCrDat = m_time;
  779.             if (err == noErr)
  780.                 err = PBSetFInfo(&pbr, 0L);
  781.             if (err != noErr)
  782.                 printf("error:  can't set the time for %s\n", filename);
  783.         }
  784.  
  785.         /* set read-only perms if needed */
  786.         if ((err == noErr) && !(pInfo->unix_attr & S_IWRITE)) {
  787.             if (hfsflag) {
  788.                 hpbr.fileParam.ioNamePtr = (StringPtr)filename;
  789.                 hpbr.fileParam.ioVRefNum = gnVRefNum;
  790.                 hpbr.fileParam.ioDirID = glDirID;
  791.                 err = PBHSetFLock(&hpbr, 0);
  792.             } else
  793.                 err = SetFLock((ConstStr255Param)filename, 0);
  794.         }
  795.         PtoCstr(filename);
  796.     }
  797. }
  798.  
  799.  
  800.  
  801.  
  802.  
  803. #else /* !MACOS... */
  804. #if (!defined(MTS) && !defined(VMS))   /* && !MTS (can't do) && !VMS: only one
  805.                                   * left is UNIX (for VMS use code in vms.c) */
  806.  
  807. /**************************************/
  808. /* Function set_file_time_and_close() */
  809. /**************************************/
  810.  
  811. void set_file_time_and_close()
  812.  /*
  813.   * UNIX VERSION (MS-DOS & OS/2, Mac versions are above)
  814.   */
  815. {
  816.     static short yday[]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  817.     long m_time;
  818.     int yr, mo, dy, hh, mm, ss, leap, days=0;
  819.     struct utimbuf {
  820.         time_t actime;          /* new access time */
  821.         time_t modtime;         /* new modification time */
  822.     } tp;
  823. #ifdef AMIGA
  824. #   define YRBASE  1978         /* in AmigaDos, counting begins 01-Jan-1978 */
  825.     struct DateStamp myadate;
  826. /*  extern char *_TZ;   no longer used? */
  827. #else /* !AMIGA */
  828. #   define YRBASE  1970
  829. #ifdef BSD
  830. #ifndef __386BSD__
  831.     static struct timeb tbp;
  832. #endif /* !__386BSD__ */
  833. #else /* !BSD */
  834.     extern long timezone;
  835. #endif /* ?BSD */
  836. #endif /* ?AMIGA */
  837.  
  838.  
  839.     /*
  840.      * Close the file *before* setting its time under Unix and AmigaDos.
  841.      */
  842. #ifdef AMIGA
  843.     if (cflag)                  /* can't set time on stdout */
  844.         return;
  845.     close(outfd);
  846. #else /* !AMIGA */
  847.     close(outfd);
  848.     if (cflag)                  /* can't set time on stdout */
  849.         return;
  850. #endif /* ?AMIGA */
  851.  
  852.     /*
  853.      * These date conversions look a little weird, so I'll explain.
  854.      * UNIX bases all file modification times on the number of seconds
  855.      * elapsed since Jan 1, 1970, 00:00:00 GMT.  Therefore, to maintain
  856.      * compatibility with MS-DOS archives, which date from Jan 1, 1980,
  857.      * with NO relation to GMT, the following conversions must be made:
  858.      *      the Year (yr) must be incremented by 10;
  859.      *      the Date (dy) must be decremented by 1;
  860.      *      and the whole mess must be adjusted by TWO factors:
  861.      *          relationship to GMT (ie.,Pacific Time adds 8 hrs.),
  862.      *          and whether or not it is Daylight Savings Time.
  863.      * Also, the usual conversions must take place to account for leap years,
  864.      * etc.
  865.      *                                     C. Seaman
  866.      */
  867.  
  868.     /* dissect date */
  869.     yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + (1980 - YRBASE);
  870.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1;
  871.     dy = (lrec.last_mod_file_date & 0x1f) - 1;
  872.  
  873.     /* dissect time */
  874.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;
  875.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  876.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  877.  
  878.     /* leap = # of leap years from BASE up to but not including current year */
  879.     leap = ((yr + YRBASE - 1) / 4);   /* leap year base factor */
  880.  
  881.     /* How many days from BASE to this year? (& add expired days this year) */
  882.     days = (yr * 365) + (leap - 492) + yday[mo];
  883.  
  884.     /* if year is a leap year and month is after February, add another day */
  885.     if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100))
  886.         ++days;                 /* OK through 2199 */
  887.  
  888. #ifdef AMIGA
  889. /*  _TZ = getenv("TZ"); does Amiga not have TZ and tzset() after all? */
  890.     myadate.ds_Days   =   days+dy-2;   /* off by one? */
  891.     myadate.ds_Minute =   hh*60+mm;
  892.     myadate.ds_Tick   =   ss*TICKS_PER_SECOND;
  893.  
  894.     if (!(SetFileDate(filename, &myadate)))
  895.         fprintf(stderr, "error:  can't set the time for %s\n", filename);
  896.  
  897. #else /* !AMIGA */
  898.     /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */
  899.     m_time = ((days + dy) * 86400) + (hh * 3600) + (mm * 60) + ss;
  900.  
  901. #ifdef BSD
  902. #ifndef __386BSD__
  903.     ftime(&tbp);
  904.     m_time += tbp.timezone * 60L;
  905. #endif
  906. /* #elif WIN32
  907.  * don't do anything right now (esp. since "elif" is not legal for old cc's */
  908. #else /* !BSD */
  909.     tzset();                    /* set `timezone' */
  910.     m_time += timezone;         /* account for timezone differences */
  911. #endif /* ?BSD */
  912.  
  913. #ifdef __386BSD__
  914.     m_time += localtime(&m_time)->tm_gmtoff;
  915. #else
  916.     if (localtime(&m_time)->tm_isdst)
  917.         m_time -= 60L * 60L;    /* adjust for daylight savings time */
  918. #endif
  919.  
  920.     tp.actime = m_time;         /* set access time */
  921.     tp.modtime = m_time;        /* set modification time */
  922.  
  923.     /* set the time stamp on the file */
  924.     if (utime(filename, &tp))
  925.         fprintf(stderr, "error:  can't set the time for %s\n", filename);
  926. #endif /* ?AMIGA */
  927. }
  928.  
  929. #endif /* !MTS && !VMS */
  930. #endif /* ?MACOS */
  931. #endif /* ?DOS_OS2 */
  932.  
  933.  
  934.  
  935.  
  936.  
  937. /************************/
  938. /*  Function handler()  */
  939. /************************/
  940.  
  941. void handler(signal)   /* upon interrupt, turn on echo and exit cleanly */
  942.     int signal;
  943. {
  944. #if (defined(SIGBUS) || defined(SIGSEGV))
  945.     static char *corrupt = "error:  zipfile probably corrupt\n";
  946. #endif
  947.  
  948. #ifndef DOS_OS2
  949. #ifdef CRYPT
  950.     echon();
  951. #endif /* CRYPT */
  952.     putc('\n', stderr);
  953. #endif /* !DOS_OS2 */
  954. #ifdef SIGBUS
  955.     if (signal == SIGBUS) {
  956.         fprintf(stderr, corrupt);
  957.         exit(3);
  958.     }
  959. #endif /* SIGBUS */
  960. #ifdef SIGSEGV
  961.     if (signal == SIGSEGV) {
  962.         fprintf(stderr, corrupt);
  963.         exit(3);
  964.     }
  965. #endif /* SIGSEGV */
  966.     exit(0);
  967. }
  968.  
  969.  
  970.  
  971.  
  972.  
  973. /*******************************/
  974. /*  Non-echoing password code  */
  975. /*******************************/
  976.  
  977. #ifdef CRYPT
  978. #ifndef DOS_OS2
  979. #ifdef VMS
  980.  
  981. int echo(opt)
  982.     int opt;
  983. {
  984. /*---------------------------------------------------------------------------
  985.     Based on VMSmunch.c, which in turn was based on Joe Meadows' file.c code.
  986.   ---------------------------------------------------------------------------
  987.      * For VMS v5.x:
  988.      *   IO$_SENSEMODE/SETMODE info:  Programming, Vol. 7A, System Programming,
  989.      *     I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
  990.      *   sys$assign(), sys$qio() info:  Programming, Vol. 4B, System Services,
  991.      *     System Services Reference Manual, pp. sys-23, sys-379
  992.      *   fixed-length descriptor info:  Programming, Vol. 3, System Services,
  993.      *     Intro to System Routines, sec. 2.9.2
  994.      * GRR, 15 Aug 91
  995.   ---------------------------------------------------------------------------*/
  996.     static struct dsc$descriptor_s DevDesc =
  997.         {9, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$INPUT"};
  998.      /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
  999.     static short           DevChan, iosb[4];
  1000.     static long            i, status;
  1001.     static unsigned long   oldmode[2], newmode[2];   /* each = 8 bytes */
  1002.   
  1003.  
  1004. /*---------------------------------------------------------------------------
  1005.     Assign a channel to standard input.
  1006.   ---------------------------------------------------------------------------*/
  1007.  
  1008.     status = sys$assign(&DevDesc, &DevChan, 0, 0);
  1009.     if (!(status & 1))
  1010.         return status;
  1011.  
  1012. /*---------------------------------------------------------------------------
  1013.     Use sys$qio and the IO$_SENSEMODE function to determine the current tty
  1014.     status (for password reading, could use IO$_READVBLK function instead,
  1015.     but echo on/off will be more general).
  1016.   ---------------------------------------------------------------------------*/
  1017.  
  1018.     status = sys$qio(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
  1019.                      oldmode, 8, 0, 0, 0, 0);
  1020.     if (!(status & 1))
  1021.         return status;
  1022.     status = iosb[0];
  1023.     if (!(status & 1))
  1024.         return status;
  1025.  
  1026. /*---------------------------------------------------------------------------
  1027.     Copy old mode into new-mode buffer, then modify to be either NOECHO or
  1028.     ECHO (depending on function argument opt).
  1029.   ---------------------------------------------------------------------------*/
  1030.  
  1031.     newmode[0] = oldmode[0];
  1032.     newmode[1] = oldmode[1];
  1033.     if (opt == OFF)
  1034.         newmode[1] |= TT$M_NOECHO;                      /* set NOECHO bit */
  1035.     else
  1036.         newmode[1] &= ~((unsigned long) TT$M_NOECHO);   /* clear NOECHO bit */
  1037.  
  1038. /*---------------------------------------------------------------------------
  1039.     Use the IO$_SETMODE function to change the tty status.
  1040.   ---------------------------------------------------------------------------*/
  1041.  
  1042.     status = sys$qio(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
  1043.                      newmode, 8, 0, 0, 0, 0);
  1044.     if (!(status & 1))
  1045.         return status;
  1046.     status = iosb[0];
  1047.     if (!(status & 1))
  1048.         return status;
  1049.  
  1050. /*---------------------------------------------------------------------------
  1051.     Deassign the sys$input channel by way of clean-up, then exit happily.
  1052.   ---------------------------------------------------------------------------*/
  1053.  
  1054.     status = sys$dassgn(DevChan);
  1055.     if (!(status & 1))
  1056.         return status;
  1057.  
  1058.     return SS$_NORMAL;   /* we be happy */
  1059.  
  1060. } /* end function echo() */
  1061.  
  1062.  
  1063.  
  1064.  
  1065.  
  1066. #else /* !VMS */
  1067.  
  1068. static int echofd=(-1);       /* file descriptor whose echo is off */
  1069.  
  1070. void echoff(f)
  1071.     int f;                    /* file descriptor for which to turn echo off */
  1072. /* Turn echo off for file descriptor f.  Assumes that f is a tty device. */
  1073. {
  1074.     struct sgttyb sg;         /* tty device structure */
  1075.  
  1076.     echofd = f;
  1077.     GTTY(f, &sg);             /* get settings */
  1078.     sg.sg_flags &= ~ECHO;     /* turn echo off */
  1079.     STTY(f, &sg);
  1080. }
  1081.  
  1082.  
  1083.  
  1084. void echon()
  1085. /* Turn echo back on for file descriptor echofd. */
  1086. {
  1087.     struct sgttyb sg;         /* tty device structure */
  1088.  
  1089.     if (echofd != -1) {
  1090.         GTTY(echofd, &sg);    /* get settings */
  1091.         sg.sg_flags |= ECHO;  /* turn echo on */
  1092.         STTY(echofd, &sg);
  1093.         echofd = -1;
  1094.     }
  1095. }
  1096.  
  1097. #endif /* ?VMS */
  1098. #endif /* !DOS_OS2 */
  1099.  
  1100.  
  1101.  
  1102.  
  1103.  
  1104. char *getp(m, p, n)
  1105.     char *m;                  /* prompt for password */
  1106.     char *p;                  /* return value: line input */
  1107.     int n;                    /* bytes available in p[] */
  1108. /* Get a password of length n-1 or less into *p using the prompt *m.
  1109.    The entered password is not echoed.  Return p on success, NULL on
  1110.    failure (can't get controlling tty). */
  1111. {
  1112.     char c;                   /* one-byte buffer for read() to use */
  1113.     int i;                    /* number of characters input */
  1114.     char *w;                  /* warning on retry */
  1115.  
  1116. #ifndef DOS_OS2
  1117. #ifndef VMS
  1118.     int f;                    /* file decsriptor for tty device */
  1119.  
  1120.     /* turn off echo on tty */
  1121.     if (!isatty(2))
  1122.         return NULL;          /* error if not tty */
  1123.     if ((f = open(ttyname(2), 0, 0)) == -1)
  1124.         return NULL;
  1125. #endif /* !VMS */
  1126.     echoff(f);                /* turn echo off */
  1127. #endif /* !DOS_OS2 */
  1128.  
  1129.     /* get password */
  1130.     w = "";
  1131.     do {
  1132. #ifdef VMS   /* bug:  VMS adds '\n' to NULL fputs (apparently) */
  1133.         if (*w)
  1134. #endif /* VMS */
  1135.             fputs(w, stderr); /* warning if back again */
  1136.         fputs(m, stderr);     /* prompt */
  1137.         fflush(stderr);
  1138.         i = 0;
  1139.         do {                  /* read line, keeping n */
  1140. #ifdef MSVMS
  1141.             if ((c = (char)getch()) == '\r')
  1142.                 c = '\n';
  1143. #else /* !MSVMS */
  1144.             read(f, &c, 1);
  1145. #endif /* ?MSVMS */
  1146.             if (i < n)
  1147.                 p[i++] = c;
  1148.         } while (c != '\n');
  1149.         putc('\n', stderr);  fflush(stderr);
  1150.         w = "(line too long--try again)\n";
  1151.     } while (p[i-1] != '\n');
  1152.     p[i-1] = 0;               /* terminate at newline */
  1153.  
  1154. #ifndef DOS_OS2
  1155.     echon();                  /* turn echo back on */
  1156. #ifndef VMS
  1157.     close(f);
  1158. #endif /* !VMS */
  1159. #endif /* !DOS_OS2 */
  1160.  
  1161.     /* return pointer to password */
  1162.     return p;
  1163. }
  1164.  
  1165. #endif /* CRYPT */
  1166.