Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (02/21/90)
Submitted-by: Olaf 'Rhialto' Seibert <U211344%HNYKUN11.BITNET@CUNYVM.CUNY.EDU>
Posting-number: Volume 90, Issue 083
Archive-name: devices/msh-1.5/part05
#!/bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 5 (of 6)."
# Contents: src/pack.c
# Wrapped by tadguy@xanth on Tue Feb 20 20:57:13 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/pack.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/pack.c'\"
else
echo shar: Extracting \"'src/pack.c'\" \(26316 characters\)
sed "s/^X//" >'src/pack.c' <<'END_OF_FILE'
X/*-
X * $Id: pack.c,v 1.3 90/02/03 17:02:05 Rhialto Exp $
X * $Log: pack.c,v $
X * Revision 1.3 90/02/03 17:02:05 Rhialto
X * Add error checking wrt dosalloc()
X *
X * Revision 1.2 89/12/17 23:06:54 Rhialto
X * Add ACTION_SET_PROTECT
X *
X * Revision 1.1 89/12/17 19:53:24 Rhialto
X * Initial revision
X *
X *
X * Originally:
X *
X * DOSDEVICE.C V1.10 2 November 1987
X *
X * EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C PUBLIC DOMAIN.
X *
X * By Matthew Dillon.
X *
X * This has been stripped and refilled with messydos code
X * by Olaf Seibert.
X *
X * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
X * not be used or copied without a licence.
X *
X * Please note that we are NOT pure, so if you wish to mount
X * multiple MSDOS units, you must use different copies of this driver.
X *
X * This file forms the interface between the actual handler code and all
X * AmigaDOS requirements. It shields it from ugly stuff like BPTRs, BSTRs,
X * FileLocks, FileHandles and VolumeNodes (in the form of DeviceLists).
X * Also, most protection against non-inserted disks is done here.
X-*/
X
X#include "dos.h"
X#include "han.h"
X
X#ifdef DEBUG
X# define debug(x) dbprintf x
X#else
X# define debug(x)
X#endif
X
X/*
X * Since this code might be called several times in a row without being
X * unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!! This also goes
X * for any global/static assignments that might be changed by running the
X * code.
X */
X
XPORT *DosPort; /* Our DOS port... */
XDEVNODE *DevNode; /* Our DOS node.. created by DOS for us */
XDEVLIST *VolNode; /* Device List structure for our volume
X * node */
X
Xvoid *SysBase; /* EXEC library base */
XDOSLIB *DOSBase; /* DOS library base for debug process */
Xlong PortMask; /* The signal mask for our DosPort */
Xlong WaitMask; /* The signal mask to wait for */
Xshort DiskChanged; /* Set by disk change interrupt */
Xshort Inhibited; /* Are we inhibited (ACTION_INHIBIT)? */
Xlong UnitNr; /* From */
Xchar *DevName; /* the */
Xulong DevFlags; /* mountlist */
XPACKET *DosPacket; /* For the SystemRequest pr_WindowPtr */
X
Xvoid ChangeIntHand(), DiskChange();
Xvoid NewVolNodeName(), NewVolNodeDate();
X
Xstruct Interrupt ChangeInt = {
X { 0 }, /* is_Node */
X 0, /* is_Data */
X ChangeIntHand, /* is_Code */
X};
X
X/*
X * Don't call the entry point main(). This way, if you make a mistake
X * with the compile options you'll get a link error.
X */
X
Xvoid
Xmessydoshandler()
X{
X register PACKET *packet;
X MSG *msg;
X byte notdone;
X long OpenCount; /* How many open files/locks there are */
X
X /*
X * Initialize all global variables. SysBase MUST be initialized
X * before we can make Exec calls. AbsExecBase is a library symbol
X * referencing absolute memory location 4.
X */
X
X SysBase = AbsExecBase;
X DOSBase = OpenLibrary("dos.library", 0L);
X
X#ifdef DEBUG
X /*
X * Initialize debugging code as soon as possible. Only SysBase and
X * DOSBase are required.
X */
X
X dbinit();
X#endif /* DEBUG */
X
X DosPort = &((struct Process *)FindTask(NULL))->pr_MsgPort;
X
X WaitPort(DosPort); /* Get Startup Packet */
X msg = GetMsg(DosPort);
X packet = (PACKET *) msg->mn_Node.ln_Name;
X
X
X DevNode = BTOC(PArg3);
X {
X struct FileSysStartupMsg *fssm;
X ulong *environ;
X
X DevName = "messydisk.device";
X UnitNr = 0;
X DevFlags = 0;
X
X MaxCache = 5;
X BufMemType = MEMF_PUBLIC;
X Disk.nsides = MS_NSIDES;
X Disk.spt = MS_SPT;
X Disk.bps = MS_BPS;
X Disk.lowcyl = 0;
X
X if (fssm = (struct FileSysStartupMsg *)BTOC(DevNode->dn_Startup)) {
X /* Same as BTOC(packet->dp_Arg2) */
X UnitNr = fssm->fssm_Unit;
X if (fssm->fssm_Device)
X DevName = (char *)BTOC(fssm->fssm_Device)+1;
X DevFlags = fssm->fssm_Flags;
X
X if (environ = BTOC(fssm->fssm_Environ)) {
X debug(("environ size %ld\n", environ[0]));
X#define get(xx,yy) if (environ[0] >= yy) xx = environ[yy];
X
X get(MaxCache, DE_NUMBUFFERS);
X get(BufMemType, DE_MEMBUFTYPE);
X get(Disk.nsides, DE_NUMHEADS);
X get(Disk.spt, DE_BLKSPERTRACK);
X get(Disk.bps, DE_SIZEBLOCK);
X Disk.bps *= 4;
X debug(("Disk.bps %d\n", Disk.bps));
X get(Disk.lowcyl, DE_LOWCYL);
X#undef get
X }
X }
X Disk.lowcyl *= (long)MS_BPS * Disk.spt * Disk.nsides;
X }
X
X if (DOSBase && HanOpenUp()) {
X /*
X * Loading DevNode->dn_Task causes DOS *NOT* to startup a new
X * instance of the device driver for every reference. E.G. if
X * you were writing a CON: device you would want this field to be
X * NULL.
X */
X
X DevNode->dn_Task = DosPort;
X
X PRes1 = DOSTRUE;
X PRes2 = 0;
X } else { /* couldn't open dos.library */
X PRes1 = DOSFALSE;
X PRes2 = ERROR_NO_FREE_STORE; /* no better message available */
X returnpacket(packet);
X goto exit; /* exit process */
X }
X returnpacket(packet);
X
X /* Initialize some more global variables */
X
X PortMask = 1L << DosPort->mp_SigBit;
X VolNode = NULL;
X OpenCount = 0;
X Inhibited = 0;
X
X /* Get the first real packet */
X WaitPort(DosPort);
X msg = GetMsg(DosPort);
X notdone = 1;
X WaitMask = PortMask | (1L << DiskReplyPort->mp_SigBit);
X TDAddChangeInt(&ChangeInt);
X DiskInserted(WhichDiskInserted());
X
X goto entry;
X
X /*
X * Here begins the endless loop, waiting for requests over our message
X * port and executing them. Since requests are sent over the message
X * port in our device and volume nodes, we must not use our Process
X * message port for this: this precludes being able to call DOS
X * functions ourselves.
X */
X
Xtop:
X for (notdone = 1; notdone;) {
X Wait(WaitMask);
X if (DiskChanged)
X DiskChange();
X while (msg = GetMsg(DosPort)) {
X byte buf[256]; /* Max length of BCPL strings is
X * 255 + 1 for \0. */
X
X entry:
X if (DiskChanged)
X DiskChange();
X packet = (PACKET *) msg->mn_Node.ln_Name;
X PRes1 = DOSFALSE;
X PRes2 = 0;
X error = 0;
X debug(("Packet: %3ld %08lx %08lx %08lx %10s\n",
X PType, PArg1, PArg2, PArg3, typetostr(PType)));
X
X DosPacket = packet; /* For the System Requesters */
X switch (PType) {
X case ACTION_DIE: /* attempt to die? */
X notdone = 0; /* try to die */
X break;
X case ACTION_CURRENT_VOLUME: /* - VolNode,UnitNr */
X PRes1 = (long) CTOB(VolNode);
X PRes2 = UnitNr;
X break;
X case ACTION_LOCATE_OBJECT: /* Lock,Name,Mode Lock */
X {
X register struct FileLock *newlock;
X struct FileLock *lock;
X struct MSFileLock *msfl;
X long lockmode;
X
X lock = BTOC(PArg1);
X if (CheckRead(lock))
X break;
X btos(PArg2, buf);
X if ((lockmode = PArg3) != EXCLUSIVE_LOCK)
X lockmode = SHARED_LOCK;
X msfl = MSLock(lock ? lock->fl_Key : NULL,
X buf,
X lockmode);
X if (msfl) {
X if (newlock = NewFileLock(msfl, lock)) {
X newlock->fl_Access = lockmode;
X PRes1 = (long) CTOB(newlock);
X OpenCount++;
X } else
X MSUnLock(msfl);
X }
X }
X break;
X case ACTION_RENAME_DISK: /* BSTR:NewName Bool */
X if (CheckWrite(NULL))
X break;
X btos(PArg1, buf);
X buf[31] = '\0';
X if (PRes1 = MSRelabel(buf))
X NewVolNodeName();
X break;
X case ACTION_FREE_LOCK: /* Lock Bool */
X {
X struct FileLock *lock;
X struct MSFileLock *msfl;
X
X PRes1 = DOSTRUE;
X lock = BTOC(PArg1);
X if (lock == NULL)
X break;
X
X msfl = (struct MSFileLock *)lock->fl_Key;
X FreeFileLock(lock); /* may remove last lock on volume */
X MSUnLock(msfl); /* may call MayFreeVolNode */
X OpenCount--;
X }
X break;
X case ACTION_DELETE_OBJECT: /* Lock,Name Bool */
X {
X struct FileLock *lock;
X
X lock = BTOC(PArg1);
X if (CheckWrite(lock))
X break;
X btos(PArg2, buf);
X PRes1 = MSDeleteFile(lock ? lock->fl_Key : NULL,
X buf);
X }
X break;
X case ACTION_RENAME_OBJECT: /* SLock,SName,DLock,DName Bool */
X {
X struct FileLock *slock, *dlock;
X char buf2[256];
X
X slock = BTOC(PArg1);
X dlock = BTOC(PArg3);
X if (CheckWrite(slock) || CheckWrite(dlock))
X break;
X btos(PArg2, buf);
X btos(PArg4, buf2);
X PRes1 = MSRename(slock ? slock->fl_Key : NULL,
X buf,
X dlock ? dlock->fl_Key : NULL,
X buf2);
X }
X break;
X case ACTION_MORECACHE: /* #BufsToAdd Bool */
X if ((MaxCache += (short) PArg1) <= 0) {
X MaxCache = 1;
X } else
X PRes1 = DOSTRUE;
X debug(("Now %d cache sectors\n", MaxCache));
X break;
X case ACTION_COPY_DIR: /* Lock Lock */
X {
X register struct FileLock *newlock;
X struct FileLock *lock;
X struct MSFileLock *msfl;
X
X lock = BTOC(PArg1);
X
X msfl = MSDupLock(lock ? lock->fl_Key : NULL);
X
X if (msfl) {
X if (newlock = NewFileLock(msfl, lock)) {
X newlock->fl_Access =
X lock ? lock->fl_Access : SHARED_LOCK;
X PRes1 = (long) CTOB(newlock);
X OpenCount++;
X } else
X MSUnLock(msfl);
X }
X }
X break;
X case ACTION_SET_PROTECT: /* -,Lock,Name,Mask Bool */
X {
X struct FileLock *lock;
X
X lock = BTOC(PArg2);
X if (CheckWrite(lock))
X break;
X btos(PArg3, buf);
X PRes1 = MSSetProtect(lock ? lock->fl_Key : NULL, buf, PArg4);
X }
X break;
X case ACTION_CREATE_DIR: /* Lock,Name Lock */
X {
X register struct FileLock *newlock;
X struct FileLock *lock;
X struct MSFileLock *msfl;
X
X lock = BTOC(PArg1);
X if (CheckWrite(lock))
X break;
X btos(PArg2, buf);
X
X msfl = MSCreateDir(lock ? lock->fl_Key : NULL, buf);
X
X if (msfl) {
X if (newlock = NewFileLock(msfl, lock)) {
X newlock->fl_Access = SHARED_LOCK;
X PRes1 = (long) CTOB(newlock);
X OpenCount++;
X } else
X MSUnLock(msfl);
X }
X }
X break;
X case ACTION_EXAMINE_OBJECT: /* Lock,Fib Bool */
X {
X struct FileLock *lock;
X
X lock = BTOC(PArg1);
X if (CheckRead(lock))
X break;
X PRes1 = MSExamine(lock ? lock->fl_Key : NULL, BTOC(PArg2));
X }
X break;
X case ACTION_EXAMINE_NEXT: /* Lock,Fib Bool */
X {
X struct FileLock *lock;
X
X lock = BTOC(PArg1);
X if (CheckRead(lock))
X break;
X PRes1 = MSExNext(lock ? lock->fl_Key : NULL, BTOC(PArg2));
X }
X break;
X case ACTION_DISK_INFO: /* InfoData Bool:TRUE */
X PRes1 = MSDiskInfo(BTOC(PArg1));
X break;
X case ACTION_INFO: /* Lock,InfoData Bool:TRUE */
X if (CheckRead(BTOC(PArg1)))
X break;
X PRes1 = MSDiskInfo(BTOC(PArg2));
X break;
X case ACTION_FLUSH: /* writeout bufs, disk motor off */
X MSUpdate(1);
X break;
X/* case ACTION_SET_COMMENT: /* -,Lock,Name,Comment Bool */
X case ACTION_PARENT: /* Lock ParentLock */
X {
X register struct FileLock *newlock;
X struct FileLock *lock;
X struct MSFileLock *msfl;
X long mode;
X
X lock = BTOC(PArg1);
X
X msfl = MSParentDir(lock ? lock->fl_Key : NULL);
X
X if (msfl) {
X if (newlock = NewFileLock(msfl, lock)) {
X newlock->fl_Access = SHARED_LOCK;
X PRes1 = (long) CTOB(newlock);
X OpenCount++;
X } else
X MSUnLock(msfl);
X }
X }
X break;
X case ACTION_INHIBIT: /* Bool Bool */
X if (Inhibited = PArg1) {
X DiskRemoved();
X } else { /* Fall through to ACTION_DISK_CHANGE: */
X case ACTION_DISK_CHANGE: /* ? ? */
X DiskChange();
X }
X PRes1 = DOSTRUE;
X break;
X case ACTION_SET_DATE: /* -,Lock,Name,CPTRDateStamp Bool */
X {
X struct FileLock *lock;
X
X lock = BTOC(PArg2);
X if (CheckWrite(lock))
X break;
X btos(PArg3, buf);
X PRes1 = MSSetDate(lock ? lock->fl_Key : NULL,
X buf,
X PArg4);
X }
X break;
X case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */
X if (CheckRead(NULL)) {
X PRes1 = -1;
X } else
X PRes1 = MSRead(PArg1, PArg2, PArg3);
X break;
X case ACTION_WRITE: /* FHArg1,CPTRBuffer,Length ActLength */
X if (CheckWrite(NULL)) {
X PRes1 = -1;
X } else
X PRes1 = MSWrite(PArg1, PArg2, PArg3);
X break;
X case ACTION_OPENNEW: /* FileHandle,Lock,Name Bool */
X {
X struct MSFileHandle *msfh;
X struct FileHandle *fh;
X struct FileLock *lock;
X
X if (CheckWrite(BTOC(PArg2)))
X break;
X case ACTION_OPENRW: /* FileHandle,Lock,Name Bool */
X case ACTION_OPENOLD: /* FileHandle,Lock,Name Bool */
X
X fh = BTOC(PArg1);
X lock = BTOC(PArg2);
X if (CheckRead(lock))
X break;
X btos(PArg3, buf);
X debug(("'%s' ", buf));
X msfh = MSOpen(lock ? lock->fl_Key : NULL,
X buf,
X PType);
X if (msfh) {
X fh->fh_Arg1 = (long) msfh;
X PRes1 = DOSTRUE;
X OpenCount++;
X }
X }
X break;
X case ACTION_CLOSE: /* FHArg1 Bool:TRUE */
X MSClose(PArg1);
X PRes1 = DOSTRUE;
X OpenCount--;
X break;
X case ACTION_SEEK: /* FHArg1,Position,Mode OldPosition */
X if (CheckRead(NULL)) {
X PRes1 = -1;
X } else
X PRes1 = MSSeek(PArg1, PArg2, PArg3);
X break;
X /*
X * A few other packet types which we do not support
X */
X/* case ACTION_WAIT_CHAR: /* Timeout, ticks Bool */
X/* case ACTION_RAWMODE: /* Bool(-1:RAW 0:CON) OldState */
X default:
X error = ERROR_ACTION_NOT_KNOWN;
X break;
X } /* end switch */
X if (packet) {
X if (error) {
X debug(("ERR=%d\n", error));
X PRes2 = error;
X }
X#ifdef DEBUG
X else {
X debug(("RES=%06lx\n", PRes1));
X }
X#endif
X returnpacket(packet);
X DosPacket = NULL;
X }
X#ifdef DEBUG
X else {
X debug(("NOREP\n"));
X }
X#endif
X } /* end while (GetMsg()) */
X
X /*
X * Now check for an other cause of events: timer IO.
X * Unfortunately we cannot be sure that we always get a signal
X * when the timeout has elapsed, since the same message port is
X * used for other IO.
X */
X if (CheckIO(TimeIOReq)) { /* Timer finished? */
X debug(("TimeIOReq is finished\n"));
X if (DelayState != DELAY_OFF) {
X MSUpdate(0); /* Also may switch off motor */
X }
X }
X } /* end for (;notdone) */
X
X#ifdef DEBUG
X debug(("Can we remove ourselves? "));
X Delay(50L); /* I wanna even see the debug message! */
X#endif /* DEBUG */
X Forbid();
X if (OpenCount || packetsqueued()) {
X Permit();
X debug((" .. not yet!\n"));
X goto top; /* sorry... can't exit */
X }
X debug((" .. yes!\n"));
X
X /*
X * Causes a new process to be created on next reference.
X */
X
X DevNode->dn_Task = NULL;
X TDRemChangeInt();
X DiskRemoved();
X HanCloseDown();
X debug(("HanCloseDown returned. dbuninit in 2 seconds:\n"));
X
X /*
X * Remove debug window, closedown, fall of the end of the world.
X */
Xexit:
X#ifdef DEBUG
X Delay(100L); /* This is dangerous! */
X dbuninit();
X#endif /* DEBUG */
X
X#if 1
X UnLoadSeg(DevNode->dn_SegList); /* This is real fun. We are still */
X DevNode->dn_SegList = NULL; /* Forbid()den, fortunately */
X#endif
X
X CloseLibrary(DOSBase);
X
X /* Fall off the end of the world. Implicit Permit(). */
X}
X
Xvoid
XChangeIntHand()
X{
X/* INDENT OFF */
X#asm
X move.l a6,-(sp)
X#endasm
X DiskChanged = 1;
X Signal(DosPort->mp_SigTask, PortMask);
X#asm
X move.l (sp)+,a6
X#endasm
X/* INDENT ON */
X}
X
X/*
X * Make a new struct FileLock, for DOS use. It is put on a singly linked
X * list, which is attached to the same VolumeNode the old lock was on.
X *
X * Also note that we must ALWAYS be prepared to UnLock() or DupLock()
X * any FileLocks we ever made, even if the volume in question has been
X * removed and/or inserted into another drive with another FileSystem
X * handler!
X *
X * DOS makes certain assumptions about LOCKS. A lock must minimally be a
X * FileLock structure, with additional private information after the
X * FileLock structure. The longword before the beginning of the structure
X * must contain the length of structure + 4.
X *
X * NOTE!!!!! The workbench does not follow the rules and assumes it can copy
X * lock structures. This means that if you want to be workbench
X * compatible, your lock structures must be EXACTLY sizeof(struct
X * FileLock). Also, it sometimes uses uninitialized values for the lock mode...
X */
X
Xstruct FileLock *
XNewFileLock(msfl, fl)
Xstruct MSFileLock *msfl;
Xstruct FileLock *fl;
X{
X struct FileLock *newlock;
X DEVLIST *volnode;
X
X if (fl) {
X volnode = BTOC(fl->fl_Volume);
X } else {
X volnode = VolNode;
X }
X
X if (newlock = dosalloc((ulong)sizeof (*newlock))) {
X newlock->fl_Key = (ulong) msfl;
X newlock->fl_Task = DosPort;
X newlock->fl_Volume = (BPTR) CTOB(volnode);
X Forbid();
X newlock->fl_Link = volnode->dl_LockList;
X volnode->dl_LockList = (BPTR) CTOB(newlock);
X Permit();
X } else
X error = ERROR_NO_FREE_STORE;
X
X return newlock;
X}
X
X/*
X * This should be called before MSUnLock(), so that it may call
X * MayFreeVolNode() which then calls FreeVolNode(). A bit tricky,
X * I'm sorry for that.
X */
X
Xlong
XFreeFileLock(lock)
Xstruct FileLock *lock;
X{
X register struct FileLock *fl;
X register struct FileLock **flp;
X DEVLIST *volnode;
X
X volnode = (DEVLIST *)BTOC(lock->fl_Volume);
X flp = (struct FileLock **) &volnode->dl_LockList;
X for (fl = BTOC(*flp); fl && fl != lock; fl = BTOC(fl->fl_Link))
X flp = (struct FileLock **)&fl->fl_Link;
X
X if (fl == lock) {
X *(BPTR *)flp = fl->fl_Link;
X dosfree(fl);
X return DOSTRUE;
X } else {
X debug(("Huh?? Could not find filelock!\n"));
X return DOSFALSE;
X }
X}
X
X/*
X * Create Volume node and add to the device list. This will
X * cause the WORKBENCH to recognize us as a disk. If we
X * don't create a Volume node, Wb will not recognize us.
X * However, we are a MESSYDOS: disk, Volume node or not.
X */
X
XDEVLIST *
XNewVolNode(name, date)
Xstruct DateStamp *date;
Xchar *name;
X{
X DOSINFO *di;
X register DEVLIST *volnode;
X char *volname; /* This is my volume name */
X
X di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
X
X if (volnode = dosalloc((ulong)sizeof (DEVLIST))) {
X if (volname = dosalloc(32L)) {
X volname[0] = strlen(name);
X strcpy(volname + 1, name); /* Make sure \0 terminated */
X
X volnode->dl_Type = DLT_VOLUME;
X volnode->dl_Task = DosPort;
X volnode->dl_DiskType = IDDiskType;
X volnode->dl_Name = CTOB(volname);
X volnode->dl_VolumeDate = *date;
X volnode->dl_MSFileLockList = NULL;
X
X Forbid();
X volnode->dl_Next = di->di_DevInfo;
X di->di_DevInfo = (long) CTOB(volnode);
X Permit();
X } else {
X dosfree(volnode);
X volnode = NULL;
X }
X } else {
X error = ERROR_NO_FREE_STORE;
X }
X
X return volnode;
X}
X
X/*
X * Get the current VolNode a new name from the volume label.
X */
X
Xvoid
XNewVolNodeName()
X{
X if (VolNode) {
X register char *volname = BTOC(VolNode->dl_Name);
X
X strncpy(volname + 1, Disk.vollabel.de_Msd.msd_Name, 8+3);
X volname[1+8+3] = '\0'; /* Make sure \0 terminated */
X ZapSpaces(volname + 1, volname + 1 + 8+3);
X volname[0] = strlen(volname+1);
X }
X}
X
X/*
X * Get the current VolNode a new date, from the last root directory.
X */
X
Xvoid
XNewVolNodeDate()
X{
X if (VolNode) {
X ToDateStamp(&VolNode->dl_VolumeDate,
X Disk.vollabel.de_Msd.msd_Date,
X Disk.vollabel.de_Msd.msd_Time);
X }
X}
X
X/*
X * Remove Volume entry. Since DOS uses singly linked lists, we must
X * (ugg) search it manually to find the link before our Volume entry.
X */
X
Xvoid
XFreeVolNode(volnode)
XDEVLIST *volnode;
X{
X DOSINFO *di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
X register DEVLIST *dl;
X register void *dlp;
X
X debug(("FreeVolNode %08lx\n", volnode));
X
X if (volnode == NULL)
X return;
X
X dlp = &di->di_DevInfo;
X Forbid();
X for (dl = BTOC(di->di_DevInfo); dl && dl != volnode; dl = BTOC(dl->dl_Next))
X dlp = &dl->dl_Next;
X if (dl == volnode) {
X *(BPTR *) dlp = dl->dl_Next;
X dosfree(BTOC(dl->dl_Name));
X dosfree(dl);
X }
X#ifdef DEBUG
X else {
X debug(("****PANIC: Unable to find volume node\n"));
X }
X#endif /* DEBUG */
X Permit();
X
X if (volnode == VolNode)
X VolNode = NULL;
X}
X
X/*
X * This is also called from the real handler when the last lock on a
X * volume is UnLock()ed, or the last file has been Close()d.
X */
X
Xint
XMayFreeVolNode(volnode)
XDEVLIST *volnode;
X{
X if (volnode->dl_LockList == NULL) {
X FreeVolNode(volnode);
X return 1;
X }
X
X return 0;
X}
X
X/*
X * Our disk has been removed. Save the FileLocks in the dl_LockList,
X * and let the handler save its MSFileLocks in the dl_MSFileLockList field.
X * If it has nothing to save, forget about the volume, and return
X * DOSTRUE.
X * There is one subtlety that MSDiskRemoved must know about:
X * If it MSUnLock()s the last lock on the volume, the VolNode is
X * deleted via FreeLockList().. MayFreeVolNode().. FreeVolNode().
X * But then there is no place anymore to put NULL in, so that needs
X * to be done first.
X */
X
Xint
XDiskRemoved()
X{
X debug(("DiskRemoved %08lx\n", VolNode));
X
X if (VolNode == NULL) {
X IDDiskType = ID_NO_DISK_PRESENT;/* really business of MSDiskRemoved */
X return DOSTRUE;
X }
X
X VolNode->dl_Task = NULL;
X MSDiskRemoved(&VolNode->dl_MSFileLockList);
X if (VolNode == NULL) { /* Could happen via MSDiskRemoved() */
X return DOSTRUE;
X }
X NewVolNodeDate(); /* Fetch new date of root directory */
X VolNode = NULL;
X return DOSFALSE;
X}
X
X/*
X * Reconstruct everything from a Volume node
X */
X
Xvoid
XDiskInserted(volnode)
Xregister DEVLIST *volnode;
X{
X debug(("DiskInserted %08lx\n", volnode));
X
X VolNode = volnode;
X
X if (volnode) {
X volnode->dl_Task = DosPort;
X MSDiskInserted(&volnode->dl_MSFileLockList, volnode);
X volnode->dl_MSFileLockList = NULL;
X }
X}
X
XDEVLIST *
XWhichDiskInserted()
X{
X char name[34];
X struct DateStamp date;
X register DEVLIST *dl = NULL;
X
X if (!Inhibited && IdentifyDisk(name, &date) == 0) {
X DOSINFO *di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
X byte *nodename;
X int namelen = strlen(name);
X
X for (dl = BTOC(di->di_DevInfo); dl; dl = BTOC(dl->dl_Next)) {
X nodename = BTOC(dl->dl_Name);
X if (nodename[0] != namelen || strncmp(nodename+1,name,namelen))
X continue;
X if (dl->dl_VolumeDate == date) /* Non-standard! Structure compare! */
X break;
X }
X
X name[31] = '\0';
X if (dl == NULL)
X dl = NewVolNode(name, &date);
X }
X
X return dl;
X}
X
Xvoid
XDiskChange()
X{
X debug(("DiskChange\n"));
X DiskChanged = 0;
X DiskRemoved();
X DiskInserted(WhichDiskInserted());
X}
X
Xint
XCheckRead(lock)
Xstruct FileLock *lock;
X{
X if (lock && BTOC(lock->fl_Volume) != VolNode)
X error = ERROR_DEVICE_NOT_MOUNTED;
X else if (IDDiskType == ID_NO_DISK_PRESENT)
X error = ERROR_NO_DISK;
X else if (IDDiskType != ID_DOS_DISK)
X error = ERROR_NOT_A_DOS_DISK;
X
X return error;
X}
X
Xint
XCheckWrite(lock)
Xstruct FileLock *lock;
X{
X if (lock && BTOC(lock->fl_Volume) != VolNode)
X error = ERROR_DEVICE_NOT_MOUNTED;
X else if (IDDiskType == ID_NO_DISK_PRESENT)
X error = ERROR_NO_DISK;
X else if (IDDiskType != ID_DOS_DISK)
X error = ERROR_NOT_A_DOS_DISK;
X else if (IDDiskState == ID_VALIDATING)
X error = ERROR_DISK_NOT_VALIDATED;
X else if (IDDiskState != ID_VALIDATED)
X error = ERROR_DISK_WRITE_PROTECTED;
X
X return error;
X}
X
X#ifdef DEBUG
X /* DEBUGGING */
XPORT *Dbport; /* owned by the debug process */
XPORT *Dback; /* owned by the DOS device driver */
Xshort DBEnable;
X
X/*
X * DEBUGGING CODE. You cannot make DOS library calls that access other
X * devices from within a DOS device driver because they use the same
X * message port as the driver. If you need to make such calls you must
X * create a port and construct the DOS messages yourself. I do not
X * do this. To get debugging info out another PROCESS is created to which
X * debugging messages can be sent.
X */
X
Xextern void debugproc();
X
Xdbinit()
X{
X TASK *task = FindTask(NULL);
X
X Dback = CreatePort("MSH:Dback", -1L);
X CreateProc("MSH_DB", (long)task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096L);
X WaitPort(Dback); /* handshake startup */
X GetMsg(Dback); /* remove dummy msg */
X DBEnable = 1;
X dbprintf("Debugger running V1.10\n");
X}
X
Xdbuninit()
X{
X MSG killmsg;
X
X if (Dbport) {
X killmsg.mn_Length = 0; /* 0 means die */
X PutMsg(Dbport, &killmsg);
X WaitPort(Dback); /* He's dead jim! */
X GetMsg(Dback);
X DeletePort(Dback);
X
X /*
X * Since the debug process is running at a greater priority, I
X * am pretty sure that it is guarenteed to be completely removed
X * before this task gets control again. Still, it doesn't hurt...
X */
X
X Delay(50L); /* ensure he's dead */
X }
X}
X
Xdbprintf(a,b,c,d,e,f,g,h,i,j)
Xlong a,b,c,d,e,f,g,h,i,j;
X{
X struct {
X MSG msg;
X char buf[256];
X } msgbuf;
X register MSG *msg = &msgbuf.msg;
X register long len;
X
X if (Dbport && DBEnable) {
X sprintf(msgbuf.buf,a,b,c,d,e,f,g,h,i,j);
X len = strlen(msgbuf.buf)+1;
X msg->mn_Length = len; /* Length NEVER 0 */
X PutMsg(Dbport, msg);
X WaitPort(Dback);
X GetMsg(Dback);
X }
X}
X
X/*
X * BTW, the DOS library used by debugmain() was actually opened by
X * the device driver.
X */
X
Xdebugmain()
X{
X register MSG *msg;
X register long len;
X register void *fh;
X void *fh2;
X MSG DummyMsg;
X
X Dbport = CreatePort("MSH:Dbport", -1L);
X fh = Open("CON:0/10/640/190/FileSystem debug", MODE_NEWFILE);
X fh2 = Open("PAR:", MODE_OLDFILE);
X PutMsg(Dback, &DummyMsg);
X for (;;) {
X WaitPort(Dbport);
X msg = GetMsg(Dbport);
X len = msg->mn_Length;
X if (len == 0)
X break;
X --len; /* Fix length up */
X if (DBEnable & 1)
X Write(fh, msg+1, len);
X if (DBEnable & 2)
X Write(fh2, msg+1, len);
X PutMsg(Dback, msg);
X }
X Close(fh);
X Close(fh2);
X DeletePort(Dbport);
X PutMsg(Dback, msg); /* Kill handshake */
X}
X
X/*
X * The assembly tag for the DOS process: CNOP causes alignment problems
X * with the Aztec assembler for some reason. I assume then, that the
X * alignment is unknown. Since the BCPL conversion basically zero's the
X * lower two bits of the address the actual code may start anywhere
X * within 8 bytes of address (remember the first longword is a segment
X * pointer and skipped). Sigh.... (see CreateProc() above).
X */
X
X#asm
X public _debugproc
X public _debugmain
X
X cseg
X_debugproc:
X nop
X nop
X nop
X nop
X nop
X movem.l D2-D7/A2-A6,-(sp)
X jsr _debugmain
X movem.l (sp)+,D2-D7/A2-A6
X rts
X#endasm
X
X#endif /* DEBUG */
END_OF_FILE
if test 26316 -ne `wc -c <'src/pack.c'`; then
echo shar: \"'src/pack.c'\" unpacked with wrong size!
fi
# end of 'src/pack.c'
fi
echo shar: End of archive 5 \(of 6\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
Mail comments to the moderator at <amiga-request@cs.odu.edu>.
Post requests for sources, and general discussion to comp.sys.amiga.