Path: wuarchive!zaphod.mps.ohio-state.edu!usc!cs.utexas.edu!tut.cis.ohio-state.edu!ukma!xanth!cs.odu.edu!Amiga-Request
From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
Newsgroups: comp.sources.amiga
Subject: v90i125: DNet 2.13 - multiple windows/file transfers over a serial line, Part08/08
Message-ID: <11945@xanth.cs.odu.edu>
Date: 27 Mar 90 01:25:41 GMT
Sender: tadguy@cs.odu.edu
Reply-To: dales%teksce.sce.tek.com@RELAY.CS.NET
Lines: 1086
Approved: tadguy@cs.odu.edu (Tad Guy)
X-Mail-Submissions-To: Amiga@cs.odu.edu
X-Post-Discussions-To: comp.sys.amiga

Submitted-by: dales%teksce.sce.tek.com@RELAY.CS.NET
Posting-number: Volume 90, Issue 125
Archive-name: comm/dnet/dnet-2.13/part08

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 8 (of 8)."
# Contents:  amiga/doshand/nfs-handler.c
# Wrapped by tadguy@xanth on Mon Mar 26 20:15:24 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'amiga/doshand/nfs-handler.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'amiga/doshand/nfs-handler.c'\"
else
echo shar: Extracting \"'amiga/doshand/nfs-handler.c'\" \(26186 characters\)
sed "s/^X//" >'amiga/doshand/nfs-handler.c' <<'END_OF_FILE'
X
X/*
X *  NFS-HANDLER.C	V1.11	27-June-89
X *
X *  DNet DOS level NFS handler.
X *
X *  By Matthew Dillon.
X *
X *  This handler converts DOS packets into a form suitable for transmission
X *  over a DNet link to a remote server which will execute the operations.
X */
X
X#include "dos.h"
X#include <exec/alerts.h>
X
X#define BTOC(bp)    ((void *)(((long)bp) << 2))
X#define CTOB(cp)    ((BPTR)(((long)cp) >> 2))
X
X/*
X *  Since this code might be called several times in a row without being
X *  unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
X *  for any global/static assignments that might be changed by running the
X *  code.
X */
X
XPROC	*DosProc;   /*	Our Process				    */
XDEVNODE *DosNode;   /*	Our DOS node.. created by DOS for us	    */
XDEVLIST *DevList;   /*	Device List structure for our volume node   */
X
Xvoid	*SysBase;   /*	EXEC library base			*/
X/*
Xvoid	*DResBase;
X*/
X
XDOSLIB	*DOSBase;   /*	DOS library base for debug process	*/
XMLIST	FHBase;     /*	Open Files				*/
XMLIST	LCBase;     /*	Open Locks				*/
X
Xlong	TotalBytes; /*	total bytes of data in filesystem	*/
X
Xvoid	*CHan;	    /*	DNet channel				*/
XHANDLE	RFRoot;
X
Xchar	TmpBuf[256];
X
X#ifdef DEBUG
Xshort DBDisable = 0;	/*  Debug code				    */
X#endif
X
X
XHANDLE *AllocHandle();
X
X/*
X *  Don't call the entry point main().  This way, if you make a mistake
X *  with the compile options you'll get a link error.
X */
X
Xvoid __saveds noname ARGS((void));
X
Xvoid returnpacket ARGS((PACKET *));
Xint packetsqueued ARGS((void));
XHANDLE *GetHandleForLock ARGS((LOCK *));
Xvoid *GetLockForHandle ARGS((HANDLE *));
XHANDLE *AllocHandle ARGS((char *, RtOpen *));
Xvoid FreeHandle ARGS((HANDLE *));
Xvoid *dosalloc ARGS((ulong));
Xvoid dosfree ARGS((ulong *));
Xchar *bstos ARGS((ubyte *));
Xchar *skipdevice ARGS((char *));
Xint DoNetworkOp ARGS((char, void *, int, void *, int, void *, int));
X
Xvoid __saveds
Xnoname()
X{
X    PACKET  *packet;
X    short   error;
X    MSG     *msg;
X    ubyte   notdone;
X    void    *tmp;
X
X#ifndef LATTICE
X    mygeta4();
X#endif
X
X    /*
X     *	Initialize all global variables.  SysBase MUST be initialized before
X     *	we can make Exec calls.
X     */
X
X    TotalBytes = 0;
X    SysBase = *(void **)4;
X    DOSBase = (void *)OpenLibrary("dos.library",0);
X    /*
X    DResBase= OpenLibrary("dres.library",0);
X    */
X    DosProc = (PROC *)FindTask(NULL);
X    CHan = 0;
X    {
X	WaitPort(&DosProc->pr_MsgPort);         /*  Get Startup Packet  */
X	msg = GetMsg(&DosProc->pr_MsgPort);
X	packet = (PACKET *)msg->mn_Node.ln_Name;
X
X	/*
X	 *  Loading DosNode->dn_Task causes DOS *NOT* to startup a new
X	 *  instance of the device driver for every reference.	E.G. if
X	 *  you were writing a CON device you would want this field to
X	 *  be NULL.
X	 */
X
X	if (DOSBase /*&& DResBase*/) {
X	    DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
X	    DEVLIST *dl = dosalloc(sizeof(DEVLIST));
X
X	    DosNode = BTOC(packet->dp_Arg3);
X	    DosNode->dn_Task = &DosProc->pr_MsgPort;
X
X	    /*
X	     *	Create Volume node and add to the device list.	This will
X	     *	cause the WORKBENCH to recognize us as a disk.	If we don't
X	     *	create a Volume node, Wb will not recognize us.  However,
X	     *	we are a RAM: disk, Volume node or not.
X	     */
X
X	    DevList = dl;
X	    dl->dl_Type = DLT_VOLUME;
X	    dl->dl_Task = &DosProc->pr_MsgPort;
X	    dl->dl_DiskType = ID_DOS_DISK;
X	    dl->dl_Name = (BSTR)DosNode->dn_Name;
X	    dl->dl_Next = di->di_DevInfo;
X	    di->di_DevInfo = (long)CTOB(dl);
X
X	    packet->dp_Res1 = DOS_TRUE;
X	    packet->dp_Res2 = 0;
X	} else {			    /*	couldn't open dos.library   */
X	    packet->dp_Res1 = DOS_FALSE;
X	    returnpacket(packet);
X	    return;			    /*	exit process		    */
X	}
X	returnpacket(packet);
X    }
X
X    /*	Initialize  RAM disk	*/
X#ifdef DEBUG
X    dbinit();
X#endif
X
X    {
X	NewList((LIST *)&FHBase);                   /*  more globals    */
X	NewList((LIST *)&LCBase);
X
X	BZero(&RFRoot, sizeof(RFRoot));
X	DateStamp(&RFRoot.Date);
X	RFRoot.Type = FILE_DIR;
X	RFRoot.Name = "Root";
X    }
X
X    /*
X     *	Here begins the endless loop, waiting for requests over our
X     *	message port and executing them.  Since requests are sent over
X     *	our message port, this precludes being able to call DOS functions
X     *	ourselves (that is why the debugging routines are a separate process)
X     */
X
Xtop:
X    for (notdone = 1; notdone;) {
X	WaitPort(&DosProc->pr_MsgPort);
X	while (msg = GetMsg(&DosProc->pr_MsgPort)) {
X	    packet = (PACKET *)msg->mn_Node.ln_Name;
X	    packet->dp_Res1 = DOS_TRUE;
X	    packet->dp_Res2 = 0;
X	    error = 0;
X
X	    if (!CHan) {            /*  attempt to open server channel      */
X		CHan = DOpen(NULL, PORT_NFS, -80, -80);
X		if (!CHan) {        /*  otherwise giveup!                   */
X		    notdone = 0;
X		    goto fail;
X		}
X	    }
X
X#ifdef DEBUG
X	    dbprintf("ACTION %ld\n", packet->dp_Type);
X#endif
X	    switch(packet->dp_Type) {
X	    case ACTION_DIE:	    /*	attempt to die? 		    */
X		notdone = 0;	    /*	try to die			    */
X		break;
X	    case ACTION_OPENRW:     /*	FileHandle,Lock,Name	    Bool    */
X	    case ACTION_OPENOLD:    /*	FileHandle,Lock,Name	    Bool    */
X	    case ACTION_OPENNEW:    /*	FileHandle,Lock,Name	    Bool    */
X		{
X		    OpOpen	opkt;
X		    RtOpen	rpkt;
X		    short	r;
X		    char	*name = skipdevice(bstos((ubyte *)packet->dp_Arg3));
X		    HANDLE	*handle;
X
X		    opkt.DirHandle = GetHandleForLock((LOCK *)packet->dp_Arg2)->Handle;
X		    opkt.Modes = packet->dp_Type;
X
X		    r = DoNetworkOp('O',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt));
X		    if (r) {
X			error = ERROR_OBJECT_IN_USE;
X		    } else if (rpkt.Handle == -1) {
X			error = ERROR_OBJECT_NOT_FOUND;
X		    } else if (rpkt.Type > 0) {     /* can't open dir */
X			OpClose  opkt;
X
X			opkt.Handle = rpkt.Handle;
X			DoNetworkOp('C',&opkt,sizeof(opkt),NULL,0,NULL,0);
X			error = ERROR_OBJECT_WRONG_TYPE;
X		    } else {
X			if (name[0] == 0)
X			    name = GetHandleForLock((LOCK *)packet->dp_Arg2)->Name;
X			handle = AllocHandle(name, &rpkt);
X			((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long)handle;
X		    }
X		}
X		break;
X	    case ACTION_READ:	    /*	 FHArg1,CPTRBuffer,Length   ActLength  */
X		{
X		    HANDLE  *handle = (HANDLE *)packet->dp_Arg1;
X		    OpRead	opkt;
X		    RtRead	rpkt;
X		    short	err;
X
X		    opkt.Handle = handle->Handle;
X		    opkt.Bytes	    = packet->dp_Arg3;
X
X		    err = DoNetworkOp('R',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
X		    if (err)
X			rpkt.Bytes = -1;
X		    if (rpkt.Bytes > 0 && rpkt.Bytes <= opkt.Bytes)
X			DRead(CHan, (void *)packet->dp_Arg2, rpkt.Bytes);
X		    packet->dp_Res1 = rpkt.Bytes;
X		}
X		break;
X	    case ACTION_WRITE:	    /*	 FHArg1,CPTRBuffer,Length   ActLength  */
X		{
X		    HANDLE  *handle = (HANDLE *)packet->dp_Arg1;
X		    OpWrite	opkt;
X		    RtWrite	rpkt;
X		    short	err;
X
X		    opkt.Handle = handle->Handle;
X		    opkt.Bytes	    = packet->dp_Arg3;
X
X		    err = DoNetworkOp('W',&opkt,sizeof(opkt),(void *)packet->dp_Arg2,packet->dp_Arg3,&rpkt,sizeof(rpkt));
X
X		    if (err)
X			rpkt.Bytes = -1;
X		    packet->dp_Res1 = rpkt.Bytes;
X		}
X		break;
X	    case ACTION_CLOSE:	    /*	 FHArg1 		    Bool:TRUE  */
X		{
X		    HANDLE  *handle = (HANDLE *)packet->dp_Arg1;
X		    OpClose	opkt;
X
X		    if (packet->dp_Arg1 == NULL || handle->Magic != MAGIC) {
X			Alert(AT_Recovery|0, (char *)0x12345555);
X		    } else {
X			opkt.Handle = handle->Handle;
X
X			DoNetworkOp('C',&opkt,sizeof(opkt),NULL,0,NULL,0);
X			FreeHandle(handle);
X		    }
X		}
X		if (!GetHead(&FHBase))
X		    notdone = 0;
X		break;
X	    case ACTION_SEEK:	    /*	 FHArg1,Position,Mode	    OldPosition*/
X		{
X		    HANDLE  *handle = (HANDLE *)packet->dp_Arg1;
X		    OpSeek  opkt;
X		    RtSeek  rpkt;
X		    short   err;
X
X		    opkt.Handle = handle->Handle;
X		    opkt.Offset = packet->dp_Arg2;
X		    opkt.How	= packet->dp_Arg3 + 1;
X
X		    err = DoNetworkOp('S',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
X		    if (err)
X			rpkt.NewOffset = -1;
X		    if (rpkt.NewOffset < 0)
X			error = ERROR_SEEK_ERROR;
X		    else
X			packet->dp_Res1 = rpkt.OldOffset;
X		}
X		break;
X	    case ACTION_EXAMINE_NEXT: /*   Lock,Fib		      Bool	 */
X		{
X		    HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
X		    FIB *fib = BTOC(packet->dp_Arg2);
X		    OpNextDir opkt;
X		    RtNextDir rpkt;
X		    short err;
X
X#ifdef DEBUG
X		    dbprintf("FIB = %08lx\n", fib);
X#endif
X		    if (handle->Type < 0) {
X			error = ERROR_OBJECT_WRONG_TYPE;
X			break;
X		    }
X
X		    opkt.Handle = handle->Handle;
X		    opkt.Index	= fib->fib_DiskKey;
X		    err = DoNetworkOp('N',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
X		    if (err || rpkt.Handle == -1) {
X			error = ERROR_NO_MORE_ENTRIES;
X		    } else {	/* not a real file handle, just info & name */
X			unsigned char fn;
X
X			if (DRead(CHan, &fn, 1) != 1)
X			    TmpBuf[fn = 0] = 0;
X			if (DRead(CHan, TmpBuf, fn) != fn)
X			    TmpBuf[fn = 0] = 0;
X			++fib->fib_DiskKey;	/*  next key */
X			fib->fib_DirEntryType = rpkt.Type;
X			fib->fib_Protection = rpkt.Prot;
X			fib->fib_EntryType = NULL;
X			fib->fib_Size = rpkt.Size;
X			fib->fib_NumBlocks = rpkt.Size >> 9;
X			if (strlen(TmpBuf) >= sizeof(fib->fib_FileName) - 2) {
X			    fib->fib_FileName[0] = 1;
X			    fib->fib_FileName[1] = '?';
X			    fib->fib_FileName[2] = 0;
X			} else {
X			    strcpy(fib->fib_FileName+1, TmpBuf);
X			    fib->fib_FileName[0] = strlen(TmpBuf);
X			}
X			fib->fib_Comment[0] = 0;
X			fib->fib_Comment[1] = 0;
X			fib->fib_Date = rpkt.Date;
X		    }
X		}
X		break;
X	    case ACTION_EXAMINE_OBJECT: /*   Lock,Fib			Bool	   */
X		{
X		    HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
X		    FIB *fib = BTOC(packet->dp_Arg2);
X
X#ifdef DEBUG
X		    dbprintf("FIB = %08lx\n", fib);
X#endif
X		    fib->fib_DiskKey = 0;
X		    fib->fib_DirEntryType = handle->Type;
X		    /*
X		     *	fib->fib_FileName bcpl type string
X		     */
X		    fib->fib_Protection = handle->Prot;
X		    fib->fib_EntryType = NULL;
X		    fib->fib_Size = handle->Size;
X		    fib->fib_NumBlocks = handle->Size >> 9;
X
X		    if (strlen(handle->Name) >= sizeof(fib->fib_FileName) - 2) {
X			fib->fib_FileName[0] = 1;
X			fib->fib_FileName[1] = '?';
X			fib->fib_FileName[2] = 0;
X		    } else {
X			strcpy(fib->fib_FileName+1, handle->Name);
X			fib->fib_FileName[0] = strlen(handle->Name);
X		    }
X		    fib->fib_Comment[0] = 0;
X		    fib->fib_Comment[1] = 0;
X		    fib->fib_Date = handle->Date;
X		}
X		break;
X	    case ACTION_INFO:	    /*	Lock, InfoData	  Bool:TRUE    */
X		tmp = BTOC(packet->dp_Arg2);
X		error = -1;
X		/*  fall through    */
X	    case ACTION_DISK_INFO:  /*	InfoData	  Bool:TRUE    */
X		{
X		    INFODATA *id;
X
X		    /*
X		     *	Note:	id_NumBlocks is never 0, but only to get
X		     *	around a bug I found in my shell (where I divide
X		     *	by id_NumBlocks).  Other programs probably break
X		     *	as well.
X		     */
X
X		    (error) ? (id = tmp) : (id = BTOC(packet->dp_Arg1));
X		    error = 0;
X		    BZero(id, sizeof(*id));
X		    id->id_DiskState = ID_VALIDATED;
X		    id->id_NumBlocks	 = (TotalBytes >> 9) + 1;
X		    id->id_NumBlocksUsed = (TotalBytes >> 9) + 1;
X		    id->id_BytesPerBlock = 512;
X		    id->id_DiskType = ID_DOS_DISK;
X		    id->id_VolumeNode = (long)CTOB(DosNode);
X		    id->id_InUse = (long)GetHead(&LCBase);
X		}
X		break;
X	    case ACTION_PARENT:     /*	 Lock			    ParentLock */
X		{
X		    HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
X		    OpParent	opkt;
X		    RtParent	rpkt;
X		    short	err;
X
X		    opkt.Handle = handle->Handle;
X
X		    err = DoNetworkOp('P',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
X		    if (err)
X			rpkt.Handle = NULL;
X		    if (rpkt.Handle == -1) {
X			error = ERROR_OBJECT_NOT_FOUND;
X		    } else {	/*  create a file handle and return a lock */
X			HANDLE *newhandle;
X			unsigned char fn;
X
X			if (DRead(CHan, &fn, 1) != 1)
X			    TmpBuf[fn = 0] = 0;
X			if (DRead(CHan, TmpBuf, fn) != fn)
X			    TmpBuf[fn = 0] = 0;
X			newhandle = AllocHandle(TmpBuf, &rpkt);
X			packet->dp_Res1 = (long)GetLockForHandle(newhandle);
X		    }
X		}
X		break;
X	    case ACTION_DELETE_OBJECT: /*Lock,Name		    Bool       */
X		{
X		    OpDelete	opkt;
X		    RtDelete	rpkt;
X		    short	err;
X		    char	*name = skipdevice(bstos((ubyte *)packet->dp_Arg2));
X
X		    opkt.DirHandle = GetHandleForLock((LOCK *)packet->dp_Arg1)->Handle;
X
X		    err = DoNetworkOp('D',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt));
X		    if (err || rpkt.Error)
X			error = ERROR_OBJECT_NOT_FOUND;
X		}
X		break;
X	    case ACTION_CREATE_DIR: /*	 Lock,Name		    Lock       */
X		{
X		    OpCreateDir opkt;
X		    RtCreateDir rpkt;
X		    short	err;
X		    char	*name = skipdevice(bstos((ubyte *)packet->dp_Arg2));
X
X		    opkt.DirHandle = GetHandleForLock((LOCK *)packet->dp_Arg1)->Handle;
X
X		    err = DoNetworkOp('M',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt));
X		    if (err)
X			rpkt.Handle = NULL;
X		    if (rpkt.Handle == -1) {
X			error = ERROR_OBJECT_EXISTS;
X		    } else {	/*  create a file handle and return a lock */
X			HANDLE *newhandle = AllocHandle(name, &rpkt);
X
X			packet->dp_Res1 = (long)GetLockForHandle(newhandle);
X		    }
X		}
X		break;
X	    case ACTION_LOCATE_OBJECT:	/*   Lock,Name,Mode		Lock	   */
X		{
X		    OpOpen	opkt;
X		    RtOpen	rpkt;
X		    short	err;
X		    char	*name = skipdevice(bstos((ubyte *)packet->dp_Arg2));
X		    HANDLE	*handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
X
X		    opkt.DirHandle = handle->Handle;
X		    opkt.Modes = 1005;
X
X		    err = DoNetworkOp('O',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt));
X		    if (err) {
X			error = ERROR_OBJECT_IN_USE;
X		    } else if (rpkt.Handle == -1) {
X			error = ERROR_OBJECT_NOT_FOUND;
X		    } else {
X			HANDLE *newhandle;
X			if (name[0] == 0)
X			    name = handle->Name;
X
X			newhandle = AllocHandle(name, &rpkt);
X			packet->dp_Res1 = (long)GetLockForHandle(newhandle);
X		    }
X		}
X		break;
X	    case ACTION_COPY_DIR:   /*	 Lock,			    Lock       */
X		{
X		    OpDup	opkt;
X		    RtDup	rpkt;
X		    short	err;
X		    HANDLE	*oldhandle = GetHandleForLock((LOCK *)packet->dp_Arg1);
X
X		    opkt.Handle = oldhandle->Handle;
X
X		    err = DoNetworkOp('d',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
X		    if (err) {
X			error = ERROR_OBJECT_IN_USE;
X		    } else if (rpkt.Handle == -1) {
X			error = ERROR_OBJECT_NOT_FOUND;
X		    } else {
X			HANDLE *handle = AllocHandle(oldhandle->Name, &rpkt);
X
X			packet->dp_Res1 = (long)GetLockForHandle(handle);
X		    }
X		}
X		break;
X	    case ACTION_FREE_LOCK:  /*	 Lock,			    Bool       */
X		{
X		    HANDLE  *handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
X		    OpClose	opkt;
X
X		    opkt.Handle = handle->Handle;
X
X		    DoNetworkOp('C',&opkt,sizeof(opkt),NULL,0,NULL,0);
X		    FreeHandle(handle);
X		}
X		break;
X	    case ACTION_SET_PROTECT:/*	 -,Lock,Name,Mask	   Bool       */
X		error = ERROR_ACTION_NOT_KNOWN;
X		break;
X	    case ACTION_SET_COMMENT:/*	 -,Lock,Name,Comment	   Bool       */
X		error = ERROR_ACTION_NOT_KNOWN;
X		break;
X	    case ACTION_RENAME_OBJECT:/* SLock,SName,DLock,DName    Bool       */
X		{
X		    OpRename	opkt;
X		    RtRename	rpkt;
X		    short	err;
X		    char	*name1= skipdevice(bstos((ubyte *)packet->dp_Arg2));
X		    char	*name2= skipdevice(bstos((ubyte *)packet->dp_Arg4));
X		    short	len1 = strlen(name1);
X		    short	len2 = strlen(name2);
X		    char	*name = AllocMem(len1+len2+2, MEMF_PUBLIC);
X
X		    opkt.DirHandle1 = GetHandleForLock((LOCK *)packet->dp_Arg1)->Handle;
X		    opkt.DirHandle2 = GetHandleForLock((LOCK *)packet->dp_Arg3)->Handle;
X		    strcpy(name, name1);
X		    strcpy(name+len1+1,name2);
X
X		    err = DoNetworkOp('r',&opkt,sizeof(opkt),name,len1+len2+2,&rpkt,sizeof(rpkt));
X		    FreeMem(name, len1+len2+2);
X		    if (err) {
X			error = ERROR_OBJECT_IN_USE;
X		    } else if (rpkt.Error) {
X			error = ERROR_OBJECT_NOT_FOUND;
X		    }
X		}
X		break;
X	    /*
X	     *	A few other packet types which we do not support
X	     */
X	    case ACTION_INHIBIT:    /*	 Bool			    Bool       */
X		/*  Return success for the hell of it	*/
X		break;
X	    case ACTION_RENAME_DISK:/*	 BSTR:NewName		    Bool       */
X	    case ACTION_MORECACHE:  /*	 #BufsToAdd		    Bool       */
X	    case ACTION_WAIT_CHAR:  /*	 Timeout, ticks 	    Bool       */
X	    case ACTION_FLUSH:	    /*	 writeout bufs, disk motor off	       */
X	    case ACTION_RAWMODE:    /*	 Bool(-1:RAW 0:CON)         OldState   */
X	    default:
Xfail:
X		error = ERROR_ACTION_NOT_KNOWN;
X		break;
X	    }
X	    if (packet) {
X		if (error) {
X		    packet->dp_Res1 = DOS_FALSE;
X		    packet->dp_Res2 = error;
X		}
X		returnpacket(packet);
X	    }
X	}
X    }
X    Delay(50);      /*  I wanna even see the debug message! */
X    Forbid();
X    if (packetsqueued() || GetHead(&FHBase)) {
X	Permit();
X	goto top;		/*  sorry... can't exit     */
X    }
X
X    /*
X     *	Causes a new process to be created on next reference
X     */
X
X    DosNode->dn_Task = FALSE;
X
X    /*
X     *	Remove Volume entry.  Since DOS uses singly linked lists, we
X     *	must (ugg) search it manually to find the link before our
X     *	Volume entry.
X     */
X
X    {
X	DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
X	DEVLIST *dl;
X	void *dlp;
X
X	dlp = &di->di_DevInfo;
X	for (dl = BTOC(di->di_DevInfo); dl && dl != DevList; dl = BTOC(dl->dl_Next))
X	    dlp = &dl->dl_Next;
X	if (dl == DevList) {
X	    *(BPTR *)dlp = dl->dl_Next;
X	    dosfree((ulong *)dl);
X	} else {
X	    ;
X	}
X    }
X
X    /*
X     *	closedown, fall of the end of the world
X     *
X     *	(which is how you kill yourself if a PROCESS.  A TASK would have
X     *	had to RemTask(NULL) itself).
X     */
X
X    if (CHan)
X	DClose(CHan);
X    CHan = 0;
X#ifdef DEBUG
X    dbuninit();
X#endif
X    CloseLibrary((LIB *)DOSBase);
X    /*
X    CloseLibrary(DResBase);
X    */
X}
X
X
X/*
X *  PACKET ROUTINES.	Dos Packets are in a rather strange format as you
X *  can see by this and how the PACKET structure is extracted in the
X *  GetMsg() of the main routine.
X */
X
Xvoid
Xreturnpacket(packet)
XPACKET *packet;
X{
X    struct Message *mess;
X    struct MsgPort *replyport;
X
X    replyport		     = packet->dp_Port;
X    mess		     = packet->dp_Link;
X    packet->dp_Port	     = &DosProc->pr_MsgPort;
X    mess->mn_Node.ln_Name    = (char *)packet;
X    mess->mn_Node.ln_Succ    = NULL;
X    mess->mn_Node.ln_Pred    = NULL;
X    PutMsg(replyport, mess);
X}
X
X/*
X *  Are there any packets queued to our device?
X */
X
Xint
Xpacketsqueued()
X{
X    return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
X	    (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
X}
X
X/*
X *  Handle structure, locks, and manipulation.
X */
X
XHANDLE *
XGetHandleForLock(block)
XLOCK *block;
X{
X    LOCK *lock = BTOC(block);
X    HANDLE *handle;
X
X#ifdef DEBUG
X    dbprintf("GetHandleForLock: %08lx ", lock);
X#endif
X    if (lock) {
X	handle = (HANDLE *)lock->fl_Key;
X#ifdef DEBUG
X	dbprintf("Handle=%08lx (h=$%08lx)\n", handle, handle->Handle);
X#endif
X	if (handle->Magic == MAGIC)
X	    return(handle);
X	Alert(AT_Recovery|1, (char *)handle);
X    }
X#ifdef DEBUG
X    dbprintf("\n");
X#endif
X    /*Alert(AT_Recovery|2, (char *)-2);*/
X    return(&RFRoot);
X}
X
Xvoid *
XGetLockForHandle(handle)
XHANDLE *handle;
X{
X    LOCK *lock = handle->Lock;
X    LOCKLINK *ln;
X
X#ifdef DEBUG
X    dbprintf("GetLockForHandle: %08lx ", handle);
X#endif
X    if (!lock) {
X	lock = dosalloc(sizeof(LOCK));
X#ifdef DEBUG
X	dbprintf("(allocate) %08lx\n", lock);
X#endif
X	ln = AllocMem(sizeof(LOCKLINK), MEMF_PUBLIC|MEMF_CLEAR);
X	AddHead((LIST *)&LCBase,(NODE *)ln);
X	ln->Lock = lock;
X	lock->fl_Link = (long)ln;
X	lock->fl_Key = (long)handle;
X	lock->fl_Access = ACCESS_READ;
X	lock->fl_Task= &DosProc->pr_MsgPort;
X	lock->fl_Volume = (BPTR)CTOB(DosNode);
X
X	handle->Lock = lock;
X    }
X#ifdef DEBUG
X    dbprintf("Lock=%08lx\n", lock);
X#endif
X    return((void *)CTOB(lock));
X}
X
XHANDLE *
XAllocHandle(name, rpkt)
Xchar *name;
XRtOpen *rpkt;
X{
X    HANDLE *handle;
X    char *ptr;
X
X    for (ptr = name + strlen(name) - 1; ptr >= name && *ptr != '/'; --ptr);
X    ++ptr;
X
X    handle = AllocMem(sizeof(HANDLE), MEMF_PUBLIC|MEMF_CLEAR);
X    handle->Magic = MAGIC;
X    handle->Handle= rpkt->Handle;
X    handle->Type = rpkt->Type;
X    handle->Prot = rpkt->Prot;
X    handle->Size = rpkt->Size;
X    handle->Name = AllocMem(strlen(ptr)+1, MEMF_PUBLIC);
X    handle->Date = rpkt->Date;
X    strcpy(handle->Name, ptr);
X    AddHead((LIST *)&FHBase, (NODE *)handle);
X
X#ifdef DEBUG
X    dbprintf("AllocHandle: %08lx '%s' h=$%08lx\n", handle, ptr, handle->Handle);
X#endif
X    return(handle);
X}
X
Xvoid
XFreeHandle(handle)
XHANDLE *handle;
X{
X#ifdef DEBUG
X    dbprintf("FreeHandle: %08lx %08lx\n", handle, handle->Lock);
X#endif
X    if (handle->Lock) {
X	LOCK *lock = handle->Lock;
X	Remove((NODE *)lock->fl_Link);
X	FreeMem((void *)lock->fl_Link, sizeof(LOCKLINK));
X	dosfree((ulong *)lock);
X    }
X    Remove((NODE *)handle);
X    handle->Magic = 0;
X    FreeMem(handle->Name, strlen(handle->Name)+1);
X    FreeMem(handle, sizeof(HANDLE));
X}
X
X/*
X *  DOS MEMORY ROUTINES
X *
X *  DOS makes certain assumptions about LOCKS.	A lock must minimally be
X *  a FileLock structure, with additional private information after the
X *  FileLock structure.  The longword before the beginning of the structure
X *  must contain the length of structure + 4.
X *
X *  NOTE!!!!! The workbench does not follow the rules and assumes it can
X *  copy lock structures.  This means that if you want to be workbench
X *  compatible, your lock structures must be EXACTLY sizeof(struct FileLock).
X */
X
Xvoid *
Xdosalloc(bytes)
Xulong bytes;
X{
X    ulong *ptr;
X
X    bytes += 4;
X    ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
X    *ptr = bytes;
X    return(ptr+1);
X}
X
Xvoid
Xdosfree(ptr)
Xulong *ptr;
X{
X    --ptr;
X    FreeMem(ptr, *ptr);
X}
X
X/*
X *  Convert a BSTR into a normal string.. copying the string into buf.
X *  I use normal strings for internal storage, and convert back and forth
X *  when required.
X */
X
Xchar *
Xbstos(bstr)
Xubyte *bstr;
X{
X    static char buf[512];
X    static char *ptr = buf;
X
X    if (ptr == buf)     /*  switch which buffer to use */
X	ptr = buf + 256;
X    else
X	ptr = buf;
X
X    bstr = BTOC(bstr);
X    BMov(bstr+1,ptr,*bstr);
X    ptr[*bstr] = 0;
X    return(ptr);
X}
X
Xchar *
Xskipdevice(str)
Xchar *str;
X{
X    char *base = str;
X
X    while (*str && *str != ':')
X	++str;
X    if (*str == 0)
X	str = base;
X    else
X	++str;
X    return(str);
X}
X
X/*
X *  data = DoNetworkOp(&cmd, &len, data)
X */
X
Xint
XDoNetworkOp(cmd, s, _slen, d, dlen, r, rlen)
Xchar cmd;
Xint _slen;
Xvoid *s;
Xvoid *d;
Xvoid *r;
X{
X    ubyte slen = _slen;
X    if (CHan) {
X	if (DWrite(CHan, &cmd, 1) < 0)
X	    goto fail;
X	if (DWrite(CHan, &slen, 1) < 0)
X	    goto fail;
X	if (DWrite(CHan, &dlen, 4) < 0)
X	    goto fail;
X	if (DWrite(CHan, s, slen) < 0)
X	    goto fail;
X
X	if (dlen) {
X	    if (DWrite(CHan, d, dlen) < 0)
X		goto fail;
X	}
X	if (r) {
X	    if (DRead(CHan, r, rlen) != rlen)
X		goto fail;
X	}
X	return(0);
X    }
Xfail:
X    if (CHan) {
X	DClose(CHan);
X	CHan = 0;
X    }
X    return(1);
X}
X
X#ifndef LATTICE
X
X#asm
X
X_mygeta4:
X	far	data
X	lea	__H1_org+32766,a4
X	rts
X
X	public	__H0_org
X
X	dseg
X
X	public	__H1_org
X
X	cseg
X#endasm
X
X#endif
X
X
X#ifdef DEBUG	    /*	note, doesn't work w/ Lattice   */
X
X/*
X *			    DEBUG CODE
X */
X
X
X		    /*	DEBUGGING			*/
XPORT *Dbport;	    /*	owned by the debug process	*/
XPORT *Dback;	    /*	owned by the DOS device driver	*/
XMSG DummyMsg;	    /*	Dummy message that debug proc can use	*/
X
X/*
X *  DEBUGGING CODE.	You cannot make DOS library calls that access other
X *  devices from within a DOS device driver because they use the same
X *  message port as the driver.  If you need to make such calls you must
X *  create a port and construct the DOS messages yourself.  I do not
X *  do this.  To get debugging info out another PROCESS is created to which
X *  debugging messages can be sent.
X *
X *  You want the priority of the debug process to be larger than the
X *  priority of your DOS handler.  This is so if your DOS handler crashes
X *  you have a better idea of where it died from the debugging messages
X *  (remember that the two processes are asyncronous from each other).
X */
X
Xextern void debugproc();
X
Xdbinit()
X{
X    TASK *task = FindTask(NULL);
X
X    Dback = CreatePort(NULL,NULL);
X    CreateProc("DEV_DB", task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096);
X    WaitPort(Dback);                                /* handshake startup    */
X    GetMsg(Dback);                                  /* remove dummy msg     */
X    dbprintf("Debugger running V1.10, 2 November 1987\n");
X    dbprintf("Works with WORKBENCH!\n");
X}
X
Xdbuninit()
X{
X    MSG killmsg;
X
X    if (Dbport) {
X	killmsg.mn_Length = 0;	    /*	0 means die	    */
X	PutMsg(Dbport,&killmsg);
X	WaitPort(Dback);            /*  He's dead jim!      */
X	GetMsg(Dback);
X	DeletePort(Dback);
X
X	/*
X	 *  Since the debug process is running at a greater priority, I
X	 *  am pretty sure that it is guarenteed to be completely removed
X	 *  before this task gets control again.  Still, it doesn't hurt...
X	 */
X
X	Delay(50);                  /*  ensure he's dead    */
X    }
X}
X
Xdbprintf(a,b,c,d,e,f,g,h,i,j)
X{
X    char buf[256];
X    MSG *msg;
X
X    if (Dbport && !DBDisable) {
X	sprintf(buf,a,b,c,d,e,f,g,h,i,j);
X	msg = AllocMem(sizeof(MSG)+strlen(buf)+1, MEMF_PUBLIC|MEMF_CLEAR);
X	msg->mn_Length = strlen(buf)+1;     /*  Length NEVER 0  */
X	strcpy(msg+1,buf);
X	PutMsg(Dbport,msg);
X    }
X}
X
X/*
X *  BTW, the DOS library used by debugmain() was actually openned by
X *  the device driver.	Note: DummyMsg cannot be on debugmain()'s stack
X *  since debugmain() goes away on the final handshake.
X */
X
Xvoid
Xdebugmain()
X{
X    MSG *msg;
X    short len;
X    void *fh;
X
X    mygeta4();
X    Dbport = CreatePort(NULL,NULL);
X    fh = Open("con:0/0/640/100/debugwindow", 1006);
X    PutMsg(Dback, &DummyMsg);
X    for (;;) {
X	WaitPort(Dbport);
X	msg = GetMsg(Dbport);
X	len = msg->mn_Length;
X	if (len == 0)
X	    break;
X	--len;			      /*  Fix length up   */
X	Write(fh, msg+1, len);
X	FreeMem(msg,sizeof(MSG)+len+1);
X    }
X    Close(fh);
X    DeletePort(Dbport);
X    PutMsg(Dback,&DummyMsg);          /*  Kill handshake  */
X}
X
X/*
X *  The assembly tag for the DOS process:  CNOP causes alignment problems
X *  with the Aztec assembler for some reason.  I assume then, that the
X *  alignment is unknown.  Since the BCPL conversion basically zero's the
X *  lower two bits of the address the actual code may start anywhere around
X *  the label....  Sigh....  (see CreatProc() above).
X */
X
X#asm
X	public	_debugproc
X	public	_debugmain
X
X	cseg
X	nop
X	nop
X	nop
X_debugproc:
X	nop
X	nop
X	movem.l D2-D7/A2-A6,-(sp)
X	jsr	_debugmain
X	movem.l (sp)+,D2-D7/A2-A6
X	rts
X#endasm
X
X
X#endif
X
X
END_OF_FILE
if test 26186 -ne `wc -c <'amiga/doshand/nfs-handler.c'`; then
    echo shar: \"'amiga/doshand/nfs-handler.c'\" unpacked with wrong size!
fi
# end of 'amiga/doshand/nfs-handler.c'
fi
echo shar: End of archive 8 \(of 8\).
cp /dev/null ark8isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 8 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
Mail comments to the moderator at <amiga-request@cs.odu.edu>.
Post requests for sources, and general discussion to comp.sys.amiga.
