home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * DOSDEVICE.C V1.10 2 November 1987
- *
- * EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C PUBLIC DOMAIN.
- *
- * By Matthew Dillon.
- *
- * Debugging routines are disabled by simply attempting to open the
- * file "debugoff", turned on again with "debugon". No prefix may be
- * attached to these names (you must be CD'd to TEST:).
- *
- * See Documentation for a detailed discussion.
- *
- * BUGS:
- * Currently the only known bug is with the implementation of the
- * RAM disk itself. Specifically, if filehandle A is at the end of
- * the file, and somebody appends to the file with another filehandle,
- * B, filehandle A will get confused as to it's current position in
- * the file.
- *
- * I am probably not updating all the right timestamps. This is
- * easy to fix... All you have to do is fool with the floppy and
- * see which datestamps get updated for certain operations.
- */
-
- #include "dos.h"
-
- /*
- * Since this code might be called several times in a row without being
- * unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!! This also goes
- * for any global/static assignments that might be changed by running the
- * code.
- */
-
- PROC *DosProc; /* Our Process */
- DEVNODE *DosNode; /* Our DOS node.. created by DOS for us */
- DEVLIST *DevList; /* Device List structure for our volume node */
-
- void *SysBase; /* EXEC library base */
- DOSLIB *DOSBase; /* DOS library base for debug process */
- RAMFILE RFRoot; /* Directory/File structure (root node) */
- LIST FHBase; /* Open Files */
- LIST LCBase; /* Open Locks */
-
- long TotalBytes; /* total bytes of data in filesystem */
-
-
- /* DEBUGGING */
- PORT *Dbport; /* owned by the debug process */
- PORT *Dback; /* owned by the DOS device driver */
- short DBDisable;
- MSG DummyMsg; /* Dummy message that debug proc can use */
-
- /*
- * Don't call the entry point main(). This way, if you make a mistake
- * with the compile options you'll get a link error.
- */
-
- void
- noname()
- {
- register PACKET *packet;
- register short error;
- MSG *msg;
- ubyte notdone;
- ubyte buf[256];
- void *tmp;
-
- /*
- * 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 only.
- */
-
- DBDisable = 0; /* Init. globals */
- Dbport = Dback = NULL;
- TotalBytes = 0;
- SysBase = AbsExecBase;
- DOSBase = OpenLibrary("dos.library",0);
- DosProc = FindTask(NULL);
- {
- WaitPort(&DosProc->pr_MsgPort); /* Get 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) {
- DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
- register DEVLIST *dl = dosalloc(sizeof(DEVLIST));
-
- DosNode = BTOC(packet->dp_Arg3);
-
- /*
- * Create Volume node and add to the device list. This will
- * cause the WORKBENCH to recognize us as a disk. If we don't
- * create a Volume node, Wb will not recognize us. However,
- * we are a RAM: disk, Volume node or not.
- */
-
- DevList = dl;
- dl->dl_Type = DLT_VOLUME;
- dl->dl_Task = &DosProc->pr_MsgPort;
- dl->dl_DiskType = ID_DOS_DISK;
- dl->dl_Name = (void *)DosNode->dn_Name;
- dl->dl_Next = di->di_DevInfo;
- di->di_DevInfo = (long)CTOB(dl);
-
- /*
- * Set dn_Task field which tells DOS not to startup a new
- * process on every reference.
- */
-
- DosNode->dn_Task = &DosProc->pr_MsgPort;
- packet->dp_Res1 = DOS_TRUE;
- packet->dp_Res2 = 0;
- } else { /* couldn't open dos.library */
- packet->dp_Res1 = DOS_FALSE;
- returnpacket(packet);
- return; /* exit process */
- }
- returnpacket(packet);
- }
-
- /*
- * Initialize debugging code
- */
-
- dbinit(); /* this can be removed */
-
- /* Initialize RAM disk */
-
- {
- ubyte *ptr = BTOC(DosNode->dn_Name);
- short len = *ptr;
-
- NewList(&FHBase); /* more globals */
- NewList(&LCBase);
- bzero(&RFRoot,sizeof(RFRoot));
- RFRoot.type = FILE_DIR; /* root directory */
- DateStamp(&RFRoot.date); /* datestamp */
- NewList(&RFRoot.list); /* sub dirs */
- RFRoot.name = AllocMem(len+1, MEMF_PUBLIC); /* Root NAME */
- bmov(ptr+1,RFRoot.name,len);
- RFRoot.name[len] = 0;
- dbprintf("ROOT NAME: %ld '%s'\n", len, RFRoot.name);
- }
-
- /*
- * Here begins the endless loop, waiting for requests over our
- * message port and executing them. Since requests are sent over
- * our message port, this precludes being able to call DOS functions
- * ourselves (that is why the debugging routines are a separate process)
- */
-
- top:
- for (notdone = 1; notdone;) {
- WaitPort(&DosProc->pr_MsgPort);
- 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 %10s ",
- packet->dp_Type,
- packet->dp_Arg1, packet->dp_Arg2,
- packet->dp_Arg3,
- typetostr(packet->dp_Type)
- );
-
- switch(packet->dp_Type) {
- case ACTION_DIE: /* attempt to die? */
- notdone = 0; /* try to die */
- 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);
- dbprintf("'%s' ", buf);
- if (strcmp(buf,"debugoff") == 0)
- DBDisable = 1;
- if (strcmp(buf,"debugon") == 0)
- DBDisable = 0;
- if (ramfile = searchpath(&parentdir,buf,&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->protection = 0;
- }
- --ramfile->locks;
- }
- }
- } else {
- if (!parentdir) {
- error = ERROR_INVALID_COMPONENT_NAME;
- goto openbreak;
- }
- if (packet->dp_Type == ACTION_OPENNEW) {
- ramfile = createramfile(parentdir, FILE_FILE, ptr);
- --ramfile->locks;
- } 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;
- 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;
-
- while (left && fen) {
- scr = fen->bytes - mfh->offset;
- 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;
- ubyte *ptr = (ubyte *)packet->dp_Arg2;
- long left = packet->dp_Arg3;
- long scr;
-
- /*
- * Doesn't work right if multiple readers/appenders.
- */
-
- while (left) {
- if (fen) {
- dbprintf("FEN: %ld left: %ld\n", fen->bytes, left);
- scr = fen->bytes - mfh->offset;
- if (left < scr) {
- if (fen->bytes < mfh->offset + left)
- dbprintf("PANIC! AWR0\n");
- else
- bmov(ptr, fen->buf + mfh->offset, left);
- mfh->offset += left;
- left = 0;
- } else {
- if (fen->bytes < mfh->offset + scr)
- dbprintf("PANIC! AWR1\n");
- else
- bmov(ptr, fen->buf + mfh->offset, scr);
- ptr += scr;
- left -= scr;
- mfh->base += fen->bytes;
- mfh->offset = 0;
- fen = NextNode(fen);
- }
- } else {
- fen = AllocMem(sizeof(FENTRY), MEMF_PUBLIC);
- if (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);
- dbprintf("NEWFEN: (%ld)\n", fen->bytes);
- bmov(ptr, fen->buf, left);
- left = 0;
- } else {
- FreeMem(fen, sizeof(FENTRY));
- dbprintf("NEWFEN: ****** Unable to allocate buffer %ld\n", left);
- mfh->offset = 0;
- break;
- }
- 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;
- /*
- * This implementation sucks. The right way to do it is with
- * a hash table. The directory must be searched for the file
- * name, then the next entry retrieved. If the next entry is
- * NULL there are no more entries. If the filename could not
- * be found we return the first entry, if any.
- *
- * You can't simply keep a pointer around to the next node
- * because it can be moved or removed at any time.
- */
-
- case ACTION_EXAMINE_NEXT: /* Lock,Fib Bool */
- {
- register FIB *fib = BTOC(packet->dp_Arg2);
- register RAMFILE *dir = getlockfile(packet->dp_Arg1);
- register RAMFILE *file;
-
- if (dir->type == FILE_FILE) {
- error = ERROR_OBJECT_WRONG_TYPE;
- break;
- }
- file = GetHead(&dir->list);
- if (fib->fib_DiskKey) {
- register int len = *(ubyte *)fib->fib_FileName;
- for (; file; file = NextNode(file)) {
- if (strlen(file->name) == len && nccmp(file->name, fib->fib_FileName+1, len))
- break;
- }
- if (file)
- file = NextNode(file);
- else
- file = GetHead(&dir->list);
- }
- fib->fib_DiskKey = 1;
- error = -1;
- if (!(tmp=file)) {
- error = ERROR_NO_MORE_ENTRIES;
- break;
- }
- }
- /* fall through */
- case ACTION_EXAMINE_OBJECT: /* Lock,Fib Bool */
- {
- register FIB *fib;
- register RAMFILE *file;
- register RAMFILE *dummy;
-
- fib = BTOC(packet->dp_Arg2);
- if (error) {
- file = tmp; /* fall through from above */
- } else {
- file = getlockfile(packet->dp_Arg1);
- fib->fib_DiskKey = 0;
- }
- error = 0;
- 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;
- }
- }
- break;
- case ACTION_INFO: /* Lock, InfoData Bool:TRUE */
- tmp = BTOC(packet->dp_Arg2);
- error = -1;
- /* fall through */
- case ACTION_DISK_INFO: /* InfoData Bool:TRUE */
- {
- register INFODATA *id;
-
- /*
- * Note: id_NumBlocks is never 0, but only to get
- * around a bug I found in my shell (where I divide
- * by id_NumBlocks). Other programs probably break
- * as well.
- */
-
- (error) ? (id = tmp) : (id = BTOC(packet->dp_Arg1));
- error = 0;
- bzero(id, sizeof(*id));
- id->id_DiskState = ID_VALIDATED;
- id->id_NumBlocks = (TotalBytes >> 9) + 1;
- id->id_NumBlocksUsed = (TotalBytes >> 9) + 1;
- id->id_BytesPerBlock = 512;
- id->id_DiskType = ID_DOS_DISK;
- id->id_VolumeNode = (long)CTOB(DosNode);
- id->id_InUse = (long)GetHead(&LCBase);
- }
- 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);
- DateStamp(&parentdir->date);
- }
- } 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);
- dbprintf("'%s' %ld ", buf, packet->dp_Arg3);
- 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;
- RAMFILE *sourcedir = getlockfile(packet->dp_Arg1);
- RAMFILE *destdir = getlockfile(packet->dp_Arg3);
- char *ptr;
-
- btos(packet->dp_Arg2,buf);
- dbprintf("\nRENAME '%s' (%ld) ", buf, strlen(buf));
- if (file1 = searchpath(&sourcedir,buf,NULL)) {
- btos(packet->dp_Arg4,buf);
- dbprintf("TO '%s' (%ld)", buf, strlen(buf));
- if (searchpath(&destdir,buf,&ptr)) {
- error = ERROR_OBJECT_EXISTS;
- } else {
- if (destdir) {
- if (file1 == destdir) { /* moving inside self */
- error = ERROR_OBJECT_IN_USE;
- break;
- }
- dbprintf("REN '%s' %ld", ptr, strlen(ptr));
- DateStamp(&sourcedir->date);
- DateStamp(&destdir->date);
- /*FreeMem(file1->name, strlen(file1->name)+1);*/
- Remove(file1);
- file1->name = AllocMem(strlen(ptr)+1,MEMF_PUBLIC);
- file1->parent = destdir;
- strcpy(file1->name, ptr);
- AddHead(&destdir->list, file1);
- } 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_INHIBIT: /* Bool Bool */
- /* Return success for the hell of it */
- break;
- case ACTION_RENAME_DISK:/* BSTR:NewName Bool */
- case ACTION_MORECACHE: /* #BufsToAdd 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) {
- dbprintf("ERR=%ld\n", error);
- packet->dp_Res1 = DOS_FALSE;
- packet->dp_Res2 = error;
- } else {
- dbprintf("RES=%06lx\n", packet->dp_Res1);
- }
- returnpacket(packet);
- }
- }
- }
- dbprintf("Can we remove ourselves? ");
- Delay(50); /* I wanna even see the debug message! */
- Forbid();
- if (packetsqueued(DosProc) || GetHead(&FHBase) || GetHead(&LCBase)
- || GetHead(&RFRoot.list)) {
- Permit();
- dbprintf(" .. not yet!\n");
- goto top; /* sorry... can't exit */
- }
-
- /*
- * Causes a new process to be created on next reference
- */
-
- DosNode->dn_Task = FALSE;
-
- /*
- * Remove Volume entry. Since DOS uses singly linked lists, we
- * must (ugg) search it manually to find the link before our
- * Volume entry.
- */
-
- {
- DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
- register DEVLIST *dl;
- register void *dlp;
-
- dlp = &di->di_DevInfo;
- for (dl = BTOC(di->di_DevInfo); dl && dl != DevList; dl = BTOC(dl->dl_Next))
- dlp = &dl->dl_Next;
- if (dl == DevList) {
- *(BPTR *)dlp = dl->dl_Next;
- dosfree(dl);
- } else {
- dbprintf("****PANIC: Unable to find volume node\n");
- }
- }
-
- /*
- * Remove debug process, closedown, fall of the end of the world
- * (which is how you kill yourself if a PROCESS. A TASK would have
- * had to RemTask(NULL) itself).
- */
-
- 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.
- *
- * NOTE!!!!! The workbench does not follow the rules and assumes it can
- * copy lock structures. This means that if you want to be workbench
- * compatible, your lock structures must be EXACTLY sizeof(struct FileLock).
- */
-
- 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.
- * I use normal strings for internal storage, and convert back and forth
- * when required.
- */
-
- void
- btos(bstr,buf)
- ubyte *bstr;
- ubyte *buf;
- {
- bstr = BTOC(bstr);
- bmov(bstr+1,buf,*bstr);
- buf[*bstr] = 0;
- }
-
- /*
- * Some EXEC list handling routines not found in the EXEC library.
- */
-
- 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);
- }
-
- /*
- * Compare two names which are at least n characters long each,
- * ignoring case.
- */
-
- 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);
- DateStamp(&ramfile->date);
- DateStamp(&ramfile->parent->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)) {
- dbprintf("FREE FEN: %08lx %08lx %ld\n", fen, fen->buf, fen->bytes);
- FreeMem(fen->buf, fen->bytes);
- FreeMem(fen, sizeof(*fen));
- }
- ramfile->bytes = 0;
- DateStamp(&ramfile->date);
- DateStamp(&ramfile->parent->date);
- }
-
- /*
- * Unlink and remove a file. Any data associated with the file or
- * directory has already been freed up.
- */
-
- void
- freeramfile(ramfile)
- RAMFILE *ramfile;
- {
- Remove(ramfile); /* unlink from parent directory */
- if (ramfile->name)
- FreeMem(ramfile->name,strlen(ramfile->name)+1);
- if (ramfile->comment)
- FreeMem(ramfile->comment,strlen(ramfile->comment)+1);
- FreeMem(ramfile,sizeof(*ramfile));
- }
-
- /*
- * The lock function. The file has already been checked to see if it
- * is lockable given the mode.
- */
-
- LOCK *
- ramlock(ramfile, mode)
- RAMFILE *ramfile;
- {
- LOCK *lock = dosalloc(sizeof(LOCK));
- LOCKLINK *ln;
-
- if (mode != ACCESS_WRITE)
- mode = ACCESS_READ;
- ln = AllocMem(sizeof(LOCKLINK), MEMF_PUBLIC);
- AddHead(&LCBase,ln);
- ln->lock = lock;
- lock->fl_Link= (long)ln;
- lock->fl_Key = (long)ramfile;
- lock->fl_Access = mode;
- lock->fl_Task = &DosProc->pr_MsgPort;
- lock->fl_Volume = (BPTR)CTOB(DosNode);
- if (mode == ACCESS_READ)
- ++ramfile->locks;
- else
- ramfile->locks = -1;
- return(lock);
- }
-
- void
- ramunlock(lock)
- LOCK *lock;
- {
- RAMFILE *file = (RAMFILE *)lock->fl_Key;
-
- Remove(lock->fl_Link); /* unlink from list */
- FreeMem(lock->fl_Link, sizeof(LOCKLINK)); /* free link node */
- if (lock->fl_Access == ACCESS_READ) /* undo lock effect */
- --file->locks;
- else
- file->locks = 0;
- dosfree(lock); /* free 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 LOCK */
- {
- register LOCK *rl = BTOC(lock);
-
- if (rl)
- return((RAMFILE *)rl->fl_Key);
- 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;
-
- *ppar = NULL;
- for (;*buf && file;) {
- ptr = getpathelement(&buf,&len);
- if (buf[0] == ':') { /* go to root */
- ++buf;
- file = &RFRoot;
- continue;
- }
- if (*ptr == '/') { /* go back a directory */
- if (!file->parent) { /* no parent directory */
- return(NULL);
- }
- file = file->parent;
- continue;
- }
- if (file->type == FILE_FILE)
- return(NULL);
- for (srch = GetHead(&file->list); srch; srch = NextNode(srch)) {
- if (srch->type && 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 */
- if (pptr)
- *pptr = ptr;
- return(NULL);
- }
- }
- if (pptr)
- *pptr = ptr;
- *ppar = 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;
- return(base);
- }
-
-
- char *
- typetostr(ty)
- {
- switch(ty) {
- case ACTION_DIE: return("DIE");
- case ACTION_OPENRW: return("OPEN-RW");
- case ACTION_OPENOLD: return("OPEN-OLD");
- case ACTION_OPENNEW: return("OPEN-NEW");
- case ACTION_READ: return("READ");
- case ACTION_WRITE: return("WRITE");
- case ACTION_CLOSE: return("CLOSE");
- case ACTION_SEEK: return("SEEK");
- case ACTION_EXAMINE_NEXT: return("EXAMINE NEXT");
- case ACTION_EXAMINE_OBJECT: return("EXAMINE OBJ");
- case ACTION_INFO: return("INFO");
- case ACTION_DISK_INFO: return("DISK INFO");
- case ACTION_PARENT: return("PARENTDIR");
- case ACTION_DELETE_OBJECT: return("DELETE");
- case ACTION_CREATE_DIR: return("CREATEDIR");
- case ACTION_LOCATE_OBJECT: return("LOCK");
- case ACTION_COPY_DIR: return("DUPLOCK");
- case ACTION_FREE_LOCK: return("FREELOCK");
- case ACTION_SET_PROTECT: return("SETPROTECT");
- case ACTION_SET_COMMENT: return("SETCOMMENT");
- case ACTION_RENAME_OBJECT: return("RENAME");
- case ACTION_INHIBIT: return("INHIBIT");
- case ACTION_RENAME_DISK: return("RENAME DISK");
- case ACTION_MORECACHE: return("MORE CACHE");
- case ACTION_WAIT_CHAR: return("WAIT FOR CHAR");
- case ACTION_FLUSH: return("FLUSH");
- case ACTION_RAWMODE: return("RAWMODE");
- default: return("---------UNKNOWN-------");
- }
- }
-
- /*
- * 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.10, 2 November 1987\n");
- dbprintf("Works with WORKBENCH!\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 around
- * the label.... Sigh.... (see CreatProc() above).
- */
-
- #asm
- public _debugproc
- public _debugmain
-
- cseg
- nop
- nop
- nop
- _debugproc:
- nop
- nop
- movem.l D2-D7/A2-A6,-(sp)
- jsr _debugmain
- movem.l (sp)+,D2-D7/A2-A6
- rts
- #endasm
-
-