[comp.sys.amiga] SAMPLE DOS DEVICE DRIVER, source and binary

dillon@CORY.BERKELEY.EDU (Matt Dillon) (10/21/87)

	O.K. folks, here it is.  Even with Andy's help I was unable to
get Info() (as in disk info) to work with it... It might have something to
do with my device node.  Everything else works, however.

	By the way, this is definately a *guru* posting.... don't even bother
if you don't know what a BSTR is.  This is NOT a utility, but an example for
those programmers interested in writing DOS device drivers.

	As usual, any and all Feedback will be appreciated.  I plan to do
another one in the future which exploits the packet types not implemented
in this one (some just don't apply to a simple ram disk).  I plan to update
this one as soon as I can figure out (or somebody can describe to me) how
to make the system recognize the thing in INFO and Info()... sigh.

	The binary is included in case some people have problems compiling
and want to compare their conglomeration with one that works.

					-Matt


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Makefile
#	bset.asm
#	device.c
#	device.uue
#	dos.h
#	flush.c
#	mountlist
# This archive created: Wed Oct 21 00:17:21 1987
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Makefile'" '(237 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'

CFLAGS= +BCDL +Ivd0:include/symbols.m
OBJS= device.o bset.o

.c.o:
    cc $(CFLAGS) $*.c

all: $(OBJS)
    ln +Q $(OBJS) -lcl32 -O ram:device

flush:
    cc +L +Ivd0:include/symbols.m flush.c -o ram:flush.o
    ln +Q ram:flush.o -lc32

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'bset.asm'" '(1076 characters)'
if test -f 'bset.asm'
then
	echo shar: "will not over-write existing file 'bset.asm'"
else
cat << \!Funky!Stuff! > 'bset.asm'

;BSET.ASM
;BZERO.ASM
;
;   Uses longword operations if data is aligned on a longword boundry
;   and the size is a mulitple of 4.  Otherwise, uses byte operations.

	xdef  _bset
	xdef  _bzero

_bzero
	clr.l	D1
	bra	begin
_bset
	move.b	15(A7),D1	;12(A7)-> msb . . lsb	(D1 = data)
begin
	move.l	4(A7),A0	;A0 = address
	move.l	8(A7),D0	;D0 = byte count
	andi.b	#3,11(A7)	;byte count on long word boundry?
	bne	drop
	andi.b	#3,7(A7)	;address on longword boundry?
	bne	drop
	bra	lwb
loop	move.b	D1,(A0)+	;BYTE SET LOOP
drop	dbf.w	D0,loop 	;remember, only effects lower word
	sub.l	#$10000,D0	;for buffers >65535
	bpl	loop		;branch to loop because D0.W now is FFFF
	rts

lwb	lsr.l	#2,D0		;byte count / 4 (longword chunks)
	tst.l	D1		;BZERO
	beq	dropl
	move.b	D1,14(A7)	;15(A7) already contains the byte
	move.w	14(A7),D1	;D1 0..15 set
	swap	D1
	move.w	14(A7),D1	;D1 16..31 set
	bra	dropl

loopl	move.l	D1,(A0)+	;BYTE SET LOOP
dropl	dbf.w	D0,loopl	;remember, only effects lower word
	sub.l	#$10000,D0	;for buffers >65535
	bpl	loopl		;branch to loop because D0.W now is FFFF
	rts



!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'device.c'" '(26693 characters)'
if test -f 'device.c'
then
	echo shar: "will not over-write existing file 'device.c'"
else
cat << \!Funky!Stuff! > 'device.c'

/*
 *  DOSDEVICE.C
 *
 *  EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C   PUBLIC DOMAIN.
 *
 *  By Matthew Dillon.
 *
 *  Debugging routines are disabled by simply attempting to access the
 *  file "debugoff"
 */

#include "dos.h"

/*
 *  Since this code might be called as a processes multiple times, or
 *  might exit and be recalled later by DOS, you CANNOT ASSUME GLOBALS
 *  HAVE BEEN ZERO'D!!!.    This also goes for static assignments that
 *  running the code might change.
 */

PROC	*DosProc;
DEVNODE *DosNode;

long	SysBase;
long	DOSBase;
RAMFILE RFRoot;     /*	Directory/File structure    (root node) */
LIST	FHBase;     /*	Open Files				*/
LIST	LCBase;     /*	Open Locks				*/

long	TotalBytes;


		    /*	DEBUGGING			*/
PORT *Dbport;	    /*	owned by the debug process	*/
PORT *Dback;	    /*	owned by the DOS device driver	*/
short DBDisable;
MSG DummyMsg;

void
noname()
{
    register PACKET *packet;
    register short   error;
    MSG     *msg;
    ubyte   notdone;
    ubyte   buf[256];

    /*
     *	Initialize all global variables.  SysBase MUST be initialized before
     *	we can make Exec calls.  AbsExecBase is a library symbol
     *	referencing absolute memory location 4.  The DOS library is openned
     *	for the debug process.
     */

    DBDisable = 0;
    Dbport = Dback = NULL;
    TotalBytes = 0;
    SysBase = AbsExecBase;
    DOSBase = OpenLibrary("dos.library",0);
    DosProc = FindTask(NULL);
    {
	WaitPort(&DosProc->pr_MsgPort); 	/*  Startup Packet  */
	msg = GetMsg(&DosProc->pr_MsgPort);
	packet = (PACKET *)msg->mn_Node.ln_Name;

	/*
	 *  Loading DosNode->dn_Task causes DOS *NOT* to startup a new
	 *  instance of the device driver for every reference.	E.G. if
	 *  you were writing a CON device you would want this field to
	 *  be NULL.
	 */

	if (DOSBase) {
	    DosNode = BTOC(packet->dp_Arg3);
	    DosNode->dn_Task = &DosProc->pr_MsgPort;
	    packet->dp_Res1 = DOS_TRUE;
	    packet->dp_Res2 = 0;
	} else {
	    packet->dp_Res1 = DOS_FALSE;
	    returnpacket(packet);
	    return;
	}
	returnpacket(packet);
    }

    /*	DEBUGGING   */

    dbinit();	    /* this can be removed  */

    /*	Initialize  RAM disk	*/

    {
	ubyte *ptr = BTOC(DosNode->dn_Name);
	short len = *ptr;

	NewList(&FHBase);
	NewList(&LCBase);
	bzero(&RFRoot,sizeof(RFRoot));
	RFRoot.type = FILE_DIR;
	NewList(&RFRoot.list);
	RFRoot.name = AllocMem(len+1, MEMF_PUBLIC);
	bmov(ptr+1,RFRoot.name,len);
	RFRoot.name[len] = 0;
	dbprintf("ROOT NAME: %ld '%s'\n", len, RFRoot.name);
    }

top:
    for (notdone = 1; notdone;) {
	WaitPort(&DosProc->pr_MsgPort);
	stats();
	while (msg = GetMsg(&DosProc->pr_MsgPort)) {
	    register ubyte *ptr;
	    packet = (PACKET *)msg->mn_Node.ln_Name;
	    packet->dp_Res1 = DOS_TRUE;
	    packet->dp_Res2 = 0;
	    error = 0;
	    dbprintf("Packet: %3ld %08lx %08lx %08lx %08lx\n",
		packet->dp_Type, packet->dp_Arg1, packet->dp_Arg2, packet->dp_Arg3, packet->dp_Arg4
	    );

	    switch(packet->dp_Type) {
	    case ACTION_DIE:	    /*	attempt to die? 		    */
		notdone = 0;
		break;
	    case ACTION_OPENRW:     /*	FileHandle,Lock,Name	    Bool    */
	    case ACTION_OPENOLD:    /*	FileHandle,Lock,Name	    Bool    */
	    case ACTION_OPENNEW:    /*	FileHandle,Lock,Name	    Bool    */
		{
		    register RAMFILE *ramfile;
		    RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
		    char    *ptr;

		    btos(packet->dp_Arg3,buf);
		    if (strcmp(buf,"debugoff") == 0)
			DBDisable = 1;
		    if (strcmp(buf,"debugon") == 0)
			DBDisable = 0;
		    if (ramfile = searchpath(&parentdir,buf,&ptr)) {
			dbprintf("Found: parentdir %08lx  tail '%s'\n", parentdir, ptr);
			if (ramfile->type == FILE_DIR) {
			    error = ERROR_OBJECT_WRONG_TYPE;
			    goto openbreak;
			}
			if (ramfile->locks < 0) {
			    error = ERROR_OBJECT_IN_USE;
			    goto openbreak;
			}
			if (packet->dp_Type == ACTION_OPENOLD) {
			    ++ramfile->locks;
			} else {
			    if (ramfile->locks > 0) {
				error = ERROR_OBJECT_IN_USE;
			    } else {
				if (packet->dp_Type == ACTION_OPENNEW)
				    freedata(ramfile);
				--ramfile->locks;
			    }
			}
		    } else {
			dbprintf("Not found..");
			if (!parentdir) {
			    error = ERROR_INVALID_COMPONENT_NAME;
			    goto openbreak;
			}
			if (packet->dp_Type == ACTION_OPENNEW) {
			    ramfile = createramfile(parentdir, FILE_FILE, ptr);
			    --ramfile->locks;
			    dbprintf("adding file %08lx '%s'\n", ramfile, ramfile->name);
			} else {
			    error = ERROR_OBJECT_NOT_FOUND;
			}
		    }
		    if (!error) {
			register MYFH *mfh = AllocMem(sizeof(MYFH), MEMF_PUBLIC|MEMF_CLEAR);
			((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long)mfh;
			dbprintf("SET FH-ARG1 to %08lx\n", mfh);
			mfh->file = ramfile;
			mfh->fentry = GetHead(&ramfile->list);
			AddHead(&FHBase,mfh);
		    }
		}
	      openbreak:
		if (!GetHead(&FHBase) && !GetHead(&LCBase))
		    notdone = 0;
		break;
	    case ACTION_READ:	    /*	 FHArg1,CPTRBuffer,Length   ActLength  */
		{
		    register MYFH   *mfh = (MYFH *)packet->dp_Arg1;
		    register FENTRY *fen = mfh->fentry;
		    register ubyte  *ptr = (ubyte *)packet->dp_Arg2;
		    register long   left = packet->dp_Arg3;
		    register long   scr;

		    dbprintf("READ Seek:%ld MFH:%08lx FEN:%08lx\n", mfh->base + mfh->offset, mfh, fen);
		    while (left && fen) {
			scr = fen->bytes - mfh->offset;
			dbprintf(" %ld bytes avail to read. req %ld\n", scr, left);
			if (left < scr) {
			    bmov(fen->buf + mfh->offset, ptr, left);
			    mfh->offset += left;
			    left = 0;
			} else {
			    bmov(fen->buf + mfh->offset, ptr, scr);
			    left -= scr;
			    ptr += scr;
			    mfh->base += fen->bytes;
			    mfh->offset = 0;
			    fen = NextNode(fen);
			}
		    }
		    mfh->fentry = fen;
		    packet->dp_Res1 = packet->dp_Arg3 - left;
		}
		break;
	    case ACTION_WRITE:	    /*	 FHArg1,CPTRBuffer,Length   ActLength  */
		{
		    register MYFH   *mfh = (MYFH *)packet->dp_Arg1;
		    register FENTRY *fen = (FENTRY *)mfh->fentry;
		    register ubyte  *ptr = (ubyte *)packet->dp_Arg2;
		    register long   left = packet->dp_Arg3;
		    register long   scr;

		    dbprintf("MFH: %08lx\n", mfh);
		    while (left) {
			if (fen) {
			    dbprintf("WRITE: %ld FEN %ld\n", left, fen->bytes);
			    scr = fen->bytes - mfh->offset;
			    if (left < scr) {
				bmov(ptr, fen->buf + mfh->offset, left);
				mfh->offset += left;
				left = 0;
			    } else {
				bmov(ptr, fen->buf + mfh->offset, scr);
				ptr += scr;
				left -= scr;
				mfh->base += fen->bytes;
				mfh->offset = 0;
				fen = NextNode(fen);
			    }
			} else {
			    dbprintf("WRITE: %ld NOFEN\n", left);
			    fen = AllocMem(sizeof(FENTRY), MEMF_PUBLIC);
			    fen->buf = AllocMem(left, MEMF_PUBLIC);
			    fen->bytes = left;
			    mfh->file->bytes += left;
			    mfh->base  += left;
			    mfh->offset = 0;
			    TotalBytes += left;
			    AddTail(&mfh->file->list, fen);
			    bmov(ptr, fen->buf, left);
			    left = 0;
			    fen = NULL;     /*	cause append	*/
			}
		    }
		    packet->dp_Res1 = packet->dp_Arg3 - left;
		    mfh->fentry = fen;
		}
		break;
	    case ACTION_CLOSE:	    /*	 FHArg1 		    Bool:TRUE  */
		{
		    register MYFH   *mfh = (MYFH *)packet->dp_Arg1;
		    register RAMFILE *file = mfh->file;

		    Remove(mfh);
		    FreeMem(mfh,sizeof(*mfh));
		    if (--file->locks < 0)
			file->locks = 0;
		}
		if (!GetHead(&FHBase) && !GetHead(&LCBase))
		    notdone = 0;
		break;
	    case ACTION_SEEK:	    /*	 FHArg1,Position,Mode	    OldPosition*/
		{
		    register MYFH *mfh = (MYFH *)packet->dp_Arg1;
		    register FENTRY *fen;
		    register long absseek;

		    packet->dp_Res1 = mfh->base + mfh->offset;
		    absseek = packet->dp_Arg2;
		    if (packet->dp_Arg3 == 0)
			absseek += mfh->base + mfh->offset;
		    if (packet->dp_Arg3 == 1)
			absseek = mfh->file->bytes + absseek;
		    if (absseek < 0 || absseek > mfh->file->bytes) {
			error = ERROR_SEEK_ERROR;
			break;
		    }
		    mfh->base = mfh->offset = 0;

		    /*
		     *	Stupid way to do it but....
		     */

		    for (fen = GetHead(&mfh->file->list); fen; fen = NextNode(fen)) {
			if (mfh->base + fen->bytes > absseek) {
			    mfh->offset = absseek - mfh->base;
			    break;
			}
			mfh->base += fen->bytes;
		    }
		    mfh->fentry = fen;
		}
		break;
	    case ACTION_EXAMINE_NEXT: /*   Lock,Fib		      Bool	 */
		{
		    register FIB *fib = BTOC(packet->dp_Arg2);
		    register RAMFILE *file = getlockfile(packet->dp_Arg1);

		    if (file->type == FILE_FILE) {
			error = ERROR_OBJECT_WRONG_TYPE;
			break;
		    }
		    if (fib->fib_DiskKey == NULL) {
			error = ERROR_NO_MORE_ENTRIES;
			break;
		    }
		    file = (RAMFILE *)fib->fib_DiskKey;
		    fib->fib_DiskKey = (long)NextNode(file);
		    error = -1;
		}
		/*  fall through    */
	    case ACTION_EXAMINE_OBJECT: /*   Lock,Fib			Bool	   */
		{
		    register FIB *fib;
		    register RAMFILE *file;

		    fib = BTOC(packet->dp_Arg2);
		    if (error != -1) {
			file = getlockfile(packet->dp_Arg1);
			fib->fib_DiskKey = (long)GetHead(&file->list);
		    }
		    fib->fib_DirEntryType = file->type;
		    strcpy(fib->fib_FileName+1, file->name);
		    fib->fib_FileName[0] = strlen(file->name);
		    fib->fib_Protection = file->protection;
		    fib->fib_EntryType = NULL;
		    fib->fib_Size = file->bytes;
		    fib->fib_NumBlocks = file->bytes >> 9;
		    fib->fib_Date = file->date;
		    if (file->comment) {
			strcpy(fib->fib_Comment+1, file->comment);
			fib->fib_Comment[0] = strlen(file->comment);
		    } else {
			fib->fib_Comment[0] = 0;
		    }
		    error = 0;
		}
		break;
	    case ACTION_INFO:	    /*	?????????????	*/
		error = ERROR_ACTION_NOT_KNOWN;
		break;
	    case ACTION_DISK_INFO:  /*	ParamBlk		   Bool:TRUE	    */
		{
		    register INFODATA *id = BTOC(packet->dp_Arg1);
		    bzero(id, sizeof(*id));
		    id->id_DiskState = ID_VALIDATED;
		    id->id_NumBlocks	 = TotalBytes >> 9;
		    id->id_NumBlocksUsed = TotalBytes >> 9;
		    id->id_BytesPerBlock = 512; 	    /*	 total lie	    */
		    id->id_DiskType = ID_NOT_REALLY_DOS;    /*	?????? don't know   */
		    id->id_VolumeNode = NULL;
		}
		break;
	    case ACTION_PARENT:     /*	 Lock			    ParentLock */
		{
		    register RAMFILE *file = getlockfile(packet->dp_Arg1);
		    if (file->type == FILE_FILE) {
			error = ERROR_OBJECT_NOT_FOUND;
			break;
		    }
		    if (file->locks < 0) {
			error = ERROR_OBJECT_IN_USE;
			break;
		    }
		    if (file->parent)
			packet->dp_Res1 = (long)CTOB(ramlock(file->parent, ACCESS_READ));
		    else
			error = ERROR_OBJECT_NOT_FOUND;
		}
		break;
	    case ACTION_DELETE_OBJECT: /*Lock,Name		    Bool       */
		{
		    RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
		    RAMFILE *ramfile;

		    btos(packet->dp_Arg2, buf);
		    if (ramfile = searchpath(&parentdir,buf,NULL)) {
			if (ramfile->locks || ramfile == &RFRoot) {
			    error = ERROR_OBJECT_IN_USE;
			    break;
			}
			if (ramfile->type == FILE_DIR) {
			    if (GetHead(&ramfile->list))
				error = ERROR_DIRECTORY_NOT_EMPTY;
			} else {
			    freedata(ramfile);
			}
			if (!error)
			    freeramfile(ramfile);
		    } else {
			if (!parentdir)
			    error = ERROR_INVALID_COMPONENT_NAME;
			else
			    error = ERROR_OBJECT_NOT_FOUND;
		    }
		}
		if (!GetHead(&FHBase) && !GetHead(&LCBase))
		    notdone = 0;
		break;
	    case ACTION_CREATE_DIR: /*	 Lock,Name		    Lock       */
		{
		    RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
		    RAMFILE *ramfile;
		    char *ptr;

		    btos(packet->dp_Arg2, buf);
		    if (ramfile = searchpath(&parentdir,buf,&ptr)) {
			error = ERROR_OBJECT_EXISTS;
			break;
		    }
		    if (!parentdir) {
			error = ERROR_INVALID_COMPONENT_NAME;
			break;
		    }
		    ramfile = createramfile(parentdir, FILE_DIR, ptr);
		    packet->dp_Res1 = (long)CTOB(ramlock(ramfile, ACCESS_WRITE));
		}
		break;
	    case ACTION_LOCATE_OBJECT:	/*   Lock,Name,Mode		Lock	   */
		{
		    RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
		    RAMFILE *ramfile;

		    btos(packet->dp_Arg2, buf);
		    if (ramfile = searchpath(&parentdir,buf,NULL)) {
			if (ramfile->locks < 0 || (ramfile->locks && packet->dp_Arg3 == ACCESS_WRITE)) {
			    error = ERROR_OBJECT_IN_USE;
			    break;
			}
			packet->dp_Res1 = (long)CTOB(ramlock(ramfile, packet->dp_Arg3));
		    } else {
			if (!parentdir)
			    error = ERROR_INVALID_COMPONENT_NAME;
			else
			    error = ERROR_OBJECT_NOT_FOUND;
		    }
		}
		break;
	    case ACTION_COPY_DIR:   /*	 Lock,			    Lock       */
		{
		    register RAMFILE *ramfile = getlockfile(packet->dp_Arg1);
		    if (ramfile->locks < 0)
			error = ERROR_OBJECT_IN_USE;
		    else
			packet->dp_Res1 = (long)CTOB(ramlock(ramfile, ACCESS_READ));
		}
		break;
	    case ACTION_FREE_LOCK:  /*	 Lock,			    Bool       */
		if (packet->dp_Arg1);
		    ramunlock(BTOC(packet->dp_Arg1));
		if (!GetHead(&FHBase) && !GetHead(&LCBase))
		    notdone = 0;
		break;
	    case ACTION_SET_PROTECT:/*	 -,Lock,Name,Mask	   Bool       */
		{
		    register RAMFILE *ramfile;
		    RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
		    char *ptr;

		    btos(packet->dp_Arg3, buf);
		    if (ramfile = searchpath(&parentdir,buf,&ptr)) {
			ramfile->protection = packet->dp_Arg4;
		    } else {
			if (parentdir)
			    error = ERROR_OBJECT_NOT_FOUND;
			else
			    error = ERROR_INVALID_COMPONENT_NAME;
		    }
		}
		break;
	    case ACTION_SET_COMMENT:/*	 -,Lock,Name,Comment	   Bool       */
		{
		    register RAMFILE *ramfile;
		    RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
		    char *ptr;

		    btos(packet->dp_Arg3, buf);
		    if (ramfile = searchpath(&parentdir,buf,&ptr)) {
			btos(packet->dp_Arg4, buf);
			if (ramfile->comment)
			    FreeMem(ramfile->comment,strlen(ramfile->comment)+1);
			ramfile->comment = AllocMem(strlen(buf)+1, MEMF_PUBLIC);
			strcpy(ramfile->comment, buf);
		    } else {
			if (parentdir)
			    error = ERROR_OBJECT_NOT_FOUND;
			else
			    error = ERROR_INVALID_COMPONENT_NAME;
		    }
		}
		break;
	    case ACTION_RENAME_OBJECT:/* SLock,SName,DLock,DName    Bool       */
		{
		    register RAMFILE *file1, *file2;
		    RAMFILE *sourcedir = getlockfile(packet->dp_Arg1);
		    RAMFILE *destdir   = getlockfile(packet->dp_Arg3);
		    char *ptr;

		    btos(packet->dp_Arg2,buf);
		    if (file1 = searchpath(&sourcedir,buf,NULL)) {
			btos(packet->dp_Arg4,buf);
			if (file2 = searchpath(&destdir,buf,&ptr)) {
			    error = ERROR_OBJECT_EXISTS;
			} else {
			    if (destdir) {
				Remove(file1);
				AddTail(&destdir->list, file1);
				FreeMem(file1->name,strlen(file1->name)+1);
				file1->name = AllocMem(strlen(ptr)+1,MEMF_PUBLIC);
				strcpy(file1->name,ptr);
			    } else {
				error = ERROR_INVALID_COMPONENT_NAME;
			    }
			}
		    } else {
			if (sourcedir)
			    error = ERROR_OBJECT_NOT_FOUND;
			else
			    error = ERROR_INVALID_COMPONENT_NAME;
		    }
		}
		break;
	    /*
	     *	A few other packet types which we do not support
	     */
	    case ACTION_RENAME_DISK:/*	 BSTR:NewName		    Bool       */
	    case ACTION_MORECACHE:  /*	 #BufsToAdd		    Bool       */
	    case ACTION_INHIBIT:    /*	 Bool			    Bool       */
	    case ACTION_WAIT_CHAR:  /*	 Timeout, ticks 	    Bool       */
	    case ACTION_FLUSH:	    /*	 writeout bufs, disk motor off	       */
	    case ACTION_RAWMODE:    /*	 Bool(-1:RAW 0:CON)	    OldState   */
	    default:
		error = ERROR_ACTION_NOT_KNOWN;
		break;
	    }
	    if (packet) {
		if (error) {
		    packet->dp_Res1 = DOS_FALSE;
		    packet->dp_Res2 = error;
		}
		returnpacket(packet);
	    }
	}
    }
    dbprintf("REMOVING DOS DEVICE");
    Delay(50);	    /*	I wanna even see the debug message! */
    Forbid();
    if (packetsqueued(DosProc) || GetHead(&FHBase) || GetHead(&LCBase)
      || GetHead(&RFRoot.list)) {
	Permit();
	dbprintf("Not ready to die yet!\n");
	goto top;		/*  sorry... can't exit     */
    }
    DosNode->dn_Task = FALSE;
    dbuninit();
    CloseLibrary(DOSBase);
}

/*
 *  PACKET ROUTINES.	Dos Packets are in a rather strange format as you
 *  can see by this and how the PACKET structure is extracted in the
 *  GetMsg() of the main routine.
 */

void
returnpacket(packet)
register struct DosPacket *packet;
{
    register struct Message *mess;
    register struct MsgPort *replyport;

    replyport		     = packet->dp_Port;
    mess		     = packet->dp_Link;
    packet->dp_Port	     = &DosProc->pr_MsgPort;
    mess->mn_Node.ln_Name    = (char *)packet;
    mess->mn_Node.ln_Succ    = NULL;
    mess->mn_Node.ln_Pred    = NULL;
    PutMsg(replyport, mess);
}

/*
 *  Are there any packets queued to our device?
 */

packetsqueued()
{
    return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
	    (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
}

/*
 *  DOS MEMORY ROUTINES
 *
 *  DOS makes certain assumptions about LOCKS.	A lock must minimally be
 *  a FileLock structure, with additional private information after the
 *  FileLock structure.  The longword before the beginning of the structure
 *  must contain the length of structure + 4.
 */

void *
dosalloc(bytes)
register ulong bytes;
{
    register ulong *ptr;

    bytes += 4;
    ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
    *ptr = bytes;
    return(ptr+1);
}

dosfree(ptr)
register ulong *ptr;
{
    --ptr;
    FreeMem(ptr, *ptr);
}

/*
 *  Convert a BSTR into a normal string.. copying the string into buf
 */

void
btos(bstr,buf)
ubyte *bstr;
ubyte *buf;
{
    bstr = BTOC(bstr);
    bmov(bstr+1,buf,*bstr);
    buf[*bstr] = 0;
    dbprintf("btos: %ld %s\n", *bstr, buf);
}

void *
NextNode(node)
NODE *node;
{
    node = node->mln_Succ;
    if (node->mln_Succ == NULL)
	return(NULL);
    return(node);
}

void *
GetHead(list)
LIST *list;
{
    if ((void *)list->mlh_Head != (void *)&list->mlh_Tail)
	return(list->mlh_Head);
    return(NULL);
}

nccmp(p1,p2,n)
register ubyte *p1, *p2;
register short n;
{
    while (--n >= 0) {
	if ((p1[n]|0x20) != (p2[n]|0x20))
	    return(0);
    }
    return(1);
}

/*
 *  Create a file or directory and link it into it's parent directory.
 */

RAMFILE *
createramfile(parentdir, type, name)
RAMFILE *parentdir;
char *name;
{
    register RAMFILE *ramfile;

    ramfile = AllocMem(sizeof(RAMFILE), MEMF_CLEAR|MEMF_PUBLIC);
    AddTail(&parentdir->list, ramfile);
    ramfile->parent = parentdir;
    ramfile->name = AllocMem(strlen(name)+1, MEMF_PUBLIC);
    strcpy(ramfile->name, name);
    ramfile->type = type;
    ramfile->protection = 0;
    NewList(&ramfile->list);
    /*	SET DATE!   */
    return(ramfile);
}

/*
 *  Free all data associated with a file
 */

void
freedata(ramfile)
RAMFILE *ramfile;
{
    FENTRY *fen;

    TotalBytes -= ramfile->bytes;
    while (fen = RemHead(&ramfile->list)) {
	FreeMem(fen->buf, fen->bytes);
	FreeMem(fen, sizeof(*fen));
    }
    ramfile->bytes = 0;
}

/*
 *  Any data associated with the file or directory has already been
 *  freed up.
 */

void
freeramfile(ramfile)
RAMFILE *ramfile;
{
    Remove(ramfile);		/*  unlink from parent directory    */
    FreeMem(ramfile->name,strlen(ramfile->name)+1);
    if (ramfile->comment)
	FreeMem(ramfile->comment,strlen(ramfile->comment)+1);
    FreeMem(ramfile,sizeof(*ramfile));
}

MYLOCK *
ramlock(ramfile, mode)
RAMFILE *ramfile;
{
    MYLOCK *lock = dosalloc(sizeof(MYLOCK));
    AddHead(&LCBase,&lock->node);
    lock->lock.fl_Access = mode;
    lock->lock.fl_Task = &DosProc->pr_MsgPort;
    lock->lock.fl_Volume = (BPTR)CTOB(DosNode);
    lock->file = ramfile;
    if (mode == ACCESS_READ)
	++ramfile->locks;
    else
	ramfile->locks = -1;
    return(lock);
}

void
ramunlock(lock)
MYLOCK *lock;
{
    RAMFILE *file = lock->file;
    Remove(&lock->node);
    if (lock->lock.fl_Access == ACCESS_READ)
	--file->locks;
    else
	file->locks = 0;
    dosfree(lock);
}

/*
 *  GETLOCKFILE(bptrlock)
 *
 *  Return the RAMFILE entry (file or directory) associated with the
 *  given lock, which is passed as a BPTR.
 *
 *  According to the DOS spec, the only way a NULL lock will ever be
 *  passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
 *  In anycase, If a NULL lock is passed to me I simply assume it means
 *  the root directory of the RAM disk.
 */

RAMFILE *
getlockfile(lock)
void *lock;		/*  actually BPTR to MYLOCK */
{
    if (lock)
	return(((MYLOCK *)BTOC(lock))->file);
    return(&RFRoot);
}

/*
 *  Search the specified path beginning at the specified directory.
 *  The directory pointer is updated to the directory containing the
 *  actual file.  Return the file node or NULL if not found.  If the
 *  path is illegal (an intermediate directory was not found), set *ppar
 *  to NULL and return NULL.
 *
 *  *ppar may also be set to NULL if the search path IS the root.
 *
 *  If pptr not NULL, Set *pptr to the final component in the path.
 */

RAMFILE *
searchpath(ppar,buf,pptr)
RAMFILE **ppar;
char *buf;
char **pptr;
{
    RAMFILE *file = *ppar;
    RAMFILE *srch;
    short len;
    char *ptr;

    dbprintf("searchpath: '%s'\n", buf);
    *ppar = NULL;
    for (;*buf && file;) {
	ptr = getpathelement(&buf,&len);
	if (buf[0] == ':') {    /*  go to root          */
	    dbprintf("colon element\n");
	    ++buf;
	    file = &RFRoot;
	    continue;
	}
	if (*ptr == '/') {          /*  go back a directory */
	    if (!file->parent) {    /*	no parent directory */
		dbprintf("Backdir.. no parent\n");
		return(NULL);
	    }
	    file = file->parent;
	    dbprintf("backdir: file %08lx (%s)\n", file, file->name);
	    continue;
	}
	if (file->type == FILE_FILE)
	    return(NULL);
	for (srch = GetHead(&file->list); srch; srch = NextNode(srch)) {
	    if (strlen(srch->name) == len && nccmp(srch->name, ptr, len)) {
		file = srch;	    /*	element found	    */
		break;
	    }
	}
	if (srch == NULL) {
	    if (*buf == 0) {	/*  Element not found.	If it was the final */
		*ppar = file;	/*  element the parent directory is valid   */
		dbprintf("element not found.. ok\n");
	    } else {
		dbprintf("element not found.. path error\n");
	    }
	    if (pptr)
		*pptr = ptr;
	    return(NULL);
	}
    }
    if (pptr)
	*pptr = ptr;
    *ppar = file->parent;
    dbprintf("DONE. File %08lx (%s) parent %08lx\n", file, file->name, file->parent);
    return(file);
}

/*
 *  Return the next path element in the string.  The routine effectively
 *  removes any trailing '/'s, but treats ':' as part of the next component
 *  (i.e. ':' is checked and skipped in SEARCHPATH()).
 */

char *
getpathelement(pstr,plen)
char **pstr;
short *plen;
{
    char *base;
    register char *ptr = *pstr;
    register short len = 0;

    if (*(base = ptr)) {
	if (*ptr == '/') {
	    ++ptr;
	    ++len;
	} else {
	    while (*ptr && *ptr != '/' && *ptr != ':') {
		++ptr;
		++len;
	    }
	    if (*ptr == '/')
		++ptr;
	}
    }
    *pstr = ptr;
    *plen = len;
    dbprintf("PATH ELEMENT: %ld '%s' next@ '%s'\n", len, base, ptr);
    return(base);
}


stats()
{
    register RAMFILE *file;
    register MYFH *mfh;

    for (file = GetHead(&RFRoot.list); file; file = NextNode(file)) {
	dbprintf("Root entry: %08lx %s %ld\n", file, file->name, file->bytes);
    }
    for (mfh = GetHead(&FHBase); mfh; mfh = NextNode(mfh)) {
	dbprintf("Openfile: %08lx %s @%ld %ld\n", mfh->file, mfh->file->name, mfh->base, mfh->offset);
    }
    /*
     *	Note that the NODE entry in the MYLOCK structure is not (cannot) be
     *	at the beginning of the structure and thus if you want to traverse
     *	the active lock list you must subtract it's position in the
     *	structure from any list pointers.
     */
    if (GetHead(&LCBase)) {
	dbprintf("ACTIVE LOCKS DO EXIST\n");
    }
    dbprintf("\n");
}

/*
 *  DEBUGGING CODE.	You cannot make DOS library calls that access other
 *  devices from within a DOS device driver because they use the same
 *  message port as the driver.  If you need to make such calls you must
 *  create a port and construct the DOS messages yourself.  I do not
 *  do this.  To get debugging info out another PROCESS is created to which
 *  debugging messages can be sent.
 *
 *  You want the priority of the debug process to be larger than the
 *  priority of your DOS handler.  This is so if your DOS handler crashes
 *  you have a better idea of where it died from the debugging messages
 *  (remember that the two processes are asyncronous from each other).
 */

extern void debugproc();

dbinit()
{
    TASK *task = FindTask(NULL);

    Dback = CreatePort(NULL,NULL);
    CreateProc("DEV_DB", task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096);
    WaitPort(Dback);				    /* handshake startup    */
    GetMsg(Dback);				    /* remove dummy msg     */
    dbprintf("Debugger running V1.00\n");
}

dbuninit()
{
    MSG killmsg;

    if (Dbport) {
	killmsg.mn_Length = 0;	    /*	0 means die	    */
	PutMsg(Dbport,&killmsg);
	WaitPort(Dback);	    /*	He's dead jim!      */
	GetMsg(Dback);
	DeletePort(Dback);

	/*
	 *  Since the debug process is running at a greater priority, I
	 *  am pretty sure that it is guarenteed to be completely removed
	 *  before this task gets control again.  Still, it doesn't hurt...
	 */

	Delay(50);		    /*	ensure he's dead    */
    }
}

dbprintf(a,b,c,d,e,f,g,h,i,j)
{
    char buf[256];
    MSG *msg;

    if (Dbport && !DBDisable) {
	sprintf(buf,a,b,c,d,e,f,g,h,i,j);
	msg = AllocMem(sizeof(MSG)+strlen(buf)+1, MEMF_PUBLIC|MEMF_CLEAR);
	msg->mn_Length = strlen(buf)+1;     /*	Length NEVER 0	*/
	strcpy(msg+1,buf);
	PutMsg(Dbport,msg);
    }
}

/*
 *  BTW, the DOS library used by debugmain() was actually openned by
 *  the device driver.	Note: DummyMsg cannot be on debugmain()'s stack
 *  since debugmain() goes away on the final handshake.
 */

debugmain()
{
    MSG *msg;
    short len;
    void *fh;

    Dbport = CreatePort(NULL,NULL);
    fh = Open("con:0/0/640/100/debugwindow", 1006);
    PutMsg(Dback, &DummyMsg);
    for (;;) {
	WaitPort(Dbport);
	msg = GetMsg(Dbport);
	len = msg->mn_Length;
	if (len == 0)
	    break;
	--len;			    /*	Fix length up	*/
	Write(fh, msg+1, len);
	FreeMem(msg,sizeof(MSG)+len+1);
    }
    Close(fh);
    DeletePort(Dbport);
    PutMsg(Dback,&DummyMsg);	      /*  Kill handshake  */
}

/*
 *  The assembly tag for the DOS process:  CNOP causes alignment problems
 *  with the Aztec assembler for some reason.  I assume then, that the
 *  alignment is unknown.  Since the BCPL conversion basically zero's the
 *  lower two bits of the address the actual code may start anywhere
 *  within 8 bytes of address (remember the first longword is a segment
 *  pointer and skipped).  Sigh....  (see CreatProc() above).
 */

#asm
	public	_debugproc
	public	_debugmain

	cseg
_debugproc:
	nop
	nop
	nop
	nop
	nop
	movem.l D2-D7/A2-A6,-(sp)
	jsr	_debugmain
	movem.l (sp)+,D2-D7/A2-A6
	rts
#endasm


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'device.uue'" '(14057 characters)'
if test -f 'device.uue'
then
	echo shar: "will not over-write existing file 'device.uue'"
else
cat << \!Funky!Stuff! > 'device.uue'
begin 644 device
M```#\P`````````#``````````(```C1````1P````$```/I```(T4Y5_NY(
MYP\P0GD```"80KD```"R0KD```"N0KD```"J(_D````$````HD*G2'H.MDZY
M```BTE!/(\````"F0J=.N0``(F)83R/`````FB!Y````FDAH`%Q.N0``(RY8
M3R!Y````FDAH`%Q.N0``(JQ83RM`__P@;?_\)&@`"DJY````IF<P("H`'.6`
M(\````">('D```">(#D```":T+P```!<(4``""5\_____P`,0JH`$&`40JH`
M#"\*3KH/?EA/3-\,\$Y=3G4O"DZZ#VY83TZZ%SP@>0```)X@*``HY8`K0/[V
M(&W^]G``$!`[0/[T2'D```"V3KD``"+`6$](>0```,).N0``(L!83TAX`#A(
M>0```.).N0``&LA03S/\``$```#V2'D```$"3KD``"+`6$](>``!,"W^]$C`
M4H`O`$ZY```B/%!/(\````#N,"W^]$C`+P`O.0```.X@;?[V4H@O"$ZY```A
M)$_O``PP+?[T('D```#N0C```"\Y````[C`M_O1(P"\`2'H-8$ZZ%W)/[P`,
M&WP``?_[('D```":2&@`7$ZY```C+EA/3KH59B!Y````FDAH`%Q.N0``(JQ8
M3RM`__QG``Q^(&W__"1H``HE?/____\`#$*J`!!X`"\J`"`O*@`<+RH`&"\J
M`!0O*@`(2'H-"4ZZ%P9/[P`8("H`"&``"WA"+?_[8``,&"\J`!A.NA'F6$\K
M0/[V2&W^^R\J`!Q.N@["4$](>@SW2&W^^TZY```;(%!/2H!F"#/\``$```"8
M2'H,Y$AM_OM.N0``&R!03TJ`9@9">0```)A(;?[R2&W^^TAM_O9.NA&P3^\`
M#"H`9W`O+?[R+RW^]DAZ#+).NA9X3^\`#"!%#&@``0`49@@X/`#48```_"!%
M2F@`%FP(.#P`RF```.P,J@```^T`"&8(($52:``68"8@14IH`!9O!C@\`,I@
M&`RJ```#[@`(9@@O!4ZZ#WA83R!%4V@`%F!82'H,;4ZZ%A!83TJM_O9F"#@\
M`-)@``":#*H```/N``AF,B\M_O)(>/__+RW^]DZZ#KQ/[P`,*@`@15-H`!8@
M12\H``PO!4AZ##-.NA7*3^\`#&`$.#P`S4I$9E1(>0`!``%(>``83KD``"(\
M4$\L`"`J`!3E@"!`(48`)"\&2'H,$TZZ%9)03R!&(44`""!%2&@`($ZZ#?18
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
M`E.`9P#S_%.`9P#X*E.`9P#X@&``_U(@"F<82D1G#$*J``PP!$C`)4``$"\*
M3KH!^%A/8`#S;$HM__MF`/-.2'H!NTZZ"JQ83TAX`#).N0``(,983TZY```B
M=B\Y````FDZZ`@183TJ`9C!(>0```+9.N@+R6$]*@&8@2'D```#"3KH"XEA/
M2H!F$$AY```!`DZZ`M)83TJ`9Q1.N0``(NI(>@%M3KH*2EA/8`#RV"!Y````
MGD*H``A.N@G:+SD```"F3KD``"$06$]@`/'@9&]S+FQI8G)A<GD`4D]/5"!.
M04U%.B`E;&0@)R5S)PH`4&%C:V5T.B`E,VQD("4P.&QX("4P.&QX("4P.&QX
M("4P.&QX"@!D96)U9V]F9@!D96)U9V]N`$9O=6YD.B!P87)E;G1D:7(@)3`X
M;'@@('1A:6P@)R5S)PH`3F]T(&9O=6YD+BX`861D:6YG(&9I;&4@)3`X;'@@
M)R5S)PH`4T54($9(+4%21S$@=&\@)3`X;'@*`%)%040@4V5E:SHE;&0@349(
M.B4P.&QX($9%3CHE,#AL>`H`("5L9"!B>71E<R!A=F%I;"!T;R!R96%D+B!R
M97$@)6QD"@!-1D@Z("4P.&QX"@!74DE413H@)6QD($9%3B`E;&0*`%=2251%
M.B`E;&0@3D]&14X*`%)%34]624Y'($1/4R!$159)0T4`3F]T(')E861Y('1O
M(&1I92!Y970A"@!.50``2.<(,"1M``@H*@`$)E(@.0```)K0O````%PE0``$
M)TH`"D*30JL`!"\++P1.N0``(O103TS?#!!.74YU3E4``"!Y````FB)Y````
MFM/\````="QH`'"]R6<$<`%@`G``3EU.=4Y5``!(YP@@*"T`"%B$2'D``0`!
M+P1.N0``(CQ03R1`)(0@"EB`3-\$$$Y=3G5.50``+PHD;0`(68HO$B\*3KD`
M`"*&4$\D7TY=3G5.50``("T`".6`*T``""!M``AP`!`0+P`O+0`,(FT`"%*)
M+PE.N0``(21/[P`,(&T`"'``$!`B;0`,0C$(`"\M``P@;0`(<``0$"\`2'H`
M#DZZ!\1/[P`,3EU.=6)T;W,Z("5L9"`E<PH`3E4``"!M``@K4``((&T`"$J0
M9@9P`$Y=3G4@+0`(8/9.50``(&T`"%B((FT`"+'19PH@;0`((!!.74YU<`!@
M^$Y5``!(YP@P)&T`""9M``PX+0`24T1*1&TD<``0,D``",``!7(`$C-```C!
M``6P@6<*<`!,WPP03EU.=6#6<`%@\DY5```O"DAY``$``4AX`#A.N0``(CQ0
M3R1`+PH@;0`(2&@`($ZY```A`%!/)6T`"``(2'@``2\M`!!.N0``(&983U*`
M+P!.N0``(CQ03R5```PO+0`0+RH`#$ZY```;4%!/-6T`#@`40JH`&$AJ`"!.
MN0``(L!83R`*)%].74YU3E7__"!M``@@*``<D;D```"J(&T`"$AH`"!.N0``
M(P183RM`__QG*B!M__PO*``,(FW__"\I``A.N0``(H903TAX`!`O+?_\3KD`
M`"*&4$]@P"!M``A"J``<3EU.=4Y5```O+0`(3KD``",26$\@;0`(+R@`#$ZY
M```@9EA/4H`O`"!M``@O*``,3KD``"*&4$\@;0`(2J@`$&<D(&T`""\H`!!.
MN0``(&983U*`+P`@;0`(+R@`$$ZY```BAE!/2'@`."\M``A.N0``(H903TY=
M3G5.5?_\2'@`($ZZ_6I83RM`__P@;?_\2&@`%$AY````PDZY```B4E!/(&W_
M_"%M``P`""!M__P@.0```)K0O````%PA0``,(#D```">Y(`@;?_\(4``$"!M
M__PA;0`(`!P,K?____X`#&8*(&T`"%)H`!9@"B!M``@Q?/__`!8@+?_\3EU.
M=4Y5__P@;0`(*V@`'/_\(&T`"$AH`!1.N0``(Q)83R!M``@,J/____X`"&8*
M(&W__%-H`!9@""!M__Q":``6+RT`"$ZZ_-A83TY=3G5.50``2JT`"&<0("T`
M".6`($`@*``<3EU.=4'Y````XB`(8/).5?_R(&T`""M0__PO+0`,2'H!H$ZZ
M!,I03R!M``A"D&```3Y(;?_V2&T`#$ZZ`C!03RM`__(@;0`,#!``.F8<2'H!
M@DZZ!)I83U*M``Q!^0```.(K2/_\8``!!B!M__(,$``O9D`@;?_\2J@`"&80
M2'H!84ZZ!&I83W``3EU.=2!M__PK:``(__P@;?_\+R@`#"\M__Q(>@%03KH$
M1$_O``Q@``"\(&W__`QH__\`%&8$<`!@QB!M__Q(:``@3KK\E%A/*T#_^&!0
M(&W_^"\H``Q.N0``(&983S(M__9(P;"!9B@P+?_V2,`O`"\M__(@;?_X+R@`
M#$ZZ_'I/[P`,2H!G""MM__C__&`4+RW_^$ZZ_")83RM`__A*K?_X9JI*K?_X
M9CH@;0`,2A!F%"!M``@@K?_\2'H`RDZZ`Z183V`*2'H`UDZZ`YA83TJM`!!G
M""!M`!`@K?_R<`!@`/\>(&T`#$H09PA*K?_\9@#^MDJM`!!G""!M`!`@K?_R
M(&W__")M``@BJ``((&W__"\H``@B;?_\+RD`#"\M__Q(>@":3KH#/$_O`!`@
M+?_\8`#^S'-E87)C:'!A=&@Z("<E<R<*`&-O;&]N(&5L96UE;G0*`$)A8VMD
M:7(N+B!N;R!P87)E;G0*`&)A8VMD:7(Z(&9I;&4@)3`X;'@@*"5S*0H`96QE
M;65N="!N;W0@9F]U;F0N+B!O:PH`96QE;65N="!N;W0@9F]U;F0N+B!P871H
M(&5R<F]R"@!$3TY%+B!&:6QE("4P.&QX("@E<RD@<&%R96YT("4P.&QX"@!.
M5?_\2.<(("!M``@D4'@`*TK__$H29RH,$@`O9@92BE)$8!Y*$F<2#!(`+V<,
M#!(`.F<&4HI21&#J#!(`+V8"4HH@;0`(((H@;0`,,(0O"B\M__PP!$C`+P!(
M>@`63KH"(D_O`!`@+?_\3-\$$$Y=3G50051(($5,14U%3E0Z("5L9"`G)7,G
M(&YE>'1`("<E<R<*``!.50``2.<`,$AY```!`DZZ^E!83R1`8"`O*@`<+RH`
M#"\*2'H`@DZZ`<1/[P`0+PI.NOH.6$\D0"`*9MQ(>0```+9.NOH<6$\F0&`J
M+RL`%"\K`!`@:P`(+R@`#"\K``A(>@!>3KH!AD_O`!0O"TZZ^=!83R9`(`MF
MTDAY````PDZZ^=Y83TJ`9PI(>@!13KH!7%A/2'H`7DZZ`5)83TS?#`!.74YU
M4F]O="!E;G1R>3H@)3`X;'@@)7,@)6QD"@!/<&5N9FEL93H@)3`X;'@@)7,@
M0"5L9"`E;&0*`$%#5$E612!,3T-+4R!$3R!%6$E35`H`"@!.5?_\0J=.N0``
M(F)83RM`__Q"IT*G3KD``"$X4$\CP````+)(>!``0?H"=B`(Y(`O`"!M__P2
M*``)2(%(P5*!+P%(>@`V3KD``""P3^\`$"\Y````LDZY```C+EA/+SD```"R
M3KD``"*L6$](>@`33KH`A%A/3EU.=41%5E]$0@!$96)U9V=E<B!R=6YN:6YG
M(%8Q+C`P"@``3E7_[$JY````KF=,0FW__DAM_^PO.0```*Y.N0``(O103R\Y
M````LDZY```C+EA/+SD```"R3KD``"*L6$\O.0```+).N0``(=!83TAX`#).
MN0``(,983TY=3G5.5?[\2KD```"N9P``HDIY````F&8``)@O+0`L+RT`*"\M
M`"0O+0`@+RT`'"\M`!@O+0`4+RT`$"\M``PO+0`(2&W_`$ZY```;8$_O`"Q(
M>0`!``%(;?\`3KD``"!F6$\@0$AH`!5.N0``(CQ03RM`_OQ(;?\`3KD``"!F
M6$]2@"!M_OPQ0``22&W_`"!M_OQ(:``43KD``!M04$\O+?[\+SD```"N3KD`
M`"+T4$].74YU3E7_]D*G0J=.N0``(3A03R/`````KDAX`^Y(>@#`3KD``"#4
M4$\K0/_V2'D```#.+SD```"R3KD``"+T4$\O.0```*Y.N0``(RY83R\Y````
MKDZY```BK%A/*T#__"!M__P[:``2__I*;?_Z9SQ3;?_Z,"W_^DC`+P`@;?_\
M2&@`%"\M__9.N0``(.I/[P`,,"W_^DC`($!(:``5+RW__$ZY```BAE!/8)0O
M+?_V3KD``""<6$\O.0```*Y.N0``(=!83TAY````SB\Y````LDZY```B]%!/
M3EU.=6-O;CHP+S`O-C0P+S$P,"]D96)U9W=I;F1O=P!.<4YQ3G%.<4YQ2.<_
M/DZZ_OA,WWS\3G5"@6`$$B\`#R!O``0@+P`(`B\``P`+9@P"+P`#``=F!&`0
M$,%1R/_\D+P``0``:O).=>2(2H%G$A]!``XR+P`.2$$R+P`.8`(@P5'(__R0
MO``!``!J\DYU,#Q__V`$,"\`#E-`:Q0@;P`$(F\`"+$)9@Q32$H85\C_]G``
M3G5C!'`!3G5P_TYU(&\`!"`((F\`"!#99OQ.=4Y5``!(YS@`(^T`"````)1(
M;0`0+RT`#$AZ`"!.N0``'%)/[P`,*``@>0```)1"$"`$3-\`'$Y=3G5.50``
M2.<P`"!Y````E%*Y````E!`M``L0@$B`2,#`O````/],WP`,3EU.=4Y5``!(
MYS@@)&T`$`RM````!``49@@@;0`(*!!@%$JM``QO""!M``@H$&`&(&T`""@0
M0JT`%$JM``QL$D2M``Q*A&P*1(0K?`````$`%"(M``P@!$ZY```@`$'Y````
M`%.*%+`(`"(M``P@!$ZY```@#"@`9MA*K0`49P93BA2\`"T@"DS?!!Q.74YU
M3E7_%$CG.#`D;0`()FT`#$*M__@K;0`0__P@2U*+$!!(@$C`*`!G``,\N+P`
M```E9@`#%D(M_R(K?`````'_]"M\````(/_P*WP``"<0_^P@2U*+$!!(@$C`
M*`"PO````"UF$$*M__0@2U*+$!!(@$C`*`"XO````#!F%"M\````,/_P($M2
MBQ`02(!(P"@`N+P````J9AH@;?_\6*W__"M0_^@@2U*+$!!(@$C`*`!@.$*M
M_^A@)'(*("W_Z$ZY```@>-"$D+P````P*T#_Z"!+4HL0$$B`2,`H`$'Y````
M$P@P``)(`&;.N+P````N9F8@2U*+$!!(@$C`*`"PO````"IF&B!M__Q8K?_\
M*U#_["!+4HL0$$B`2,`H`&`X0JW_[&`D<@H@+?_L3KD``"!XT(20O````#`K
M0/_L($M2BQ`02(!(P"@`0?D````3"#```D@`9LXK?`````3_Y+B\````;&86
M($M2BQ`02(!(P"@`*WP````$_^1@%+B\````:&8,($M2BQ`02(!(P"@`(`1@
M``""*WP````(_^!@'"M\````"O_@8!(K?````!#_X&`(*WS____V_^`O+?_D
M2&W_(B\M_^`O+?_\3KK]I$_O`!`K0/_<("W_Y-&M__Q@7"!M__Q8K?_\*U#_
MW"\M_]Q.N0``(&983RM`_^1@2B!M__Q8K?_\*!!![?\A*TC_W!"$8"B0O```
M`&-GXE.`9Y*0O`````MG`/]L68!GLE6`9P#_;%>`9P#_<&#,0>W_(I'M_]PK
M2/_D("W_Y+"M_^QO!BMM_^S_Y$JM__1G<"!M_]P,$``M9PHB;?_<#!$`*V8T
M#*T````P__!F*E.M_^@@;?_<4JW_W!`02(!(P"\`3I)83["\_____V8*</],
MWPP<3EU.=6`8+RW_\$Z26$^PO/____]F!'#_8.)2K?_X("W_Z%.M_^BPK?_D
M;MI"K?_@8"0@;?_<4JW_W!`02(!(P"\`3I)83["\_____V8$</]@JE*M_^`@
M;?_<2A!G"B`M_^"PK?_L;<H@+?_@T:W_^$JM__1F*F`:2'@`($Z26$^PO/__
M__]F!G#_8`#_<%*M__@@+?_H4ZW_Z+"M_^1NV&`8+P1.DEA/L+S_____9@9P
M_V``_TA2K?_X8`#\N"`M__A@`/\X2.=(`$*$2H!J!$2`4D1*@6H&1($*1``!
M83Y*1&<"1(!,WP`22H!.=4CG2`!"A$J`:@1$@%)$2H%J`D2!81H@`6#8+P%A
M$B`!(A]*@$YU+P%A!B(?2H!.=4CG,`!(04I!9B!(038!-`!"0$A`@,,B`$A`
M,@*"PS`!0D%(04S?``Q.=4A!)@$B`$)!2$%(0$)`=`_0@-.!MH%B!)*#4D!1
MRO_R3-\`#$YU(&\`!"`(2AAF_)'`(`A3@$YU2.=P`#0!Q,`F`4A#QL!(0T)#
MU(-(0,#!2$!"0-""3-\`#DYU3OD``""B(B\`!"QY````ID[N_]PO!$SO`!X`
M""QY````IDZN_W8H'TYU(B\`!"QY````ID[N_SI.^0``(-I,[P`&``0L>0``
M`*9.[O_B3OD``"#P3.\`#@`$+'D```"F3N[_T$SO`P``!"QY````HD[N_PI.
M^0``(18B;P`$+'D```"B3N[^8DSO`P``!"`O``PL>0```*).[OV03E4``$CG
M."!(>/__3KD``"(N6$\H`+"\_____V8*<`!,WP0<3EU.=4AY``$``4AX`").
MN0``(CQ03R1`2H!F#B\$3KD``"*>6$]P`&#2)6T`"``*%6T`#P`)%7P`!``(
M0BH`#A5$``]"ITZY```B8EA/)4``$$JM``AG#"\*3KD``"(@6$]@#$AJ`!1.
MN0``(L!83R`*8(A.50``2.<P("1M``A*J@`*9PHO"DZY```C(%A/%7P`_P`(
M)7S_____`!1P`!`J``\O`$ZY```BGEA/2'@`(B\*3KD``"*&4$],WP0,3EU.
M=2)O``0L>0```*).[OZ>("\`!"QY````HD[N_K9.^0``(D),[P`#``0L>0``
M`*).[O\Z3.\#```$+'D```"B3N[_$$[Y```B:")O``0L>0```*).[O[:3OD`
M`")\+'D```"B3N[_?$[Y```BC")O``0@+P`(+'D```"B3N[_+B`O``0L>0``
M`*).[OZP3OD``"*R(&\`!"QY````HD[N_HP@;P`$((A8D$*H``0A2``(3G5.
M^0``(M@L>0```*(B;P`$("\`"$[N_=@L>0```*).[O]V3.\#```$+'D```"B
M3N[^DB!O``0L>0```*).[O[^(F\`!"QY````HD[N_P0B;P`$+'D```"B3N[^
MF$[Y```C-"!O``0L>0```*).[OZ```````/L````>0`````````R````0@``
M`%H```!L````^@```0@```$:```!,````48```%J```!K````<(```(\```"
M6````U@```.:```$3```!'H```4X```%9@``!;(```7$```&#@``!B(```98
M```&9@``!^X```?\```(7@``"&P```B>```,&@``#"P```P\```,2```#&``
M``ST```-!@``#10```TF```--@``#4(```U:```.9```#FP```ZR```.V@``
M$&X``!"\```0Y```$18``!'N```2`@``$A@``!(D```2.```$DX``!)X```2
ME@``$J8``!+$```2U```$N@``!,"```3%@``$R8``!-2```3S@``%/H``!@8
M```8*```&%@``!AH```8=@``&,8``!C4```8X@``&/```!C\```93```&6``
M`!EN```9?@``&9P``!FN```9P@``&=@``!GP```9_@``&@P``!I````:6@``
M&F@``!IV```:B@``&WX``!P<```<-```'1(``!V````>2```()X``"#6```@
M[```(1(``"%&```A;```(7P``"&D```AN```(<8``"'F```B!```(A(``"(^
M```B9```(G@``"*(```BK@``(M0``",P````;`````$````*````$````!8`
M```<````)@```#H```!*````4````&(```"`````C@```)0```":````V```
M`/0```$"```!%````20```$J```!3@```5P```%X```!@@```:(```&X```"
M2@```F0```.4```#H@```[(```7\```&@```!I````BR```(P@``"8(```GF
M```)]@``"U````M@```.<@``#H(```Z2```.H@``#L8```[4```04```$((`
M`!"(```2:@``$TP``!-H```3>```%!X``!1V```7)```%U@``!>6```8,```
M&&(``!AP```8L```&,```!C.```8W```&.H``!D,```9%@``&:@``!G*```9
MY```&>H``!GX```:!@``&G```!I^```:A```&VP``!N*```;I```&ZH``!PB
M```=,```'9X``""H```@N@``(,P``"#B```@^```(0@``"$<```A,```(B8`
M`"(T```B2@``(EH``")N```B?@``(I8``"*D```BN```(MH``"+L```B_```
M(PH``",8```C)@``(SH````````#\@```^H````E,#$R,S0U-C<X.6%B8V1E
M9@```"`@("`@("`@(#`P,#`P("`@("`@("`@("`@("`@("`@D$!`0$!`0$!`
M0$!`0$!`0`P,#`P,#`P,#`Q`0$!`0$!`"0D)"0D)`0$!`0$!`0$!`0$!`0$!
M`0$!`0%`0$!`0$`*"@H*"@H"`@("`@("`@("`@("`@("`@("`D!`0$`@````
.`_(```/K`````0```_(*
`
end
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'dos.h'" '(2163 characters)'
if test -f 'dos.h'
then
	echo shar: "will not over-write existing file 'dos.h'"
else
cat << \!Funky!Stuff! > 'dos.h'

/*
 *  PARALLEL NETWORK INTERFACE
 */

#define ACTION_OPENRW	    1004
#define ACTION_OPENOLD	    1005
#define ACTION_OPENNEW	    1006
#define ACTION_CLOSE	    1007
#define ACTION_SEEK	    1008
#define ACTION_RAWMODE	    994
#define ACTION_MORECACHE    18
#define ACTION_FLUSH	    27

#define CTOB(x) (void *)(((long)(x))>>2)
#define BTOC(x) (void *)(((long)(x))<<2)

#define bmov(ss,dd,nn) CopyMem(ss,dd,nn)

#define DOS_FALSE   0
#define DOS_TRUE    -1

#define RAMFILE struct _RAMFILE
#define FENTRY	struct _FENTRY
#define MYLOCK	struct _MYLOCK
#define MYFH	struct _MYFH

typedef unsigned char	ubyte;
typedef unsigned short	uword;
typedef unsigned long	ulong;

typedef struct Interrupt	INTERRUPT;
typedef struct Task		TASK;
typedef struct FileLock 	LOCK;
typedef struct FileInfoBlock	FIB;
typedef struct DosPacket	PACKET;
typedef struct Process		PROC;
typedef struct DeviceNode	DEVNODE;
typedef struct FileHandle	FH;
typedef struct MsgPort		PORT;
typedef struct Message		MSG;
typedef struct MinList		LIST;
typedef struct MinNode		NODE;
typedef struct DateStamp	STAMP;
typedef struct InfoData 	INFODATA;

#define FILE_DIR    1
#define FILE_FILE   -1

RAMFILE {
    NODE    node;
    RAMFILE *parent;
    char    *name;
    char    *comment;
    short   type;	/*  -1 = file,	1 = dir 	    */
    short   locks;	/*  <0:exclusive 0:none >0:shared   */
    ulong   protection;
    ulong   bytes;
    LIST    list;	/*  list of FENTRY's or RAMFILE's   */
    STAMP   date;
};

FENTRY {
    NODE    node;
    ubyte   *buf;
    ulong   bytes;
};

MYLOCK {
    LOCK    lock;
    NODE    node;
    RAMFILE *file;
};

MYFH {
    NODE    node;
    RAMFILE *file;	/*  file header     */
    FENTRY  *fentry;
    long    base;	/*  base of FENTRY	*/
    long    offset;	/*  offset into FENTRY	*/
};

extern long AbsExecBase;

extern void *AllocMem(), *RemHead(), *CreatePort(), *GetMsg();
extern void *FindTask(), *Open();

extern void   *dosalloc(), *NextNode(), *GetHead();
extern void   freedata(), freeramfile(), ramunlock(), btos(), returnpacket();
extern MYLOCK *ramlock();
extern RAMFILE *searchpath(), *createramfile(), *getlockfile();

extern char *getpathelement();

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'flush.c'" '(302 characters)'
if test -f 'flush.c'
then
	echo shar: "will not over-write existing file 'flush.c'"
else
cat << \!Funky!Stuff! > 'flush.c'

/*
 *  Allocate memory until we can't ... force the system to flush all
 *  non-active DOS devices, libraries, fonts, etc....
 */

extern void *AllocMem();

main()
{
    char *ptr;
    long bytes = 1 << 9;

    while (ptr = AllocMem(bytes, MEMF_PUBLIC)) {
	FreeMem(ptr, bytes);
	bytes <<= 1;
    }
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'mountlist'" '(89 characters)'
if test -f 'mountlist'
then
	echo shar: "will not over-write existing file 'mountlist'"
else
cat << \!Funky!Stuff! > 'mountlist'

TEST:	   Handler = ram:device
	   Stacksize = 2048
	   Priority = 5
	   GlobVec  = 1
#

!Funky!Stuff!
fi  # end of overwriting check
exit 0
#	End of shell archive

steveb@cbmvax.UUCP (Steve Beats) (10/21/87)

In article <8710210733.AA18361@cory.Berkeley.EDU> dillon@CORY.BERKELEY.EDU (Matt Dillon) writes:
>	As usual, any and all Feedback will be appreciated.  I plan to do
>another one in the future which exploits the packet types not implemented
>in this one (some just don't apply to a simple ram disk).  I plan to update
>this one as soon as I can figure out (or somebody can describe to me) how
>to make the system recognize the thing in INFO and Info()... sigh.

The problem you are having with these various _INFO packets is the different
arrangements of the args.  The following should clarify things :-

ACTION_INFO		dp_Arg1 = BPTR to DiskInfo structure

ACTION_DISK_INFO	dp_Arg1 = BPTR to a lock on this volume
			dp_Arg2 = BPTR to DiskInfo structure

The ACTION_DISK_INFO packet appears to be used exclusively by WorkBench but it'spossible that other applications will use it too.  When DOS gets this packet it
just checks the lock for validity before dropping through to the ACTION_INFO
handler.

Hope this speeds up the second release :-)

Steve