/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* |_o_o|\\ Copyright (c) 1986 The Software Distillery. All Rights Reserved */ /* |. o.| || This program may not be distributed without the permission of */ /* | . | || the authors. */ /* | o | || Dave Baker Ed Burnette Stan Chow Jay Denebeim */ /* | . |// Gordon Keener Jack Rouse John Toebes Doug Walker */ /* ====== BBS:(919)-471-6436 VOICE:(919)-469-4210 */ /* */ /* Contributed to Columbia University for inclusion in C-Kermit. */ /* Permission is granted to any individual or institution to use this software as long as it is not sold for profit. This copyright notice must be retained. This software may not be included in commercial products without written permission of Columbia University. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* C K I U T L -- July 17, 1986 * Utility functions for C-Kermit on the Amiga */ #ifndef _lint static char *ckuv = "Amiga utility functions, $Id: ckiutl.c,v 1.10 1999/09/12 00:50:38 swalton Exp swalton $"; #endif /* Author: Jack Rouse, The Software Distillery The file status routines assume all file protection modes are real, instead of just delete protection on files and write protection on disks. * $Log: ckiutl.c,v $ * Revision 1.10 1999/09/12 00:50:38 swalton * Changed some quotes on include files to angle brackets, since they * are really system files. Also deleted a few trailing spaces and tabs. * * Revision 1.9 1993/08/03 08:37:10 swalton * Changes from Olaf Barthel: Use standard include files and add handling * for the NIL: handler * * Revision 1.8 92/10/30 16:18:58 swalton * Added code to call the V37 routine System() rather than the old Execute() * routine in the system() utility. It is conditional on the extern int * v37 being TRUE. This value is set in ckitio.c. * * Revision 1.7 92/01/15 17:15:22 swalton * Use Id rather than Header in the RCS ID string. * * Revision 1.6 91/07/18 16:05:28 swalton * pipeopen() fixed---it was inadvertently broken somewhere. A system() * call was written to replace the no-longer-working Manx one. Both * pipeopen() and system() will use the new AmigaOS System() call if * the switch V37 was defined to be non-zero when Kermit was compiled. * * Revision 1.5 91/05/29 09:09:21 swalton * 1. Changed function definitions to prototype style. Required adding * a few forward declarations. * 2. Removed includes of stdio.h, stdlib.h, and string.h, as they are * now pulled in by ckcdeb.h, provided we compile with -DCK_ANSILIBS. * * Revision 1.4 90/11/19 21:47:38 swalton * Modifications for compiling with SAS/C Version 5.10, courtesy of * Larry Rosenman (ler@lerami.lonestar.org, ler on BIX) * * Revision 1.3 90/11/07 14:42:33 swalton * Version 1.3--released to world as first beta test version simultaneously * with release of edit 5A(160). * * Revision 1.2 90/08/10 10:05:01 swalton * A few changes for edit 150 of C Kermit. Also deleted the include of * ckipro.h, as it is confusing and somewhat unnecessary right now. * * Revision 1.1 90/07/12 22:31:24 swalton * Minor changes were made to ckiutl.c, mainly to maintain Manx Aztec C * compatibility. * * Revision 1.0 90/04/30 11:54:40 swalton * Initial revision * */ #include "ckcasc.h" /* ASCII symbols */ #include "ckcdeb.h" /* Debug formats, typedefs, etc. */ #include "ckcker.h" /* Symbol definitions for Kermit */ #undef ULONG #undef UWORD #undef USHORT #include #include #include #include #include #define fh_Interact fh_Port #define fh_Process fh_Type #include #include #include #include #include #if __SASC #include #include #endif #ifdef AZTEC_C /* translate Unix file handle (0, 1, or 2) to AmigaDOS file handle */ #define DOSFH(n) (_devtab[n].fd) /* translate Unix file handle (0, 1, or 2) to Aztec file handle */ #define FILENO(n) (n) #endif #ifdef __SASC #define DOSFH(n) (chkufb(n)->ufbfh) #define FILENO(n) (n) #endif /* Amiga Kermit externals (defined in ckitio.c) */ extern struct Process *CurProc; extern struct CommandLineInterface *CurCLI; /* * CreatePacket -- allocate and set up a AmigaDOS packet */ struct DosPacket * CreatePacket(void) { register struct StandardPacket *sp; sp = (struct StandardPacket *) AllocMem((LONG)sizeof(struct StandardPacket), (LONG)MEMF_PUBLIC|MEMF_CLEAR); if (sp == NULL) return(NULL); sp->sp_Pkt.dp_Link = &sp->sp_Msg; sp->sp_Msg.mn_Node.ln_Type = NT_MESSAGE; sp->sp_Msg.mn_Node.ln_Name = (char *)&sp->sp_Pkt; sp->sp_Msg.mn_Length = sizeof(struct DosPacket); return(&sp->sp_Pkt); } /* * DeletePacket -- deallocate packet from CreatePacket() */ void DeletePacket(struct DosPacket *pkt) { FreeMem(pkt->dp_Link, (LONG)sizeof(struct StandardPacket)); } /* * zsyscmd(cmd) -- execute a command. * Identical to system except it makes sure that all priveleges are off, * so cmd is executed as a system process. */ int system(const char *cmd); int zsyscmd(char *cmd) { return(system(cmd)); } /* * readstat -- determine file's read status * returns -3 if file read protected * returns -2 if file is a directory * returns -1 if file doesn't exist * returns file size otherwise */ long readstat(char *name) { BPTR lock; struct FileInfoBlock *fib; long size; /* locate the file */ if ((lock = Lock(name, (LONG)ACCESS_READ)) == 0) return(-1); /* allocate a file info block */ if ((fib = (struct FileInfoBlock *)malloc(sizeof(*fib))) == NULL) { size = -1; goto quit; } /* make sure it's not a directory */ if (!Examine(lock, fib) || fib->fib_DirEntryType >= 0) { size = -2; goto quit; } /* make sure it's readable */ if (fib->fib_Protection & FIBF_READ) { size = -3; goto quit; } size = fib->fib_Size; quit: if (fib) free(fib); UnLock(lock); return(size); } /* * writestat -- determines file's write status * returns 0 if file should be writable, -1 otherwise * * The following logic is used to determine if a file is writable: * 1. If the file exists, it must not be write or delete protected. * (Delete protection subsumes write protection for overwriting.) * 2. The parent directory must not be write protected ??? * 3. The volume that the parent directory resides on must be * validated and not write protected. */ int writestat(char *name) { register char *p; char *lastslash; char path[100]; BPTR lock; struct FileInfoBlock *fib; struct InfoData *id = NULL; int rc = -1; /* allocate a FileInfoBlock */ fib = (struct FileInfoBlock *)malloc(sizeof(*fib)); if (fib == NULL) goto quit; /* see if the file exists */ if ((lock = Lock(name, (LONG)ACCESS_READ)) != 0) { /* make sure it's not a directory or write protected */ if (!Examine(lock, fib) || fib->fib_DirEntryType >= 0 || (fib->fib_Protection & (FIBF_WRITE|FIBF_DELETE)) ) goto quit; UnLock(lock); } else if (IoErr() == ERROR_ACTION_NOT_KNOWN || stricmp(name, "NIL:") == 0) { rc = 0; goto quit; } /* strip path from name */ lastslash = NULL; for (p = path; *p = *name; ++p, ++name) if (*p == '/' || *p == ':') lastslash = p; /* make sure the path exists */ if (lastslash) { lastslash[1] = 0; lock = Lock(path, (LONG)ACCESS_READ); } else lock = (CurProc->pr_CurrentDir) ? DupLock(CurProc->pr_CurrentDir) : 0; /* make sure it is a directory that is not write protected */ if (lock == 0 || !Examine(lock, fib) || fib->fib_DirEntryType <= 0 || (fib->fib_Protection & FIBF_WRITE) ) goto quit; /* get device info */ if ((id = (struct InfoData *)malloc(sizeof(*id))) == NULL) goto quit; /* make sure the disk is writeable */ if (Info(lock, id) && id->id_DiskState == ID_VALIDATED) rc = 0; /* clean up */ quit: if (id) free(id); if (fib) free(fib); if (lock) UnLock(lock); return(rc); } #include static struct TagItem MyTags[] = { { SYS_Output, 0L}, { TAG_END, 0L} }; extern short v37; /* * pipeopen -- execute command to read output like a file */ #define PIPEHOLDER "RAM:Pipe-Holder" FILE * pipeopen(char *command) { BPTR fh; /* create holder file */ fh = Open(PIPEHOLDER, (LONG)MODE_NEWFILE); if (fh == 0) return(0); if (v37) { /* execute the command */ MyTags[0].ti_Data = fh; if (System(command, MyTags) != 0) return NULL; } else Execute(command, 0, fh); /* close the holder file */ Close(fh); /* reopen it for input */ return(fopen(PIPEHOLDER, "r")); } /* * pipeclose -- clean up after pipe open */ void pipeclose(FILE *f) { fclose(f); DeleteFile(PIPEHOLDER); } /* * existobj -- return true if file system object exists */ int existobj(char *name) { BPTR lock; if (*name == 0) return(CurProc->pr_CurrentDir != 0); if ((lock = Lock(name, (LONG)ACCESS_READ)) == 0) return(0); UnLock(lock); return(1); } /* opendir handle structure */ struct DirHandle { struct FileInfoBlock fib; BPTR lock; }; /* * attempt to open a directory, fill in a handle structure */ struct DirHandle * opendir(char *name) { BPTR lock; struct DirHandle *dh; /* get lock on name ("" is current dir) */ lock = (*name != 0) ? Lock(name, (LONG)ACCESS_READ) : (CurProc->pr_CurrentDir) ? DupLock(CurProc->pr_CurrentDir) : 0; if (lock == 0) return(NULL); dh = (struct DirHandle *)malloc(sizeof(*dh)); if (dh == NULL) { UnLock(lock); return(NULL); } if (!Examine(lock, &dh->fib) || dh->fib.fib_DirEntryType <= 0) { UnLock(lock); free(dh); return(NULL); } /* pass it into the caller's care */ dh->lock = lock; return(dh); } /* * return name for next entry in dir */ char * readdir(struct DirHandle *dh) { return(ExNext(dh->lock, &dh->fib) ? dh->fib.fib_FileName : NULL); } /* * finish accessing a directory */ void closedir(struct DirHandle *dh) { UnLock(dh->lock); free(dh); } #ifdef __SASC /*** Based on sendpkt.c from AmigaMail Volume 1, Page II-17ff. ***/ LONG dos_packet(struct MsgPort *pid,LONG action, LONG a1, LONG a2, LONG a3, LONG a4, LONG a5, LONG a6, LONG a7) { struct MsgPort *replyport; struct StandardPacket *packet; LONG res1; replyport=(struct MsgPort *)CreatePort(NULL,0); if (!replyport) return(NULL); packet=(struct StandardPacket *) AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR); if (!packet) { DeletePort(replyport); return(NULL); } 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; packet->sp_Pkt.dp_Arg1 = a1; packet->sp_Pkt.dp_Arg2 = a2; packet->sp_Pkt.dp_Arg3 = a3; packet->sp_Pkt.dp_Arg4 = a4; packet->sp_Pkt.dp_Arg5 = a5; packet->sp_Pkt.dp_Arg6 = a6; packet->sp_Pkt.dp_Arg7 = a7; PutMsg(pid,(struct Message *)packet); WaitPort(replyport); GetMsg(replyport); res1 = packet->sp_Pkt.dp_Res1; FreeMem(packet,(long)sizeof(struct StandardPacket)); DeletePort(replyport); return(res1); } /* Return 1 if `y' is a leap year, 0 otherwise. */ static int leap (int y) { y += 1900; if (y % 400 == 0) return (1); if (y % 100 == 0) return (0); return (y % 4 == 0); } /* Return the number of days between Jan 1, 1970 and the given * broken-down time. */ static int ndays (struct tm *p) { register n = p->tm_mday; register m, y; register char *md = "\37\34\37\36\37\36\37\37\36\37\36\37"; for (y = 70; y < p->tm_year; ++y) { n += 365; if (leap (y)) ++n; } for (m = 0; m < p->tm_mon; ++m) n += md[m] + (m == 1 && leap (y)); return (n); } /* Convert a broken-down time (such as returned by localtime()) * back into a `time_t'. */ time_t mktime(struct tm *tp) { register int m1, m2; time_t t; struct tm otm; t = (ndays (tp) - 1) * 86400L + tp->tm_hour * 3600L + tp->tm_min * 60 + tp->tm_sec; /* * Now the hard part -- correct for the time zone: */ otm = *tp; tp = localtime (&t); m1 = tp->tm_hour * 60 + tp->tm_min; m2 = otm.tm_hour * 60 + otm.tm_min; t -= ((m1 - m2 + 720 + 1440) % 1440 - 720) * 60L; return (t); } #endif int system(const char *command) { debug(F110, "system called with command", command, 0L); if (v37) { MyTags[0].ti_Data = DOSFH(1); return(System((UBYTE *) command, MyTags)); } else { Execute((UBYTE *) command, 0, DOSFH(1)); return 0; } }