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.