; ; File: TFS.a ; ; Contains: This file is the controlling file for the Macintosh Turbo file ; system. It contains initialization code and the file system's ; queueing and dispatch routines. ; ; Roots: This system exploits the dispatching mechanism used by the earlier ; Macintosh file system written by Larry Kenyon et al. Relevant ; code was taken from that system and modified as appropriate. ; ; Copyright: © 1982-1993 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 8/27/93 BH Made DSAlertRect bigger for the disk-switch alert in ; manual-eject systems to keep it the same size as the various ; manual-eject alerts, which have also been enlarged. ; 8/3/93 BH Rewrote DSHook for manual-eject drive support. ; 6/7/93 kc Roll in missing part of DSHookPatch from reality that sets the fsNoAllocate bits. ; 11/12/92 PN Get rid of ³ 020 conditionals ; 10/29/92 SWC Changed SCSIEqu.a->SCSI.a. ; 9/15/92 RB #1042050,#1042640,#Fixed a bug in DSHook where the PostUpdate ; routine was not duplicating a rectangle pointer in the stack ; correctly. This caused a bomb after a disk had been asked for ; and it got inserted in the drive. The satck was trashed 4 bytes. ; 5/21/92 kc Append "Trap" to the names of ; OpenWD,CloseWD,GetWDInfo,OpenDF,UnMountVol,FlushVol,OpenWD,Close ; WD,GetWDInfo,ReName,OpenRF,OpenDF,GetFPos,SetFPos,GetEOF,SetEOF, ; Eject,SetVol,GetVolTrap,Enqueue and Dequeue to avoid name ; conflict with the glue. ; 5/18/92 CS Fix bug in OpenCall that I (kc) introduced in the patch roll in. ; 4/1/92 kc Rolled in HFSDispHook from FileMgrPatches.a. ; Moved the stub dispatch handlers (VolumeCall, ; RefNumCall,OpenCall and UnknownCall) and copied the ; routines InstallVectors, FSGrowPatchInit, ; QMInit, CountFCBs, OpenAttemptHook, AllocateFCBs, DoFSCleanUp ; Rolled in patches to DSHook. ; include FileMgrHooks.a till someone rolls it in. ; ¥ Pre-SuperMario comments follow ¥ ; <4> 9/27/91 JSM DonÕt use hasCQD conditional, all future ROMs will have color ; QuickDraw. ; <3> 9/12/91 JSM Cleanup header. ; <2> 6/12/91 LN Changed #include 'HardwareEqu.a' to 'HardwarePrivateEqu.a' ; <2.6> 6/12/89 GGD Fixed bugs in which intended to allow ; cmd-shift-0/1/2 to eject disks during a disk switch dialog, but ; never worked. (ESPRIT SHOULD ALSO GET THIS FIX) ; <2.5> 5/25/89 GGD Deleted 4 extra lines of code that were accidently pasted in the ; wrong place, in the Switcher Table initialization code. This ; would cause a random long word (whose address is a function of ; the number of FCBs from the boot blocks) in the system heap to ; get trashed. This fixes problems noticed in Aurora B1 ROMs, and ; needs to be fixed in Esprit also. ; <2.4> 5/23/89 DAF Corrected color updates in DSHook ; <2.3> 4/13/89 dnf Completed export ; <2.2> 4/13/89 DNF Exported vFileRead, vFileWrite, and vFileClose ; <2.0> 3/27/89 DNF = ; <2.1> 3/27/89 DNF This comment documents the change from V1.7 to V1.8/V1.9/V2.0. ; There have been node real code changes since V1.7. V1.8 Added ; forROM conditionals around the disk-switch code, since it jumps ; to other spots in the ROM. Note that the comment in V1.6 is no ; longer true; RAM versions use the ROM's disk switch code. The ; overridden V1.8, V1.9, the accidentally commentless V2.0 and ; this file all contain the same code. ; <¥1.9> 3/27/89 DNF whoops. v1.8 was checked in from the wrong directory. Here's the ; right one. ; <¥1.7> 3/20/89 CCH Added Export of FSQueueSync and CmdDone for CacheControl.a. ; <1.6> 3/2/89 DNF removed references to forROM; HFS now builds identically for ram ; or rom ; <1.5> 2/20/89 rwh changed from CPU-based to feature-based conditionals. ; <1.4> 1/16/89 GGD Added a scratch register parameter to the BigJSR macro calls ; since it will be needed when they change to use PC relative ; addressing. ; <1.3> 11/21/88 CCH Replaced references to forRAM with ÒNOT forROM.Ó ; <1.2> 11/17/88 GGD Moved file system initialization code from StartBoot into TFS.a, ; Changed BigJsr's into Jsr, since they now reach. ; <1.1> 11/10/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <¥1.1> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles ; <1.0> 2/11/88 BBM Adding file for the first time into EASEÉ ; 11/10/87 JB (C957) Rolled in changes from patches S084, PM120, PP227, & ; PM289. Fixed CmdDone logic for "NoMacDskErr". Instead of special ; casing here, disk format package (PACK 2) will be modified to ; accept "ExtFSErr" as a legitimate format request. ; 10/19/87 rwh Port to Modern Victorian ; 10/16/87 MSH Added nHardwareEqu.a to INCLUDES for Laguna support. ; 6/10/87 EHB Added INCLUDEs for colorEqu.a and nsysequ.a again. ; 6/2/87 DAF Added INCLUDEs for colorEqu.a and nsysequ.a. Added 020 asm ; directive if on numac. ; 5/12/87 DAF Rolled in DSHook patch to not save bits behind dialog when on ; CQD-equipped system and in >1-bit mode. ; 3/3/87 BB Modified CmdDone to call external file systems if "NoMacDskErr" ; is returned from MountVol. ; 2/19/87 BB Added EXPORTs for vectored MtCheck, CheckReMount, FindDrive, ; DtrmV2, FClose, and FlushMDB. ; 10/27/86 BB Added EXPORTs for vectored CkExtFS, DtrmV3, TstMod, and BMChk ; routines. ; 9/25/86 BB Updated to use new MPW equate files. ; 9/9/86 TJ Added vDoEject vector for access by other system routines that ; need to handle manual diskette ejection. Extended to accept ; Command-Shift-0 for drive #3. ; 1/20/86 LAK Added .DEF of FindDrive for BTAlloc usage in updating alternate ; MDB. ; 11/3/85 LAK One more tweak to disk-switch: if we get a non-memfull error on ; our mount (e.g., IOErr because double-sided disk was inserted ; into 1-sided drive), we eject that disk and reenter our wait ; loop. Also fixed bug when remounting an offline volume (D3 not ; set up). ; 11/2/85 LAK Call DoEject for cmd-shift-1 or 2 during disk switch DIP wait. ; In case user has inserted needed 2-sided disk into his old ; external 1-sided drive (removes need for paper clip eject). ; 10/29/85 LAK Added Defs for vectored routines. ; 10/22/85 PWD Fixed CmdDone to check PMSP for traps w. TFS bit set but ; DirID=0. ; 10/16/85 PWD Added _LockRng and _UnlockRng dispatches ; 10/14/85 PWD Added _ReadWDCB dispatch (trap 15) ; 10/8/85 LAK Added .Def of vLg2Phys (for ROM vector). ; 10/2/85 LAK Added debug code at CmdDone to check for a non-released buffer. ; (may want to take this out since it is time-consuming). ; 10/1/85 LAK Added .Ref of MarkA5Block. Add .Def of Lg2Phys for Cache. ; Convert positive internal errors to FSDSIntErr at CmdDone. Cut ; out Queue code convert drive numbers to VRefNums (this is now ; handled by GetVCBDrv in TFSCommon). Added Refs of ; CacheWrIP,CacheRdIP. Added Def of TFSVCBTst. Set up global ; asynchronicity flag, FSCallAsync, at FSDispatch. Patched ; disk-switch hook for ROM to look for cmd-. abort and return ; VolOffLinErr for that case (let's see how it goes). ; 9/26/85 PWD Added SetupDef entry point dispatch for external FS support. ; 9/25/85 PWD Changed to allow SkipPMSP to come on in mid-parse in CmdDone ; path ; 9/20/85 LAK Added .Ref of TrashFBlocks. ; 9/8/85 LAK Added Def of MarkVCBTime. Added Ref of UpdateFree. ; 9/5/85 LAK Clear CacheFlag on exit. ; 9/5/85 LAK ParamErr instead of IOErr if D0 parameter to $Ax60 trap is out ; of range. ; 9/2/85 LAK Added .Ref of MarkBlock. ; 8/30/85 LAK Added .Ref of TrashVBlks. Removed .Ref of RelCache. ; 8/27/85 LAK Why waste a word in _FSControl? Remunged dispatch a bit, too. ; 8/22/85 PWD Added _SetUpWDCB trap dispatch ; 7/31/85 PWD Added _FSControl trap ; 7/27/85 PWD Added Poor Man's Search Path mechanism ; 7/17/85 PWD Changed TFSDispatch to store trap index in ioTrap for use by ; ext. FS and volume switch re-trap (TrapAgain) ; 6/14/85 PWD Added EXT.L to make error codes into longs at CmdDone ; 5/1/85 PWD Expanded dispatch table to accomodate new TFS traps ; 4/22/85 PWD Fixed dispatcher table indexing to use word offsets ; consistently. ; 3/13/85 PWD Added TFS trap dispatcher ; 2/8/85 PWD Added .Include of ToolEqu for TIOCore use. ; 2/5/85 PWD Changed to use Tlasm- equates (including TFSEqu) ; 9/24/84 GSS Added include of RAM version trap install code, and def for ; Offline call ; 8/5/84 GSS New today. (taken from Larry Kenyon's Mac File System) ; ;_______________________________________________________________________ ; ; External Routines: Enqueue,Dequeue,InitQueue ; ; Internal Routines: FSQueue,FSQueueSync ; ;_______________________________________________________________________ BLANKS ON STRING ASIS MACHINE MC68020 SonyNonPortable EQU 1 PRINT OFF LOAD 'StandardEqu.d' INCLUDE 'HardwarePrivateEqu.a' INCLUDE 'SonyEqu.a' INCLUDE 'Processes.a' INCLUDE 'MFPrivate.a' INCLUDE 'FileMgrPrivate.a' INCLUDE 'SCSI.a' INCLUDE 'SCSIPriv.a' INCLUDE 'GestaltEqu.a' INCLUDE 'InternalMacros.a' INCLUDE 'SysPrivateEqu.a' INCLUDE 'BTreeEqu.a' PRINT ON PRINT NOGEN ;_______________________________________________________________________ ; ; Routine: TFSDispatch ; ; Arguments: D0.W = TFS trap index ; D1.W = Trap ($Ax60) ; A0.L = Parameter Block Pointer ; ; Called by: EMT1010 ; ; Function: Dispatch routine for the _HFSDispatch trap. ; ; The deal with $A060 trap numbers: ; $00-$1f HFS calls ; $20-$2f Desktop Manager Calls ; $30-$3f AppleShare calls (owned by AppleShare group) ; $40-$4f More appleshare calls ; $60-$7f More HFS calls ; ; Modification History: ; ; 13-Mar-85 PWD New today. ; <25Sep85> PWD Added SetPMSP (trap 12): bumped _SetupWDCB to index 13. ; <14Oct85> PWD Added _ReadWDCB dispatch (trap 15) ;_______________________________________________________________________ MaxTrapNum Equ $70 TFSDispatch Proc Export Import UnknownCall tst.w d0 ; check lower bound of selector blt.l UnknownCall ; negative traps are no good cmp.w #MaxTrapNum,d0 ; check upper bound of selector bge.l UnknownCall ; off the deep end move.w d1,ioTrap(a0) ; save the unmunged trap andi.w #$0F00,ioTrap(a0) ; leave only modifiers (Async etc.) move.b d0,ioTrap+1(a0) ; save the trap selector lea TFSTrpTbl,a2 ; address of the dispatch table adda.l (a2,d0.w*4),a2 ; add the routine offset jmp (a2) ; jump to the routine macro DispatchEntry &where import &where dc.l &where-TFSTrpTbl endm TFSTrpTbl ; pc relative data DispatchEntry FSControl ; $00 Special control entry point DispatchEntry OpenWDTrap ; $01 Open a working directory DispatchEntry CloseWDTrap ; $02 Close a working directory DispatchEntry SetDir ; $03 Set a default directory DispatchEntry GetDir ; $04 Get default directory information DispatchEntry TFMove ; $05 Move a CNode into another directory DispatchEntry CreateDir ; $06 Create a directory CNode DispatchEntry GetWDInfoTrap ; $07 Get WDCB infomation DispatchEntry GetFCBInfo ; $08 Get FCB information DispatchEntry GetCatInfo ; $09 Get expanded file/dir information DispatchEntry SetCatInfo ; $0A Change CNode information DispatchEntry SetVolInfo ; $0B Change volume information DispatchEntry SetPMSP ; $0C Set up PMSP hook and enable/disable PMSP DispatchEntry SetUpWDCB ; $0D Set up WDCB [raw internal call only] DispatchEntry SetUpDef ; $0E Set up default vol&dir [raw internal] DispatchEntry ReadWDCB ; $0F Get WDCB information [raw internal] DispatchEntry LockRng ; $10 Lock a byte range DispatchEntry UnLockRng ; $11 Unlock a byte range DispatchEntry UnknownCall ; $12 DispatchEntry UnknownCall ; $13 DispatchEntry CreateFileIDRef ; $14 DispatchEntry DeleteFileIDRef ; $15 DispatchEntry ResolveFileIDRef ; $16 DispatchEntry PBHExchangeFiles ; $17 DispatchEntry CMCatSearch ; $18 DispatchEntry CheckCSPB ; $19 DispatchEntry OpenDFTrap ; $1A DispatchEntry MakeFSSpec ; $1B DispatchEntry UnknownCall ; $1C DispatchEntry UnknownCall ; $1D DispatchEntry UnknownCall ; $1E DispatchEntry UnknownCall ; $1F DispatchEntry DTGetPath ; $20 DispatchEntry DTCloseDown ; $21 DispatchEntry DTAddIcon ; $22 DispatchEntry DTGetIcon ; $23 DispatchEntry DTGetIconInfo ; $24 DispatchEntry DTAddAPPL ; $25 DispatchEntry DTRemoveAPPL ; $26 DispatchEntry DTGetAPPL ; $27 DispatchEntry DTSetComment ; $28 DispatchEntry DTRemoveComment ; $29 DispatchEntry DTGetComment ; $2a DispatchEntry DTFlush ; $2b DispatchEntry DTReset ; $2c DispatchEntry DTGetInfo ; $2d DispatchEntry DTOpenInform ; $2e DispatchEntry DTDelete ; $2f DispatchEntry GetVolParms ; $30 GetVolParms DispatchEntry VolumeCall ; $31 GetLogInInfo DispatchEntry VolumeCall ; $32 GetDirAccess DispatchEntry VolumeCall ; $33 SetDirAccess DispatchEntry VolumeCall ; $34 MapID DispatchEntry VolumeCall ; $35 MapName DispatchEntry VolumeCall ; $36 CopyFile DispatchEntry VolumeCall ; $37 MoveRename DispatchEntry OpenCall ; $38 OpenDeny DispatchEntry OpenCall ; $39 OpenRFDeny DispatchEntry VolumeCall ; $3A Reserved for future use DispatchEntry VolumeCall ; $3B Reserved for future use DispatchEntry VolumeCall ; $3C Reserved for future use DispatchEntry VolumeCall ; $3D Reserved for future use DispatchEntry VolumeCall ; $3E Reserved for future use DispatchEntry VolumeCall ; $3F GetVolMountInfoSize DispatchEntry VolumeCall ; $40 GetVolMountInfo DispatchEntry UnknownCall ; $41 VolumeMount DispatchEntry VolumeCall ; $42 Share DispatchEntry VolumeCall ; $43 UnShare DispatchEntry UnknownCall ; $44 GetUGEntry DispatchEntry UnknownCall ; $45 ServerControl DispatchEntry UnknownCall ; $46 ServerStartup DispatchEntry UnknownCall ; $47 Reserved for future use DispatchEntry UnknownCall ; $48 Reserved for future use DispatchEntry UnknownCall ; $49 Reserved for future use DispatchEntry UnknownCall ; $4A Reserved for future use DispatchEntry UnknownCall ; $4B Reserved for future use DispatchEntry UnknownCall ; $4C Reserved for future use DispatchEntry UnknownCall ; $4D Reserved for future use DispatchEntry UnknownCall ; $4E Reserved for future use DispatchEntry UnknownCall ; $4F Reserved for future use DispatchEntry GetParallelFCBFromRefnum ; $50 DispatchEntry RefNumCall ; $51 Reserved for future use DispatchEntry RefNumCall ; $52 Reserved for future use DispatchEntry RefNumCall ; $53 Reserved for future use DispatchEntry RefNumCall ; $54 Reserved for future use DispatchEntry RefNumCall ; $55 Reserved for future use DispatchEntry RefNumCall ; $56 Reserved for future use DispatchEntry RefNumCall ; $57 Reserved for future use DispatchEntry RefNumCall ; $58 Reserved for future use DispatchEntry RefNumCall ; $59 Reserved for future use DispatchEntry RefNumCall ; $5A Reserved for future use DispatchEntry RefNumCall ; $5B Reserved for future use DispatchEntry RefNumCall ; $5C Reserved for future use DispatchEntry RefNumCall ; $5D Reserved for future use DispatchEntry RefNumCall ; $5E Reserved for future use DispatchEntry RefNumCall ; $5F Reserved for future use DispatchEntry VolumeCall ; $60 GetAltPrivs DispatchEntry VolumeCall ; $61 SetAltPrivs DispatchEntry DoFSCleanUp ; $62 FSCleanUp DispatchEntry AllocateFCBs ; $63 AllocateFCBs DispatchEntry VolumeCall ; $64 Reserved for future use DispatchEntry VolumeCall ; $65 Reserved for future use DispatchEntry VolumeCall ; $66 Reserved for future use DispatchEntry VolumeCall ; $67 Reserved for future use DispatchEntry VolumeCall ; $68 Reserved for future use DispatchEntry VolumeCall ; $69 Reserved for future use DispatchEntry VolumeCall ; $6A Reserved for future use DispatchEntry VolumeCall ; $6B Reserved for future use DispatchEntry VolumeCall ; $6C Reserved for future use DispatchEntry VolumeCall ; $6D Reserved for future use DispatchEntry VolumeCall ; $6E Reserved for future use DispatchEntry VolumeCall ; $6F Reserved for future use EndProc TurboFS PROC EXPORT Export UNLOCKRNG,LOCKRNG,READWDCB,SETUPDEF,SETUPWDCB,SETPMSP,FSCONTROL Export ALLOCATEFCBS,DOFSCLEANUP,GTNXTMATCH,GT1STMATCH,GETVOLPARMS Export FLUSHVFILES,FCLOSE,REFNUMCHECK,PUSHCNAME,CVFLGS,POPCNAME Export ExtOffLinCk,FNDFILNAME,DTRMV3,GT1STFCB,GTNXTFCB,FSQUEUE EXPORT vDoEject ; EXPORT DivUp,RoundAlloc,Lg2Phys,TFSVCBTst ; <01Oct85> EXPORT FInitQueue EXPORT MountVol,UnMountVolTrap,FlushVolTrap,MarkVCB,MarkVCBTime,FlushMDB ; <08Sep85> EXPORT OpenWDTrap,CloseWDTrap,SetDir,GetDir,GetWDInfoTrap EXPORT FileOpen,FileClose EXPORT FileRead,FileWrite EXPORT FSQueueSync, CmdDone EXPORT CreateDir,FileCreate,FileDelete,ReNameTrap,TFMove,OpenRFTrap,OpenDFTrap EXPORT GetFPosTrap,SetFPosTrap,FileAlloc EXPORT GetEOFTrap,SetEOFTrap,FlushFile EXPORT GetFCBInfo EXPORT GetFileInfo,SetFileInfo,SetFilType,RstFilLock,SetFilLock EXPORT GetCatInfo,SetCatInfo EXPORT GetVCBRfn,GetVolInfo,SetVolInfo,EjectTrap,Offline EXPORT SetVolTrap,GetVolTrap EXPORT DoEject,MakeStkPB,FindDrive ;<20Jan86> EXPORT vDtrmV1,vFileOpen,vPermssnChk,vFndFilName,vRfNCall,vAdjEOF ;<29Oct85> EXPORT vCkExtFS,vDtrmV3,vTstMod,vBMChk ;<27Oct86> EXPORT vMtCheck,vCheckReMount,vFindDrive,vDtrmV2,vFClose,vFlushMDB ;<19Feb87> EXPORT vLg2Phys ; <08Oct85> EXPORT DSHook EXPORT vFileRead, vFileWrite, vFileClose ; EXPORT InitFS ;<1.2> IF hasManEject THEN ; EXPORT SwitchDisk ; for Desk Mgr EXPORT CleanDSErr ; for Eject patch in FileMgrHooks (ExtFSHookPatch) ENDIF IMPORT AllocFakeRgns IMPORT EnqueueTrap,DequeueTrap,InitQueue IMPORT InitCache,GetBlock,RelBlock,FlushCache,TrashBlocks,TrashVBlks IMPORT MarkBlock,MarkA5Block,TrashFBlocks ; <01Oct85> IMPORT CacheWrIP,CacheRdIP ; <01Oct85> IMPORT MapFBlock,ExtendFile,TruncateFile,DeallocFile,BlkChk,UpdateFree ; <08Sep85> IMPORT BTOpen,BTFlush,BTClose,FXMKeyCmp,CMKeyCmp IMPORT BTSearch,BTGetRecord,BTUpdate IMPORT CMCreateCN,CMGetCN,CMDeleteCN,CMGetOff,CMMoveCN,CMRenameCN IMPORT CMUpdateCN IMPORT WDCBSwOS ; <1.2> IMPORT PMSPSwOS ; <1.2> IMPORT DTDBMgrInit,QMInit,CheckDesktopSupport,DesktopCloseDownProc ; from DTDBMgr.a IMPORT vSyncWait ; from FileMgrHooks.a IMPORT vAfterFSQHook ; from FileMgrHooks.a IMPORT fsGeneralWakeUp ; from FileMgrHooks.a IMPORT fsSCSIFreeHookProc ; from FileMgrHooks.a IMPORT ProcessMgrExists ; from FileMgrHooks.a ;________________________________________________________________________________ ; ; Routine: Stub dispatch handlers ; ; Function: Pass a call to the external File System if it refers to an ; external File System volume. ; ; VolumeCall handles calls defined to take a vRefnum/ioNamePtr ; RefNumCall handles calls which take an FCB refnum ; OpenCall handles all forms of Open (which need to set up an FCB in d1) ; UnknownCall handles call for which there isn't yet a definition ; ; Inputs: A0 = Parameter block ; Output: D0 = error code, RfNumErr or zero. ;________________________________________________________________________________ ExtFSErrExit: moveq.l #ExtFSErr,d0 ; Good news! bra.l CmdDone ParamErrExit: moveq.l #paramErr, d0 ; It's an unknown trap for a local volume bra.l CmdDone ;________________________________________________________________________________ ; ; Routine: VolumeCall ; ; Function: Handles calls defined to take a vRefnum/ioNamePtr. If ; the call refers to an External File System's volume, ; the call is passed to the external FS. Otherwise, ; a #paramErr is returned to the caller. ;________________________________________________________________________________ entry VolumeCall VolumeCall: jsr FSQueue ; Patiently wait our turn jsr DtrmV3 ; Determine the volume being referred to bne CmdDone ; Punt at the slightest hint of trouble move.l a2,ReqstVol ; Point to the volume being referred to tst.w VCBFSID(a2) ; External FS? bne ExtFSErrExit ; Branch if it's not a local FS bra ParamErrExit ;________________________________________________________________________________ ; ; Routine: RefNumCall ; ; Function: Handle a refNum-based call. If the call refers to an External ; File System's volume, the call is passed to the external FS. ; Otherwise, a #paramErr is returned to the caller. ;________________________________________________________________________________ entry RefNumCall RefNumCall: jsr FSQueue ; chill in line move.w ioRefNum(a0),d0 ; Pick up the refNum jsr RefNumCheck ; Check the refNum supplied bne CmdDone ; Punt at first hint of trouble movea.l FCBsPtr,a1 ; Point to the FCB table move.w ioRefNum(a0),d1 ; Pick up the specified refNum movea.l FCBVPtr(a1,d1),a1 ; Point to the VCB for this volume move.l a1, ReqstVol ; In case it's #extFSErr tst.w VCBFSID(a1) ; Local FS? bne.s ExtFSErrExit ; No - let external file systems have it bra.s ParamErrExit ; Local doesn't implement this call ;________________________________________________________________________________ ; ; Routine: OpenCall ; ; Function: Open a fork with specific Deny modes; pass the call to the External; ; file system if it's for an Ext. FS volume. ;________________________________________________________________________________ ; entry OpenCall OpenCall: jsr FSQueue ; Wait our turn jsr DtrmV3 ; Determine the volume being referred to bne CmdDone ; Punt at the slightest hint of trouble move.l a2,ReqstVol ; Point to the volume being referred to tst.w VCBFSID(a2) ; External FS? beq.s ParamErrExit ; It's an unknown trap for a local volume bsr OpenAttemptHook ; let ourselves know we're trying <38> jsr Gt1stFCB ; get (A1,D1) pointing to first FCB @1 tst.l FCBFlNm(a1,d1) ; FCB unused beq.s @90 ; br if so jsr GtNxtFCB ; get next one until we run out bcs.s @1 moveq.l #TMFOErr,d0 ; too many files open clr.w IORefNum(a0) ; make refnum invalid bra CmdDone @90 add.l a1,d1 ; Point to the FCB bra.s ExtFSErrExit ; ... and pass it along ;________________________________________________________________________________ ; ; Routine: UnknownCall ; ; Function: Pass a call to the external File System. This routine is called for ; call selectors that are unknown to HFS and the Desktop Manager, but ; which might be implemented for External File Systems. ;________________________________________________________________________________ ; entry UnknownCall UnknownCall: jsr FSQueue ; Wait our turn movea.l VCBQHdr+qHead, a2 ; Pick up pointer to first VCB move.l a2, ReqstVol ; Point someplace semi-innocuous bra.s ExtFSErrExit ; ... and pass it along ;_______________________________________________________________________ ; ; Routine: FSControl ; Arguments: D1 = trap ; A0 = parameter list pointer ; ; Function: The FSControl entry point is provided in part to allow a ; program to sync up with the file system - the completion ; routine is called with exclusive access to all file system ; data structures... ; ;_______________________________________________________________________ FSControl: BSR.S FSQueue ; Wait out turn (sync up with FS) MOVE.L #FSVrsn,ioFSVrsn(A0); Return the current version of TFS <27Aug85> MOVEQ #0,D0 ; Indicate success BRA CmdDone ; And call it a day ;________________________________________________________________________________ ; ; Routine: RefNumCheck ; ; Function: Check the refNum supplied to make sure it's a real file RefNum. ; ; Inputs: d0 = refnum ; Output: d0 = error code, RfNumErr or noErr ; ; Note: ; This routine is called by the desktop manager and the UnTagFCB _Close patch. ;________________________________________________________________________________ ; This routine was rolled into into the file TFS.a. RefNumCheckRegs reg a1/d1 entry RefNumCheck RefNumCheck movem.l RefNumCheckRegs, -(sp) moveq.l #0, d1 ; clear high word move.w d0, d1 ; make a copy of the refnum bmi.s @RefNumErrExit ; no negative refnums divu FSFCBLen,d1 ; Divide by the FCB size swap d1 ; Get remainder in low word subq.w #2,d1 ; Is the remainder 2? bne.s @RefNumErrExit ; If not, no way this could be a refnum move.l FCBSPtr, a1 ; point to length word of FCB array cmp.w (a1), d0 ; check against size of FCB array bgt.s @RefNumErrExit ; Too high? Too bad. moveq.l #noErr, d0 ; No pwobwem! bra.s @Exit @RefNumErrExit: moveq.l #RfNumErr,d0 ; Indicate a bad refNum @Exit: movem.l (sp)+, RefNumCheckRegs tst.w d0 ; Set condition codes rts ;_______________________________________________________________________ ; ; Routine: FSQueueSync ; Arguments: D1 = trap ; A0 = parameter list pointer ; Calls: calling routine ; Called by: File system routines which must be executed synchronously ; (MountVol,UnMountVol). ; ; Function: This entry point waits until the file system queue is ; empty, and then calls the calling routine, ensuring ; synchronous (with other file system calls) execution of ; the file system routine at user-level (memory manager calls ; are ok). The called routine calls CmdDon when through. ; ; Modification History: ; ; 02 Dec 82 LAK New today. ; ;_______________________________________________________________________ FSQueueSync BCLR #AsyncTrpBit,D1 ; ensure async bit is not on ; fall thru to FSSync ;_______________________________________________________________________ ; ; Routine: FSQueue,CmdDone ; Arguments: D1 = trap ; A0 = parameter list pointer ; Calls: FSQue dispatches to the calling routine unless the call is ; asynchronous and the file system queue is not empty. Pascal ; register save conventions are observed. ; Called by: All file system routines when they may be executed asynchronously ; (i.e., they don't call the memory manager). ; ; Function: This entry point determines whether a call is synchronous ; or asynchronous; it queues up the call, then, if async and ; there is a command already executing, returns immediately. ; Otherwise, it enters the sync wait routine, then goes to ; command dispatch. ; ; All of these commands finish by branching to CmdDone; this ; routine calls any completion routine and dispatches the ; next queued command, if any . . . ; ; Modification History: ; ; 05 Aug 84 GSS New today (taken from Larry Kenyon's Mac File System) ; 24 Sep 84 GSS Removed JSR Enqueue and put in a trap ; 10-Feb-85 PWD Re-inserted JSR to Enqueue (now directly accessible again) ; 13-Mar-85 PWD Added code to set up A6 stack for async context storage\ ; 26-Jul-85 PWD Changed to restore ioTrap to $Ax60 and D0 to TFS trap index ; before going off to external file system hook. ; 25-Sep-85 PWD Changed to allow SkipPMSP to come on in mid-parse ; 22-Oct-85 PWD Fixed to check PMSP for traps w. TFS bit set but DirID=0. ; ; Do async calls have to be forced synchronous if the file system is not busy? ; Make sure interrupts are disabled at this time, though, so another request ; issued at interrupt time doesn't interfere. ;_______________________________________________________________________ FSQueue MOVE.L FSQueueHook,D2 ; queue hook? BLE.S @0 ; br if not . . . MOVE.L D2,A1 JSR (A1) ; D2 and A1 are expendable @0 MOVE.W #1,IOResult(A0) ; set IOResult to "in process" MOVE.W D1,IOTrap(A0) ; save the trap number CMP.B #$60,D1 ; TFS trap dispatch? BNE.S @2 ; If not, leave ioTrap alone AND.B #$0F,ioTrap(A0) ; Leave only modifier bits <27Aug85> MOVE.B D0,ioTrap+1(A0) ; Store trap index in low byte <27Aug85> @2 MOVE.L (SP)+,IOCmdAddr(A0) ; save address to go to when ready MOVE.W #FSQType,IOType(A0) ; say its a file system queueing element BTST #AsyncTrpBit,D1 ; async bit on? BEQ.S @3 ; br if not TST.B FrcSync ; force it synchronous? BEQ.S FSAsync ; if not, do it async BRA.S @4 @3 CLR.L IOCompletion(A0) ; no completion routines for sync calls @4 MOVE.L A0,-(SP) ; save parameter block ptr BSR.S FSAsync ; queue it up (and maybe call it) MOVE.L (SP)+,A0 SyncWait MOVE.W IOResult(A0),D0 ; get the result code into D0 BGT.S SyncWait ; done when result is zero or negative EXT.L D0 ; ALWAYS return a long error code. CMP.W #VolOffLinErr,D0 ; volume off-line error? (detected by file BNE.S @1 ; system) br if not MOVE.L DskSwtchHook,-(SP) ; OffLineVol points to VCB, A0 to request BGT.S @1 ; br if there is a hook proc ADDQ #4,SP ; otherwise, just return IF ForROM THEN ; <27Mar89 V1.8> BTST #7, DSAlertRect ; already in our proc? <06Mar85> BNE DSHook ; br if not <06Mar85> ENDIF ; <27Mar89 V1.8> @1 RTS ; return to caller FSAsync LEA FSQHdr,A1 ; get pointer to file system queue MOVE SR,-(SP) ; only allow level 3 ORI #HiIntMask,SR ; interrupts for debugging JSR EnqueueTrap ; queue up the request ToFSDispatch BSET #0,FSBusy ; is a request already executing? BEQ.S FSDispatch ; if not, just call it ; The file system is busy so we're done for now. We'll get to it when ; CmdDone is called. (maybe check here for async call with off-line vols, ; since only eject will force something off-line . . .) MOVEQ #0,D0 ; no errors (yet) MOVE.W (SP)+,SR ; re-enable interrupts and return RTS ; dispatch the next request (also called by CmdDon) FSDispatch MOVE (SP)+,SR ; re-enable interrupts MOVE.L FSQHead,A0 ; get first parameter block MOVE.L IOCmdAddr(A0),A1 ; get address to call MOVEM.L D3-D7/A2-A6,-(SP) ; observe Pascal regsave conventions ; Just before the initial dispatch into the routine, ; clear the Poor Man's Search Path: MOVEA.L PMSPPtr,A6 ; Point to the PMSP table CLR.W PMSPIndx(A6) ; No entries used yet BTST #AsyncTrpBit,ioTrap(A0) ; set the flavor for this trap <01Oct85> IF HFSDebug THEN ST FSCallAsync ; If we're debugging, always do async <27Oct85> ELSE SNE FSCallAsync ; if sync, we'll do our I/O synchronous <01Oct85> ENDIF ; MOVEA.L HFSStkTop,A6 ; Set up A6 for use as stack pointer JSR (A1) ; MOVEM.L (SP)+,D3-D7/A2-A6 ; restore registers RTS ; and return (all commands finish by ; jumping to CmdDone) toDSFSErr MOVEQ #DSFSErr,D0 _SysError CmdDone IF HFSDebug THEN BRA.S @3 ; check to see if cache is cool <02Oct85> @0 MOVEA.L A3,A4 ; start at top of queue <02Oct85> @1 MOVEA.L CBHFlink(A4),A4 ; position to next buffer <02Oct85> CMPA.L A3,A4 ; back to top of queue ? <02Oct85> BEQ.S @2 ; yes -> <02Oct85> BTST #CBHinuse,CBHFlags(A4) ; buffer in-use? <02Oct85> BEQ.S @1 ; no, continue search -> <02Oct85> _HFSDebug $500 ; trap if we exit FS with a buf in-use <02Oct85> @2 RTS ; 02Oct85 @3 MOVEM.L A3-A4,-(SP) ; save registers <02Oct85> MOVEA.L SysCtlCPtr,A3 ; A3 = ptr(control cache header) <02Oct85> BSR.S @0 ; check out the control cache <02Oct85> MOVEA.L SysBMCPtr,A3 ; <02Oct85> BSR.S @0 ; check out the alloc map cache <02Oct85> MOVEA.L SysVolCPtr,A3 ; <02Oct85> BSR.S @0 ; check out the volume cache <02Oct85> MOVEM.L (SP)+,A3-A4 ; restore registers <02Oct85> RealCmdDone ENDIF CLR.B CacheFlag ; we're always clean here . . . <05Sep85> EXT.L D0 ; Make a long of it <14Jun85> BLE.S @0 ; If zero or negative, we're OK <01Oct85> MOVE.W D0,HFSDSErr ; Save internal error for debug <01Oct85> MOVEQ #FSDSIntErr,D0 ; 1-127 codes are internal errors <01Oct85> @0 MOVE.L FSQHead,A0 ; A0 -> current request CMP #FSQType,IOType(A0) ; it better be an I/O queue element BNE.S toDSFSErr ; or else die CMP.W #FNFErr,D0 ; File not found error? BNE.S cd_CkExtFS ; If not, we're gone. BTST #HFSBit,ioTrap(A0) ; Use of HFSBit (=9) is OK on high byte ref. BEQ.S @2 ; If clear, consider the next entry on the PMSP <22Oct85> TST.L ioDirID(A0) ; TFS trap: was DidID specified? <22Oct85> BNE.S cd_CkExtFS ; Yes - there's no search path to consider <22Oct85> @2 BTST #NoPMSP,HFSFlags ; PMSP disabled? <25Sep85> BNE.S cd_CkExtFS ; If set, don't search any other directories <25Sep85> BTST #SkipPMSP,HFSFlags ; Don't bother with PMSP for this operation? <22Aug85> BNE.S cd_CkExtFS ; If flag isn't set, give it a chance <22Aug85> MOVEA.L PMSPPtr,A1 ; Point to the search path list MOVEM.L D1/A2,-(SP) ; Save them across the offline check MOVE.W PMSPIndx(A1),D1 ; Pick up the index @3 ADDQ.W #SPEntLen,D1 ; Advance to the next entry CMP.W (A1),D1 ; Index outside table yet? BGE.S @5 ; Yes - give up. MOVE.W SPVRefNum(A1,D1),D0 ; Pick up the VRefNum BEQ.S @5 ; If there isn't one, give up. BSR GetVCBRfn ; Find the VCB BNE.S @5 ; Punt on errors MOVE.W vcbDrvNum(A2),D0 ; Volume on-line? BLE.S @3 ; No - try next entry. @5 MOVE.W D1,PMSPIndx(A1) ; Point to this entry MOVE.W D1,D0 ; Save the index MOVEM.L (SP)+,D1/A2 ; Restore scratch registers CMP.W (A1),D0 ; Exceeded PMSP table limits? BGE.S @10 ; Yes - punt. TST.W SPVRefNum(A1,D0) ; Was a new default volume found? BEQ.S @10 ; Nope - give up. MOVEQ #0,D0 ; Clear high 3 bytes MOVE.B ioTrap+1(A0),D0 ; Pick up the TFS trap index again, too MOVEA.L ioCmdAddr(A0),A1 ; Pick up the CmdAddr from FSQueue JMP (A1) ; Repeat the trap with a different default @10 MOVEQ #FNFErr,D0 ; Restore error code cd_CkExtFS BCLR #SkipPMSP,HFSFlags ; Don't skip PMSP now that this trap's done <25Sep85> MOVE.L ExtFSHook,D2 ; queue hook? BLE.S @1 ; br if not . . . MOVE.L D2,A1 ; (external fs, debug) JSR (A1) ; leave CmdDone address on the stack @1 move.l toExtFS,d2 ; Any external file systems defined? <10Nov87> ble.s cd_DeQueue ; Xfer if not... <10Nov87> move.l d2,a1 ; Else, point to first proc in chain <10Nov87> cmp.w #ExtFSErr,d0 ; Pass request on to external FS's? <10Nov87> beq.s @2 ; Xfer if so... <10Nov87> cmp.w #NoMacDskErr,d0 ; Did a MountVol call fail? <10Nov87> bne.s cd_DeQueue ; Xfer if not... <10Nov87> clr.l ReqstVol ; Force 'No VCB' for this call <10Nov87> @2 MOVE.L FSQHead,A0 ; A0 -> current request CMP #FSQType,IOType(A0) ; it better be an I/O queue element BNE toDSFSErr ; or else die MOVEQ #ExtFSErr,D0 ; Code to ExtFS's unless an $Ax60 call <03Mar87> TST.W ioTrap(A0) ; Check trap word: BLT.S @3 ; If it's negative ($A...), go ahead <27Aug85> MOVEQ #0,D0 ; Clear high 3 bytes <27Aug85> MOVE.B ioTrap+1(A0),D0 ; Pick up the TFS trap index <27Aug85> CLR.B ioTrap+1(A0) ; and restore original trap <27Aug85> ORI.W #$A060,ioTrap(A0) ; keeping modifier bits <27Aug85> @3 JSR (A1) ; leave CmdDone address on the stack <25Jan85> cd_DeQueue MOVE SR,-(SP) ; save interrupt state <27Aug85> ORI #HiIntMask,SR ; only debug interrupts allowed CLR.W FSBusy ; clear file system busy boolean ; delete the current request from the queue and post any completion routines MOVE.L FSQHead,A0 ; A0 -> current request CMP #FSQType,IOType(A0) ; it better be an I/O queue element BNE toDSFSErr ; or else die MOVE.L QLink(A0),FSQHead ; get next request, if any BNE.S cd_CallComp ; branch if queue not empty <27Aug85> CLR.L FSQTail ; clear tail ptr, too cd_CallComp ; <27Aug85> MOVE (SP)+,SR ; restore interrupt state MOVE.W D0,IOResult(A0) ; post error code MOVE.L IOCompletion(A0),D1 ; is there a completion routine? BEQ.S cd_DispNext ; skip if there's not <27Aug85> MOVE.L D1,A1 ; get the completion routine address TST.W D0 ; test result code JSR (A1) ; call it ; check if there's anything else for this driver to do cd_DispNext ; <27Aug85> MOVE SR,-(SP) ; save interrupt state ORI #HiIntMask,SR ; only debug interrupts allowed TST.L FSQHead ; is a command pending? BNE ToFSDispatch ; if so, launch new command MOVE.W (SP)+,SR ; restore rupt state and return RTS ;_______________________________________________________________________ ; ; Routine: FInitQueue ; Arguments: none ; Calls: ; Function: Clear the queue of all pending commands except for the one ; running (if there is one . . .). ; ; Modification History: ; ; 05 Aug 84 New today. Taken directly from LAK's FS code ; ;_______________________________________________________________________ FInitQueue MOVE SR,-(SP) ; save interrupt state ORI #HiIntMask,SR ; only debug interrupts MOVE.L FSQHead,D0 ; any commands? BEQ.S @1 ; if not, we are done MOVE.L D0,A0 ; get pointer to the current routine CLR.L IOLink(A0) ; get rid of any others MOVE.L A0,FSQTail ; only this one @1 MOVEQ #0,D0 ; this routine has no errors MOVE.W (SP)+, SR RTS ;_______________________________________________________________________ ; ; Routine: DSHook ; Arguments: none ; Calls: ; Function: Implements disk-switch recovery. ; ; 29 Jan 85 LAK Doubled amount of stack slop needed. ; ; To Do: ; - be smarter about number of bytes to save of rectangle (compute from ; rectangle). ; ; There was a bug in the DSHook code used to force updates that is used when there is insufficient ; room on the stack to save the room behind the disk switch dialog. We now use the new global, ; SysErrorUpdateRect, instead. See the patch to GetNextEvent that uses SysErrorUpdateRect for more ; information ;_______________________________________________________________________ DSHook MOVEM.L A0-A3/A6/D0-D7,-(SP) ; save registers LEA TrapAgain,A1 ; fill in the trap now MOVE.W IOTrap(A0),(A1)+ ; Set up the trap to be retried... MOVE.W #$4E75,(A1) ; Follow it with an RTS ; first try mounting the volume in case it was forced off-line due to mem-full: IF NOT hasManEject THEN ; if man-eject, defer this a bit BSR MakeStkPB ; get a parameter block off the stack . . MOVE.L A0,D7 ; remember it in D7 ENDIF MOVE.L ReqstVol,A2 ; VCB for requested volume MOVE.W VCBDRefNum(A2),D3 ; Original drive BPL.S TellUser ; br if ejected-offline NEG.W D3 ; negative means non-ejected offline IF hasManEject THEN ; BSR MakeStkPB ; get a parameter block off the stack . . MOVE.W D3,ioDrvNum(A0) ; remount this drive MOVE.L FSVarsPtr,A1 BSET.B #fsNoAllocate,FSVars.fsFlags(A1) ; inform _Mount that it can't allocate memory _MountVol BCLR.B #fsNoAllocate,FSVars.fsFlags(A1) ADDA.L #IOVQElSize,SP ; goodbye paramblock TST ioResult(A0) ; success? BEQ.S DSExit TellUser MOVE.W #dsReinsert,D4 ; err code for SwitchDisk BSR.S SwitchDisk ; ask for the disk ; CCR: Z set if disk received, clear if request aborted DSExit ELSE ; if NOT hasManEject, here's the old DSHook, most of which resides in ; SwitchDisk for the manual-eject case. MOVE.W D3,IODrvNum(A0) ; so just remount (reload the buffers) MOVE.L FSVarsPtr,A2 ; BSET.B #fsNoAllocate,FSVars.fsFlags(A2) ; inform _Mount that it can't allocate memory _MountVol ; BCLR.B #fsNoAllocate,FSVars.fsFlags(A2); TST ioResult(A0) ; BNE.S TellUser ; ?? tell user something ?? <03Nov85> LAK MOVEQ #0,D3 ; yes, retry the fs call <03Nov85> LAK BRA DSExit ; exit . . . <03Nov85> LAK TellUser MOVE.L #$00500078,DSAlertRect ; use alternate alert rect MOVE.L #$00980195,DSAlertRect+4 ;(high bit is also flag) ; the code the saved the screen behind the dialog has been removed. MOVEQ #DSReInsert,D0 ; ask for diskette back _SysError EjectCurDisk MOVE.L DrvQHdr+QHead,D0 ; figure out if this drive has a disk-in-place @0 BEQ.S WaitForDsk MOVE.L D0,A1 CMP.W DQDrive(A1),D3 ; find queue element for this drive BEQ.S @1 MOVE.L QLink(A1),D0 BRA.S @0 @1 MOVE.B -3(A1),D0 ; DiskInPlace CMP.B #1,D0 ; BEQ.S @2 CMP.B #2,D0 BNE.S WaitForDsk ; just wait for disk-insert if no DIP @2 MOVE.W D3,D1 ; disk to eject EjectMtDisk ; <03Nov85> LAK MOVEQ #2,D2 ; a disk-switch eject <03Nov85> LAK BSR DoEject WaitForDsk SUB #EvtBlkSize,SP ; get event buffer space off the stack @0 MOVE.W #128+8,D0 ; only disk-inserted/key down events interest us MOVE.L SP,A0 ; event buffer _GetOSEvent BNE.S @0 ; loop until we get one . . . MOVE.L evtMessage(SP),D0 ; drive number/key MOVE.W evtNum(SP),D3 ; event MOVE.W evtMeta(SP),D1 ; meta keys (for command bit) ADD #EvtBlkSize,SP ; free up event buffer space SUBQ #diskInsertEvt,D3 ; disk-insert event? BEQ.S @3 ; br if so <02Nov85> LAK CMP.B #$2E,D0 ; period? BEQ.S @2 ; br if so <02Nov85> LAK MOVEQ #$0B,D2 ; seek cmd, shift, not alphaLock, and option <02Nov85> LAK LSR.W #8,D1 ; get high byte of meta-key info, clear D1.W hi byte <02Nov85> LAK AND.B D1,D2 ; high byte of meta word contains mod bits <02Nov85> LAK SUBQ.B #$03,D2 ; want cmd AND shift BUT NOT option <02Nov85> LAK BNE.S WaitForDsk ; if not so, no FKey action! <02Nov85> LAK moveq.l #-'3',d1 ; prepare to convert ascii to binary <2.6> add.b d0,d1 ; keyCode - '3' <2.6> addq.b #3,d1 ; convert key to drivenum, range check <2.6> bhs.s WaitForDsk ; if >= '3', or < '0', not an eject req <2.6> ext.w d1 ; drive number in D1.W <2.6> bne.s @1 ; 1, 2 handled as is, moveq #3,D1 ; 0 becomes 3 (drive #3) <2.6> @1 moveq #1,D2 ; flag from keyboard, move.l jDoEject,A0 ; jsr (A0) ; eject the diskette BRA.S WaitForDsk ; keep waiting for Disk-In-Place <02Nov85> LAK @2 BTST #cmdKey,D1 ; command-. for abort? <02Nov85> LAK BEQ.S WaitForDsk ; keep waiting if not BRA.S PostUpdate ; otherwise, let the user beware! ; D3 non-zero denotes abort . . . @3 MOVE.L D7,A0 ; point to the I/O block <02Nov85> LAK MOVE.W D0,IODrvNum(A0) ; drive to mount MOVE.W D0,D1 ; save in case we have to eject it <03Nov85> LAK MOVE.L FSVarsPtr,A2 ; BSET.B #fsNoAllocate,FSVars.fsFlags(A2) ; inform _Mount that it can't allocate memory _MountVol ; BCLR.B #fsNoAllocate,FSVars.fsFlags(A2) ; TST ioResult(A0) ; BEQ.S PostUpdate ; cruise on if ok <03Nov85> LAK CMP.W #MemFullErr,D0 ; memory full? BNE.S EjectMtDisk ; br if not - eject it and wait some more <03Nov85> LAK MOVEQ #-1,D3 ; make it an abort (avoid DS) <01Oct85> ; OK, we're basically done with the disk switched stuff. ; The code the saved the screen behind the dialog has been removed. PostUpdate ; CLR.B DSWndUpdate ; flag GNE to remove the alert . . . PEA DSAlertRect ; union this in MOVE.L ExpandMem,a0 ; PEA ExpandMemRec.SysErrorUpdateRect(a0) ; into this rect move.l (sp),-(sp) ; do it in place rb _UnionRect ; DSExit BSET #7, DSAlertRect ; return to old DS rect (also clears exclusion) <06Mar85> ; <06Mar85> ADD #IOVQElSize,SP ; clean up stack TST.W D3 ; zero for non-abort . . . <01Oct85> ENDIF ; hasManEject--the manual-eject and non-manual-eject threads rejoin here MOVEM.L (SP)+,A0-A3/A6/D0-D7 ; restore registers BEQ.S @1 ; br for retry <01Oct85> MOVEQ #VolOffLinErr,D0 ; well, not much else to do . . . <01Oct85> RTS ; <01Oct85> @1 MOVE.W ioTrap(A0),D0 ; Pick up trap word again <01Oct85> BLE.S FlushTrapAgain ; Go re-execute the original I/O trap <2> rb ; (should we be using a signed branch?) ; ; Repeat a TFS trap: the word in ioTrap (copied into TrapAgain by now) usually ; looks like 0mxx, where m contains the modifiers (,ASYNC and ,IMMED for TFS) ; and xx is the TFS trap dispatch. TrapAgain must be changed to Ay60 and D0 ; to $00xx. ; TFSAgain: OR.B #$A0,TrapAgain ; Set up top nibble MOVE.B #$60,TrapAgain+1 ; Overwrite lower bytes w. TFS trap AND.W #$00FF,D0 ; Remove modifier bits from saved index ; FlushTrapAgain ; MOVE.L D1,-(SP) ; save D1 for 020/030's <2> rb JSR ([jCacheFlush]) ; flush the cache <2> rb MOVE.L (SP)+,D1 ; restore D1 <2> rb JMP TrapAgain ; Go re-execute the original I/O trap <2> rb IF hasManEject THEN ; ; This is now a subroutine so it can be used by the Desk Manager to get back dirty ; disks that have been manually ejected. It largely duplicates the old code. ; Inputs: A2 -> VCB of desired volume ; D4 == DS err ID for alert to be displayed SwitchDisk MOVEM.L D1-D3/A0-A1/A3-A4,-(SP) ; save regs BSR MakeStkPB ; get ioPB space on stack MOVEA.L A0,A3 ; A3 -> paramblock SUBA.L #EvtBlkSize,SP ; stack space for evt record MOVEA.L SP,A4 ; A4 -> evt buffer MOVE.L #$004B006A,DSAlertRect ; set up alternate sys alert rect MOVE.L #$00A50196,DSAlertRect+4 ; (high bit is also flag) ; all NEW, all BIGGER DSAlertRect! MOVEA.L FSVarsPtr,A0 BSET.B #fsNoAllocate,FSVars.fsFlags(A0) ; prevent new mounts LEA vcbVN(A2),A1 MOVE.L A1,FSVars.dsRecoverNamePtr(A0) ; vol name for DS code MOVEQ #1,D3 ; first time through, do draw alert at @getdisk MOVEQ #2,D2 ; prepare disk-switch eject MOVE.W vcbDrvNum(A2),D1 ; try to get the drive in which the vol was last seen BNE.S @freeDrive MOVE.W vcbDRefNum(A2),D1 ; offline vol's drive num is in DRefNum field BPL.S @freeDrive ; positive if ejected-offline NEG.W D1 ; negative if only offline @freeDrive ; eject the disk in drive number D1, if any. D2 has "message" for EjectNotify-- ; 1 for an FKEY eject, 2 for disk-switch. MOVEA.L DrvQHdr+qHead,A0 ; Find drive queue element: get the first @chkdrv CMP.W dqDrive(A0),D1 ; match? BEQ.S @gotdrv ; yes: go check it out MOVEA.L qLink(A0),A0 ; no: get next drive MOVE.L A0,D0 ; any more? BEQ.S @getdisk ; can't find the drive BRA.S @chkdrv @gotdrv BTST #dqManEjBit,dqInstall(A0) ; is this a manual eject drive? BEQ.S @0 ; if so, the "Insert the disk" dialog will need to be MOVEQ #1,D3 ; redrawn after ejection--set D3 to indicate this @0 MOVEA.L jDoEject,A0 JSR (A0) @getdisk TST.W D3 ; does the dialog need to be drawn? BEQ.S @getevt MOVE.W D4,D0 ; get DS code _SysError ; draw it MOVEQ #0,D3 ; flag it drawn @getevt MOVE.W #128+8,D0 ; only disk-inserted/key down events interest us MOVE.L A4,A0 ; event buffer _GetOSEvent BNE.S @getevt ; loop until we get one . . . MOVE.L evtMessage(A4),D0 ; drive number or key CMPI.W #diskInsertEvt,evtNum(A4) ; disk-insert event? BEQ.S @dievt ; br if so <02Nov85> LAK MOVE.W evtMeta(A4),D1 ; meta keys (for command bit) CMP.B #$2E,D0 ; period? BEQ.S @chkabort ; br if so <02Nov85> LAK MOVEQ #$0B,D2 ; seek cmd, shift, not alphaLock, and option <02Nov85> LAK LSR.W #8,D1 ; get high byte of meta-key info, clear D1.W hi byte <02Nov85> LAK AND.B D1,D2 ; high byte of meta word contains mod bits <02Nov85> LAK SUBQ.B #$03,D2 ; want cmd AND shift BUT NOT option <02Nov85> LAK BNE.S @getevt ; if not so, no FKey action! <02Nov85> LAK moveq.l #-'3',d1 ; prepare to convert ascii to binary <2.6> add.b d0,d1 ; keyCode - '3' <2.6> addq.b #3,d1 ; convert key to drivenum, range check <2.6> bhs.s @getevt ; if >= '3', or < '0', not an eject req <2.6> ext.w d1 ; drive number in D1.W <2.6> bne.s @1 ; 1, 2 handled as is, moveq #3,D1 ; 0 becomes 3 (drive #3) <2.6> @1 moveq #1,D2 ; flag from keyboard, BRA.S @freeDrive @chkabort BTST #cmdKey,D1 ; command-. for abort? <02Nov85> LAK BEQ.S @getevt ; keep waiting if not BRA.S @aborted ; otherwise, let the user beware! ; D0 non-zero denotes abort . . . @dievt MOVE.L D0,D1 ; get drive num in D1.W SWAP D0 TST.W D0 ; is this a genuine insert event? BNE.S @ejectevt ; no: it's some sort of ejection MOVEA.L A3,A0 ; yes: get mountvol paramblock MOVE.W D1,ioDrvNum(A0) ; drive to mount _MountVol BEQ.S @exitok ; success! MOVEQ #2,D2 ; going to be a disk-switch eject BRA.S @freeDrive ; wrong disk--go eject it and try again @ejectevt CMP.W #-1,D0 ; is this an ejection request? BEQ.S @1 ; yes: treat it like an FKEY CMP.W vcbDRefNum(A2),D1 ; no: manual eject--is it the drive we expected the vol in? BEQ.S @getevt ; yes: probably spurious, so drop it...that drive should be empty ; no: hmm, what to do...repost, deal with it later SWAP D0 ; restore message MOVEA.W #DiskInsertEvt,A0 ; event type _PostEvent ; post it BRA.S @getevt ; go back for another @aborted MOVEQ #1,D3 BRA.S PostUpdate @exitok MOVEQ #0,D3 ; OK, we're basically done with the disk switched stuff. ; The code the saved the screen behind the dialog has been removed. PostUpdate ; BSR.S CleanDSErr ; cleanup code now a subroutine, for sharing CLR.W DSErrCode ; don't freak out the Process Mgr MOVEA.L FSVarsPtr,A0 BCLR.B #fsNoAllocate,FSVars.fsFlags(a0) ; new mounts are OK again MOVE.W D3,D0 ; get result, set CC ADDA.L #EvtBlkSize+IOVQElSize,SP ; clean that stack MOVEM.L (SP)+,D1-D3/A0-A1/A3-A4 ; restore those registers RTS ; Clean up the disk-switch error box--now a subroutine for sharing purposes. ; It is called from CmdDone after _Eject has been called for a manual-eject ; drive; CmdDone uses a DS alert to tell the user to take the disk out of the ; drive. CleanDSErr CLR.B DSWndUpdate ; flag GNE to remove the alert . . . PEA DSAlertRect ; union this in MOVE.L ExpandMem,a0 ; PEA ExpandMemRec.SysErrorUpdateRect(a0) ; into this rect move.l (sp),-(sp) ; do it in place rb _UnionRect ; BSET #7, DSAlertRect ; return to old DS rect (also clears exclusion) <06Mar85> ; <06Mar85> RTS ENDIF ; ; ;________________________________________________________________ ; ; Routine: vDoEject,DoEject ; Arguments: ; D1 = drive # to eject ; D2 = 1 for keyboard/eject button source, ; 2 for Disk Switch code hook ; ; calls EjectNotify function as: ; ; Function EjectNotify(drive:int;caller:int):boolean; ; ; if false is returned, the disk is not ejected; ; caller=1 for eject key, caller=2 for DS hook ;_______________________________________; vDoEject ;this label for export only DoEject BSR MakeStkPB ; get a parameter block MOVE.W D1,IODrvNum(A0) MOVE.L EjectNotify,D0 ; notify proc? BLE.S @1 ; br if not MOVEM.L D2/A0-A2,-(SP) CLR.W -(SP) MOVE.W D1,-(SP) ; pass eject drive MOVE.W D2,-(SP) ; 1=fkey eject, 2=ds hook eject MOVE.L D0,A0 ; procedure pointer JSR (A0) ; call it (it should preserve Pascal regs) TST.B (SP)+ ; still want to eject? MOVEM.L (SP)+,D2/A0-A2 BEQ.S @2 ; br if not @1 _Eject ; get rid of it . . . BEQ.S @2 MOVE.W #8,-(SP) _SysBeep ; make a beep @2 ADD #IOVQElSize,SP ; clean up stack and return RTS ;----------------------------------------------------------------- ; Initialize the file system. ; ; D0 -> number of FCBs to allocate. ; ;----------------------------------------------------------------- InitFS TST.W FSFCBLen ; are we in already? BPL FSInitOK ; br if so ; first, announce the presence of TFS by publishing the FCB size: MOVE.W #FCBEntLen,FSFCBLen ; Store size of TFS FCB there; non- -1 value means TFS is in ; next, zero the low-memory file system area LEA FileVars,A0 ; initialize our lomem vars to 0 MOVEQ #(FSClrWdLen/2)-1,D1 ; esp. VCB, FS queue hdrs, params, FSBusy @1 CLR.W (A0)+ DBRA D1,@1 MOVE.W #StrtDir,DRMstrBlk ; set up master block address ; get some memory for the FCBs CMP.W #2,MemTop ; 128K machine? <25Oct85> BLE.S @2 ; no multiplier for 128K <22Oct85> LSL.W #2,D0 ; mult by 4 for 512K+ <25Oct85> @2 MOVE D0,D2 ; save for WDCB allocation <25Oct85> MULU #FCBEntLen,D0 ; number of bytes needed for FCBs <25Oct85> ADDQ.W #2,D0 ; and 2 for length prefix <25Oct85> MOVE.W D0,D1 ; and save in D1 <25Oct85> _NewPtr ,SYS,CLEAR ; get buffer with D0 bytes in it. BNE FSInitErr ; Stop execution on any errors MOVE.W D1,(A0) ; first word is FCB part length MOVE.L A0,FCBSPtr ; set the FCB pointer ; Set up a WDCB array with the same number of entries as the FCB array: MULU #WDCBLen,D2 ; number of bytes needed for WDCBs <25Oct85> MOVE.L D2,D0 ; <25Oct85> ADDQ.W #2,D0 ; and 2 for length prefix <08Aug85> MOVE.W D0,D1 ; and save in D1 <11Apr85> _NewPtr ,SYS,CLEAR ; Allocate room for the WDCB array <11Apr85> BNE FSInitErr ; Crash and burn on errors <11Apr85> MOVE.W D1,(A0) ; Store length of WDCB array <11Apr85> MOVE.L A0,WDCBsPtr ; Store pointer in lomem <11Apr85> BigLEA WDCBSwOS,A2 ; point to offset to the WDCB entry <1.2> MOVE.W (A2),A2 ; Get the offset to the WDCB entry <1.2> ADD.L SwitcherTPtr,A2 ; Index into Switcher Table <1.2> MOVE.L A0,(A2) ; Fill in entry for WDCB switch <27Oct86><1.2> NOT.L (A2)+ ; ... complement for long addresses <27Oct86><1.2> MOVE.W D1,(A2) ; <27Oct86><1.2> ; Allocate a File System Stack: MOVE.L #(HFSStkLen+HFSTmpSize),D0 ; Size of stack area <26Aug85> _NewPtr ,SYS,CLEAR ; Allocate space in system heap <11Apr85> BNE FSInitErr ; Stop execution on any errors <11Apr85> ADD #HFSStkLen,A0 ; Point beyond the end of the stack <25Oct85> MOVE.L A0,HFSStkTop ; Store pointer in lo-mem <11Apr85> MOVEQ #PMSPSize,D0 ; Size of Poor Man's Search Path <18Aug85> _NewPtr ,SYS,CLEAR ; Allocate space for it <18Aug85> BNE FSInitErr ; Punt on errors <18Aug85> BigLEA PMSPSwOS,A2 ; point to offset to the PMSP entry <1.2> MOVE.W (A2),A2 ; Get the offset to the PMSP entry <1.2> ADD.L SwitcherTPtr,A2 ; Index into Switcher Table <1.2> MOVE.L A0,(A2) ; Fill in entry for PMSP hook switch <27Oct86><1.2> NOT.L (A2) ; ... complement for long addresses <27Oct86><1.2> ADDQ.L #SPHdrSize,A0 ; Point beyond PMSP header <18Aug85> MOVEQ #(PMSPSize-SPHdrSize),D0 ; Get length of remaining table <18Aug85> MOVE.W D0,(A0) ; Stash it at the start of the table <18Aug85> MOVE.L A0,PMSPPtr ; Set up the lo-mem pointer <18Aug85> ; Set up the lomem system cache pointers: (hack in until new cache arrives . . .) MOVE.W #512,D1 ; Set up cache block size <26Aug85> MOVEQ #1,D0 ; Allocate 1-block bitmap cache <26Aug85> Jsr InitCache ; Set up the cache <26Aug85><1.2> BNE.S FSInitErr ; <26Aug85> MOVE.L A1,SysBMCPtr ; Bitmap cache pointer. <26Aug85> MOVEQ #1,D0 ; Allocate a 1-block volume cache <20Sep85> CMP.W #2,MemTop ; 128K machine? <20Sep85> BLE.S @4 ; br if so <20Sep85> MOVEQ #2,D0 ; Allocate a 2-block volume cache <20Sep85> @4 Jsr InitCache ; Set up the cache <20Sep85><1.2> BNE.S FSInitErr ; <26Aug85> MOVE.L A1,SysVolCPtr ; Volume cache pointer <26Aug85> MOVEQ #4,D0 ; Allocate a small B*-Tree cache <04Nov85> CMP.W #2,MemTop ; 128K machine? <27Aug85> BLE.S @5 ; br if so <27Aug85> MOVEQ #16,D0 ; Allocate a LARGE B*-Tree cache <20Sep85> @5 Jsr InitCache ; Create a new cache <26Aug85><1.2> BNE.S FSInitErr ; <26Aug85> MOVE.L A1,SysCtlCPtr ; B*-Tree Control cache pointer <26Aug85> ; Set up a disk switch hook LEA DSHook,A0 ; Point to the disk switch code <22Jul85> MOVE.L A0,DskSwtchHook ; Make it available for use <22Jul85> ; Begin SuperMario ; allocate our file system variable block FM move.l FSVarsPtr,D0 ; has this been initialized? cmp.l #-1,D0 ; $FFFF FFFF if not bne.s FSInitOK ; initialized move.l #FSVars.size, d0 ; d0 = size of file system variable block _NewPtr sys, clear ; go get the block bne FSInitErr ; die horribly if we don't get it move.l a0, FSVarsPtr ; stash the address in lomem move.w #FSVars.size, FSVars.length(a0) ; store length of block in 1st word jsr FSGrowPatchInit ; FCBs, WDCBs and vectors jsr QMInit ; initialize the Queue Manager jsr DTDBMgrInit ; initialize desktop DB manager jsr InstallVectors ; install the vectors that hang off ExpandMem ; End of SuperMario patch roll inÉ FM FSInitOK MOVEQ #0,D0 ; success! RTS FSInitErr MOVEQ #-1,D0 ; we failed RTS ;_____________________________________________________________________________________ ; <38> ; CountFCBs ; ; Function: ; Return the number of free FCBs ; Return the total number of FCBs ; ; Use d0 as a max number to count, to allow for callers to check for a ; specific quantity of free FCBs. ; ; Input: ; d0.w - requested # of free FCBs ; ; Output: ; d0.w - number of free FCBs (clipped to input value of d0) ; d1.w - total number of FCBs ; ; ccr - Z set if requested number were free ; Z clear if not ; ; Note: When called with d0.w = #-1, the output in d1 is the total number ; of FCBs that exist. ; ;_____________________________________________________________________________________ ; This routine was copied FileMgrPatches.a CountFCBs @Regs reg d2/a0/a1 movem.l @Regs,-(sp) move.l FCBSPtr,a1 ; point to base of FCB array moveq.l #0,d1 ; clear high word move.w (a1),d1 ; grab length of the array lea.l 2(a1),a0 ; point to base of 1st FCB add.w d1,a1 ; point to end of FCB array divu FSFCBLen,d1 ; d1 = number of FCBs move.w d0,d2 ; copy limit value @loop: suba.w FSFCBLen,a1 ; point to beginning of previous FCB tst.l (a1) ; is it free? bne.s @notFree subq.w #1,d2 ; tally the free FCB beq.s @enough ; hit our quota? @notFree: cmpa.l a0,a1 ; are we done with the array? bhi.s @loop ; as long as we're above the bottom now @enough: sub.w d2,d0 ; d0 = number of free FCBs tst.w d2 ; d2 is zero if we hit our target movem.l (sp)+,@Regs rts ;_____________________________________________________________________________________ ; <38> ; OpenAttemptHook ; ; Function: ; This procedure is called each time some sort of Open call (one that allocates ; an FCB) is attempted. We're here to schedule the FCB allocator if ; necessary. The FCB allocator is now run after the sync wait loop (on failed ; opens) and at _SynchIdleTime, although it could be run anytime moving memory ; is cool. ; ; Optimization: ; Since counting the number of free FCBs is time consuming, we use fsFCBCounter ; to hold the approximate number of free FCBs in excess of the fsFCBBurst amount. ; We conservatively assume that each time we attempt an open we use up an FCB. This ; is obviously wrong, since some opens fail and _Close frees up FCBs, but this ; will allow us to avoid our more expensive check most of the time. When the counter ; does hit zero we count the array and set fsFCBCounter back up. We also might set ; the fsNeedsFCBs value if there are too few FCBs around. ; ; Input: ; a0 - pointer to caller's PB ; ; Output: ; none ;_____________________________________________________________________________________ ; This routine was copied FileMgrPatches.a OpenAttemptHook: @regs reg d0/d1/a1 movem.l @regs,-(sp) move.l FSVarsPtr,a1 with FSVars btst.b #fsNoFCBExpansion,fsFlags(a1) ; are we in the ballgame? bne.s @exit sub.w #1,fsFCBCounter(a1) ; see if we need to check bgt.s @exit ; no need to check if we're > 0 moveq.l #-1,d0 ; we want to know about all FCBs bsr CountFCBs ; see how many there are sub.w fsFCBBurst(a1),d0 ; do we have enough headroom? bls.s @needMore ; need more if (#free) <= (burst amount) move.w d0,fsFCBCounter(a1) ; remember the amount of slack bra.s @exit @needMore: bset.b #fsNeedFCBs,fsFlags(a1) ; remind ourselves of our need clr.w fsFCBCounter(a1) ; and make sure we check next time @exit: movem.l (sp)+,@regs rts ;_____________________________________________________________________________________ ; <38> ; AllocateFCBs ; ; Function: ; This is a private queued file system call which returns information ; about the FCB array and can allocate more FCBs. ; ; If a request for more FCBs is being made then AllocateFCBs must be ; called only when moving memory is legal. If the call is made for ; information only it can be made anytime. ; ; parameter block: ; ioFCBBurst offset $20, word, input requested burst headroom ; ioFCBGrow offset $22 word, input requested free if allocation triggered ; ioTotalFCBs offset $24 word, output returns number of FCBs present ; ioTotalFreeFCBs offset $26 word, output returns number of free FCBs ; ioFCBsAdded offset $2A, word, output returns number allocated this time ; ; Input: ; a0.l - pointer to PB ; ; Output: ; d0.w - #noErr if at least one FCB is free on exit. ; - #tmfoErr if no FCBs are free on exit ; ; AllocateFCBs always counts the total number of FCBs and the total number free. If there ; are ioFCBBurst FCBs free, no other work is performed. If there are fewer than ioFCBBurst ; FCBs free then AllocateFCBs will attempt to allocate enough new ones so that ioFCBGrow ; are free. ; ; ioFCBBurst and ioFCBGrow work together. ioFCBBurst is the number of opens that we'd ; like to be able to perform between visits to sync time. ioFCBGrow is the number that ; we'd like to have available when we go to the trouble of growing the array. ioFCBBurst ; must always be <= ioFCBGrow. ; ;_____________________________________________________________________________________ ; This routine was copied FileMgrPatches.a AllocateFCBs import MoreFCBs bsr.s FSQueue ; Wait out turn moveq.l #-1,d0 ; more FCBs than we'll ever have bsr CountFCBs ; count all of them move.w d0,ioTotalFreeFCBs(a0) ; remember how many are free move.w d1,ioTotalFCBs(a0) ; remember how many there are movea.l FSVarsPtr,a1 with FSVars move.w ioFCBBurst(a0),d2 ; get the # we'd like to keep free cmp.w d2,d0 ; see if we have that many free bhs.s @noAllocate move.w ioFCBGrow(a0),d2 ; d2 = the number of free FCBs we'd like to grow to sub.w d0,d2 ; d2 = the number we need to grow to there move.w fsFCBMax(a1),d3 ; d3 = the most FCBs we can have sub.w d1,d3 ; d3 = the most we can grow beq.s @noAllocate ; bail if we're out of array room cmp.w d2,d3 ; can we grow as much as we want to? bhs.s @grow ; if (most we can grow) >= (amount desired), we're OK move.w d3,d2 ; otherwise, just grow as much as we can @grow: bsr MoreFCBs ; try to get the FCBs beq.s @gotSome ; leave with a smile asr.w #1,d2 ; try to get half that many beq.s @noAllocate ; if we're down to zero, bail bra.s @grow @gotSome: add.w d2,ioTotalFCBs(a0) ; update the total count add.w d2,ioTotalFreeFCBs(a0) ; update the free count move.w d2,ioFCBsAdded(a0) ; note the number added bra.s @done @noAllocate: clr.w ioFCBsAdded(a0) ; we didn't add any new ones @done: tst.w ioTotalFreeFCBs(a0) ; check the number that are free now beq.s @noFCBsAvailable ; if none are left, report the problem moveq.l #noErr,d0 ; if some are left, we're happy @exit: bra CmdDone ; And call it a day @noFCBsAvailable: moveq.l #tmfoErr,d0 bra.s @exit endwith ;________________________________________________________________________________ ; Routine: File System cleanup routine <2.7> ; Function: Closes all open files belong to the process upon process termination. ; The process serial number in the Ext. FCB is cleared. ; ; By: Kenny Tung ; Copyright © 1989 Apple Computer, Inc. ; Input: D1 = trap, A0 = parameter block pointer ; HFS call requires an ioPB, but in this call no parameter is passed in. ; However, A0 is used to make the PBClose call within the routine. (Therefore ; it should be at least 26 bytes long). ; Revision History: ; 26Sep89 KSCT New today (from TFSDir1.a) ;________________________________________________________________________________ DoFSCleanUp ; serial ID is 64 bits FSCleanupRegs REG A2-A3/D2-D6 MOVEM.L FSCleanupRegs,-(SP) ; ask the Process Mgr which process is current MOVE.L A0,-(SP) ; save needed, but volatile, register LEA -10(SP),SP ; get current PSN and verify it's for us PEA 2(SP) ; push address of PSN _GetCurrentProcess ; call the OS MOVE.W (SP)+,D0 ; save result MOVE.L (SP)+,D6 ; D6 = process ID1 MOVE.L (SP)+,D2 ; D2 = process ID2 MOVEA.L (SP)+,A0 ; restore volatile register TST.W D0 ; check result now that stack restored BLT CleanupDone ; if so, we can do nothing MOVEA.L FSVarsPtr,A1 MOVEa.L FSVars.fcbPBuf(A1),A2 ; A2=parallel array MOVE cbPBufCount(A2),D3 ; D3=number of FCBs SUBQ #1,D3 ; for DBcc MOVE cbPBufULen(A2),D4 ; D4=ext. FCB unit size LEA fcbPBufData(A2),A2 ; A2=ext. fcb array MOVE FSFCBLen,D5 ; D5=FCB len jsr Gt1stFCB ; A1=FCB, D1=1st RefNum ; First close all the open files belong to this process: ; A1=FCBptr, A2=Ext. FCBptr, D1.W=RefNum, D2=id2, D3.W=loop index, ; D4.W=ext FCBlen, D5.W=original FCBlen, D6=id1 (not D1!) @cleanLoop MOVE.L xFCBPid2(A2),D0 ; do the 2nd one first CMP.L D0,D2 ; FCB belongs to this process? BNE.S @3 ; no-> MOVE.L xFCBPid1(A2),D0 CMP.L D0,D6 ; FCB belongs to this process? BNE.S @3 ; no-> ;; close the file only if it is open and not a system file. MOVE.L fcbFlNm(A1,D1),D0 ; file open? BEQ.S @2 ; not open -> invalidate PIDs CMP.L #FSUsrCNID,D0 ; Is it a system control file? BLO.S @2 ; yes, don't touch it ;; this open path belongs to this proc, let's close it BSR clearPB ; clear iopb in A0 MOVE D1,ioRefNum(A0) ; close this access path MOVEM.L A1/D1/D2,-(SP) ; these registers are trashed _Close ,Async ; close the file ASYNCly (to avoid deadlock) ;; but we will wait synchronously until it's done ..... @wait TST ioResult(A0) BGT.S @wait MOVEM.L (SP)+,A1/D1/D2 BNE.S @3 ; if error don't clear IDs @2 CLR.L xFCBPid1(A2) ; clear procID 1 CLR.L xFCBPid2(A2) ; clear procID 2 @3 ADDA D4,A2 ; go to next ext.FCB ADD.W D5,D1 ; go to next FCB RefNum DBF D3,@cleanLoop ; process them all É ;; Then close all the working direstories: D2.L/D6.L=procID, others are free MOVEA.L FSVarsPtr,A1 ; FSVars MOVEA.L FSVars.WDCBPBuf(A1),A2 MOVE cbPBufCount(A2),D3 ; D3=number of WDCBs SUBQ #1,D3 ; for DBcc MOVE cbPBufULen(A2),D4 ; D4=ext. WDCB unit size LEA wdcbPBufData(A2),A2 ; A2=1st ext. WDCB array MOVE #WDCBLen,D5 ; D5 = old WDCB len jsr Gt1stWDCB ; A1=WDCB array, D1=WDRefNum ;; A1=WDCBptr, A2=Ext WDCB, D1.W=WD RefNum, D2=id2, D3.W=loop index, ;; D4.W=ext wdcblen, D5.W= orginal WDCBlen, D6=id1 @WDLoop MOVE.L xWDCBPid2(A2),D0 CMP.L D0,D2 ; same process? BNE.S @6 ; no-> MOVE.L xWDCBPid1(A2),D0 CMP.L D0,D6 ; WDCB belongs to this process? BNE.S @6 ; no-> TST.L WDVCBPtr(A1,D1) ; WD open? BEQ.S @5 ; no-> already closed BSR.S clearPB ; clear iopb MOVEM.L A1/D1/D2,-(SP) ; these registers are trashed ADD.W #WDRfnMin,D1 ; Offset the index to make a WDRefNum (-32767) MOVE D1,ioVRefNum(A0) ; close this WD _CloseWD MOVEM.L (SP)+,A1/D1/D2 BNE.S @6 ; if error don't clear IDs @5 CLR.L xWDCBPid1(A2) ; clear procID 1 CLR.L xWDCBPid2(A2) ; clear procID 2 @6 ADDA D4,A2 ; go to next ext.WDCB ADD.W D5,D1 ; go to next WDCB RefNum DBF D3,@WDLoop ; process them all É BSR.S clearPB ; all done, return a clear PB CleanupDone MOVEM.L (SP)+,FSCleanupRegs MOVEQ #0,D0 ; happy ending RTS ; clear iopb in A0 up to ioRefnum. (28 bytes), A3 is free clearPB MOVEA.L A0,A3 ; A3=A0=iopb MOVEQ #(fscPBLen/4)-1,D0 ; iopb len in long -1 @2 CLR.L (A3)+ DBRA D0,@2 ; clear 28 bytes RTS ; __________________________________________________________________________________ ; InstallVectors ; ; Function: ; Attach ourselves to the appropriate vectors. ; ; For fsQueueHook, ExtFSHook and jFileOpen we selfishly insist that ; we're the first piece of code hooked in so that we can assume ; that we're the last one called. ; ; __________________________________________________________________________________ InstallVectors ; slam onto fsQueueHook, ExtFSHook and jFileOpen Import fsQueueHookPatch,ExtFSHookPatch Lea fsQueueHookPatch, a0 ; our patch address move.l a0, fsQueueHook ; be the first ones Lea ExtFSHookPatch, a0 ; our patch address <38> move.l a0, ExtFSHook ; be the first ones <38> ; install some vectors: move.l ExpandMem, a1 lea vSyncWait, a0 ; get addr of syncwait (in this fsQueueHook patch) move.l a0, ExpandMemRec.jSyncWait(a1) lea vAfterFSQHook, a0 ; get addr just past call to fsQueueHook (in fsQueueHook patch) move.l a0, ExpandMemRec.jAfterFSQHook(a1) lea CmdDone, a0 ; get addr of CmdDone move.l a0, ExpandMemRec.jCmdDone(a1) lea fsGeneralWakeUp, a0 ; get addr of general purpose File System kickstart move.l a0, ExpandMemRec.jDispatchNext(a1) lea fsSCSIFreeHookProc, a0 ; get addr of File System SCSI Busy deferral completion move.l a0, ExpandMemRec.jSCSIFreeHook(a1) rts ;__________________________________________________________________________________ ; ; Initialize FCB expansion patch, WDCB expansions patch, and vectors ;__________________________________________________________________________________ ; Roll into SuperMario fm FSGrowPatchInit: ; allocate the FCB parallel array movea.L FCBSPtr,a1 ; a1 = address of main FCB array moveq #0,d0 ; clear d0 for long calc move.w (a1),d0 ; bytes in FCB array and header divu.w FSFCBLen,d0 ; divide by element size to get count of FCBs andi.l #$FFFF,d0 ; clear d0 top word set by divu move.w d0,d1 ; Save # of FCBs in d1 lsl #L2ExtFCBLen,d0 ; d0 = total size of the parallel array addq #fcbPBufData,d0 ; include info words _NewPtr sys, clear ; Allocate buffer for FCBs bne.s GrowErrExit ; Any errors are fatal ; initialize parallel FCB array header and install the array in FSVars move.w d1,cbPBufCount(a0) ; first word = count move.w #ExtFCBLen,cbPBufULen(a0) ; second word = unit size movea.L FSVarsPtr,a1 ; save array address in FSVars move.l a0,FSVars.FCBPBuf(a1) ; now we're ready to record file opens! ; allocate the WDCB parallel array move.l WDCBSPtr,a1 ; a1 = address of main WDCB array moveq #0,d0 ; clear d0 for long calc move.w (a1),d0 ; length of WDCB array divu.w #WDCBLen,d0 ; divide by element size to get count of WDCBs andi.l #$FFFF,d0 ; clear d0 top word move.w d0,d1 ; Save # of WDCBs in d1 lsl #L2ExtWDCBLen,d0 ; d0 = total size of the parallel array addq #wdcbPBufData,d0 ; include info words _NewPtr sys, clear ; Allocate buffer for FCBs bne.s GrowErrExit ; Any errors are fatal ; initialize parallel WDCB array header and install the array in FSVars move.w d1,cbPBufCount(a0) ; first word = count move.w #ExtWDCBLen,cbPBufULen(a0) ; second word = unit size movea.L FSVarsPtr,a1 ; save array address in FSVars move.l a0,FSVars.WDCBPBuf(a1) ; now we're ready to record _OpenWDs! ; initialize FCB expansion mechanism <38> movea.l FSVarsPtr,a1 move.w #fsDesiredFCBBurst,FSVars.fsFCBBurst(a1) move.w #fsDesiredFCBFree,FSVars.fsFCBGrow(a1) clr.w FSVars.fsFCBCounter(a1) ; make us check on the next open move.w #$7fff,d0 ; max signed int is all we can have for the FCB array ext.l d0 ; divide takes a long input divs fsFCBLen,d0 ; d0 = max # of FCBs move.w d0,FSVars.fsFCBMax(a1) rts GrowErrExit: MOVEQ #dsMemFullErr,D0 ; no mem _SysError ;________________________________________________________________________________ ; ; Routine: GetVolParms ; ; Input: a0 - pointer to user's param block ; Output: d0 - result code ; ; Function: Return a version 2 GetVolParms param block ; ; Interesting problems with GetVolParms (which aren't important enough to cause ; us to make a change this close to 7.0 final. Obviously, if you're reading this ; after 7.0 final, please make these changes for the good of humanity. You should find ; these written up in the BRC). ; 2) The suba.w @VolParmsBufferSize,a6 instruction needs to be changed to a long subtract. ; What happens now is that zero is subtracted from a6, but the size of the saved registers ; happens to be bigger than the buffer, so there's enough room on the stack. Since the File ; Manager happens to save registers before dispatching, the fact that GetVolParms trashes ; the registers is unimportant. Thus, the three parallel changes are to get rid of the ; regster save/restore, change the suba.w to a suba.l, and add an adda.l at the bottom of ; the routine to deallocate the buffer. ; ;________________________________________________________________________________ ; Roll in for SuperMario. Fix up the GetVolParms: @GetVolRegs reg d2/d3/a1-a4 ; FM bclr #asyncTrpBit, ioTrap(a0) ; force synchronous (wrong. See note, above) jsr FSQueue ; Patiently wait our turn in line ; FM movem.l @GetVolRegs, -(a6) ; save regs on FS stack suba.l @VolParmsBufferSize, a6 ; FM allocate a GetVolParms buffer on the stack ; ; Find the VCB in question: ; jsr DtrmV3 ; find vol using ioNamePtr & ioVRefNum (D023/A234 trashed) bne.s @GetVolParmsExit ; (DtrmV3 puts VCBPtr in A2) tst.w vcbFSID(a2) ; Check: external file system? (¥¥ TFSVCBTst?) beq.s @ForUs ; If zero, it's HFS. ; ; This call is for an External File System volume: ; moveq #extFSErr, d0 ; Tell the world bra.s @GetVolParmsExit ; and let them worry about it ; ; This call is for us. First, make a modifiable copy of the return buffer. ; @ForUs: movea.l a0, a4 ; move user's pb to a safe register move.l @VolParmsBufferSize, d0 ; d0 = size of GetVolParms' ioBuffer movea.l a6, a1 ; onto our stack buffer lea.l @HFSVolParmsBuffer, a0 ; copy the static values for HFS volumes cmp.w #SigWord,vcbSigWord(a2) ; is this an MFS volume? bne.s @notMFS ; no, skip the following lea.l @MFSVolParmsBuffer, a0 ; copy the static values for MFS volumes @notMFS: _BlockMove bsr CheckDesktopSupport ; returns zero clear if support, set if none beq.s @NoDTSupport ; z set means no support move.l vmAttrib(a6), d0 ; get the attributes word bset.l #bHasDesktopMgr, d0 ; set the bit indicating support move.l d0, vmAttrib(a6) ; put the modified word back in the buffer @noDTSupport: ; ; The buffer on the stack reflects the correct values for this volume. ; Copy back as much of it as the caller gave us room. ; move.l ioReqCount(a4), d0 ; get user's buffer size cmp.l @VolParmsBufferSize, d0 ; is it smaller than our buffer? bls.s @NoClip ; then just return that amount move.l @VolParmsBufferSize, d0 ; clip the return to just the size of our data @noClip: move.l d0, ioActCount(a4) ; tell'em how much we're copying move.l a6, a0 ; copy from our stack buffer move.l ioBuffer(a4), a1 ; copy into the user's pb buffer _BlockMove @GetVolParmsExit: adda.l @VolParmsBufferSize, a6 ; FM deallocate a GetVolParms buffer on the stack ; fm movem.l (a6)+, @GetVolRegs ; restore regs jmp CmdDone ; Go home ; This buffer contains the appropriate values for local HFS volumes. @HFSVolParmsBuffer: dc.w 2 ; this is a version 2 getvolparms dc.l localvMAttribs ; static set of local attribute bits dc.l 0 ; no local window handle dc.l 0 ; no server address dc.l localVolGrade ; standard volume grade dc.w 0 ; local volumes don't support alt priv models @VolParmsBufferSize: dc.l *-@HFSVolParmsBuffer ; This buffer contains the appropriate values for local MFS volumes. @MFSVolParmsBuffer: dc.w 2 ; this is a version 2 getvolparms dc.l 0 ; no optional calls supported for MFS volumes dc.l 0 ; no local window handle dc.l 0 ; no server address dc.l localVolGrade ; standard volume grade dc.w 0 ; local volumes don't support alt priv models ; .NoList INCLUDE 'TFSCommon.a' ; Common subroutines w. TFSUtil INCLUDE 'TFSVol.a' ; TFS volume level routines INCLUDE 'MFSVol.a' ; MFS-specific volume level stuff INCLUDE 'TFSDir1.a' ; include routines using filenames INCLUDE 'MFSDir1.a' ; INCLUDE 'TFSDir2.a' ; INCLUDE 'MFSDir2.a' ; INCLUDE 'TFSDir3.a' ; INCLUDE 'MFSDir3.a' ; INCLUDE 'TFSRfN1.a' ; include routines using refnums INCLUDE 'MFSRfN1.a' ; INCLUDE 'TFSRfN2.a' ; INCLUDE 'MFSRfN2.a' ; INCLUDE 'TFSRfN3.a' ; INCLUDE 'MFSRfN3.a' ; ****************************************************************************************** * some lucky person gets to roll the following file into the rest of the sources INCLUDE 'FileMgrHooks.a' ****************************************************************************************** END