/* Low-level Amiga routines shared between Zip and UnZip. * * Contains: FileDate() * tzset() [replaces bad C library versions] * gmtime() [ditto] * localtime() [ditto] * time() [ditto] * sendpkt() * Agetch() * * The first two are used by all Info-Zip programs except fUnZip. The last two * are used by all except the non-CRYPT version of fUnZip. Probably some of * the stuff in here is unused by ZipNote and ZipSplit too... sendpkt() is * used by Agetch() and FileDate(), and by windowheight() in amiga/amiga.c * (UnZip). */ /* HISTORY/CHANGES * 2 Sep 92, Greg Roelofs, Original coding. * 6 Sep 92, John Bush, Incorporated into UnZip 5.1 * 6 Sep 92, John Bush, Interlude "FileDate()" defined, which calls or * redefines SetFileDate() depending upon AMIGADOS2 definition. * 11 Oct 92, John Bush, Eliminated AMIGADOS2 switch by determining * revision via OpenLibrary() call. Now only one version of * the program runs on both platforms (1.3.x vs. 2.x) * 11 Oct 92, John Bush, Merged with Zip version and changed arg passing * to take time_t input instead of struct DateStamp. * Arg passing made to conform with utime(). * 22 Nov 92, Paul Kienitz, fixed includes for Aztec and cleaned up some * lint-ish errors; simplified test for AmigaDOS version. * 11 Nov 95, Paul Kienitz, added Agetch() for crypt password input and * UnZip's "More" prompt -- simplifies crypt.h and avoids * use of library code redundant with sendpkt(). Made it * available to FUnZip, which does not use FileDate(). * 22 Nov 95, Paul Kienitz, created a new tzset() that gets the current * timezone from the Locale preferences. These exist only under * AmigaDOS 2.1 and up, but it is probably correctly set on more * Amigas than the TZ environment variable is. We check that * only if TZ is not validly set. We do not parse daylight * savings syntax except to check for presence vs. absence of a * DST part; United States rules are assumed. This is better * than the tzset()s in the Amiga compilers' libraries do. * 15 Jan 96, Chr. Spieler, corrected the logic when to select low level * sendpkt() (when FileDate(), Agetch() or windowheight() is used), * and AMIGA's Agetch() (CRYPT, and UnZip(SFX)'s UzpMorePause()). * 10 Feb 96, Paul Kienitz, re-fiddled that selection logic again, moved * stuff around for clarity. * 16 Mar 96, Paul Kienitz, created a replacement localtime() to go with the * new tzset(), because Aztec's is hopelessly broken. Also * gmtime(), which localtime() calls. * 12 Apr 96, Paul Kienitz, daylight savings was being handled incorrectly. * 21 Apr 96, Paul Kienitz, had to replace time() as well, Aztec's returns * local time instead of GMT. That's why their localtime() was bad, * because it assumed time_t was already local, and gmtime() was * the one that checked TZ. * 23 Apr 96, Chr. Spieler, deactivated time() replacement for UnZip stuff. * Currently, the UnZip sources do not make use of time() (and do * not supply the working mktime() replacement, either!). */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AZTEC_C # include # include # include # define ESRCH ENOENT # define EOSERR EIO #endif #if defined(LATTICE) || defined(__SASC) # include # include #endif #define OF(x) x /* so crypt.h prototypes compile okay */ #if defined(ZIP) || defined(FUNZIP) # define near /* likewise */ typedef unsigned long ulg; /* likewise */ typedef size_t extent; /* likewise */ typedef void zvoid; /* likewise */ #endif #include "crypt.h" /* just so we can tell if CRYPT is defined */ #ifndef FUNZIP /***********************/ /* Function filedate() */ /***********************/ /* FileDate() (originally utime.c), by Paul Wells. Modified by John Bush * and others (see also sendpkt() comments, below); NewtWare SetFileDate() * clone cheaply ripped off from utime(). */ /* DESCRIPTION * This routine chooses between 2 methods to set the file date on AMIGA. * Since AmigaDOS 2.x came out, SetFileDate() was available in ROM (v.36 * and higher). Under AmigaDOS 1.3.x (less than v.36 ROM), SetFileDate() * must be accomplished by constructing a message packet and sending it * to the file system handler of the file to be stamped. * * The system's ROM version is extracted from the external system Library * base. * * NOTE: although argument passing conforms with utime(), note the * following differences: * - Return value is boolean success/failure. * - If a structure or array is passed, only the first value * is used, which *may* correspond to date accessed and not * date modified. */ # ifndef SUCCESS # define SUCCESS (-1L) # define FAILURE 0L # endif # define ReqVers 36L /* required library version for SetFileDate() */ # define TZSIZE 40 /* max space allowed for a timezone string */ extern struct Library *SysBase; long timezone = 0; /* should be pretty safe for reentrancy */ int daylight = 0; LONG FileDate (char *filename, time_t u[]); void tzset(void); /* =============================================================== */ LONG FileDate(filename, u) char *filename; time_t u[]; { LONG SetFileDate(UBYTE *filename, struct DateStamp *pDate); LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs); struct MsgPort *taskport; BPTR dirlock, lock; struct FileInfoBlock *fib; LONG pktargs[4]; UBYTE *ptr; long ret; struct DateStamp pDate; time_t mtime; tzset(); mtime = u[0] - timezone; /* magic number = 2922 = 8 years + 2 leaps between 1970 - 1978 */ pDate.ds_Days = (mtime / 86400L) - 2922L; mtime = mtime % 86400L; pDate.ds_Minute = mtime / 60L; mtime = mtime % 60L; pDate.ds_Tick = mtime * TICKS_PER_SECOND; if (SysBase->lib_Version >= ReqVers) { return (SetFileDate(filename,&pDate)); /* native routine at 2.0+ */ } else /* !(SysBase->lib_Version >=ReqVers) */ { if( !(taskport = (struct MsgPort *)DeviceProc(filename)) ) { errno = ESRCH; /* no such process */ return FAILURE; } if( !(lock = Lock(filename,SHARED_LOCK)) ) { errno = ENOENT; /* no such file */ return FAILURE; } if( !(fib = (struct FileInfoBlock *)AllocMem( (long)sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)) ) { errno = ENOMEM; /* insufficient memory */ UnLock(lock); return FAILURE; } if( Examine(lock,fib)==FAILURE ) { errno = EOSERR; /* operating system error */ UnLock(lock); FreeMem(fib,(long)sizeof(*fib)); return FAILURE; } dirlock = ParentDir(lock); ptr = (UBYTE *)AllocMem(64L,MEMF_PUBLIC); strcpy((ptr+1),fib->fib_FileName); *ptr = strlen(fib->fib_FileName); FreeMem(fib,(long)sizeof(*fib)); UnLock(lock); /* now fill in argument array */ pktargs[0] = 0; pktargs[1] = (LONG)dirlock; pktargs[2] = (LONG)&ptr[0] >> 2; pktargs[3] = (LONG)&pDate; errno = ret = sendpkt(taskport,ACTION_SET_DATE,pktargs,4L); FreeMem(ptr,64L); UnLock(dirlock); return SUCCESS; } /* ?(SysBase->lib_Version >= ReqVers) */ } /* FileDate() */ void tzset(void) /* check Locale and TZ -- the environment overrides */ { struct Library *LocaleBase; struct Locale *ll; char TZstring[TZSIZE], *p; struct Process *me = (void *) FindTask(NULL); void *old_window = me->pr_WindowPtr; BPTR eh; int z, valid = FALSE; static zone_is_set = FALSE; /* should be okayish with reentrancy */ if (zone_is_set) return; timezone = 5 * 60; /* default */ me->pr_WindowPtr = (void *) -1; /* suppress any "Please insert" popups */ if (SysBase->lib_Version >= ReqVers) { if (GetVar("TZ", TZstring, TZSIZE - 1, /* GVF_GLOBAL_ONLY */ 0) <= 0) TZstring[0] = 0; } else { /* early AmigaDOS, get env var the crude way */ z = 0; if (eh = Open("ENV:TZ", MODE_OLDFILE)) { z = Read(eh, TZstring, TZSIZE - 1); Close(eh); if (z < 0) z = 0; } TZstring[z] = '\0'; } if (TZstring[0]) { z = 3600; for (p = TZstring; *p && !isdigit(*p) && *p != '-'; p++) ; if (*p == '-') z = -3600, p++; if (*p) { timezone = 0; do { while (isdigit(*p)) timezone = timezone * 10 + z * (*p++ - '0'), valid = TRUE; if (*p == ':') p++; } while (isdigit(*p) && (z /= 60) > 0); } while (isspace(*p)) p++; /* probably not needed */ if (valid) zone_is_set = TRUE, daylight = !!*p; /* a DST name part exists */ } if (!valid && (LocaleBase = OpenLibrary("locale.library", 0))) { if (ll = OpenLocale(NULL)) { z = ll->loc_GMTOffset; if (z == -5) { if (eh = Lock("ENV:sys/locale.prefs", ACCESS_READ)) UnLock(eh); else z = 5; /* bug: locale not initialized, default is bogus! */ } else zone_is_set = TRUE; timezone = z * 60; daylight = (z >= 4*60 && z <= 9*60); /* apply in the Americas */ CloseLocale(ll); } CloseLibrary(LocaleBase); } me->pr_WindowPtr = old_window; } struct tm *gmtime(const time_t *when) { static struct tm tbuf; /* this function is intrinsically non-reentrant */ static short smods[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; long days = *when / 86400; long secs = *when % 86400; short yell, yday; tbuf.tm_wday = (days + 4) % 7; /* 1/1/70 is a Thursday */ tbuf.tm_year = 70 + 4 * (days / 1461); yday = days % 1461; while (yday >= (yell = (tbuf.tm_year & 3 ? 365 : 366))) yday -= yell, tbuf.tm_year++; smods[1] = (tbuf.tm_year & 3 ? 28 : 29); tbuf.tm_mon = 0; tbuf.tm_yday = yday; while (yday >= smods[tbuf.tm_mon]) yday -= smods[tbuf.tm_mon++]; tbuf.tm_mday = yday + 1; tbuf.tm_isdst = 0; tbuf.tm_sec = secs % 60; tbuf.tm_min = (secs / 60) % 60; tbuf.tm_hour = secs / 3600; #ifdef AZTEC_C tbuf.tm_hsec = 0; #endif return &tbuf; } struct tm *localtime(const time_t *when) { struct tm *t; time_t localwhen; int dst = FALSE, sundays, lastweekday; tzset(); localwhen = *when - timezone; t = gmtime(&localwhen); /* So far we support daylight savings correction by the USA rule only: */ if (daylight && t->tm_mon >= 3 && t->tm_mon <= 9) { if (t->tm_mon > 3 && t->tm_mon < 9) /* May Jun Jul Aug Sep: yes */ dst = TRUE; else { sundays = (t->tm_mday + 6 - t->tm_wday) / 7; if (t->tm_wday == 0 && t->tm_hour < 2 && sundays) sundays--; /* a Sunday does not count until 2:00am */ if (t->tm_mon == 3 && sundays > 0) /* first sunday in April */ dst = TRUE; else if (t->tm_mon == 9) { lastweekday = (t->tm_wday + 31 - t->tm_mday) % 7; if (sundays < (37 - lastweekday) / 7) dst = TRUE; /* last sunday in October */ } } if (dst) { localwhen += 3600; t = gmtime(&localwhen); /* crude but effective */ t->tm_isdst = 1; } } return t; } #ifdef ZIP time_t time(time_t *tp) { time_t t; struct DateStamp ds; DateStamp(&ds); t = ds.ds_Tick / TICKS_PER_SECOND + ds.ds_Minute * 60 + (ds.ds_Days + 2922) * 86400; t = mktime(gmtime(&t)); /* gmtime leaves ds in the local timezone, mktime converts it to GMT */ if (tp) *tp = t; return t; } #endif /* ZIP */ #endif /* !FUNZIP */ #if defined(CRYPT) || !defined(FUNZIP) /* sendpkt.c * by A. Finkel, P. Lindsay, C. Sheppner * returns Res1 of the reply packet */ /* #include #include #include #include #include #include */ LONG sendpkt(pid,action,args,nargs) struct MsgPort *pid; /* process identifier (handler message port) */ LONG action, /* packet type (desired action) */ *args, /* a pointer to argument list */ nargs; /* number of arguments in list */ { struct MsgPort *replyport, *CreatePort(UBYTE *, long); void DeletePort(struct MsgPort *); struct StandardPacket *packet; LONG count, *pargs, res1; replyport = CreatePort(NULL,0L); if( !replyport ) return(0); packet = (struct StandardPacket *)AllocMem( (long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR); if( !packet ) { DeletePort(replyport); return(0); } packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt); packet->sp_Pkt.dp_Link = &(packet->sp_Msg); packet->sp_Pkt.dp_Port = replyport; packet->sp_Pkt.dp_Type = action; /* copy the args into the packet */ pargs = &(packet->sp_Pkt.dp_Arg1); /* address of 1st argument */ for( count=0; countsp_Pkt.dp_Res1; FreeMem((char *)packet,(long)sizeof(*packet)); DeletePort(replyport); return(res1); } /* sendpkt() */ #endif /* CRYPT || !FUNZIP */ #if defined(CRYPT) || (defined(UNZIP) && !defined(FUNZIP)) /* Agetch() reads one raw keystroke -- uses sendpkt() */ int Agetch(void) { LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs); struct Task *me = FindTask(NULL); struct CommandLineInterface *cli = BADDR(((struct Process *) me)->pr_CLI); BPTR fh = cli->cli_StandardInput; /* this is immune to < redirection */ void *conp = ((struct FileHandle *) BADDR(fh))->fh_Type; char longspace[8]; long *flag = (long *) ((ULONG) &longspace[4] & ~3); /* LONGWORD ALIGNED! */ UBYTE c; *flag = 1; sendpkt(conp, ACTION_SCREEN_MODE, flag, 1); /* assume success */ Read(fh, &c, 1); *flag = 0; sendpkt(conp, ACTION_SCREEN_MODE, flag, 1); if (c == 3) /* ^C in input */ Signal(me, SIGBREAKF_CTRL_C); return c; } #endif /* CRYPT || (UNZIP && !FUNZIP) */