home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format 56
/
af056sub.adf
/
parnfs.lha
/
pack.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-02
|
22KB
|
830 lines
/*-
* $Id: pack.c,v 1.1 1993/12/02 20:45:46 Rhialto Exp $
* $Log: pack.c,v $
* Revision 1.1 1993/12/02 20:45:46 Rhialto
* Initial revision
*
*
* Originally:
*
* DOSDEVICE.C V1.10 2 November 1987
*
* EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C PUBLIC DOMAIN.
*
* By Matthew Dillon.
*
* This has been stripped and refilled with network filesystem code
* by Olaf Seibert.
*
* This code is (C) Copyright 1993 by Olaf Seibert. All rights reserved.
* May not be used or copied without a licence.
-*/
#include "netfs.h"
#include <string.h>
#ifdef DEBUG
# include "syslog.h"
#else
# define debug(x)
#endif
#define NETFL(something) ((NetFileLock *)(something))
#define NETFH(something) ((NetFileHandle *)(something))
Prototype struct ExecBase *SysBase;
Prototype struct MsgPort *DosPort;
Prototype struct DeviceNode *DevNode;
Prototype struct DeviceList *VolNode;
Prototype long UnitNr;
Prototype char *DevName;
Prototype ULONG DevFlags;
Prototype struct DosPacket *DosPacket;
Prototype ULONG error;
Local BPTR MakeFileLock(NetFileLock *netfl, struct FileLock *fl, long mode);
/*
* 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.
*/
struct MsgPort *DosPort; /* Our DOS port... */
struct DeviceNode *DevNode; /* Our DOS node.. created by DOS for us */
struct DeviceList *VolNode; /* Device List structure for our volume
* node */
struct DosLibrary *DOSBase; /* DOS library base */
long WaitMask; /* The signal mask to wait for */
long UnitNr; /* From */
char *DevName; /* the */
ULONG DevFlags; /* mountlist */
struct DosPacket *DosPacket; /* For the SystemRequest pr_WindowPtr */
long OpenCount; /* How many open files/locks there are */
ULONG error;
/*
* Don't call the entry point main(). This way, if you make a mistake
* with the compile options you'll get a link error.
*/
Prototype void netfilesyshandler(void);
void
handlermain(void)
{
register struct DosPacket *packet;
struct Message *msg;
short done;
/*
* Initialize all global variables. SysBase MUST be initialized
* before we can make Exec calls. AbsExecBase is a library symbol
* referencing absolute memory location 4.
*/
DOSBase = OpenLibrary("dos.library", 0L);
#ifdef DEBUG
/*
* Initialize debugging code as soon as possible. Only SysBase required.
*/
initsyslog();
#endif /* DEBUG */
DosPort = &((struct Process *)FindTask(NULL))->pr_MsgPort;
debug(("WaitPort DosPort for startup...\n"));
WaitPort(DosPort); /* Get Startup Packet */
debug(("WaitPort DosPort done\n"));
msg = GetMsg(DosPort);
packet = (struct DosPacket *) msg->mn_Node.ln_Name;
DevNode = BTOC(PArg3);
{
struct FileSysStartupMsg *fssm;
struct DosEnvec *de;
DevName = "parnet.device";
UnitNr = 0;
DevFlags = 0;
if (fssm = (struct FileSysStartupMsg *)BTOC(DevNode->dn_Startup)) {
/* Same as BTOC(packet->dp_Arg2) */
UnitNr = fssm->fssm_Unit;
if (fssm->fssm_Device)
DevName = (char *)BTOC(fssm->fssm_Device)+1;
DevFlags = fssm->fssm_Flags;
de = BTOC(fssm->fssm_Environ);
ClientDefaults(de->de_BlocksPerTrack, de->de_Interleave);
}
}
if (DOSBase && OpenNetFS() == 0) {
/*
* Loading DevNode->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.
*/
DevNode->dn_Task = DosPort;
PRes1 = DOSTRUE;
PRes2 = 0;
} else { /* couldn't open dos.library */
PRes1 = DOSFALSE;
PRes2 = ERROR_DEVICE_NOT_MOUNTED; /* no better message available */
returnpacket(packet);
goto exit; /* exit process */
}
returnpacket(packet);
/*
* Get the first real packet.
* This seems to be necessary because adding our Volume node at
* this point causes some kind of deadlock. Which is kind
* of silly since we returned the startup packet. Even calling
* AttemptLockDosList does not seem to give any indication...
*/
debug(("WaitPort DosPort for 1st real packet...\n"));
WaitPort(DosPort);
debug(("WaitPort DosPort done\n"));
msg = GetMsg(DosPort);
{
struct DateStamp ds;
DateStamp(&ds);
VolNode = NewVolNode("Network", &ds);
debug(("VolNode done\n"));
}
/* Initialize some more global variables */
OpenCount = 0;
WaitMask = (1L << DosPort->mp_SigBit) |
(1L << RdPort->mp_SigBit);
done = -1;
goto entry;
/*
* Here begins the endless loop, waiting for requests over our message
* port and executing them. Since requests are sent over the message
* port in our device and volume nodes, we must not use our Process
* message port for this: this precludes being able to call DOS
* functions ourselves.
*/
top:
for (done = -1; done < 0;) {
Wait(WaitMask);
wakeup:
while (msg = GetMsg(RdPort)) {
/* Handle unsollicited network input */
DoProtocol(msg, ((struct IOStdReq *)msg)->io_Data);
}
while (msg = GetMsg(DosPort)) {
entry:
packet = (PACKET *) msg->mn_Node.ln_Name;
PRes1 = DOSFALSE;
PRes2 = 0;
error = 0;
debug(("Packet: %4ld %08lx %08lx %08lx %s\n",
PType, PArg1, PArg2, PArg3, typetostr(PType)));
DosPacket = packet; /* For the System Requesters */
ReqPacket.p_Action = PType;
switch (PType) {
case ACTION_DIE: /* attempt to die? */
done = (PArg1 == MSH_MAGIC) ? PArg2 : 0; /* Argh! Hack! */
break;
case ACTION_CURRENT_VOLUME: /* - VolNode,UnitNr*/
PRes1 = (long) CTOB(VolNode);
PRes2 = UnitNr;
break;
case ACTION_LOCATE_OBJECT: /* Lock,Name,Mode Lock */
{
struct FileLock *lock;
NetFileLock *netfl;
long lockmode;
lock = BTOC(PArg1);
if ((lockmode = PArg3) != EXCLUSIVE_LOCK)
lockmode = SHARED_LOCK;
netfl = NetLock(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg2),
lockmode);
PRes1 = MakeFileLock(netfl, lock, lockmode);
}
break;
case ACTION_RENAME_DISK: /* BSTR:NewName Bool */
NewVolNodeName(BTOC(PArg1));
PRes1 = DOSTRUE;
break;
case ACTION_FREE_LOCK: /* Lock Bool */
{
struct FileLock *lock;
NetFileLock *netfl;
PRes1 = DOSTRUE;
lock = BTOC(PArg1);
if (lock == NULL)
break;
netfl = NETFL(lock->fl_Key);
FreeFileLock(lock);
NetUnLock(netfl);
}
break;
case ACTION_DELETE_OBJECT: /* Lock,Name Bool */
{
struct FileLock *lock;
lock = BTOC(PArg1);
PRes1 = NetDeleteFile(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg2));
}
break;
case ACTION_RENAME_OBJECT: /* SLock,SName,DLock,DName Bool */
{
struct FileLock *slock, *dlock;
slock = BTOC(PArg1);
dlock = BTOC(PArg3);
PRes1 = NetRename(NETFL(slock ? slock->fl_Key : 0),
BTOC(PArg2),
NETFL(dlock ? dlock->fl_Key : 0),
BTOC(PArg4));
}
break;
case ACTION_MORECACHE: /* #BufsToAdd bool,numbufs */
PRes1 = 0; /* observed behaviour in std filesystem */
PRes2 = 0; /* documented behaviour in manual */
break;
case ACTION_COPY_DIR: /* Lock Lock */
{
struct FileLock *lock;
NetFileLock *netfl;
lock = BTOC(PArg1);
netfl = NetDupLock(NETFL(lock ? lock->fl_Key : 0));
PRes1 = MakeFileLock(netfl, lock,
lock ? lock->fl_Access : SHARED_LOCK);
}
break;
case ACTION_SET_PROTECT: /* -,Lock,Name,Mask Bool */
{
struct FileLock *lock;
lock = BTOC(PArg2);
PRes1 = NetSetProtect(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg3), PArg4);
}
break;
case ACTION_CREATE_DIR: /* Lock,Name Lock */
{
struct FileLock *lock;
NetFileLock *netfl;
lock = BTOC(PArg1);
netfl = NetCreateDir(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg2));
PRes1 = MakeFileLock(netfl, lock, SHARED_LOCK);
}
break;
case ACTION_EXAMINE_OBJECT: /* Lock,Fib Bool */
{
struct FileLock *lock;
lock = BTOC(PArg1);
PRes1 = NetExamine(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg2));
}
break;
case ACTION_EXAMINE_NEXT: /* Lock,Fib Bool */
{
struct FileLock *lock;
lock = BTOC(PArg1);
PRes1 = NetExNext(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg2));
}
break;
case ACTION_DISK_INFO: /* InfoData Bool:TRUE */
PRes1 = NetDiskInfo(BTOC(PArg1));
break;
case ACTION_INFO: /* Lock,InfoData Bool:TRUE */
{
struct FileLock *lock;
lock = BTOC(PArg1);
PRes1 = NetInfo(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg2));
}
break;
/* case ACTION_FLUSH: / * writeout bufs, disk motor off */
case ACTION_SET_COMMENT: /* -,Lock,Name,Comment Bool */
{
struct FileLock *lock;
lock = BTOC(PArg2);
PRes1 = NetSetComment(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg3), BTOC(PArg4));
}
break;
case ACTION_PARENT: /* Lock ParentLock */
{
struct FileLock *lock;
NetFileLock *netfl;
lock = BTOC(PArg1);
netfl = NetParentDir(NETFL(lock ? lock->fl_Key : 0));
PRes1 = MakeFileLock(netfl, lock, SHARED_LOCK);
}
break;
case ACTION_INHIBIT: /* Bool Bool */
PRes1 = DOSFALSE;
break;
case ACTION_SET_DATE: /* -,Lock,Name,CPTRDateStamp Bool */
{
struct FileLock *lock;
lock = BTOC(PArg2);
PRes1 = NetSetDate(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg3),
(struct DateStamp *)PArg4);
}
break;
case ACTION_SAME_LOCK: /* Lock1,Lock2 Result */
{
struct FileLock *fl1, *fl2;
fl1 = BTOC(PArg1);
fl2 = BTOC(PArg2);
if (fl1->fl_Volume == fl2->fl_Volume &&
BTOC(fl1->fl_Volume) == VolNode) {
PRes1 = NetSameLock(NETFL(fl1->fl_Key),
NETFL(fl2->fl_Key));
} else {
PRes1 = DOSFALSE;
error = ERROR_INVALID_LOCK;
}
}
break;
case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */
PRes1 = NetRead(NETFH(PArg1), (UBYTE *)PArg2, PArg3);
break;
case ACTION_WRITE: /* FHArg1,CPTRBuffer,Length ActLength */
PRes1 = NetWrite(NETFH(PArg1), (UBYTE *)PArg2, PArg3);
break;
case ACTION_OPENRW: /* FileHandle,Lock,Name Bool */
case ACTION_OPENOLD: /* FileHandle,Lock,Name Bool */
case ACTION_OPENNEW: /* FileHandle,Lock,Name Bool */
{
NetFileHandle *netfh;
struct FileHandle *fh;
struct FileLock *lock;
fh = BTOC(PArg1);
lock = BTOC(PArg2);
netfh = NetOpen(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg3),
PType);
if (netfh) {
fh->fh_Arg1 = (long) netfh;
PRes1 = DOSTRUE;
OpenCount++;
}
}
break;
case ACTION_CLOSE: /* FHArg1 Bool:Success */
PRes1 = NetClose(NETFH(PArg1));
OpenCount--;
break;
case ACTION_SEEK: /* FHArg1,Position,Mode OldPosition */
PRes1 = NetSeek(NETFH(PArg1), PArg2, PArg3);
break;
#ifdef notdef
case ACTION_FORMAT: /* vol,type Bool:success */
PRes1 = NetFormat(BTOC(PArg1), PArg2);
break;
#endif
case ACTION_MAKE_LINK: /* parent,name,target,soft Bool */
{
struct FileLock *lock;
void *dest;
lock = BTOC(PArg1);
dest = PArg4 ? (char *)PArg3 /* C string! */
: (void *)((struct FileLock *)BTOC(PArg3))->fl_Key;
PRes1 = NetMakeLink(NETFL(lock ? lock->fl_Key : 0),
BTOC(PArg2),
dest,
PArg4);
}
break;
case ACTION_READ_LINK: /* parent,name,target,size length */
{
struct FileLock *lock;
lock = BTOC(PArg1);
PRes1 = NetReadLink(NETFL(lock ? lock->fl_Key : 0),
(char *)PArg2, /* C string! */
(char *)PArg3,
PArg4);
}
break;
case ACTION_SET_FILE_SIZE:
PRes1 = NetSetFileSize(NETFH(PArg1), PArg2, PArg3);
break;
/* case ACTION_WRITE_PROTECT: */
/* FH,Lock BOOL */
case ACTION_FH_FROM_LOCK:
{
NetFileHandle *netfh;
struct FileHandle *fh;
struct FileLock *lock;
fh = BTOC(PArg1);
lock = BTOC(PArg2);
netfh = NetOpenFromLock(NETFL(lock ? lock->fl_Key : 0));
if (netfh) {
fh->fh_Arg1 = (long) netfh;
PRes1 = DOSTRUE;
OpenCount++;
/* Discard the lock */
FreeFileLock(lock);
}
}
break;
case ACTION_IS_FILESYSTEM:
PRes1 = DOSTRUE;
break;
case ACTION_CHANGE_MODE:
{
void *object;
switch (PArg1) {
case CHANGE_FH:
object = NETFH(((struct FileHandle *)BTOC(PArg2))->fh_Arg1);
break;
case CHANGE_LOCK:
object = NETFL(((struct FileLock *)BTOC(PArg2))->fl_Key);
break;
}
PRes1 = NetChangeMode(PArg1, object, PArg3);
}
break;
case ACTION_COPY_DIR_FH: /* fh_Arg1 Lock */
case ACTION_PARENT_FH:
{
NetFileLock *netfl;
if (PType == ACTION_PARENT_FH)
netfl = NetParentOfFH(NETFH(PArg1));
else
netfl = NetDupLockFromFH(NETFH(PArg1));
/* User has inserted disk by now, so we can use VolNode */
PRes1 = MakeFileLock(netfl, NULL, SHARED_LOCK);
}
break;
case ACTION_EXAMINE_FH: /* fh_Arg1,Fib Bool */
PRes1 = NetExamineFH(NETFH(PArg1), BTOC(PArg2));
break;
/*
* A few other packet types which we do not support
*/
case ACTION_LOCK_RECORD: /* fh,pos,len,mode,time Bool */
{
debug(("fh(arg1) %x\n", PArg1));
NetLockRecord(packet, NETFH(PArg1), PArg2, PArg3, PArg4, PArg5);
packet = NULL;
}
break;
case ACTION_FREE_RECORD: /* fh,pos,len Bool */
{
debug(("fh(arg1) %x\n", PArg1));
/* NetFileHandle *netfh = NETFH(((struct FileHandle *)
PArg1)->fh_Arg1); */
PRes1 = NetFreeRecord(NETFH(PArg1), PArg2, PArg3);
}
break;
/* case ACTION_WAIT_CHAR: / * Timeout, ticks Bool */
/* case ACTION_RAWMODE: / * Bool(-1:RAW 0:CON) OldState */
default:
PRes1 = DOSFALSE;
error = ERROR_ACTION_NOT_KNOWN;
break;
} /* end switch */
if (packet) {
if (error)
PRes2 = error;
debug(("RES=%06lx, ERR=%ld\n", PRes1, error));
returnpacket(packet);
DosPacket = NULL;
}
#ifdef DEBUG
else {
debug(("NOREP\n"));
}
#endif
} /* end while (GetMsg()) */
} /* end for (;done) */
#ifdef DEBUG
debug(("Can we remove ourselves? "));
#endif /* DEBUG */
Forbid();
if (OpenCount || packetsqueued()) {
Permit();
debug((" .. not yet!\n"));
goto top; /* sorry... can't exit */
}
debug((" .. yes!\n"));
/*
* Causes a new process to be created on next reference.
*/
DevNode->dn_Task = NULL;
CloseNetFS();
FreeVolNode(VolNode);
debug(("CloseNetFS() returned.\n"));
/*
* Remove debug, closedown, fall of the end of the world.
*/
exit:
#ifdef DEBUG
uninitsyslog();
#endif /* DEBUG */
if (done & 2)
UnLoadSeg(DevNode->dn_SegList); /* This is real fun. We are still */
if (done & (2 | 1))
DevNode->dn_SegList = NULL; /* Forbid()den, fortunately */
CloseLibrary((struct Library *)DOSBase);
/* Fall off the end of the world. Implicit Permit(). */
}
/*
* Make a new struct FileLock, for DOS use. It is put on a singly linked
* list, which is attached to the same VolumeNode the old lock was on.
*
* Also note that we must ALWAYS be prepared to UnLock() or DupLock()
* any FileLocks we ever made, even if the volume in question has been
* removed and/or inserted into another drive with another FileSystem
* handler!
*
* 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). Also, it sometimes uses uninitialized values for the lock mode...
*/
Prototype struct FileLock *NewFileLock(NetFileLock *netfl, struct FileLock *fl);
struct FileLock *
NewFileLock(NetFileLock *netfl, struct FileLock *fl)
{
struct FileLock *newlock;
struct DeviceList *volnode = NULL;
if (fl) {
volnode = BTOC(fl->fl_Volume);
}
if (volnode == NULL) {
volnode = VolNode;
debug(("volnode 0->%lx\n", volnode));
}
#ifdef DEBUG
if (volnode != VolNode) {
debug(("volnode != VolNode %lx != %lx\n",
volnode, VolNode));
}
if (volnode->dl_Task != DosPort) {
debug(("volnode->dl_Task != DosPort %lx != %lx\n",
volnode->dl_Task, DosPort));
}
#endif
if (newlock = dosalloc((ULONG)sizeof (*newlock))) {
newlock->fl_Key = (ULONG) netfl;
newlock->fl_Task = DosPort;
newlock->fl_Volume = (BPTR) CTOB(volnode);
Forbid();
newlock->fl_Link = volnode->dl_LockList;
volnode->dl_LockList = (BPTR) CTOB(newlock);
Permit();
} else
error = ERROR_NO_FREE_STORE;
return newlock;
}
Prototype long FreeFileLock(struct FileLock *lock);
long
FreeFileLock(struct FileLock *lock)
{
register struct FileLock *fl;
register struct FileLock **flp;
struct DeviceList *volnode;
volnode = (struct DeviceList *)BTOC(lock->fl_Volume);
flp = (struct FileLock **) &volnode->dl_LockList;
for (fl = BTOC(*flp); fl && fl != lock; fl = BTOC(fl->fl_Link))
flp = (struct FileLock **)&fl->fl_Link;
if (fl == lock) {
*(BPTR *)flp = fl->fl_Link;
dosfree((ULONG *)fl);
OpenCount--;
return DOSTRUE;
} else {
debug(("Huh?? Could not find filelock!\n"));
return DOSFALSE;
}
}
/*
* MakeFileLock allocates and initializes a new FileLock, using info
* from an existing FileLock. It always consumes the NetFileLock, even
* in case of failure.
*/
Prototype BPTR MakeFileLock(NetFileLock *netfl, struct FileLock *fl, long mode);
BPTR
MakeFileLock(NetFileLock *netfl, struct FileLock *fl, long mode)
{
struct FileLock *newlock;
newlock = NULL;
if (netfl) {
if (newlock = NewFileLock(netfl, fl)) {
newlock->fl_Access = mode;
OpenCount++;
} else
NetUnLock(netfl);
}
return CTOB(newlock);
}
/*
* 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 NET: disk, Volume node or not.
*/
Prototype struct DeviceList *NewVolNode(char *name, struct DateStamp *date);
struct DeviceList *
NewVolNode(char *name, struct DateStamp *date)
{
struct DeviceList *volnode;
char *volname; /* This is my volume name */
if (volnode = dosalloc((ULONG)sizeof (struct DeviceList))) {
if (volname = dosalloc(33L)) {
volname[0] = strlen(name);
strcpy(volname + 1, name); /* Make sure \0 terminated */
volnode->dl_Type = DLT_VOLUME;
volnode->dl_Task = DosPort;
volnode->dl_DiskType = ID_DOS_DISK;
volnode->dl_Name = (BSTR *)CTOB(volname);
volnode->dl_VolumeDate = *date;
volnode->dl_NetFileLockList = NULL;
if (DOSBase->dl_lib.lib_Version >= 37) {
struct DosList *dl;
debug(("LockDosList...\n"));
dl = AttemptLockDosList(LDF_VOLUMES | LDF_DEVICES | LDF_WRITE);
if ((ULONG)dl <= 1) {
debug(("LockDosList NOT ok\n"));
goto brute_force;
}
UnLockDosList(LDF_VOLUMES | LDF_DEVICES | LDF_WRITE);
debug(("AddDosEntry...\n"));
if (AddDosEntry((struct DosList *)volnode) == DOSFALSE) {
debug(("AddDosEntry for VolNode fails!\n"));
goto error;
}
debug(("AddDosEntry: done\n"));
} else {
struct DosInfo *di;
brute_force:
di = BTOC(((struct RootNode *) DOSBase->dl_Root)->rn_Info);
Forbid();
volnode->dl_Next = di->di_DevInfo;
di->di_DevInfo = (long) CTOB(volnode);
Permit();
}
} else {
error:
dosfree((ULONG *)volnode);
volnode = NULL;
}
} else {
error = ERROR_NO_FREE_STORE;
}
return volnode;
}
/*
* Give the VolNode a new name (given as a BCPL string).
*/
Prototype void NewVolNodeName(char *newname);
void
NewVolNodeName(char *newname)
{
if (VolNode) {
register char *volname = BTOC(VolNode->dl_Name);
memcpy(volname, newname, 1 + newname[0]);
}
}
/*
* Remove Volume entry. Since DOS uses singly linked lists, we must
* (ugg) search it manually to find the link before our Volume entry.
*/
Prototype void FreeVolNode(struct DeviceList *volnode);
void
FreeVolNode(struct DeviceList *volnode)
{
debug(("FreeVolNode %08lx\n", volnode));
if (volnode == NULL)
return;
if (DOSBase->dl_lib.lib_Version >= 37) {
struct DosList *dl;
dl = LockDosList(LDF_VOLUMES | LDF_WRITE);
(void)RemDosEntry((struct DosList *)volnode);
UnLockDosList(LDF_VOLUMES | LDF_WRITE);
} else {
struct DosInfo *di = BTOC(((struct RootNode *) DOSBase->dl_Root)->rn_Info);
register struct DeviceList *dl;
register void *dlp;
dlp = &di->di_DevInfo;
Forbid();
for (dl = BTOC(di->di_DevInfo); dl && dl != volnode; dl = BTOC(dl->dl_Next))
dlp = &dl->dl_Next;
if (dl == volnode) {
*(BPTR *) dlp = dl->dl_Next;
}
#ifdef DEBUG
else {
debug(("****PANIC: Unable to find volume node\n"));
}
#endif /* DEBUG */
Permit();
}
dosfree(BTOC(volnode->dl_Name));
dosfree((ULONG *)volnode);
if (volnode == VolNode)
VolNode = NULL;
}