/*--------------------------------------------------------------------------- file_io.c This file contains routines for doing direct input/output, file-related sorts of things. Most of the system-specific code for unzip is contained here, including the non-echoing password code for decryption (bottom). ---------------------------------------------------------------------------*/ #if (!defined(__GO32__) && !defined(NeXT)) # define const #endif #define FILE_IO_C #include "unzip.h" #ifdef MSWIN # include "wizunzip.h" #endif /************************************/ /* File_IO Local Prototypes, etc. */ /************************************/ #if (!defined(DOS_OS2) || defined(MSWIN)) static int dos2unix __((unsigned char *buf, int len)); int CR_flag = 0; /* when last char of buffer == CR (for dos2unix()) */ #endif #ifdef OS2 extern int longname; /* set in mapname.c */ extern char longfilename[]; #endif #ifdef CRYPT # if (defined(DOS_OS2) || defined(VMS)) # define MSVMS # ifdef DOS_OS2 # ifdef __EMX__ # define getch() _read_kbd(0, 1, 0) # else # ifdef __GO32__ # include # define getch() getkey() # else /* !__GO32__ */ # include # endif /* ?__GO32__ */ # endif # else /* !DOS_OS2 */ # define getch() getc(stderr) # define OFF 0 /* for echo control */ # define ON 1 # define echoff(f) echo(OFF) # define echon() echo(ON) # include # include # include # if !defined(SS$_NORMAL) # define SS$_NORMAL 1 /* only thing we need from */ # endif # endif /* ?DOS_OS2 */ # else /* !(DOS_OS2 || VMS) */ # ifdef TERMIO /* Amdahl, Cray, all SysV? */ # ifdef CONVEX # include # include # else /* !CONVEX */ # ifdef LINUX # include # else /* !LINUX */ # include # endif /* ?LINUX */ # define sgttyb termio # define sg_flags c_lflag # endif /* ?CONVEX */ int ioctl OF((int, int, voidp *)); # define GTTY(f,s) ioctl(f,TCGETA,(voidp *)s) # define STTY(f,s) ioctl(f,TCSETAW,(voidp *)s) # else /* !TERMIO */ # if (!defined(MINIX) && !defined(__386BSD__)) # include # endif /* !MINIX && !__386BSD__ */ # include # ifdef __386BSD__ # define GTTY(f, s) ioctl(f, TIOCGETP, (voidp *) s) # define STTY(f, s) ioctl(f, TIOCSETP, (voidp *) s) # else /* !__386BSD__ */ # define GTTY gtty # define STTY stty int gtty OF((int, struct sgttyb *)); int stty OF((int, struct sgttyb *)); # endif /* ?__386BSD__ */ # endif /* ?TERMIO */ int isatty OF((int)); char *ttyname OF((int)); # if (defined(PROTO) && !defined(__GNUC__) && !defined(_AIX)) int open (char *, int, ...); # endif int close OF((int)); int read OF((int, voidp *, int)); # endif /* ?(DOS_OS2 || VMS) */ #endif /* CRYPT */ /******************************/ /* Function open_input_file() */ /******************************/ int open_input_file() /* return non-zero if open failed */ { /* * open the zipfile for reading and in BINARY mode to prevent cr/lf * translation, which would corrupt the bitstreams */ #ifdef VMS zipfd = open(zipfn, O_RDONLY, 0, "ctx=stm"); #else /* !VMS */ #ifdef UNIX zipfd = open(zipfn, O_RDONLY); #else /* !UNIX */ #ifdef MACOS zipfd = open(zipfn, 0); #else /* !MACOS */ zipfd = open(zipfn, O_RDONLY | O_BINARY); #endif /* ?MACOS */ #endif /* ?UNIX */ #endif /* ?VMS */ if (zipfd < 1) { fprintf(stderr, "error: can't open zipfile [ %s ]\n", zipfn); return (1); } return 0; } /**********************/ /* Function readbuf() */ /**********************/ int readbuf(buf, size) char *buf; register unsigned size; { /* return number of bytes read into buf */ register int count; int n; n = size; while (size) { if (incnt == 0) { if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) <= 0) return (n-size); /* buffer ALWAYS starts on a block boundary: */ cur_zipfile_bufstart += INBUFSIZ; inptr = inbuf; } count = MIN(size, (unsigned)incnt); memcpy(buf, inptr, count); buf += count; inptr += count; incnt -= count; size -= count; } return (n); } #ifndef VMS /* for VMS use code in vms.c (old VMS code below is retained * in case of problems...will be removed in a later release) */ /*********************************/ /* Function create_output_file() */ /*********************************/ int create_output_file() /* return non-0 if creat failed */ { /*--------------------------------------------------------------------------- Create the output file with appropriate permissions. If we've gotten to this point and the file still exists, we have permission to blow it away. ---------------------------------------------------------------------------*/ #if (!defined(DOS_OS2) || defined(MSWIN)) CR_flag = 0; /* hack to get CR at end of buffer working */ #endif #if (defined(UNIX) && !defined(AMIGA)) { int mask; #ifndef VMS if (!stat(filename, &statbuf) && (unlink(filename) < 0)) { fprintf(stderr, "\n%s: cannot delete old copy\n", filename); return 1; } # define EXTRA_ARGS #else /* VMS */ # define EXTRA_ARGS ,"rfm=stmlf","rat=cr" #endif /* ?VMS */ mask = umask(0); /* now know that we own it */ outfd = creat(filename, 0xffff & pInfo->unix_attr EXTRA_ARGS); umask(mask); /* VMS, Unix */ } #else /* !UNIX || AMIGA */ /* file permissions set after file closed */ #ifndef MACOS outfd = creat(filename, S_IWRITE | S_IREAD); /* DOS, OS2, Mac, Amiga */ #else /* MACOS */ { short fDataFork=TRUE; MACINFO mi; OSErr err; fMacZipped = FALSE; CtoPstr(filename); if (extra_field && (lrec.extra_field_length > sizeof(MACINFOMIN)) && (lrec.extra_field_length <= sizeof(MACINFO))) { BlockMove(extra_field, &mi, lrec.extra_field_length); if ((makeword((byte *)&mi.header) == 1992) && (makeword((byte *)&mi.data) == lrec.extra_field_length-sizeof(ZIP_EXTRA_HEADER)) && (mi.signature == 'JLEE')) { gostCreator = mi.finfo.fdCreator; gostType = mi.finfo.fdType; fDataFork = (mi.flags & 1) ? TRUE : FALSE; fMacZipped = true; /* If it was Zipped w/Mac version, the filename has either */ /* a 'd' or 'r' appended. Remove the d/r when unzipping */ filename[0]-=1; } } if (!fMacZipped) { if (!aflag) gostType = gostCreator = '\?\?\?\?'; else { #ifdef THINK_C gostCreator = 'KAHL'; #else #ifdef MCH_MACINTOSH gostCreator = 'Manx'; #else gostCreator = 'MPS '; #endif #endif gostType = 'TEXT'; } } PtoCstr(filename); outfd = creat(filename, 0); if (fMacZipped) { CtoPstr(filename); if (hfsflag) { HParamBlockRec hpbr; hpbr.fileParam.ioNamePtr = (StringPtr)filename; hpbr.fileParam.ioVRefNum = gnVRefNum; hpbr.fileParam.ioDirID = glDirID; hpbr.fileParam.ioFlFndrInfo = mi.finfo; hpbr.fileParam.ioFlCrDat = mi.lCrDat; hpbr.fileParam.ioFlMdDat = mi.lMdDat; err = PBHSetFInfo(&hpbr, 0); } else { err = SetFInfo((StringPtr)filename , 0, &mi.finfo); } PtoCstr(filename); } if (outfd != -1) outfd = open(filename, (fDataFork)? 1 : 2); } #endif /* ?MACOS */ #endif /* ?(UNIX && !AMIGA) */ if (outfd < 1) { fprintf(stderr, "\n%s: cannot create\n", filename); return 1; } /*--------------------------------------------------------------------------- If newly created file is in text mode and should be binary (to disable automatic CR/LF translations), either close it and reopen as binary or else change the mode to binary (DOS, OS/2). ---------------------------------------------------------------------------*/ #if (!defined(UNIX) && !defined(MACOS)) if (!aflag) { #ifdef DOS_OS2 if (setmode(outfd, O_BINARY) == -1) { #else /* !DOS_OS2 */ close(outfd); if ((outfd = open(filename, O_RDWR | O_BINARY)) < 1) { #endif /* ?DOS_OS2 */ fprintf(stderr, "Can't make output file binary: %s\n", filename); return 1; } } #endif /* !UNIX && !MACOS */ return 0; } #endif /* !VMS */ /****************************/ /* Function FillBitBuffer() */ /****************************/ int FillBitBuffer() { /* * Fill bitbuf, which is 32 bits. This function is only used by the * READBIT and PEEKBIT macros (which are used by all of the uncompression * routines). */ UWORD temp; zipeof = 1; while (bits_left < 25 && ReadByte(&temp) == 8) { bitbuf |= (ULONG)temp << bits_left; bits_left += 8; zipeof = 0; } return 0; } /***********************/ /* Function ReadByte() */ /***********************/ int ReadByte(x) UWORD *x; { /* * read a byte; return 8 if byte available, 0 if not */ if (mem_mode) return ReadMemoryByte(x); if (csize-- <= 0) return 0; if (incnt == 0) { if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) <= 0) return 0; /* buffer ALWAYS starts on a block boundary: */ cur_zipfile_bufstart += INBUFSIZ; inptr = inbuf; #ifdef CRYPT if (pInfo->encrypted) { byte *p; int n, t; for (n = (longint)incnt > csize + 1 ? (int)csize + 1 : incnt, p = inptr; n--; p++) *p = (byte) DECRYPT(*p); } #endif /* CRYPT */ } *x = *inptr++; --incnt; return 8; } #ifndef VMS /* for VMS use code in vms.c */ /**************************/ /* Function FlushOutput() */ /**************************/ int FlushOutput() { /* * flush contents of output buffer; return PK-type error code */ #if (!defined(DOS_OS2) || defined(MSWIN)) int saved_ctrlZ = FALSE; #endif int len; if (mem_mode) { int rc = FlushMemory(); outpos += outcnt; outcnt = 0; outptr = outbuf; return rc; } if (disk_full) { outpos += outcnt; /* fake emptied buffer */ outcnt = 0; outptr = outbuf; return 50; /* ignore rest of this file */ } if (outcnt) { UpdateCRC(outbuf, outcnt); if (!tflag) { #if (!defined(DOS_OS2) || defined(MSWIN)) if (aflag) { if (outbuf[outcnt-1] == CTRLZ) { --outcnt; saved_ctrlZ = TRUE; } len = dos2unix(outbuf, outcnt); } else #endif /* !DOS_OS2 || MSWIN */ len = outcnt; #ifdef MACOS if ((giCursor+1) >> 2 != (giCursor>>2)) SetCursor( *rghCursor[((giCursor+1)>>2)&0x03] ); giCursor = (giCursor+1) & 15; #endif /* MACOS */ #ifdef MSWIN /* if writing to console vs. actual file, write to Msg Window */ if (cflag) WriteBufferToMsgWin(outout, len, FALSE); else if (_lwrite(outfd, outout, len) != (UINT)len) #else /* !MSWIN */ if (write(outfd, (char *)outout, len) != len) #endif /* ?MSWIN */ #ifdef DOS_OS2 if (!cflag) /* ^Z treated as EOF, removed with -c */ #else /* !DOS_OS2 */ #ifdef MINIX if (errno == EFBIG) if (write(fd, outout, len/2) != len/2 || write(fd, outout+len/2, len/2) != len/2) #endif /* MINIX */ #endif /* ?DOS_OS2 */ { /* GRR: add test for force_flag when has its own switch */ fprintf(stderr, "\n%s: write error (disk full?). Continue? (y/n/^C) ", filename); FFLUSH /* for Amiga and Mac MPW */ #ifdef MSWIN disk_full = 2; #else /* !MSWIN */ fgets(answerbuf, 9, stdin); if (*answerbuf == 'y') /* stop writing to this file */ disk_full = 1; /* (outfd bad?), but new OK */ else disk_full = 2; /* no: exit program */ #endif /* ?MSWIN */ return 50; /* 50: disk full */ } } outpos += outcnt; outcnt = 0; outptr = outbuf; #if (!defined(DOS_OS2) || defined(MSWIN)) if (saved_ctrlZ) { *outptr++ = CTRLZ; ++outcnt; } #endif /* !DOS_OS2 || MSWIN */ } return 0; /* 0: no error */ } #endif /* !VMS */ #if (!defined(DOS_OS2) || defined(MSWIN)) /***********************/ /* Function dos2unix() */ /***********************/ static int dos2unix(buf, len) /* GRR: rewrite for generic text conversions */ unsigned char *buf; int len; { int new_len; int i; #ifdef MSWIN unsigned char __far *walker; #else /* !MSWIN */ unsigned char *walker; #endif /* ?MSWIN */ new_len = len; walker = outout; #ifdef MACOS /* * Mac wants to strip LFs instead CRs from CRLF pairs */ if (CR_flag && *buf == LF) { buf++; new_len--; len--; CR_flag = buf[len] == CR; } else CR_flag = buf[len - 1] == CR; for (i = 0; i < len; i += 1) { *walker++ = ascii_to_native(*buf); if (*buf == LF) walker[-1] = CR; if (*buf++ == CR && *buf == LF) { new_len--; buf++; i++; } } #else /* !MACOS */ if (CR_flag && *buf != LF) *walker++ = ascii_to_native(CR); CR_flag = buf[len - 1] == CR; for (i = 0; i < len; i += 1) { *walker++ = ascii_to_native(*buf); if (*buf++ == CR && *buf == LF) { new_len--; walker[-1] = ascii_to_native(*buf++); i++; } } /* * If the last character is a CR, then "ignore it" for now... */ if (walker[-1] == ascii_to_native(CR)) new_len--; #endif /* ?MACOS */ return new_len; } #endif /* !DOS_OS2 || MSWIN */ #ifdef __GO32__ void _dos_setftime(int fd, UWORD dosdate, UWORD dostime) { asm("pushl %ebx"); asm("movl %0, %%ebx": : "g" (fd)); asm("movl %0, %%ecx": : "g" (dostime)); asm("movl %0, %%edx": : "g" (dosdate)); asm("movl $0x5701, %eax"); asm("int $0x21"); asm("popl %ebx"); } void _dos_setfileattr(char *name, int attr) { asm("movl %0, %%edx": : "g" (name)); asm("movl %0, %%ecx": : "g" (attr)); asm("movl $0x4301, %eax"); asm("int $0x21"); } #endif /* __GO32__ */ #ifdef DOS_OS2 /**************************************/ /* Function set_file_time_and_close() */ /**************************************/ void set_file_time_and_close() /* * MS-DOS AND OS/2 VERSION (Mac, Unix/VMS versions are below) * * Set the output file date/time stamp according to information from the * zipfile directory record for this member, then close the file and set * its permissions (archive, hidden, read-only, system). Aside from closing * the file, this routine is optional (but most compilers support it). */ { /*--------------------------------------------------------------------------- Allocate local variables needed by OS/2 and Turbo C. ---------------------------------------------------------------------------*/ #ifdef __TURBOC__ union { struct ftime ft; /* system file time record */ struct { UWORD ztime; /* date and time words */ UWORD zdate; /* .. same format as in .ZIP file */ } zt; } td; #endif /* __TURBOC__ */ /*--------------------------------------------------------------------------- Do not attempt to set the time stamp on standard output. ---------------------------------------------------------------------------*/ if (cflag) { close(outfd); return; } /*--------------------------------------------------------------------------- Copy and/or convert time and date variables, if necessary; then set the file time/date. ---------------------------------------------------------------------------*/ #ifndef OS2 #ifdef __TURBOC__ td.zt.ztime = lrec.last_mod_file_time; td.zt.zdate = lrec.last_mod_file_date; setftime(outfd, &td.ft); #else /* !__TURBOC__ */ #ifdef WIN32 { FILETIME ft; /* 64-bit value made up of two 32 bit [low & high] */ WORD wDOSDate; /* for vconvertin from DOS date to Windows NT */ WORD wDOSTime; HANDLE hFile; /* file handle (defined in Windows NT) */ wDOSTime = (WORD) lrec.last_mod_file_time; wDOSDate = (WORD) lrec.last_mod_file_date; /* The DosDateTimeToFileTime() function converts a DOS date/time * into a 64 bit Windows NT file time */ DosDateTimeToFileTime(wDOSDate, wDOSTime, &ft); /* Close the file and then re-open it using the Win32 * CreateFile call, so that the file can be created * with GENERIC_WRITE access, otherwise the SetFileTime * call will fail. */ close(outfd); hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (!SetFileTime(hFile, NULL, NULL, &ft)) printf("\nSetFileTime failed: %d\n", GetLastError()); CloseHandle(hFile); return; } #else /* !WIN32 */ _dos_setftime(outfd, lrec.last_mod_file_date, lrec.last_mod_file_time); #endif /* ?WIN32 */ #endif /* ?__TURBOC__ */ #endif /* ?OS2 */ /*--------------------------------------------------------------------------- And finally we can close the file...at least everybody agrees on how to do *this*. I think... Oh yeah, also change the mode according to the stored file attributes, since we didn't do that when we opened the dude. ---------------------------------------------------------------------------*/ close(outfd); #ifdef OS2 SetPathInfo(filename, lrec.last_mod_file_date, lrec.last_mod_file_time, pInfo->dos_attr); if (extra_field) SetEAs(filename, extra_field); if (longname) SetLongNameEA(filename, longfilename); #else /* !OS2 */ #ifdef __TURBOC__ if (_chmod(filename, 1, pInfo->dos_attr) != pInfo->dos_attr) fprintf(stderr, "\nwarning: file attributes may not be correct\n"); #else /* !__TURBOC__ */ #ifdef WIN32 /* Attempt to set the file attributes. SetFileAttributes returns * FALSE (0) if unsucessful, in which case print an error message, * with error value returned from GetLastError call. */ pInfo->dos_attr = pInfo->dos_attr & 0x7F; if (!(SetFileAttributes(filename, pInfo->dos_attr))) fprintf(stderr, "\nwarning (%d): could not set file attributes\n", GetLastError()); #else /* !WIN32 */ _dos_setfileattr(filename, pInfo->dos_attr); #endif /* ?WIN32 */ #endif /* ?__TURBOC__ */ #endif /* ?OS2 */ } /* end function set_file_time_and_close() (DOS, OS/2) */ #else /* !DOS_OS2 */ #ifdef MACOS /* Mac */ /**************************************/ /* Function set_file_time_and_close() */ /**************************************/ void set_file_time_and_close() /* * MAC VERSION */ { long m_time; DateTimeRec dtr; ParamBlockRec pbr; HParamBlockRec hpbr; OSErr err; if (outfd != 1) { close(outfd); /* * Macintosh bases all file modification times on the number of seconds * elapsed since Jan 1, 1904, 00:00:00. Therefore, to maintain * compatibility with MS-DOS archives, which date from Jan 1, 1980, * with NO relation to GMT, the following conversions must be made: * the Year (yr) must be incremented by 1980; * and converted to seconds using the Mac routine Date2Secs(), * almost similar in complexity to the Unix version :-) * J. Lee */ dtr.year = (((lrec.last_mod_file_date >> 9) & 0x7f) + 1980); dtr.month = ((lrec.last_mod_file_date >> 5) & 0x0f); dtr.day = (lrec.last_mod_file_date & 0x1f); dtr.hour = ((lrec.last_mod_file_time >> 11) & 0x1f); dtr.minute = ((lrec.last_mod_file_time >> 5) & 0x3f); dtr.second = ((lrec.last_mod_file_time & 0x1f) * 2); Date2Secs(&dtr, (unsigned long *)&m_time); CtoPstr(filename); if (hfsflag) { hpbr.fileParam.ioNamePtr = (StringPtr)filename; hpbr.fileParam.ioVRefNum = gnVRefNum; hpbr.fileParam.ioDirID = glDirID; hpbr.fileParam.ioFDirIndex = 0; err = PBHGetFInfo(&hpbr, 0L); hpbr.fileParam.ioFlMdDat = m_time; if ( !fMacZipped ) hpbr.fileParam.ioFlCrDat = m_time; hpbr.fileParam.ioDirID = glDirID; if (err == noErr) err = PBHSetFInfo(&hpbr, 0L); if (err != noErr) printf("error: can't set the time for %s\n", filename); } else { pbr.fileParam.ioNamePtr = (StringPtr)filename; pbr.fileParam.ioVRefNum = pbr.fileParam.ioFVersNum = pbr.fileParam.ioFDirIndex = 0; err = PBGetFInfo(&pbr, 0L); pbr.fileParam.ioFlMdDat = pbr.fileParam.ioFlCrDat = m_time; if (err == noErr) err = PBSetFInfo(&pbr, 0L); if (err != noErr) printf("error: can't set the time for %s\n", filename); } /* set read-only perms if needed */ if ((err == noErr) && !(pInfo->unix_attr & S_IWRITE)) { if (hfsflag) { hpbr.fileParam.ioNamePtr = (StringPtr)filename; hpbr.fileParam.ioVRefNum = gnVRefNum; hpbr.fileParam.ioDirID = glDirID; err = PBHSetFLock(&hpbr, 0); } else err = SetFLock((ConstStr255Param)filename, 0); } PtoCstr(filename); } } #else /* !MACOS... */ #if (!defined(MTS) && !defined(VMS)) /* && !MTS (can't do) && !VMS: only one * left is UNIX (for VMS use code in vms.c) */ /**************************************/ /* Function set_file_time_and_close() */ /**************************************/ void set_file_time_and_close() /* * UNIX VERSION (MS-DOS & OS/2, Mac versions are above) */ { static short yday[]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; long m_time; int yr, mo, dy, hh, mm, ss, leap, days=0; struct utimbuf { time_t actime; /* new access time */ time_t modtime; /* new modification time */ } tp; #ifdef AMIGA # define YRBASE 1978 /* in AmigaDos, counting begins 01-Jan-1978 */ struct DateStamp myadate; /* extern char *_TZ; no longer used? */ #else /* !AMIGA */ # define YRBASE 1970 #ifdef BSD #ifndef __386BSD__ static struct timeb tbp; #endif /* !__386BSD__ */ #else /* !BSD */ extern long timezone; #endif /* ?BSD */ #endif /* ?AMIGA */ /* * Close the file *before* setting its time under Unix and AmigaDos. */ #ifdef AMIGA if (cflag) /* can't set time on stdout */ return; close(outfd); #else /* !AMIGA */ close(outfd); if (cflag) /* can't set time on stdout */ return; #endif /* ?AMIGA */ /* * These date conversions look a little weird, so I'll explain. * UNIX bases all file modification times on the number of seconds * elapsed since Jan 1, 1970, 00:00:00 GMT. Therefore, to maintain * compatibility with MS-DOS archives, which date from Jan 1, 1980, * with NO relation to GMT, the following conversions must be made: * the Year (yr) must be incremented by 10; * the Date (dy) must be decremented by 1; * and the whole mess must be adjusted by TWO factors: * relationship to GMT (ie.,Pacific Time adds 8 hrs.), * and whether or not it is Daylight Savings Time. * Also, the usual conversions must take place to account for leap years, * etc. * C. Seaman */ /* dissect date */ yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + (1980 - YRBASE); mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1; dy = (lrec.last_mod_file_date & 0x1f) - 1; /* dissect time */ hh = (lrec.last_mod_file_time >> 11) & 0x1f; mm = (lrec.last_mod_file_time >> 5) & 0x3f; ss = (lrec.last_mod_file_time & 0x1f) * 2; /* leap = # of leap years from BASE up to but not including current year */ leap = ((yr + YRBASE - 1) / 4); /* leap year base factor */ /* How many days from BASE to this year? (& add expired days this year) */ days = (yr * 365) + (leap - 492) + yday[mo]; /* if year is a leap year and month is after February, add another day */ if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100)) ++days; /* OK through 2199 */ #ifdef AMIGA /* _TZ = getenv("TZ"); does Amiga not have TZ and tzset() after all? */ myadate.ds_Days = days+dy-2; /* off by one? */ myadate.ds_Minute = hh*60+mm; myadate.ds_Tick = ss*TICKS_PER_SECOND; if (!(SetFileDate(filename, &myadate))) fprintf(stderr, "error: can't set the time for %s\n", filename); #else /* !AMIGA */ /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */ m_time = ((days + dy) * 86400) + (hh * 3600) + (mm * 60) + ss; #ifdef BSD #ifndef __386BSD__ ftime(&tbp); m_time += tbp.timezone * 60L; #endif /* #elif WIN32 * don't do anything right now (esp. since "elif" is not legal for old cc's */ #else /* !BSD */ tzset(); /* set `timezone' */ m_time += timezone; /* account for timezone differences */ #endif /* ?BSD */ #ifdef __386BSD__ m_time += localtime(&m_time)->tm_gmtoff; #else if (localtime(&m_time)->tm_isdst) m_time -= 60L * 60L; /* adjust for daylight savings time */ #endif tp.actime = m_time; /* set access time */ tp.modtime = m_time; /* set modification time */ /* set the time stamp on the file */ if (utime(filename, &tp)) fprintf(stderr, "error: can't set the time for %s\n", filename); #endif /* ?AMIGA */ } #endif /* !MTS && !VMS */ #endif /* ?MACOS */ #endif /* ?DOS_OS2 */ /************************/ /* Function handler() */ /************************/ void handler(signal) /* upon interrupt, turn on echo and exit cleanly */ int signal; { #if (defined(SIGBUS) || defined(SIGSEGV)) static char *corrupt = "error: zipfile probably corrupt\n"; #endif #ifndef DOS_OS2 #ifdef CRYPT echon(); #endif /* CRYPT */ putc('\n', stderr); #endif /* !DOS_OS2 */ #ifdef SIGBUS if (signal == SIGBUS) { fprintf(stderr, corrupt); exit(3); } #endif /* SIGBUS */ #ifdef SIGSEGV if (signal == SIGSEGV) { fprintf(stderr, corrupt); exit(3); } #endif /* SIGSEGV */ exit(0); } /*******************************/ /* Non-echoing password code */ /*******************************/ #ifdef CRYPT #ifndef DOS_OS2 #ifdef VMS int echo(opt) int opt; { /*--------------------------------------------------------------------------- Based on VMSmunch.c, which in turn was based on Joe Meadows' file.c code. --------------------------------------------------------------------------- * For VMS v5.x: * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming, * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6 * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services, * System Services Reference Manual, pp. sys-23, sys-379 * fixed-length descriptor info: Programming, Vol. 3, System Services, * Intro to System Routines, sec. 2.9.2 * GRR, 15 Aug 91 ---------------------------------------------------------------------------*/ static struct dsc$descriptor_s DevDesc = {9, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$INPUT"}; /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */ static short DevChan, iosb[4]; static long i, status; static unsigned long oldmode[2], newmode[2]; /* each = 8 bytes */ /*--------------------------------------------------------------------------- Assign a channel to standard input. ---------------------------------------------------------------------------*/ status = sys$assign(&DevDesc, &DevChan, 0, 0); if (!(status & 1)) return status; /*--------------------------------------------------------------------------- Use sys$qio and the IO$_SENSEMODE function to determine the current tty status (for password reading, could use IO$_READVBLK function instead, but echo on/off will be more general). ---------------------------------------------------------------------------*/ status = sys$qio(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0, oldmode, 8, 0, 0, 0, 0); if (!(status & 1)) return status; status = iosb[0]; if (!(status & 1)) return status; /*--------------------------------------------------------------------------- Copy old mode into new-mode buffer, then modify to be either NOECHO or ECHO (depending on function argument opt). ---------------------------------------------------------------------------*/ newmode[0] = oldmode[0]; newmode[1] = oldmode[1]; if (opt == OFF) newmode[1] |= TT$M_NOECHO; /* set NOECHO bit */ else newmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */ /*--------------------------------------------------------------------------- Use the IO$_SETMODE function to change the tty status. ---------------------------------------------------------------------------*/ status = sys$qio(0, DevChan, IO$_SETMODE, &iosb, 0, 0, newmode, 8, 0, 0, 0, 0); if (!(status & 1)) return status; status = iosb[0]; if (!(status & 1)) return status; /*--------------------------------------------------------------------------- Deassign the sys$input channel by way of clean-up, then exit happily. ---------------------------------------------------------------------------*/ status = sys$dassgn(DevChan); if (!(status & 1)) return status; return SS$_NORMAL; /* we be happy */ } /* end function echo() */ #else /* !VMS */ static int echofd=(-1); /* file descriptor whose echo is off */ void echoff(f) int f; /* file descriptor for which to turn echo off */ /* Turn echo off for file descriptor f. Assumes that f is a tty device. */ { struct sgttyb sg; /* tty device structure */ echofd = f; GTTY(f, &sg); /* get settings */ sg.sg_flags &= ~ECHO; /* turn echo off */ STTY(f, &sg); } void echon() /* Turn echo back on for file descriptor echofd. */ { struct sgttyb sg; /* tty device structure */ if (echofd != -1) { GTTY(echofd, &sg); /* get settings */ sg.sg_flags |= ECHO; /* turn echo on */ STTY(echofd, &sg); echofd = -1; } } #endif /* ?VMS */ #endif /* !DOS_OS2 */ char *getp(m, p, n) char *m; /* prompt for password */ char *p; /* return value: line input */ int n; /* bytes available in p[] */ /* Get a password of length n-1 or less into *p using the prompt *m. The entered password is not echoed. Return p on success, NULL on failure (can't get controlling tty). */ { char c; /* one-byte buffer for read() to use */ int i; /* number of characters input */ char *w; /* warning on retry */ #ifndef DOS_OS2 #ifndef VMS int f; /* file decsriptor for tty device */ /* turn off echo on tty */ if (!isatty(2)) return NULL; /* error if not tty */ if ((f = open(ttyname(2), 0, 0)) == -1) return NULL; #endif /* !VMS */ echoff(f); /* turn echo off */ #endif /* !DOS_OS2 */ /* get password */ w = ""; do { #ifdef VMS /* bug: VMS adds '\n' to NULL fputs (apparently) */ if (*w) #endif /* VMS */ fputs(w, stderr); /* warning if back again */ fputs(m, stderr); /* prompt */ fflush(stderr); i = 0; do { /* read line, keeping n */ #ifdef MSVMS if ((c = (char)getch()) == '\r') c = '\n'; #else /* !MSVMS */ read(f, &c, 1); #endif /* ?MSVMS */ if (i < n) p[i++] = c; } while (c != '\n'); putc('\n', stderr); fflush(stderr); w = "(line too long--try again)\n"; } while (p[i-1] != '\n'); p[i-1] = 0; /* terminate at newline */ #ifndef DOS_OS2 echon(); /* turn echo back on */ #ifndef VMS close(f); #endif /* !VMS */ #endif /* !DOS_OS2 */ /* return pointer to password */ return p; } #endif /* CRYPT */