mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
5417 lines
217 KiB
Plaintext
5417 lines
217 KiB
Plaintext
;
|
|
; File: FileMgrPatches.a
|
|
;
|
|
; Contains: Patches to the file system.
|
|
;
|
|
; Copyright: © 1990-1992 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM1> 4/15/92 kc Removed the "ROM" prefix from the RomBind routines.
|
|
; Added comments to all of the patches that were rolled in.
|
|
; ¥ Pre-SuperMario comments follow ¥
|
|
; <56> 3/18/92 gs rolled in Disappearing Folder Fix from Presto (patch to CMSetup)
|
|
; Pete said it was Okay. No, Really, he did!
|
|
; <55> 11/25/91 DTY Make a new call, GetParallelFCBFromRefNum, and give it selector
|
|
; $50. This eventually calls ParallelFCBFromRefNum, but does some
|
|
; sanity checking beforehand.
|
|
; <54> 8/30/91 DTY Define has3rdFloppy here since itÕs no longer defined in
|
|
; BBSStartup. Defined to be 0 because has3rdFloppy was 0 for
|
|
; System builds before.
|
|
; <53> 6/25/91 BH fix ClosePatch which was incorrectly pushing kSystemProcess onto
|
|
; the stack which resulted in the check to see if a file was
|
|
; opened by kSystemProcess to always fail (changed code to use PEA
|
|
; kSystemProcess instead of PEA #kSystemProcess)
|
|
; <52> 4/4/91 dnf csd, #86223: Have Basic I/O pass VM errors from the driver
|
|
; through to the caller. Currently notEnoughMemoryErr is the only
|
|
; VM error we expect.
|
|
; <51> 3/28/91 dnf ewa, #CheckDesktopSupportFails: The GetVolParms call returns the
|
|
; wrong value for bHasDesktopMgr for small non-ejectable volumes.
|
|
; <50> 3/27/91 KST bb, ksTung#16: Fixing a bug in ROM BTDelete which used MOVE.W to
|
|
; move a long word.
|
|
; <49> 3/19/91 dnf dba, dty: Make sure the lenient remount check in ROM doesnÕt
|
|
; trigger.
|
|
; <48> 3/17/91 dnf dba, dty, #84670, #82944, #84977 : use
|
|
; CallWithRegistersPreserved in dispatching; save D0 across calls
|
|
; to completion routines. Save trashed registers across btree
|
|
; calls on the Mac Plus.
|
|
; <47> 3/11/91 dnf dba, #dnf10: nuke MakePBLookAsync since it never did any good
|
|
; <46> 3/11/91 dnf dba, #83239: stop relying on external file systems to preserve
|
|
; A0; for example, AppleShare client trashes A0 on a _GetVolParms
|
|
; <45> 3/11/91 dnf dba, #84288: flush the cache properly after writing the trap
|
|
; word in TrapAgain in low memory, but before jumping there; this
|
|
; is especially important for 68040 processors; we had to fix this
|
|
; in the code that re-fires a trap after running out of FCBs, but
|
|
; we didnÕt have to fix it for the Disk Switch Hook, since it
|
|
; calls MountVol, which calls BlockMove, which calls CacheFlush
|
|
; <44> 3/11/91 dnf dba, #84430,#83779: fix the extents truncation patch so that it
|
|
; is no longer confused between data and resource forks; this
|
|
; fixes fragmentation that was occurring when the Finder did
|
|
; copies
|
|
; <43> 3/11/91 dnf dba, #84257: Fix the DesktopCloseDownProc so that it works even
|
|
; when the Unmount is done by name. This was fixed by copying the
|
|
; string passed to Unmount onto the stack before calling
|
|
; GetVolInfo.
|
|
; <42> 2/28/91 dnf dba, #84095: Fix the DesktopCloseDownProc to work when called
|
|
; with parameters that aren't vRefNums.
|
|
; <41> 2/26/91 dnf gbm,bbm, #83780: Enlarge the file system stack.
|
|
; <40> 2/26/91 KST dnf, ksTung#15: FSM Hook should not call "UnMungTrapWord" if FSM
|
|
; defined foreign file system returns a real error.
|
|
; <39> 2/26/91 csd dba: Add the export for FileManagerIdleProc, fix the patches to
|
|
; FileOpen and OpenRF so that they set the RegRsrc global.
|
|
; <38> 2/25/91 dnf dfh, #80720,#82672: Fix the FCBs problem by implementing a new
|
|
; file system call, _AllocateFCBs.
|
|
; <37> 2/15/91 KST dnf, #83093: CMRenameCN binds to the wrong ROM address on the
|
|
; Plus.
|
|
; <36> 2/12/91 dnf gbm, #81716: Move the call to DTCloseDown from the Desktop
|
|
; Manager's unmount notification hook to a patch to _Unmount.
|
|
; This will ensure that it gets called after we know that none of
|
|
; the parties on the Process Manager hook have decided to reject
|
|
; the unmount.
|
|
; <35> 2/7/91 dnf kst, #79676: Set dsRecoverVCBPtr inside of CmdDone on all
|
|
; #offlineErrs. This eliminates (most of) the reentrancy problems
|
|
; with the name drawn by the disk switch hook.
|
|
; <34> 1/25/91 dnf dba, #bo3b1: Make the file system not defer itself on sync
|
|
; calls. This allows macsbug to use sync calls to implement its
|
|
; log and reboot features.
|
|
; <33> 1/21/91 dnf (ewa) Clear the error code for write-protected remounts.
|
|
; <32> 1/20/91 dnf (Eric Anderson) _Eject and _Offline need to set the ÒVCB
|
|
; unmounted OKÓ bit with a read-modify-write to the MDB.
|
|
; <31> 1/18/91 dnf (kst) Fix ROM address for FSQueueSync on the SE.
|
|
; <30> 1/18/91 dnf (dba) Use a ROMBind for FindDrive since it isn't vectored on the
|
|
; Plus and SE. Change _Unmount to make direct calls to FClose and
|
|
; TrashVBlocks instead of calling FlushBuffers, which attempts to
|
|
; set the ÒVCB unmounted OKÓ bit with a read-modify-write to the
|
|
; MDB. Patch out most of _Offline & _Eject since <29> needs the
|
|
; jFClose vector which doesn't exist on the Plus and SE.
|
|
; <29> 1/16/91 dnf (csd) Change _Offline and _Eject to never close the volume btree
|
|
; files and _UnMount to always close them.
|
|
; <28> 1/15/91 KST With dnf: ExtFSCatchAll should return if D0 is negative or zero.
|
|
; <27> 1/14/91 KST With BB: patch to CMCreateCN and CMUpdateCN to mark VCB dirty if
|
|
; VCBModTime has been changed. The other half of the patch is in
|
|
; 'CMSvcsExtra.a'.
|
|
; <26> 1/7/91 KST With dnf: Set up A0=ioParam before calling FSM hook.
|
|
; <25> 1/4/91 KST With dnf: Adding FSM hook in.
|
|
; <24> 12/26/90 dnf (csd) Make the disk switch hook think that it should never save
|
|
; bits behind the disk switch alert. The file system now relies
|
|
; completely on the system error handler and update events for
|
|
; drawing the alert and cleaning up afterwards.
|
|
; <23> 12/21/90 dnf (dfh) Have UnTagWDCBs not attempt to untag a vRefNum that is
|
|
; serving as a WD to the root.
|
|
; <22> 12/18/90 dnf (dba) Fix the second case in the Rename patch
|
|
; <21> 12/18/90 dnf (dba) Return correct error codes from async. calls (change to
|
|
; CmdDone).
|
|
; <20> 12/16/90 dnf (dba) Patch the disk switch hook to fail with a #volOffLinErr on
|
|
; #memFull from _MountVol. Patch _MountVol to not attempt to get
|
|
; more memory by calling _Offline on other already mounted
|
|
; volumes. Changed tst.l on FSID to tst.w in OpenRF sychronization
|
|
; patch. Saved fewer registers here also. Fixed both _SetVolInfo
|
|
; and _Rename to always do the right thing when renaming volumes.
|
|
; (nil, null, > 27, and keeping the root in sync with the vcb).
|
|
; <19> 12/16/90 dnf (dfh) Do a real UnTagWDCBs
|
|
; <18> 12/14/90 dnf (djw) Add SCSI-is-busy deferral code. Replace FSQueue and CmdDone
|
|
; logic by grabbing control at FSQueueHook and ExtFSHook.
|
|
; <17> 12/13/90 KST With Bill B.: Adding a come from patch to TruncateFile to fix a
|
|
; bug in FClose. See detail in the code.
|
|
; <16> 12/6/90 dnf (dfh) Get rid of obsolete ROM jump table source that didnÕt
|
|
; generate any code anyway. Implement _Close patch so that file
|
|
; that were opened in System Mode cannot be closed outside of
|
|
; system mode.
|
|
; <15> 9/26/90 dnf (dnf/pwd) Use the ol' TrapAgain lomem to re-fire calls that have been
|
|
; rescued by the more fcbs/more wdcbs code. (dnf/th) Change SetFilLock and
|
|
; RstFilLock to use the new definition of FXInfo.
|
|
; <14> 9/25/90 dnf (dnf/sab) Make sure that the dispatcher preserves the trap word
|
|
; in d1. Emulate MakeFSSpec on wPrErr for confused iso-9660 disks.
|
|
; <13> 9/23/90 csd Changed fsDeferProc to use the right register instead of jumping
|
|
; to random code which does random things with DarinÕs name.
|
|
; <12> 9/22/90 dnf Clear the fsDeferFlag when the deferred task fires.
|
|
; <11> 9/22/90 csd (dfh) Fixed a bug in ParallelFCBFromRefnum which implicitly
|
|
; expected the high word of D0 to be clear. Fixed the
|
|
; fixDiskSwitch patch to not destroy command-. events.
|
|
; <10> 9/22/90 dnf oops... we can't use D1 to put the trap word in...
|
|
; <9> 9/22/90 dnf (dnf/pwd/dfh) Modified a060 patch to dispatch all possible
|
|
; (that's 255) hfs dispatch selectors. This obviates the need for
|
|
; any patches like ASFSInit which add new selectors by stealing
|
|
; calls off of a060. Added MakeFSSpec emulation Add fsQueueHook
|
|
; patch (FCB & WDCB expansion, process serial number recording,
|
|
; file system interrupt level deferring) Change ExtFSPatch (move
|
|
; most stuff to fsQueueHook.) Add toExtFS patch (catch
|
|
; unimplemented a060 selectors)
|
|
; <8> 8/29/90 dnf Change selectGetAltAccess to selectGetForeignPrivs
|
|
; <7> 8/28/90 dnf Change references to selectCreateFileID to
|
|
; selectCreateFileIDRef.
|
|
; <6> 8/15/90 KST Grow the WDCB (and FCB) array if we are running out of WDCB.
|
|
; <5> 8/10/90 KST Renaming NuLenBTCB to lenBTCB70.
|
|
; <4> 8/6/90 dnf Rename __MakeFSSpec to MakeFSSpec
|
|
; <3> 8/6/90 KST Fixing a bug in OpenWD patch. If MultiFinder is not ready, we
|
|
; need to compare appl's ProcID.
|
|
; <2> 7/30/90 dnf Move all of the 7.0 patches into here; convert them to linked
|
|
; patch format
|
|
; <1> 4/20/90 dba first checked in
|
|
;
|
|
;
|
|
;
|
|
; Change History from HFS70PatchTail.a
|
|
;
|
|
; <23+> 7/24/90 dnf Convert to linked patch
|
|
; <23> 7/2/90 dnf Add afp inhibit bits to Set/RstFlock calls + referenced ROM
|
|
; addresses
|
|
; <22> 6/20/90 KST Don't grow FCB array beyond limit (16 bits positive word). The
|
|
; max. FCB is now 344. Also fixed the bug that doesn't close every
|
|
; 8th file after 40.
|
|
; <21> 6/1/90 dnf Add rom addresses for CMGetCN. Change _OpenDF to set the trap
|
|
; word to _Open (Ax00) for the benefit of existing external file
|
|
; systems.
|
|
; <20> 5/4/90 dnf Add dispatch to MakeFSSpec
|
|
; <19> 4/17/90 KST Fixing a bug that calls "adjEOF" with the wrong Refnum.
|
|
; <18> 4/10/90 KST Fixing a bug in FOpen, it doesn't do "adjEOF" if openning a
|
|
; resource file.
|
|
; <17> 4/10/90 KST Need to restore ioParam in A0 after calling external FS.
|
|
; <16> 4/9/90 dnf Add DTDelete to this patch's dispatch table; change all call
|
|
; names to match final versions.
|
|
; <15> 3/28/90 KST Clear D4 before storing FCB and divide by FCBLen.
|
|
; <14> 3/20/90 KST fixed a branch error.
|
|
; <13> 3/20/90 KST Record PSN or grow the FCB/WDCB only for SYNC open calls
|
|
; <12> 3/20/90 KST Record PSN or grow the FCB only for SYNC open calls.
|
|
; <11> 3/20/90 dnf Don't attempt to send shared environment calls out the
|
|
; toExtFSHook.
|
|
; <10> 3/20/90 KST Enabling the recording of PSN (again). Added support for AFP;
|
|
; pop off return address for ASYNC call; saved D1 for AppleShare.
|
|
; <9> 3/16/90 dnf Add stubs for volume and refnum based calls
|
|
; <8> 2/21/90 KST 1. Enable the recording of PSN. 2. Don't close system files on
|
|
; FSCleanUp (fileNum < 16).
|
|
; <7> 2/15/90 DNF Don't step on the result code out of GetVolParms
|
|
; <6> 2/10/90 csd with dnf. Disabled the tail patch to ExtFSHook which watched for
|
|
; the opening of files and recorded them in a parallel structure.
|
|
; The scheme prevented the unmounting of servers.
|
|
; <5> 2/6/90 KST Fixing a bug in OpenRF that doesn't record process serial number
|
|
; when openning RFile.
|
|
; <4> 2/4/90 dnf Changed equates to use StandardEqu.d
|
|
; <3> 1/23/90 csd with dnf: replaced use of constant openWDN with fsOpenWD which
|
|
; is more appropriate.
|
|
; <2> 1/9/90 dnf Move some private equates directly into this file Add CheckCSPB,
|
|
; OpenDF and xOpenDT
|
|
; <3.3> 12/8/89 dnf Changed GetVolParms' buffer
|
|
; <3.2> 11/21/89 KST Fixed a bug when growing parallel array. Forgot to include
|
|
; header length.
|
|
; <3.1> 11/17/89 dnf Moved dispatch #'s from 40-4f to 60.
|
|
; <3.0> 10/30/89 KST Fixed some ROM addresses. It should use jump table address.
|
|
; <2.9> 10/30/89 dnf AlkBlkSiz is a word, even though it is stored as a long
|
|
; <2.8> 10/17/89 KST Fixed ROM addresses for Esprit.
|
|
; <2.7> 10/16/89 KST Added routines for FSCleanUp HFS call. Allocate FCB and WDCB
|
|
; parallel array at boot time. Patched OpenWD and FileOpen to
|
|
; store Process serial ID in the parallel array. Grow FCB/WDCB
|
|
; array and friends dynamically.
|
|
; <2.6> 10/11/89 dnf updated GetVolParms, added AltPrivsStub, removed XGetInfo call
|
|
; <2.5> 9/29/89 EKN Added Gt1stFcb, GtNxtFcb, FlushCache
|
|
; <2.4> 9/18/89 dnf Added XGetInfo call
|
|
; <2.3> 9/7/89 dnf dnf for kst. Roll in BTree writecount patch
|
|
; <2.2> 8/26/89 dnf Add Aurora (Mac IIci) and Esprit (Mac Portable) ROM addresses
|
|
; <2.1> 8/7/89 dnf Don't clobber d0 in dispatch, get rid of PRNonPortable
|
|
; <2.0> 8/7/89 EMT Use inc.sum.d rather than individual includes for speed and
|
|
; accuracy.
|
|
; <1.9> 7/24/89 EKN Added TFSVCBTst, Gt1stMatch. Changed FileIDs call names from
|
|
; "PB.." to "PBH...".
|
|
; <1.8> 7/6/89 dnf Enable desktop db mgr. Change references to ExtOffLinCh to
|
|
; ExtOffLinCk to match ROM
|
|
; <1.7> 6/1/89 EKN Get PushCName and PopCName to different rom addresses, please.
|
|
; <1.6> 5/31/89 dnf Really disable Desktop Mgr this time.
|
|
; <1.5> 5/31/89 dnf Desktop mgr hangs in btree mgr. Disable Desktop mgr for 7.0a1 so
|
|
; machine won't hang opening Desktop DB
|
|
; <1.4> 5/31/89 dnf Back out of fancy new DCBind macro to old (reliable) JmpBind
|
|
; <1.3> 5/31/89 dnf Reordered equates. HFS70Equ needs to be before CatSrchPriv.a
|
|
; <1.2> 5/31/89 EKN Fixed Rom address for BTSearch. Added entries for CMDelete,
|
|
; CMRename, CMMove
|
|
; <1.1> 5/31/89 EKN Filled in rom addresses, hooked in CMSetUp correctly,and unset
|
|
; IsAnINIT.
|
|
; <1.0> 5/30/89 dnf Integrate CatSearch, FileID's and Desktop Database Mgr into one
|
|
; ptch
|
|
;
|
|
; To Do:
|
|
;
|
|
;
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; IncludesÉ
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
|
|
;
|
|
; <54> has3rdFloppy is false for System builds.
|
|
;
|
|
|
|
if (&type('has3rdFloppy') = 'UNDEFINED') then ; <54>
|
|
has3rdFloppy: equ 0 ; <54>
|
|
endif ; <54>
|
|
|
|
|
|
print push
|
|
print off
|
|
load 'StandardEqu.d'
|
|
include 'FileMgrPrivate.a'
|
|
include 'CatSrchPriv.a'
|
|
include 'BTreeEqu.a'
|
|
include 'DTDBMgrPriv.a'
|
|
include 'DTDBMgrEqu.a'
|
|
include 'LinkedPatchMacros.a'
|
|
include 'QMgrEqu.a'
|
|
include 'GestaltEqu.a'
|
|
include 'MFPrivate.a'
|
|
include 'Processes.a'
|
|
include 'HardwarePrivateEqu.a'
|
|
include 'SysPrivateEqu.a'
|
|
include 'SCSIEqu.a'
|
|
include 'SCSIPriv.a'
|
|
include 'SonyEqu.a'
|
|
include 'InternalMacros.a'
|
|
print pop
|
|
|
|
|
|
BuildHFS70Init default 0
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; exciting table of ROM Addresses
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
ROMs Plus,SE,II,Portable,IIci
|
|
|
|
romAfterExtFSHook ROMBind (Plus,$029f2), (SE,$04434), (II,$07edc), (IIci,$0f0e0), (Portable, $096e0)
|
|
romBTFlush ROMBind (Plus,$068c2), (SE,$08398), (II,$0be5c), (IIci,$13242), (Portable, $0d802)
|
|
BUILDKEY ROMBind (Plus,$065d8), (SE,$080a0), (II,$0BB64), (IIci,$12f40), (Portable, $0d50a)
|
|
BTDELETE ROMBind (Plus,$0671c), (SE,$081e6), (II,$0bcaa), (IIci,$13090), (Portable, $0d650)
|
|
BTGETRECORD ROMBind (Plus,$06928), (SE,$083fc), (II,$0bec0), (IIci,$132A6), (Portable, $0d866)
|
|
BTINSERT ROMBind (Plus,$069ea), (SE,$084b4), (II,$0bf78), (IIci,$1335E), (Portable, $0d91e)
|
|
BTSEARCH ROMBind (Plus,$06d4a), (SE,$0880c), (II,$0c2d0), (IIci,$136B6), (Portable, $0dc76)
|
|
BTUPDATE ROMBind (Plus,$06dd6), (SE,$08896), (II,$0c35a), (IIci,$13740), (Portable, $0dd00)
|
|
CACHERDIP ROMBind (Plus,$07b2a), (SE,$0967e), (II,$0d13e), (IIci,$1459C), (Portable, $0eb44)
|
|
romChgMFlLock ROMBind (Plus,$046de), (SE,$06812), (II,$0a2e8), (IIci,$11694), (Portable, $0bc7c)
|
|
CHKNODE ROMBind (Plus,$072c2), (SE,$08e22), (II,$0c8e6), (IIci,$13D42), (Portable, $0e2ec)
|
|
romCkExtFS ROMBind (Plus,$03638), (SE,$050be), (II,$08b80), (IIci,$0fefa), (Portable, $0a4e2)
|
|
romCkFilMod ROMBind (Plus,$0497a), (SE,$06420), (II,$09eec), (IIci,$11298), (Portable, $0b880)
|
|
CMDDONE ROMBind (Plus,$0295e), (SE,$043a0), (II,$07e48), (IIci,$0f04c), (Portable, $0964c)
|
|
CMFLUSH ROMBind (Plus,$06606), (SE,$080ce), (II,$0BB92), (IIci,$12f6e), (Portable, $0d538)
|
|
CMGETCN ROMBind (Plus,$06238), (SE,$07d04), (II,$0b7c8), (IIci,$12ba2), (Portable, $0d16e)
|
|
CMSETUP ROMBind (Plus,$065a0), (SE,$08068), (II,$0bb2c), (IIci,$12f06), (Portable, $0d4d2)
|
|
romCMUpdateCN ROMBind (Plus,$0656c), (SE,$08036), (II,$0bafa), (IIci,$12ed4), (Portable, $0d4a0)
|
|
CVFLGS ROMBind (Plus,$03a76), (SE,$05502), (II,$08FCA), (IIci,$10344), (Portable, $0a92c)
|
|
romDtrmV1 ROMBind (Plus,$03650), (SE,$050e2), (II,$08ba4), (IIci,$0ff1e), (Portable, $0a50c)
|
|
DTRMV3 ROMBind (Plus,$03642), (SE,$050ce), (II,$08b90), (IIci,$0ff0a), (Portable, $0a4f8)
|
|
EXTOFFLINCK ROMBind (Plus,$04aba), (SE,$06560), (II,$0A02C), (IIci,$113d8), (Portable, $0b9c0)
|
|
romFindDrive ROMBind (Plus,$03414), (SE,$04e9A), (II,$08956), (IIci,$0FC6C), (Portable, $0A258)
|
|
FNDFILNAME ROMBind (Plus,$04990), (SE,$06436), (II,$09f02), (IIci,$112ae), (Portable, $0b896)
|
|
romFSAsync ROMBind (Plus,$02912), (SE,$04354), (II,$07dfc), (IIci,$0f000), (Portable, $09600)
|
|
FSQUEUESYNC ROMBind (Plus,$028a6), (SE,$042e8), (II,$07d90), (IIci,$0ef94), (Portable, $09594)
|
|
FSQUEUE ROMBind (Plus,$028aa), (SE,$042ec), (II,$07d94), (IIci,$0ef98), (Portable, $09598)
|
|
romGt1stMatch ROMBind (Plus,$04002), (SE,$05a9c), (II,$0955c), (IIci,$108d6), (Portable, $0aebe)
|
|
romLocCNode ROMBind (Plus,$06678), (SE,$0813e), (II,$0BC02), (IIci,$12FDE), (Portable, $0d5a8)
|
|
LOCCREC ROMBind (Plus,$06698), (SE,$0815e), (II,$0bc22), (IIci,$12FFE), (Portable, $0d5c8)
|
|
LOCREC ROMBind (Plus,$07538), (SE,$0908c), (II,$0cb50), (IIci,$13FAC), (Portable, $0e556)
|
|
romMarkVCB ROMBind (Plus,$02d1e), (SE,$04766), (II,$0820e), (IIci,$0F524), (Portable, $09b10)
|
|
romMarkVCBTime ROMBind (Plus,$02d20), (SE,$04768), (II,$08210), (IIci,$0F526), (Portable, $09b12)
|
|
POPCNAME ROMBind (Plus,$04288), (SE,$05d28), (II,$097EA), (IIci,$10b96), (Portable, $0b17e)
|
|
PUSHCNAME ROMBind (Plus,$04258), (SE,$05cf8), (II,$097BA), (IIci,$10b66), (Portable, $0b14e)
|
|
romRfnCall ROMBind (Plus,$05352), (SE,$06e04), (II,$0a8c8), (IIci,$11C86), (Portable, $0c26e)
|
|
TFSVCBTST ROMBind (Plus,$04ec6), (SE,$06968), (II,$0a43e), (IIci,$117ea), (Portable, $0bdd2)
|
|
UPDCNAME ROMBind (Plus,$066c2), (SE,$0818c), (II,$0BC50), (IIci,$1302C), (Portable, $0d5f6)
|
|
romUpdRtCnts ROMBind (Plus,$065be), (SE,$08086), (II,$0BB4A), (IIci,$12f24), (Portable, $0d4f0)
|
|
romUpdVCnts ROMBind (Plus,$065ae), (SE,$08076), (II,$0BB3A), (IIci,$12f14), (Portable, $0d4e0)
|
|
XFFLUSH ROMBind (Plus,$05ed0), (SE,$0799a), (II,$0B45E), (IIci,$1282a), (Portable, $0ce04)
|
|
GT1STFCB ROMBind (Plus,$03ff2), (SE,$05a8c), (II,$0954c), (IIci,$108c6), (Portable, $0aeae)
|
|
GTNXTFCB ROMBind (Plus,$03ffa), (SE,$05a94), (II,$09554), (IIci,$108ce), (Portable, $0aeb6)
|
|
FLUSHCACHE ROMBind (Plus,$076c6), (SE,$0921a), (II,$0ccdc), (IIci,$1413a), (Portable, $0e6e2)
|
|
|
|
; The following addresses are needed for ROM B*Tree writecount patch: <2.3 kst>
|
|
romBuildIRec ROMBind (Plus,$072a0), (SE,$08E00), (II,$0C8C4), (IIci,$13D20), (Portable,$0E2CA)
|
|
romClrNode ROMBind (Plus,$0734E), (SE,$08EA6), (II,$0C96A), (IIci,$13DC6), (Portable,$0E370)
|
|
romDeleteRec ROMBind (Plus,$0736A), (SE,$08EC2), (II,$0C986), (IIci,$13DE2), (Portable,$0E38C)
|
|
romGetLtSib ROMBind (Plus,$073BA), (SE,$08F12), (II,$0C9D6), (IIci,$13E32), (Portable,$0E3DC)
|
|
romGetRtSib ROMBind (Plus,$073C4), (SE,$08F1C), (II,$0C9E0), (IIci,$13E3C), (Portable,$0E3E6)
|
|
romGetMaxKey ROMBind (Plus,$073F6), (SE,$08F4C), (II,$0CA10), (IIci,$13E6C), (Portable,$0E416)
|
|
romGetRecA ROMBind (Plus,$0746E), (SE,$08FC2), (II,$0CA86), (IIci,$13EE2), (Portable,$0E48C)
|
|
romInitNode ROMBind (Plus,$0748A), (SE,$08FDE), (II,$0CAA2), (IIci,$13EFE), (Portable,$0E4A8)
|
|
romInsertRec ROMBind (Plus,$074BC), (SE,$09010), (II,$0CAD4), (IIci,$13F30), (Portable,$0E4DA)
|
|
romLocBTCB ROMBind (Plus,$0752E), (SE,$09082), (II,$0CB46), (IIci,$13FA2), (Portable,$0E54C)
|
|
romLocTPR ROMBind (Plus,$0756A), (SE,$090BE), (II,$0CB82), (IIci,$13FDE), (Portable,$0E588)
|
|
romUpdDRec ROMBind (Plus,$07646), (SE,$0919A), (II,$0CC5E), (IIci,$140BA), (Portable,$0E664)
|
|
romUpdIKey ROMBind (Plus,$07668), (SE,$091BC), (II,$0CC80), (IIci,$140DC), (Portable,$0E686)
|
|
romBTCleanUp ROMBind (Plus,$06E02), (SE,$088C2), (II,$0C386), (IIci,$1376C), (Portable,$0DD2C)
|
|
romBTSetUp ROMBind (Plus,$06E10), (SE,$088D0), (II,$0C394), (IIci,$1377A), (Portable,$0DD3A)
|
|
romRotateLt ROMBind (Plus,$0706C), (SE,$08BC8), (II,$0C68C), (IIci,$13AE0), (Portable,$0E092)
|
|
romSplitLt ROMBind (Plus,$0715C), (SE,$08CB8), (II,$0C77C), (IIci,$13BD0), (Portable,$0E182)
|
|
romTreeSearch ROMBind (Plus,$071E4), (SE,$08D42), (II,$0C806), (IIci,$13C5A), (Portable,$0E20C)
|
|
|
|
; The following addresses are needed for file/WD cleanup patch: <2.7 kst>
|
|
romFillWDCB ROMBind (Plus,$03BB4), (SE,$05640), (II,$09100), (IIci,$1047A), (Portable,$0AA62)
|
|
romGtNxtMatch ROMBind (Plus,$04010), (SE,$05AAA), (II,$0956A), (IIci,$108E4), (Portable,$0AECC)
|
|
;PermssnChk ROMBind (Plus,$0416C), (SE,$05C06), (II,$096C8), (IIci,$10A74), (Portable,$0B05C)
|
|
;MFSOpen ROMBind (Plus,$04294), (SE,$05D34), (II,$097F6), (IIci,$10BA2), (Portable,$0B18A)
|
|
romGt1stWDCB ROMBind (Plus,$043A0), (SE,$05E3A), (II,$098FC), (IIci,$10CA8), (Portable,$0B290)
|
|
romGtNxtWDCB ROMBind (Plus,$043A8), (SE,$05E42), (II,$09904), (IIci,$10CB0), (Portable,$0B298)
|
|
|
|
FromWaitForDsk ROMBind (Plus,$2B66),(SE,$45A8),(II,$8050)
|
|
AfterSysErrorInDSHook ROMBind (Plus,$2B30),(SE,$4572),(II,$801A),(Portable,$9830),(IIci,$F244)
|
|
DSExit ROMBind (Plus,$2BE8),(SE,$4630),(II,$80D8),(Portable,$98EC),(IIci,$F300)
|
|
AfterMountVolInDSHook ROMBind (Plus,$2AAE),(SE,$44F0),(II,$7F98),(Portable,$97A8),(IIci,$F1A8)
|
|
|
|
OldMtVolAfterFSQueue ROMBind (Plus,$2E4C),(SE,$489E),(II,$834C),(Portable,$9C4E),(IIci,$F662)
|
|
MtVolOK ROMBind (Plus,$3138),(SE,$4B86),(II,$863A),(Portable,$9F3C),(IIci,$F950)
|
|
MtCheck ROMBind (Plus,$3190),(SE,$4BDE)
|
|
After2ndAccessBTInMountVol ROMBind (Plus,$2FFA),(SE,$4A4C)
|
|
AfterBTOpenInAccessBT ROMBind (Plus,$340A),(SE,$4E90)
|
|
AfterUpdateFreeInMtCheck ROMBind (Plus,$332E),(SE,$4DAE)
|
|
AfterReadBMInUpdateFree ROMBind (Plus,$59E0),(SE,$7488)
|
|
AfterGetBMBlkInReadBM ROMBind (Plus,$5A1E)
|
|
AfterGetBlockInGetBMBlk ROMBind (Plus,$5A9E)
|
|
|
|
CMRenameCN ROMBind (Plus,$6462),(SE,$7F2E),(II,$B9F2),(Portable,$D398),(IIci,$12Dcc) ;<37>
|
|
DtrmV2 ROMBind (Plus,$3788),(SE,$521A),(II,$8CDC),(IIci,$10056),(Portable,$A63E)
|
|
AfterVolCheckInRename ROMBind (Plus,$4498),(SE,$5F32),(II,$99FE),(IIci,$10DAA),(Portable,$B392)
|
|
RNmVol1 ROMBind (Plus,$45F8),(SE,$6092),(II,$9B5E),(IIci,$10F0A),(Portable,$B5F2)
|
|
RNmVol@70 ROMBind (Plus,$460E),(SE,$60B8),(II,$9B84),(IIci,$10F30),(Portable,$B518)
|
|
|
|
AfterCMSetupInCMCreateCN ROMBind (Plus,$604E), (SE,$7B1C), (II,$B5E0), (IIci,$129BA), (Portable, $0CF86) ;<27>
|
|
AfterCMSetupInCMDeleteCN ROMBind (Plus,$6194), (SE,$7c62), (II,$B726), (IIci,$12b00), (Portable, $0D0CC) ;<22>
|
|
AfterCMSetupInCMMoveCN ROMBind (Plus,$62c6), (SE,$7d92), (II,$B856), (IIci,$12c30), (Portable, $0D1FC) ;<22>
|
|
AfterCMSetupInCMRenameCN ROMBind (Plus,$646c), (SE,$7f38), (II,$B9FC), (IIci,$12dd6), (Portable, $0D3A2) ;<22>
|
|
AfterCMSetupInCMUpdateCN ROMBind (Plus,$6576), (SE,$803E), (II,$BB02), (IIci,$12EDC), (Portable, $0D4A8) ;<27>
|
|
AfterCMSetupInCMGetCN ROMBind (Plus,$6242), (SE,$7D0E), (II,$B7D2), (IIci,$12BAC), (Portable, $0D178) ;<23>
|
|
AfterCMGetCNInFndFilName ROMBind (Plus,$4A4E), (SE,$64F4), (II,$9FC0), (IIci,$1136C), (Portable, $0B954) ;<23>
|
|
AfterCMGetCNinRename ROMBind (Plus,$45ae), (SE,$6048), (II,$9B14), (IIci,$10EC0), (Portable, $0b4a8)
|
|
AfterCMRenameCNInRename ROMBind (Plus,$4554), (SE,$5ff2), (II,$9abe), (IIci,$10e6a), (Portable, $0b452) ;<22>
|
|
|
|
FlushVFiles ROMBind (Plus,$35Be), (SE,$5044), (II,$8B06), (IIci,$FE80), (Portable, $A468) ;<24>
|
|
FlUnMntCallsFlushBuffers ROMBind (Plus,$3622), (SE,$50A8), (II,$8B6A), (IIci,$FEE4), (Portable, $A4CC) ;<24>
|
|
FlUnMntAfterMFSCheck ROMBind (Plus,$3616), (SE,$509C), (II,$8B5E), (IIci,$FED8), (Portable, $A4C0) ;<24>
|
|
|
|
OfflineEjectCallsFlushBuffers ROMBind (Plus,$355E), (SE,$4FE4), (II,$8AA6), (IIci,$FDBE), (Portable, $A3AA) ;<24>
|
|
OfflineEjectCallsMFSFlush ROMBind (Plus,$3564),(SE,$4FEA), (II,$8AAC), (IIci,$FDC4), (Portable, $A3B0)
|
|
|
|
FlushBuffersAtflVCaches ROMBind (Plus,$34A0), (SE,$4F26), (II,$89E8), (IIci,$0FCFE), (Portable,$A2EA) ;<24>
|
|
FlushBuffersAtflBufExit ROMBind (Plus,$34D6), (SE,$4F5C), (II,$8A1E), (IIci,$0FD34), (Portable,$A320) ;<24>
|
|
FClose ROMBind (Plus,$5168), (SE,$6c0E), (II,$A6E4), (IIci,$11AA2), (Portable,$C08A)
|
|
DsposVBlks ROMBind (Plus,$336E), (SE,$4E28), (II,$88E4), (IIci,$0FBFA), (Portable,$A1B2)
|
|
DsposVCB ROMBind (Plus,$33A2), (SE,$4DF4), (II,$88B0), (IIci,$0FBC6), (Portable,$A1E6)
|
|
EjectIt ROMBind (Plus,$3598), (SE,$501E), (II,$8AE0), (IIci,$0FDFC), (Portable,$A3E4)
|
|
MFSFlush ROMBind (Plus,$3F00), (SE,$599A), (II,$945A), (IIci,$107D4), (Portable,$ADBC)
|
|
MarkVCBDirty ROMBind (Plus,$2D28), (SE,$4770), (II,$8218), (IIci, $0F52E), (Portable,$9B1A)
|
|
FlushMDB ROMBind (Plus,$2D2E), (SE,$4776), (II,$821E), (IIci, $0F534), (Portable,$9B20)
|
|
|
|
FOpen1 ROMBind (Plus,$4032), (SE,$5ACC), (II,$958C), (IIci,$10906), (Portable,$AEEE)
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; Routine: HFS7.0 Enhancements Dispatch
|
|
;
|
|
; Function: Look at d0 and decide whether to dispatch to FileID handling routines,
|
|
; CatSearch, or the Desktop Manager. Also implements the local version
|
|
; of GetVolParms.
|
|
;
|
|
; The deal with $a060 trap numbers:
|
|
; 0-$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
|
|
;________________________________________________________________________________
|
|
; This routine was rolled into TFSDispatch into the file TFS.a. <SM1>
|
|
HFSDispHook: PatchProc _HFSDispatch
|
|
|
|
; low and high values for the dispatch ranges we're patching
|
|
firstA60Disp equ selectCreateFileIDRef ; First entry is CreateFileIDRef, $14
|
|
lastA60Disp equ $6F ; Last entry is $6F, reserved for future use
|
|
|
|
import A60DispTbl ; all known A60 dispatch addresses
|
|
import OpenDF ; Open data fork
|
|
import AllocateFCBs
|
|
import OpenWDPatch, SetVolInfoPatch, UnknownCall
|
|
|
|
cmp.w #firstA60Disp, d0 ; dispatch less than 1st HFS 70 value?
|
|
blo.s @CheckLowStuff ; check for patches on more mature routines
|
|
cmp.w #lastA60Disp, d0 ; dispatch less than last known value?
|
|
bls.s @CoolDispatchSelector ; then go dispatch it
|
|
jmp UnknownCall ; then treat this call as unknown, possibly of
|
|
|
|
@CoolDispatchSelector:
|
|
move.w d0,d2 ; trap index into trashable reg <2.1>
|
|
sub.w #firstA60Disp, d2 ; 'normalize' dispatches to start at zero
|
|
leaResident A60DispTbl,a2 ; Point to the trap table
|
|
move.w d1, ioTrap(a0) ; Save unMunged trap word <14>
|
|
andi.w #$0f00, ioTrap(a0) ; Leave only modifiers (Async etc.) <14>
|
|
move.b d0, ioTrap+1(a0) ; Save the compacted trap information <14>
|
|
|
|
add.w d2,d2 ; double for word index
|
|
add.w d2,d2 ; double for long index
|
|
jmp (a2,d2.w) ; Pass control to routine
|
|
|
|
@CheckLowStuff:
|
|
; ever get the feeling weÕll have another dispatch table soon?
|
|
|
|
cmp.w #selectOpenWD, d0 ; openWD call?
|
|
bne.s @notOpenWD
|
|
jmp OpenWDPatch ; yes - do our special thing
|
|
@notOpenWD:
|
|
|
|
cmp.w #selectSetVolInfo, d0 ; SetVolInfo call? <20>
|
|
bne.s @notSetVolInfo
|
|
jmp SetVolInfoPatch ; yes - do our special thing (2) <20>
|
|
@notSetVolInfo:
|
|
|
|
jmpOld ; no - go call the next dude on the chain
|
|
endproc
|
|
|
|
macro
|
|
DispatchEntry &where
|
|
import &where
|
|
jmp &where
|
|
endm
|
|
|
|
A60DispTbl: proc
|
|
|
|
DispatchEntry CreateFileIDRef ; (0) dispatch $14
|
|
DispatchEntry DeleteFileIDRef ; (1) dispatch $15
|
|
DispatchEntry ResolveFileIDRef ; (2) dispatch $16
|
|
DispatchEntry PBHExchangeFiles ; (3) dispatch $17
|
|
DispatchEntry CMCatSearch ; (4) dispatch $18
|
|
DispatchEntry CheckCSPB ; (5) dispatch $19
|
|
DispatchEntry OpenDF ; (6) dispatch $1A
|
|
DispatchEntry MakeFSSpec ; (7) dispatch $1B
|
|
DispatchEntry UnknownCall ; (8) dispatch $1C
|
|
DispatchEntry UnknownCall ; (9) dispatch $1D
|
|
DispatchEntry UnknownCall ; (10) dispatch $1E
|
|
DispatchEntry UnknownCall ; (11) dispatch $1F
|
|
|
|
DispatchEntry DTGetPath ; (12) dispatch $20
|
|
DispatchEntry DTCloseDown ; (13) dispatch $21
|
|
DispatchEntry DTAddIcon ; (14) dispatch $22
|
|
DispatchEntry DTGetIcon ; (15) dispatch $23
|
|
DispatchEntry DTGetIconInfo ; (16) dispatch $24
|
|
DispatchEntry DTAddAPPL ; (17) dispatch $25
|
|
DispatchEntry DTRemoveAPPL ; (18) dispatch $26
|
|
DispatchEntry DTGetAPPL ; (19) dispatch $27
|
|
DispatchEntry DTSetComment ; (20) dispatch $28
|
|
DispatchEntry DTRemoveComment ; (21) dispatch $29
|
|
DispatchEntry DTGetComment ; (22) dispatch $2a
|
|
DispatchEntry DTFlush ; (23) dispatch $2b
|
|
DispatchEntry DTReset ; (24) dispatch $2c
|
|
DispatchEntry DTGetInfo ; (25) dispatch $2d
|
|
DispatchEntry DTOpenInform ; (26) dispatch $2e
|
|
DispatchEntry DTDelete ; (27) dispatch $2f
|
|
|
|
DispatchEntry GetVolParms ; (28) dispatch $30 GetVolParms
|
|
DispatchEntry VolumeCall ; (29) dispatch $31 GetLogInInfo
|
|
DispatchEntry VolumeCall ; (30) dispatch $32 GetDirAccess
|
|
DispatchEntry VolumeCall ; (31) dispatch $33 SetDirAccess
|
|
DispatchEntry VolumeCall ; (32) dispatch $34 MapID
|
|
DispatchEntry VolumeCall ; (33) dispatch $35 MapName
|
|
DispatchEntry VolumeCall ; (34) dispatch $36 CopyFile
|
|
DispatchEntry VolumeCall ; (35) dispatch $37 MoveRename
|
|
DispatchEntry OpenCall ; (36) dispatch $38 OpenDeny
|
|
DispatchEntry OpenCall ; (37) dispatch $39 OpenRFDeny
|
|
DispatchEntry VolumeCall ; (38) dispatch $3A Reserved for future use
|
|
DispatchEntry VolumeCall ; (39) dispatch $3B Reserved for future use
|
|
DispatchEntry VolumeCall ; (40) dispatch $3C Reserved for future use
|
|
DispatchEntry VolumeCall ; (41) dispatch $3D Reserved for future use
|
|
DispatchEntry VolumeCall ; (42) dispatch $3E Reserved for future use
|
|
|
|
DispatchEntry VolumeCall ; (43) dispatch $3F GetVolMountInfoSize
|
|
DispatchEntry VolumeCall ; (44) dispatch $40 GetVolMountInfo
|
|
DispatchEntry UnknownCall ; (45) dispatch $41 VolumeMount
|
|
DispatchEntry VolumeCall ; (46) dispatch $42 Share
|
|
DispatchEntry VolumeCall ; (47) dispatch $43 UnShare
|
|
DispatchEntry UnknownCall ; (48) dispatch $44 GetUGEntry
|
|
DispatchEntry UnknownCall ; (49) dispatch $45 ServerControl
|
|
DispatchEntry UnknownCall ; (50) dispatch $46 ServerStartup
|
|
DispatchEntry UnknownCall ; (51) dispatch $47 Reserved for future use
|
|
DispatchEntry UnknownCall ; (52) dispatch $48 Reserved for future use
|
|
DispatchEntry UnknownCall ; (53) dispatch $49 Reserved for future use
|
|
DispatchEntry UnknownCall ; (54) dispatch $4A Reserved for future use
|
|
DispatchEntry UnknownCall ; (55) dispatch $4B Reserved for future use
|
|
DispatchEntry UnknownCall ; (56) dispatch $4C Reserved for future use
|
|
DispatchEntry UnknownCall ; (57) dispatch $4D Reserved for future use
|
|
DispatchEntry UnknownCall ; (58) dispatch $4E Reserved for future use
|
|
DispatchEntry UnknownCall ; (59) dispatch $4F Reserved for future use
|
|
|
|
DispatchEntry GetParallelFCBFromRefnum ; (60) dispatch $50
|
|
DispatchEntry RefNumCall ; (61) dispatch $51 Reserved for future use
|
|
DispatchEntry RefNumCall ; (62) dispatch $52 Reserved for future use
|
|
DispatchEntry RefNumCall ; (63) dispatch $53 Reserved for future use
|
|
DispatchEntry RefNumCall ; (64) dispatch $54 Reserved for future use
|
|
DispatchEntry RefNumCall ; (65) dispatch $55 Reserved for future use
|
|
DispatchEntry RefNumCall ; (66) dispatch $56 Reserved for future use
|
|
DispatchEntry RefNumCall ; (67) dispatch $57 Reserved for future use
|
|
DispatchEntry RefNumCall ; (68) dispatch $58 Reserved for future use
|
|
DispatchEntry RefNumCall ; (69) dispatch $59 Reserved for future use
|
|
DispatchEntry RefNumCall ; (70) dispatch $5A Reserved for future use
|
|
DispatchEntry RefNumCall ; (71) dispatch $5B Reserved for future use
|
|
DispatchEntry RefNumCall ; (72) dispatch $5C Reserved for future use
|
|
DispatchEntry RefNumCall ; (73) dispatch $5D Reserved for future use
|
|
DispatchEntry RefNumCall ; (74) dispatch $5E Reserved for future use
|
|
DispatchEntry RefNumCall ; (75) dispatch $5F Reserved for future use
|
|
|
|
DispatchEntry VolumeCall ; (76) dispatch $60 GetAltPrivs
|
|
DispatchEntry VolumeCall ; (77) dispatch $61 SetAltPrivs
|
|
DispatchEntry DoFSCleanUp ; (78) dispatch $62 FSCleanUp
|
|
DispatchEntry AllocateFCBs ; (79) dispatch $63 AllocateFCBs
|
|
DispatchEntry VolumeCall ; (80) dispatch $64 Reserved for future use
|
|
DispatchEntry VolumeCall ; (81) dispatch $65 Reserved for future use
|
|
DispatchEntry VolumeCall ; (82) dispatch $66 Reserved for future use
|
|
DispatchEntry VolumeCall ; (83) dispatch $67 Reserved for future use
|
|
DispatchEntry VolumeCall ; (84) dispatch $68 Reserved for future use
|
|
DispatchEntry VolumeCall ; (85) dispatch $69 Reserved for future use
|
|
DispatchEntry VolumeCall ; (86) dispatch $6A Reserved for future use
|
|
DispatchEntry VolumeCall ; (87) dispatch $6B Reserved for future use
|
|
DispatchEntry VolumeCall ; (88) dispatch $6C Reserved for future use
|
|
DispatchEntry VolumeCall ; (89) dispatch $6D Reserved for future use
|
|
DispatchEntry VolumeCall ; (90) dispatch $6E Reserved for future use
|
|
DispatchEntry VolumeCall ; (91) dispatch $6F Reserved for future use
|
|
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; 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.
|
|
;________________________________________________________________________________
|
|
; This routine was rolled into into the file TFS.a. <SM1>
|
|
VolumeCall: proc
|
|
jsrROM FSQUEUE ; Patiently wait our turn
|
|
jsrROM DTRMV3 ; Determine the volume being referred to
|
|
bne ToCmdDone ; 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.
|
|
;________________________________________________________________________________
|
|
; This routine was rolled into into the file TFS.a. <SM1>
|
|
entry RefNumCall
|
|
RefNumCall:
|
|
import RefNumCheck
|
|
jsrROM FSQUEUE ; chill in line
|
|
move.w ioRefNum(a0),d0 ; Pick up the refNum
|
|
jsr RefNumCheck ; Check the refNum supplied
|
|
bne ToCmdDone ; 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: 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.
|
|
;
|
|
; Inputs: A0 = Parameter block
|
|
; Output: D0 = error code, RfNumErr or zero.
|
|
;________________________________________________________________________________
|
|
; This routine was rolled into into the file TFS.a. <SM1>
|
|
entry UnknownCall
|
|
UnknownCall:
|
|
jsrROM FSQUEUE ; Wait our turn
|
|
; <REALLY Fudge ReqsVol here later...>
|
|
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: 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.
|
|
;
|
|
; Inputs: A0 = Parameter block
|
|
; Output: D0 = error code, RfNumErr or zero.
|
|
;________________________________________________________________________________
|
|
; This routine was rolled into into the file TFS.a. <SM1>
|
|
entry OpenCall
|
|
OpenCall:
|
|
import OpenAttemptHook
|
|
jsrROM FSQUEUE ; Wait our turn
|
|
jsrROM DTRMV3 ; Determine the volume being referred to
|
|
bne.s ToCmdDone ; 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>
|
|
jsrROM GT1STFCB ; get (A1,D1) pointing to first FCB
|
|
@1 tst.l FCBFlNm(a1,d1) ; FCB unused
|
|
beq.s @90 ; br if so
|
|
jsrROM 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.s ToCmdDone
|
|
|
|
@90 add.l a1,d1 ; Point to the FCB
|
|
|
|
ExtFSErrExit:
|
|
moveq.l #ExtFSErr,d0 ; Good news!
|
|
bra.s ToCmdDone
|
|
|
|
ParamErrExit:
|
|
moveq.l #paramErr, d0 ; It's an unknown trap for a local volume
|
|
|
|
ToCmdDone:
|
|
jmpROM CMDDONE ; And call it a day.
|
|
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; 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. <SM1>
|
|
RefNumCheckRegs reg a1/d1
|
|
RefNumCheck: proc export
|
|
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
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; Routine: OpenDF
|
|
;
|
|
; Function: Opens a data fork. Identical to Open, except that no checking
|
|
; for drivers is done.
|
|
;
|
|
; Changes the trap word to _Open (from _HFSDispatch) so that external
|
|
; file systems will work properly. Preserves hfs and async bits
|
|
;________________________________________________________________________________
|
|
; This routine was rolled into into the file TFSDIR1.a. <SM1>
|
|
OpenDF: proc
|
|
move.b #0, d1 ; clear low byte $Ax60 -> $Ax00
|
|
move.w d1, ioTrap(a0) ; clean up the pb, too <38>
|
|
move.l jFileOpen, -(sp) ; get the vector straight into the file system
|
|
rts ; jump in with both feet
|
|
endproc
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: SetFilLock, RstFilLock
|
|
;
|
|
; (c) 1983, 1985, 1990 Apple Computer, Inc.
|
|
;
|
|
; Arguments: A0.L (input) -- pointer to I/O parameter block, uses
|
|
; IOFileName,IOFileType,IODrvNum
|
|
; D0.W (output) -- 0 if file was found and set correctly.
|
|
; Calls: FndFilName
|
|
; Function: Set or reset the file lock bit.
|
|
;
|
|
; Modification History:
|
|
; 16 Jan 83 LAK New today.
|
|
; 06 Jun 83 LAK Broke out CkFilMod as a subroutine.
|
|
; 10 Mar 85 PWD Modified for use with TFS catalog entries
|
|
; 28 Jun 90 dnf Modified to set/clear afp inhibit bits
|
|
;
|
|
; Note: if the file is locked after it has already been opened with write
|
|
; permission, the lock will not affect that opened file. If the lock bit
|
|
; is not changed by this command, the directory buffer is not marked dirty
|
|
; (allows quick lock/unlocking of a group of file, regardless of their current
|
|
; status).
|
|
;_______________________________________________________________________
|
|
; This patch was rolled back into TFSDIR3.A <SM1>
|
|
MakePatch SetFilLock,_SetFilLock
|
|
MakePatch RstFilLock,_RstFilLock
|
|
|
|
SetFilLock: proc export
|
|
export RstFilLock
|
|
|
|
JSRRom FSQUEUE ; wait our turn
|
|
ST FLckUnlck ; want to lock it
|
|
BRA.S SRFLck
|
|
|
|
RstFilLock:
|
|
jsrROM FSQUEUE
|
|
CLR.B FLckUnlck
|
|
|
|
SRFLck jsrROM romCkFilMod ; look for file and see if we can mod it
|
|
; (doesn't return on errors)
|
|
JSRROM TFSVCBTST ; Are we dealing with a TFS volume? <01Oct85>
|
|
BNEROM romChgMFlLock ; Nope - do it the old fashioned way
|
|
MOVEQ #FNFErr,D0 ; Expect the worst
|
|
CMP.B #cdrFilRec,cdrType(A5) ; Is this a file entry?
|
|
BNE.S SRFLXit3 ; No - don't touch it
|
|
TST.B FLckUnlck ; Yes! Now, what was it we wanted?
|
|
BEQ.S @1 ; br if we want to unlock it
|
|
BSET #FilWrtFlag,FilFlags(A5) ; lock it
|
|
BNE.S SRFLXit2 ; br if already locked
|
|
ori.b #xFFFilAttrLockMask, filFndrInfo+fdXFlags(a5) ; set bits in fdXFlags <28Jun90> <15>
|
|
BRA.S SRFLXit1 ; otherwise, it's been modified
|
|
|
|
@1 BCLR #FilWrtFlag,FilFlags(A5) ; unlock it
|
|
BEQ.S SRFLXit2 ; br if already unlocked
|
|
andi.b #~xFFFilAttrLockMask, filFndrInfo+fdXFlags(a5) ; clear bits in fdXFlags <28Jun90> <15>
|
|
|
|
; Mark the buffer holding the catalog entry dirty:
|
|
|
|
SRFLXit1 MOVE.L D7,D2 ; Get a hold of the catalog hint
|
|
JSRROM romCMUpdateCN ; Update the Catalog buffer
|
|
BRA.S SRFLXit3 ; If EQ, we're all set.
|
|
|
|
SRFLXit2 MOVEQ #0,D0
|
|
SRFLXit3 jmpROM CMDDONE
|
|
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
; <55>
|
|
; Routine: GetParallelFCBFromRefnum
|
|
; Function: Return a pointer to the parallel FCB entry for a given
|
|
; file RefNum.
|
|
;
|
|
; Input: ioRefNum(a0) - File reference number
|
|
;
|
|
; Output: ioMisc(a0) - Pointer to parallel FCB entry
|
|
;________________________________________________________________________________
|
|
; This routine was rolled into TFSDIR1.a
|
|
GetParallelFCBFromRefnum proc export
|
|
import ParallelFCBFromRefnum
|
|
import RefNumCheck
|
|
|
|
jsrROM FSQUEUE ; wait our turn
|
|
|
|
move.w ioRefNum(a0),d0 ; Get the file reference number
|
|
move.w d0,d1 ; Keep a copy in another register
|
|
bsr RefNumCheck ; Make sure the reference number is valid
|
|
bmi.s @exitGetParallelFCB ; Bad reference number
|
|
|
|
move.w d1,d0 ; Get the copy
|
|
bsr ParallelFCBFromRefnum ; Get the pointer to the parallel structure
|
|
move.l a1,ioFDirIndex(a0) ; Return the pointer in ioMisc
|
|
moveq #noErr,d0 ; No error
|
|
@exitGetParallelFCB
|
|
jmpROM CMDDONE ; outa here
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; Routine: ParallelFCBFromRefnum
|
|
; Function: Return a pointer to the parallel FCB entry for a given
|
|
; file RefNum.
|
|
;
|
|
; Input: d0.w - file refNum
|
|
;
|
|
; Output: d0.l - trash
|
|
; a1.l - pointer to parallel FCB entry
|
|
;
|
|
; Note: This routine assumes that d0 is really a decent, law-abiding
|
|
; refnum. RefNumCheck is a fine way to assure this.
|
|
;________________________________________________________________________________
|
|
; This routine was rolled into TFSDIR1.a
|
|
ParallelFCBFromRefnum proc export
|
|
andi.l #$FFFF, d0 ; only the low word is passed. <11>
|
|
divu.w FSFCBLen,d0 ; convert refnum to an index
|
|
movea.l FSVarsPtr,a1 ; get address of HFS variable area
|
|
movea.l FSVars.fcbPBuf(a1),a1 ; get address of parallel array
|
|
mulu.w cbPBufULen(a1),d0 ; convert file index to parallel array offset
|
|
lea fcbPBufData(a1,d0.l),a1 ; a1 -> parallel array element for file <20>
|
|
rts
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
; <20>
|
|
; Routine: ParallelWDCBFromRefnum
|
|
; Function: Return a pointer to the parallel FCB entry for a given
|
|
; working directory RefNum.
|
|
;
|
|
; Input: d0.w - working directory refNum
|
|
;
|
|
; Output: d0.l - trash
|
|
; a1.l - pointer to parallel WDCB entry
|
|
;
|
|
; Note: This routine assumes that d0 is really a decent, law-abiding
|
|
; refnum. RefNumCheck is a fine way to assure this.
|
|
;________________________________________________________________________________
|
|
; This routine was rolled into TFSDIR1.a
|
|
ParallelWDCBFromRefnum proc
|
|
subi.w #WDRfnMin,d0 ; Change WDRefNum to WDCB table offset
|
|
assert WDCBLen = 1<<4 ; ensure that this shift is still legal
|
|
lsr.w #4,d0 ; convert WDCB table offset to an index
|
|
movea.l FSVarsPtr,a1 ; get address of HFS variable area
|
|
movea.l FSVars.wdcbPBuf(a1),a1 ; get address of parallel array
|
|
mulu.w cbPBufULen(a1),d0 ; convert WDCB index to parallel array offset
|
|
lea wdcbPBufData(a1,d0.l),a1 ; a1 -> parallel array element for file
|
|
rts
|
|
endproc
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; <16>
|
|
; Routine: ClosePatch
|
|
;
|
|
; Function: Prevent a file _Close from occuring on a file that was opened by kSystemProcess
|
|
; unless we're currently running kSystemProcess. This keeps random people (apps with
|
|
; housekeeping code that closes lots of files, for example) from closing system-like
|
|
; files out from under us.
|
|
;
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; This patch was rolled into TFSRFN2.a
|
|
ClosePatch PatchProc _Close
|
|
|
|
@ClosePatchRegs reg a0-a2/d0-d1
|
|
|
|
movem.l @ClosePatchRegs,-(sp) ; save regs we use
|
|
movea.l sp,a2 ; for safe, quick stack pointer restore
|
|
|
|
; check the refnum for validity. and locate the parallel FCB array element
|
|
move.w ioRefNum(a0),d0 ; get refnum being closed
|
|
bsr RefNumCheck ; is it legit?
|
|
bne.s @DoClosePop ; if not, let the real trap deal with it
|
|
move.w ioRefNum(a0),d0 ; get refnum being closed
|
|
bsr ParallelFCBFromRefnum ; a1 = address of parallel FCB element
|
|
|
|
; check whether we have tagged the file -- this makes sure that we can even call the
|
|
; Process Mgr (since files are tagged only when the Process Mgr is available), but is
|
|
; cheaper than ProcessMgrExists
|
|
tst.l xFCBPid2(a1) ; is low long initialized?
|
|
bne.s @NeedToCheck ; jump if so, we need to make the trap calls
|
|
tst.l xFCBPid1(a1) ; is high long initialized?
|
|
beq.s @DoClosePop ; both are uninitialized, OK to close!
|
|
|
|
; the quicker of the two checks is whether file opened by kSystemProcess, do it first
|
|
@NeedToCheck
|
|
; WRONG WRONG WRONG ; <53> <53> <53>
|
|
; pea #kSystemProcess ; push low long of PSN
|
|
; ----------------------------------------------------------
|
|
pea kSystemProcess ; push low long of PSN
|
|
|
|
clr.l -(sp) ; push high long of PSN
|
|
clr.l -(sp) ; allocate storage for boolean and result
|
|
pea 4(sp) ; push address of kSystemProcess
|
|
pea xFCBPid1(a1) ; push address of PSN from parallel FCB
|
|
pea 10(sp) ; push address of Boolean
|
|
_SameProcess ; compare FCB PSN to kSystemProcess
|
|
addq.l #2,sp ; dump OSErr (Boolean OK on error)
|
|
tst.w (sp) ; check Boolean (still false if error)
|
|
beq.s @DoClosePop ; jump if FCB not opened by kSystemProcess
|
|
|
|
; OK, file was opened by kSystemProcess, see whether _Close caller is also kSystemProcess
|
|
clr.w (sp) ; set Boolean to "false", for easier check later
|
|
suba.l #10,sp ; allocate storage for PSN (8 bytes) and result
|
|
pea 2(sp) ; push address of PSN storage
|
|
_GetSystemClientProcess ; get party responsible for this _Close call
|
|
pea 2(sp) ; push address of client PSN
|
|
pea 16(sp) ; push address of kSystemProcess
|
|
pea 18(sp) ; push address of Boolean
|
|
_SameProcess ; is current client same as kSystemProcess?
|
|
tst.w 10(sp) ; check boolean
|
|
beq.s @DontClosePop ; if "false", caller is not kSystemProcess
|
|
|
|
; file not opened by kSystemProcess, or closer is also kSystemProcess
|
|
@DoClosePop
|
|
movea.l a2,sp ; restore stack
|
|
movem.l (sp)+,@ClosePatchRegs ; restore regs we used
|
|
jmpOld ; close the file
|
|
|
|
; file was opened by kSystemProcess, but is being closed by someone else. Just say no!
|
|
@DontClosePop
|
|
movea.l a2,sp ; restore stack
|
|
movem.l (sp)+,@ClosePatchRegs ; restore regs we used
|
|
moveq.l #permErr,d0 ; set error code
|
|
move.w d0,ioResult(a0) ; agree in the iopb
|
|
rts ; return to caller
|
|
|
|
endproc
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; Fix the DiskSwitch alert so disk eject FKEYs 0,1 and 2 will work.
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
fixDiskSwitch ComeFromPatchProc _GetOSEvent, FromWaitForDsk,(Plus,SE,II)
|
|
|
|
move.l a0, -(sp) ; Save the event record.
|
|
JsrOld ; Call the old routine.
|
|
move.l (sp)+, a0 ; Restore the event record.
|
|
moveq.l #keyDwnEvt,d1
|
|
cmp.w evtNum(a0),d1 ; Is it a key down?
|
|
bne.s @notKeyDwn ; nope.
|
|
|
|
; It's a key down, so munge the message so that the ROM code will accept it.
|
|
cmp.b #'0', evtMessage+3(a0) ; does it look like a number? <11>
|
|
blt.s @notKeyDwn ; if less than '0', donÕt adjust! <11>
|
|
sub.b #'0', evtMessage+3(a0) ; convert from ascii
|
|
|
|
@notKeyDwn
|
|
rts
|
|
|
|
EndProc
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; DSHook Ñ use SysErrorUpdateRect
|
|
|
|
; There is 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. This patch causes the DSHook to
|
|
; use a new global, SysErrorUpdateRect, instead. This gets rid of the bug where the high bit of the
|
|
; top coordinate was always set, and it also allows others to share this update mechanism. This was
|
|
; impossible before, since any disk switches would clobber the DSAlertRect global, which was used
|
|
; both by the deep-shit error handler, and by the updating code in GetNextEvent. See the patch to
|
|
; GetNextEvent that goes with this for more information.
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; The functionality of these patches was rolled into TFS.a <SM1>
|
|
ForceSetPortInDiskSwap comefrompatchproc _SysError,AfterSysErrorInDSHook
|
|
|
|
tst.l d4 ; check and see if we had a port saved
|
|
bnzOld ; if we had one saved, then SetPort will be called
|
|
moveq #1,d4 ; put a non-zero value in for the port, this forces a call to our SetPort patch
|
|
braOld
|
|
|
|
endproc
|
|
|
|
AccumulateDiskSwitchRectIntoUpdateRect comefrompatchproc _SetPort, DSExit
|
|
|
|
tst.l d5 ; check if we need to post an update
|
|
bnz.s @noUpdate ; nope, we did saving
|
|
|
|
pea DSAlertRect ; union this in
|
|
move.l ExpandMem,a0
|
|
pea ExpandMemRec.SysErrorUpdateRect(a0) ; into this rect
|
|
move.l (sp),-(sp) ; same rect is destination
|
|
_UnionRect
|
|
|
|
@noUpdate
|
|
|
|
subq.l #1,d4 ; did I set this to 1 earlier?
|
|
bneOld ; no, continue with the real SetPort
|
|
|
|
move.l (sp)+,(sp) ; get rid of the parameter to SetPort
|
|
rts ; return to DSHook
|
|
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
; Rename/SetVolInfo - fix bdNamErr, SetVolInfo to '', and SetVolInfo update catalog
|
|
;
|
|
; Neither of these calls returns #bdNamErr when prospective volume names are > 27
|
|
; characters. There are three cases:
|
|
; 1) Rename of a volume (specified as a volume)
|
|
; 2) Rename of a root directory (specified as a parId/cName)
|
|
; 3) SetVolInfo of a volume
|
|
;
|
|
; We also check for cases where SetVolInfo would rename a volume to ''.
|
|
; We also rename the root directory when SetVolInfo renames the volume.
|
|
;
|
|
; There are 3 patches for the three cases above, but the SetVolInfo patch
|
|
; fixes two other bugs, for a total of 3 patches, and 3 bugs.
|
|
;
|
|
; The patches for cases 1 and 3 are here.
|
|
; The patch for case 2 is tacked on to the File IDs patch in CMSvcsExtras.
|
|
; That way we get all the preflighting that the guts of Rename does, and we
|
|
; can just do the check and bail if necessary.
|
|
;
|
|
; This patch also includes Patch #40 (Volume Rename patch) from PatchPlusROM.a
|
|
; The original comment follows:
|
|
; This patch fixes a problem in the File System's Rename code - when a
|
|
; volume rename is detected, the File System doesn't check whether the
|
|
; volume being renamed belongs to an External File System and ends up
|
|
; attempting to make a CMRenameCN call for a volumes for which it has no
|
|
; access to the catalog B*-Tree, resulting in a hung system.
|
|
;________________________________________________________________________________
|
|
; <20>
|
|
; Here we fix case 1 - rename of a volume. Fixed at the head of Rename:
|
|
; This patch was rolled into TFSDIR2.a <SM1>
|
|
FixVolumeRenames PatchProc _Rename
|
|
jsrROM FSQUEUE ; what a queue command!
|
|
|
|
move.l ioNewName(a0),d2 ; check out the new name
|
|
jsrROM DtrmV2 ; find what volume the new name is on
|
|
bne.s RNmVol ; br if error (may want to rename vol)
|
|
tst.w d2 ; check name length
|
|
beq.s RNmVol1 ; if zero, may be volume-conflict rename
|
|
jmpROM AfterVolCheckInRename
|
|
|
|
; ... lots of Rename work happens in ROM ...
|
|
; (that has nothing to do with the volume case, but includes the root dir case)
|
|
|
|
; ... User is trying to rename a volume. Give it a try ...
|
|
|
|
RNmVol:
|
|
cmp.w #nsvErr,d0 ; make sure it's no-such-vol error
|
|
bneROM CMDDONE
|
|
tst.w d2 ; name length should be zero
|
|
bne.s BadNewNam
|
|
RNmVol1:
|
|
cmp.w #vcbMaxNam, d3 ; is the proposed name too long? <20>
|
|
bhi.s BadNewNam ; > 27 is just right out
|
|
jmpROM RNmVol1 ; go let'em do it like they used to
|
|
|
|
tst.w d3 ; Volume name must have been specified
|
|
beqROM CMDDONE
|
|
jsrROM DTRMV3 ; Check source volume
|
|
bneROM CMDDONE ; Punt if no such thing
|
|
jsrROM CVFLGS ; Can it be modified?
|
|
bneROM CMDDONE ; Nope - punt now.
|
|
jsrROM TFSVCBTST ; Is it a TFS volume?
|
|
beq.s @checkExtFS ; Yes - make sure it's not ext. FS
|
|
tst.w vcbDrvNum(a2) ; Volume on-line?
|
|
beqROM CMDDONE ; No - just forget it
|
|
jmpROM RNMVol@70 ; Yes - go and rename it
|
|
|
|
@checkExtFS:
|
|
jsrROM EXTOFFLINCK ; Our file system, on-line volume?
|
|
bneROM CMDDONE ; If not, get out now
|
|
jmpROM RNMVol@70 ; Otherwise, same as ever
|
|
|
|
BadNewNam:
|
|
moveq.l #bdNamErr,d0 ; get the error code
|
|
jmpROM CMDDONE ; outa here
|
|
|
|
endproc
|
|
|
|
; Here we fix case 3 - SetVolInfo.
|
|
; Of course, we also patch out the entire SetVolInfo routine, and fix the
|
|
; bugs where we formerly didnÕt rename the root directory and allowed a '' name.
|
|
|
|
SetVolInfoPatch proc
|
|
jsrROM FSQUEUE ; Wait our turn
|
|
jsrROM romDtrmV1 ; Determine volume by drvnum/refnum
|
|
bne SVIDone ; Punt on errors
|
|
jsrROM CVFLGS ; Check if volume can be modified
|
|
bne SVIDone ; Give up easily
|
|
jsrROM EXTOFFLINCK ; Check if volume is on-line, non ext. FS
|
|
bne SVIDone ; Be a wimp - give up now.
|
|
|
|
move.l ioVNPtr(a0),d2 ; New name specified?
|
|
beq.s DoneNameCheck ; If not, we can handle it
|
|
movea.l d2,a1 ; Point to new name
|
|
moveq.l #0,d2 ; start with first character and assume no name
|
|
move.b (a1), d3 ; empty string?
|
|
beq.s DoneNameCheck ; handle just like no name specified
|
|
|
|
@nextChar:
|
|
addq.b #1,d2 ; Advance to the next character
|
|
cmp.b #':',0(a1,d2.w) ; Hit a colon?
|
|
beq.s @colon ; Yes - punt.
|
|
cmp.b #vcbMaxNam,d2 ; Exceeded the max. length?
|
|
bgt.s @badName ; Yes - name is too long.
|
|
cmp.b d3,d2 ; At last character?
|
|
beq.s DoneNameCheck ; If so, we're not too long and no colons
|
|
bra.s @nextChar ; no - look for another
|
|
@colon:
|
|
cmp.b d3, d2 ; was colon the last character?
|
|
bne.s @badName ; last char is the only legal spot
|
|
subq.w #1, d2 ; was colon the only character?
|
|
bne.s DoneNameCheck ; must have at least one other
|
|
|
|
@badName:
|
|
moveq.l #bdNamErr,d0 ; get the error code
|
|
bra SVIDone ; we are finished, thatÕs for sure
|
|
|
|
DoneNameCheck:
|
|
; At this point, d2 is flag on the quality of the name
|
|
; if d2.b is non-zero, then we need to set the name
|
|
|
|
; Set user-modifiable fields in the VCB:
|
|
SetUserFields:
|
|
move.l ioVCrDate(a0),vcbCrDate(a2) ; Volume creation date
|
|
move.l ioVLsMod(a0),vcbLsMod(a2) ; Date of last modification
|
|
move.w ioVAtrb(a0),d0 ; Volume attributes
|
|
and.w #$8000,d0 ; Clear all but vol. locked bit
|
|
move.w vcbAtrb(a2),d1 ; Current volume attributes
|
|
and.w #$7FFF,d1 ; Clear vol. locked bit
|
|
or.w d0,d1 ; Combine attributes
|
|
move.w d1,vcbAtrb(a2) ; Set new volume attributes
|
|
|
|
move.l ioVNPtr(a0), d1 ; grab ptr to caller's name
|
|
|
|
jsrROM TFSVCBTST ; Is it a TFS volume?
|
|
bne.s @skipHFS ; br if not - MFS VCBs don't have this info
|
|
move.l ioVClpSiz(a0),vcbClpSiz(a2) ; Volume clump size
|
|
move.l ioVBkup(a0),vcbVolBkup(a2) ; Last backup date
|
|
move.w ioVSeqNum(a0),vcbVSeqNum(a2); Volume sequence number
|
|
lea.l ioVFndrInfo(a0),a0 ; Point to finder info source
|
|
lea.l vcbFndrInfo(a2),a1 ; Finder info in VCB
|
|
moveq.l #32,d0 ; Length of finder info
|
|
_BlockMove ; Copy it in
|
|
@skipHFS:
|
|
|
|
tst.b d2 ; do we want to rename
|
|
beq.s @skipRename ; if not, we're already done
|
|
|
|
move.l d2, d0 ; get psyched for _BlockMove
|
|
move.l d1, a0 ; recover ptr to caller's name
|
|
addq.w #1, a0 ; skip callerÕs length byte
|
|
lea.l vcbVN(a2), a1 ; VCB's copy
|
|
move.b d0, (a1)+ ; jam our length byte
|
|
_BlockMove ; change the name
|
|
|
|
jsrROM TFSVCBTST ; Are we dealing with an MFS volume?
|
|
bne.s @skipRootRename ; if so, no root to rename
|
|
|
|
; rename the root
|
|
moveq.l #0,d2 ; No catalog hint for rename
|
|
moveq.l #fsRtDirID,d0 ; Root directory
|
|
movea.l d2,a0 ; Nil CName pointer
|
|
lea.l vcbVN(a2), a1 ; VCB's copy
|
|
jsrROM CMRenameCN ; Rename the catalog root directory
|
|
bne.s SVIDone ; we're done, success or not
|
|
@skipRootRename:
|
|
@skipRename:
|
|
|
|
jsrROM romMarkVCB ; Mark VCB as dirty
|
|
moveq.l #noErr,d0 ; All went well...
|
|
|
|
SVIDone:
|
|
jmpROM CMDDONE
|
|
endproc
|
|
|
|
;__________________________________________________________________________________
|
|
; <22>
|
|
; Patch to CMSetUp
|
|
; We patch CMSetUp to trigger the following patches:
|
|
; deleteCN keep file threads current
|
|
; moveCN keep file threads current
|
|
; renameCN keep file threads current
|
|
; return #bdNamErr on renames of the root dir > 27 chars
|
|
; (this is case 2 from above)
|
|
; getCN distinguish between #fnfErr and #dirNFErr for DirCreate
|
|
; and Create.
|
|
;
|
|
; The renameCN and getCN patches have two level triggers, i.e. we watch for
|
|
; calls to CMSetUp from CMRename from PBRename.
|
|
;__________________________________________________________________________________
|
|
; The Disappearing Folder patch was rolled into TFSDIR2.a <SM1>
|
|
myCMSetUp PatchProc jCMSetup,(Plus,SE,II,IIci,Portable)
|
|
Import CMDeleteCNAfterSetup
|
|
Import CMMoveCNAfterSetup
|
|
Import CMRenameCNAfterSetup
|
|
Import CMRenameCNExit1
|
|
Import CMCreateUpdateCNPatch ; mark VCB dirty fix <10Jan91 #27>
|
|
|
|
|
|
* To fix the Disappearing Folder bug <18Mar92>
|
|
* pp, stb, jv, bb, gs, et al.
|
|
*
|
|
* High-level _Rename will attempt to adjust the FCB of the object it just renamed if that object is in
|
|
* the FCB list (meaning that the "file" is open). Unfortunately, folders donÕt have FCBÕs. Actually,
|
|
* ignoring my sarcasm, folders are not supposed to have them, and the unfortunate thing is that _Rename
|
|
* doesnÕt check before trying to update an FCB. Normally, _Rename would not be able to match a folder
|
|
* with an FCB, but there are opportunities where it can fool itself into thinking it has matched. When
|
|
* that happens, it alters some poor fileÕs FCB. This is bad. Once the FCB list has been damaged, all
|
|
* sorts of things can go wrong, including the loss of files and folders. The details are interesting,
|
|
* but the important thing is to make sure the FCBs donÕt get trashed, and thatÕs what this patch does.
|
|
|
|
cmpROM AfterCMGetCNinRename,$10(a6) ; was it ROM Rename?
|
|
beq.S @RenameAfterCMGetCN ; not what were looking for
|
|
BNE.S @NotAfterCMGetCNinRename
|
|
|
|
@RenameAfterCMGetCN
|
|
|
|
; the story so far...
|
|
|
|
; in Rename from the update FCB section
|
|
;
|
|
; movem.l FSTemp8,D2/A4
|
|
; bsr PushCName
|
|
; move.l D2,-(A6)
|
|
; move.l D6,D0
|
|
; move.l D7,D2
|
|
; jsr CMGetCN
|
|
;
|
|
; in CMGetCN
|
|
;
|
|
; move.l (sp)+,-(A6) ; save return address on A6 stack
|
|
; movem.l D1/D3/A3-A4,-(A6) ; save regs
|
|
; bsr CMSetUp ; common set up routine
|
|
;
|
|
; in CMSetUp
|
|
;
|
|
; move.l jCMSetUp,-(sp)
|
|
; rts
|
|
|
|
; now we have control, hah, hah, hah, hah, haaaaaah!
|
|
|
|
; here's what CMSetUp would have done for us
|
|
|
|
suba.w #lenCMVars,A6 ; allocate memory for CM vars on HFS stack
|
|
movea.l A6,A4 ; A4 = pointer to CM vars
|
|
addq.w #4,A7 ; pop return address to CMGetCN, instead of rts
|
|
|
|
; then we would return to this code in CMGetCN
|
|
|
|
clr.l VCBDirIDM(A2) ; invalidate current DirID marker
|
|
jsrROM romLocCNode ; locate dir/file BTree rec for the CNode (sets up A1)
|
|
|
|
@GCExit
|
|
adda.w #lenCMVars,A6 ; de-allocate memory for CM vars
|
|
movem.l (A6)+,D1/D3/A3-A4 ; restore regs
|
|
move.l (A6)+,-(sp) ; put return address back on stack
|
|
|
|
; ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ HereÕs the fix ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
; I've got an idea! Why don't we check to see if this is a file or a directory
|
|
cmpi.b #cdrDirRec,cdrType(A1) ; if it's a directory
|
|
beq @BugOut ; Hey! we shouldn't even be here...
|
|
; ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
|
|
tst.w D0 ; set condition codes
|
|
rts ; return to Rename as if from CMGetCN
|
|
|
|
@BugOut ; clean up A6 & A7 stacks and jump back to rom
|
|
addq.w #4,A7 ; remove return addr to Rename
|
|
move.l (A6)+,D2 ; recover rounded string length
|
|
jsrRom POPCNAME ; remove name from A6 stack
|
|
|
|
@RNmExit cmp.w #BTExists,D0 ; B*-Tree error?
|
|
bne.s @FinalExit
|
|
moveq #dupFNErr,D0 ; If entry exists, give better error code
|
|
@FinalExit jmpRom CMDDONE ; and now back to our regularly scheduled broadcast...
|
|
|
|
|
|
; CMSvcs calls "MarkVCBTime", which only set the mod time but doesn't mark VCB dirty.
|
|
; This leaves a dangerous window in the system. This patch will mark it dirty if the mod time
|
|
; has been changed across the CMxxxxCN calls. We rely on 2 things:
|
|
; 1. All CMxxxxCN calls set up A2 = VCB, and
|
|
; 2. These calls are single threaded.
|
|
|
|
@NotAfterCMGetCNinRename
|
|
move.l (sp)+, a4 ; grab the caller's address
|
|
|
|
; This patch was rolled into CMSVCS.a <SM1>
|
|
;; patch to CMCreateCN and CMUpdateCN to mark VCB dirty if VCBModTime has been changed:
|
|
cmpROM AfterCMSetupInCMCreateCN,A4 ; was it ROM CMCreateCN? <10Jan91 #27>
|
|
BNE.S @NotCreate ; not create <10Jan91 #27>
|
|
MOVE.L A4,-(sp) ; put the original caller back <10Jan91 #27>
|
|
;; we need to rearrange the A6 stack so it will come back to me after CMCreateCN <10Jan91 #27>
|
|
MOVEM.L (A6)+,D3-D7/A0-A4 ; restore regs that CMCreateCN saves <10Jan91 #27>
|
|
MOVE.L A4,-(SP) ; free A4 so I can use it <10Jan91 #27>
|
|
MOVE.L VCBLsMod(A2),-(A6) ; Save the mod time before the call <10Jan91 #27>
|
|
LEA CMCreateUpdateCNPatch,A4 ; get my patch address <10Jan91 #27>
|
|
MOVE.L A4,-(A6) ; push it on A6 stack <10Jan91 #27>
|
|
MOVEA.L (SP)+,A4 ; restore A4 <10Jan91 #27>
|
|
MOVEM.L D3-D7/A0-A4,-(A6) ; save regs now <10Jan91 #27>
|
|
; the A6 stack now looks like this ... (A7 points to the ret address of the caller of CMSetUp)
|
|
;; ------------- <--- A6 <10Jan91 #27>
|
|
;; D3-D7/A0-A4 <10Jan91 #27>
|
|
;; my patch address <10Jan91 #27>
|
|
;; saved VCBModTime <10Jan91 #27>
|
|
;; original return address <10Jan91 #27>
|
|
|
|
jmpOld ; do the CMSetUP and return to ROM <10Jan91 #27>
|
|
@NotCreate:
|
|
|
|
; This patch was rolled into CMSVCS.a <SM1>
|
|
cmpROM AfterCMSetupInCMUpdateCN,A4 ; was it ROM CMUpdateCN? <10Jan91 #27>
|
|
BNE.S @NotUpdate ; not update <10Jan91 #27>
|
|
MOVE.L A4,-(sp) ; put the original caller back <10Jan91 #27>
|
|
;; we need to rearrange the A6 stack so it will come back to me after CMUpdateCN <10Jan91 #27>
|
|
MOVEM.L (A6)+,D1-D2/A0-A1 ; restore regs that CMCreateCN saves <10Jan91 #27>
|
|
MOVE.L A4,-(SP) ; free A4 so I can use it <10Jan91 #27>
|
|
MOVE.L VCBLsMod(A2),-(A6) ; Save the mod time before the call <10Jan91 #27>
|
|
LEA CMCreateUpdateCNPatch,A4 ; get my patch address <10Jan91 #27>
|
|
MOVE.L A4,-(A6) ; push it on A6 stack <10Jan91 #27>
|
|
MOVEA.L (SP)+,A4 ; restore A4 <10Jan91 #27>
|
|
MOVEM.L D1-D2/A0-A1,-(A6) ; save regs now <10Jan91 #27>
|
|
jmpOld ; do the CMSetUP and return to ROM <10Jan91 #27>
|
|
@NotUpdate:
|
|
|
|
; This patch was rolled into CMSVCS.a <SM1>
|
|
; Replace CMDeleteCN with a fileID-aware version
|
|
cmpROM AfterCMSetupInCMDeleteCN,a4 ; was it ROM CMDeleteCN?
|
|
bne.s NotDelete ; not delete
|
|
jsrOld
|
|
jmp CMDeleteCNAfterSetup ; replace it with the new delete
|
|
NotDelete:
|
|
|
|
; This patch was rolled into CMSVCS.a <SM1>
|
|
; Replace CMMoveCN with a fileID-aware version
|
|
cmpROM AfterCMSetupInCMMoveCN,a4 ; was it ROM CMMoveCN?
|
|
bne.s NotMove
|
|
jsrOld
|
|
jmp CMMoveCNAfterSetup ; replace it with the new move
|
|
NotMove:
|
|
|
|
; The functionality of this patch was rolled into Rename in TFSDIR2.1
|
|
; Replace CMRenameCM with a fileID-aware version that does correct root renames
|
|
cmpROM AfterCMSetupInCMRenameCN,a4 ; was it ROM CMRenameCN?
|
|
bne.s NotRename
|
|
jsrOld
|
|
|
|
; Check for calls to CMRenameCN from PBRename. If we're from PBRename we'll
|
|
; do a quick check for root renames > 27 characters before continuing.
|
|
; Target return address is under CMVars and 10 regs.
|
|
cmpROM AfterCMRenameCNInRename,lenCMVars+(10*4)(a6) ; check if Rename called CMRenameCN
|
|
beq.s RenameCheckVolNameLength
|
|
jmp CMRenameCNAfterSetup ; replace it with the new rename
|
|
NotRename:
|
|
|
|
|
|
; It turns out that the following fix wasn't necessary. A bug had reported that
|
|
; DirCreate and Create could be confused into creating a file or directory in the
|
|
; root when the indicated dirID didn't exist. After fixing the bug I wasn't able
|
|
; to find a case that showed the bug, so I've turned the fix off. If anyone can
|
|
; actually reproduce this, feel free to turn this fix back on. It does do what it
|
|
; says it does. Until then, the dead code stipper will remove all traces of
|
|
; FndFilNameCheckDirValid.
|
|
PerformFndFilNameFix equ 0
|
|
|
|
if PerformFndFilNameFix then
|
|
; This patch was not rolled into SuperMario <SM1>
|
|
; Fix FndFilName to differentiate between #dirNFErr and #fnfErr on pathname
|
|
; parsing. Do a two-stage trigger on calls to CMSetUp from CMGetCN from FndFilName.
|
|
; Target return address is under 4 registers.
|
|
cmpROM AfterCMSetupInCMGetCN, a4 ; was it ROM CMGetCN?
|
|
bne.s NotGetCN
|
|
cmpROM AfterCMGetCNInFndFilName,lenCMVars+(4*4)(a6)
|
|
bne.s NotGetCN
|
|
|
|
import FndFilNameCheckDirValid
|
|
jsrOld ; do the CMSetUp
|
|
jmp FndFilNameCheckDirValid ; replace CMGetCN
|
|
NotGetCN:
|
|
endif
|
|
|
|
; None of the patches triggered, so restore the stack and let the old code
|
|
; do the CMSetUp.
|
|
move.l a4,-(sp) ; put the original caller back
|
|
jmpOld
|
|
|
|
;________________________________________________________________________________
|
|
; Check for renames of the root directory to names > 27 characters in length.
|
|
; We rejoin the fileID-aware version of CMRenameCN after performing our check.
|
|
;
|
|
; Registers:
|
|
; Input: A2.L - VCB pointer
|
|
; D0.L - DirID or parent DirID
|
|
; A0.L - CName pointer (or nil for zero length)
|
|
; A1.L - CName pointer (new CName)
|
|
; D2.L - catalog hint
|
|
;
|
|
; Output: D0.W - result code
|
|
; 0 = ok
|
|
; CMnotfound = CNode not found
|
|
; CMexists = CNode already exists for new CName
|
|
; -n = IO error
|
|
; D2.L - new catalog hint
|
|
;________________________________________________________________________________
|
|
; The functionality of this patch was rolled into Rename in TFSDIR2.1
|
|
RenameCheckVolNameLength:
|
|
cmp.l #FSRtParID,d0 ; Renamed an entry in root's parent [root]?
|
|
beq.s @checkName ; If so, go update vol. name
|
|
cmp.l #FSRtDirID,d0 ; Finally, check for rear entries
|
|
bne.s @noProblem ; If it's not this, we're all set.
|
|
move.l a0, -4(sp) ; test by storing onto live stack
|
|
bne.s @noProblem ; non-zero entries here are not for us
|
|
|
|
@checkName:
|
|
cmp.b #vcbMaxNam, (a1) ; max volume name is 27 characters
|
|
bls.s @noProblem
|
|
|
|
; WeÕve caught a rename of the root to a name longer than 27 characters.
|
|
@badName
|
|
moveq.l #bdNamErr,d0 ; bad name result will fall out of Rename
|
|
jmp CMRenameCNExit1
|
|
|
|
@noProblem:
|
|
jmp CMRenameCNAfterSetup ; go continue
|
|
EndProc
|
|
|
|
;________________________________________________________________________________
|
|
; Fix FndFilName <29>
|
|
;
|
|
; When FndFilName is parsing a pathname it changes #cmNotFound errors from
|
|
; CMGetCN into #fnfErr when #dirNFErr is correct. FndFilName returns #dirNFErr
|
|
; when any CMGetCN fails while parsing along a path, and #fnfErr when checking
|
|
; the last leaf in the path. The bug is that FndFilName sees dirID+single segment
|
|
; pathname inputs as the Òlast segmentÓ case, and returns #fnfErr if the lookup fails,
|
|
; even though the dirID could be invalid.
|
|
;
|
|
; The solution is to do an extra lookup on failed CMGetCN calls while parsing
|
|
; pathnames. We look for the directory thread of the parent of the failed call
|
|
; and set D6 (FndFilName's error register) to #dirNFErr if the second call fails.
|
|
;
|
|
; There may be apps out there which count on #fnfErr to happen in certain cases,
|
|
; so we only trigger on DirCreate and Create, where incorrect handling of this
|
|
; error causes these calls to create file system objects in the wrong directory.
|
|
;
|
|
;
|
|
; Input: A2.L - VCB pointer
|
|
; D0.L - DirID or parent DirID
|
|
; A0.L - CName pointer
|
|
; D2.L - catalog hint
|
|
;
|
|
; Output: D0.W - result code
|
|
; 0 = ok
|
|
; CMnotfound = CNode not found
|
|
; -n = IO error
|
|
; A0.L - pointer to catalog key record (ckr)
|
|
; A1.L - pointer to catalog data record (cdr)
|
|
; D2.L - catalog hint
|
|
;________________________________________________________________________________
|
|
; This patch was not rolled into SuperMario <SM1>
|
|
FndFilNameCheckDirValid: proc
|
|
|
|
createTrapWord equ $a008
|
|
dirCreateTrapWord equ selectDirCreate
|
|
|
|
move.l d0, -(a6) ; stash target parent directory
|
|
|
|
movea.l FSQHead,a1 ; get frontmost file system call
|
|
move.w ioTrap(a1),d0 ; get trap word
|
|
andi.w #$f0ff,d0 ; clear modifiers
|
|
cmpi.w #createTrapWord,d0 ; is this a create call?
|
|
beq.s @trigger
|
|
cmpi.w #dirCreateTrapWord,d0 ; is this a DirCreate call?
|
|
beq.s @trigger
|
|
|
|
move.l (a6)+, d0 ; restore d0
|
|
rts
|
|
|
|
@trigger:
|
|
clr.l vcbDirIDM(A2) ; invalidate current DirID marker
|
|
|
|
jsrROM romLocCNode ; do FndFilName's requested lookup
|
|
bne.s @checkParent
|
|
|
|
addq.w #4,a6 ; restore a6 stack level
|
|
bra.s @exit ; and return to a happy FndFilName
|
|
|
|
@checkParent:
|
|
suba.l a0, a0 ; go after the parent
|
|
move.l (a6)+,d0 ; retrieve target parent directory
|
|
|
|
jsrROM LOCCREC
|
|
bne.s @dirNotFound
|
|
cmpi.b #cdrThdRec,cdrType(a1) ; is it a directory thread?
|
|
beq.s @fileNotFound ; yes, so it was just the leaf that was missing
|
|
@dirNotFound:
|
|
moveq.l #dirNFErr,d6 ; stuff correct error code in FndFilName's register
|
|
@fileNotFound:
|
|
move.w #cmNotFound,d0 ; just like they expected
|
|
@exit:
|
|
add.w #lenCMVars,a6 ; de-allocate memory for CM vars
|
|
movem.l (a6)+,d1/d3/a3-a4 ; restore regs
|
|
move.l (a6)+,-(sp) ; put return address back on stack
|
|
tst.w d0 ; set condition codes
|
|
rts ; exit CMGetCN back to FndFilName
|
|
|
|
;_____________________________________________________________________________________
|
|
; <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 has been copied to TFS.a <SM1>
|
|
CountFCBs proc
|
|
@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
|
|
endproc
|
|
|
|
;_____________________________________________________________________________________
|
|
; <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 has been copied to TFS.a <SM1>
|
|
OpenAttemptHook: proc
|
|
@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
|
|
|
|
endproc
|
|
|
|
;_____________________________________________________________________________________
|
|
; <38>
|
|
; PreflightFileOpen
|
|
;
|
|
; Function:
|
|
; Call OpenAttemptHook for calls to _Open/_HOpen/_OpenDF/_HOpenDF
|
|
;
|
|
; Input:
|
|
; a0 - pointer to caller's PB
|
|
;
|
|
; This function sits at the bottom of the jFileOpen vector
|
|
;_____________________________________________________________________________________
|
|
; This patch was rolled into TFSDIR1.a
|
|
PreflightFileOpen proc
|
|
|
|
jsrROM FSQUEUE ; serialize things
|
|
bsr OpenAttemptHook ; tell'em we're trying
|
|
ST RegRsrc ; open regular part of file <39>
|
|
jmpROM FOpen1
|
|
|
|
endproc
|
|
|
|
;_____________________________________________________________________________________
|
|
; <38>
|
|
; PreflightOpenRF
|
|
;
|
|
; Function:
|
|
; Call OpenAttemptHook for calls to _OpenRF/_HOpenRF
|
|
;
|
|
; Input:
|
|
; a0 - pointer to caller's PB
|
|
;
|
|
;_____________________________________________________________________________________
|
|
; This patch was rolled into TFSDIR1.a
|
|
PreflightOpenRF PatchProc _OpenRF
|
|
|
|
jsrROM FSQUEUE ; serialize things
|
|
bsr OpenAttemptHook ; tell'em we're trying
|
|
clr.b RegRsrc ; open resource part of file <39>
|
|
jmpROM FOpen1
|
|
|
|
endproc
|
|
|
|
;_____________________________________________________________________________________
|
|
; <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 rolled into TFS.a
|
|
AllocateFCBs proc
|
|
import MoreFCBs
|
|
|
|
jsrROM FSQUEUE ; wait our 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: jmpROM CMDDONE
|
|
|
|
@noFCBsAvailable:
|
|
moveq.l #tmfoErr,d0
|
|
bra.s @exit
|
|
endwith
|
|
endproc
|
|
|
|
;_____________________________________________________________________________________
|
|
; <38>
|
|
; CheckFCBAllocation
|
|
;
|
|
; Function:
|
|
; Check to see if there's a pending request for more FCBs. If
|
|
; there is a request, service it.
|
|
;
|
|
; This routine is called from both the tail of the syncwait loop and
|
|
; from idle time.
|
|
;
|
|
; Note that we only attempt to allocate more FCBs when the #fsNeedsFCBs
|
|
; bit is set. This allows the syncwait loop to come here for all
|
|
; #tmfoErr cases, even when those cases were generated by remote
|
|
; volumes failing to get FCBs.
|
|
;
|
|
; Note that this routine makes a file system call (_AllocateFCBs), so
|
|
; it can't be called from within the file system.
|
|
;
|
|
; Input:
|
|
; none
|
|
;
|
|
; Output:
|
|
; d0.w - #noErr if nobody has any outstanding FCB requests or
|
|
; the outstanding request was successfully fulfilled
|
|
;
|
|
; - #tmfoErr if FCBs were requested and none could be made
|
|
; available
|
|
;
|
|
; ccr's - tst.w of d0
|
|
;_____________________________________________________________________________________
|
|
; This routine was rolled into TFS.a
|
|
CheckFCBAllocation: proc
|
|
@regs reg d1/a0/a1
|
|
|
|
movem.l @regs,-(sp)
|
|
move.l FSVarsPtr,a1
|
|
with FSVars
|
|
|
|
btst.b #fsNoFCBExpansion,fsFlags(a1) ; does anybody even care?
|
|
bne.s @quickExit
|
|
|
|
bclr.b #fsNeedFCBs,fsFlags(a1) ; does anybody need any FCBs?
|
|
beq.s @quickExit ; if not, cruise
|
|
|
|
sub.w #ioHQElSize,sp ; allocate an iopb
|
|
movea.l sp,a0 ; grab the iopb pointer
|
|
move.w fsFCBBurst(a1),ioFCBBurst(a0) ; indicate desired FCB headroom
|
|
move.w fsFCBGrow(a1),ioFCBGrow(a0) ; indicate target when we do grow
|
|
_AllocateFCBs ; go see what we can get
|
|
move.w ioTotalFCBs(a0),d1 ; grab the total now
|
|
add.w #ioHQElSize,sp ; deallocate iopb
|
|
|
|
cmp.w fsFCBMax(a1),d1 ; are we at max FCBs?
|
|
blt.s @exit ; if not, don't worry
|
|
bset.b #fsNoFCBExpansion,fsFlags(a1) ; if so, don't bother keeping track anymore
|
|
|
|
@exit:
|
|
movem.l (sp)+,@regs
|
|
tst.w d0
|
|
rts
|
|
|
|
@quickExit:
|
|
moveq.l #noErr,d0
|
|
bra.s @exit
|
|
|
|
endwith
|
|
endproc
|
|
|
|
;_____________________________________________________________________________________
|
|
; <38>
|
|
; FileManagerIdleProc
|
|
;
|
|
; Function:
|
|
; This function is called from _IdleSynchTime to allow the file system
|
|
; to perform periodic activity.
|
|
;
|
|
; Currently we check to make sure that enough FCBs are free.
|
|
;
|
|
; Input:
|
|
; Output:
|
|
; none
|
|
;_____________________________________________________________________________________
|
|
; This routine was rolled into TFS.a
|
|
FileManagerIdleProc: proc export
|
|
jsr CheckFCBAllocation
|
|
rts
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
; Fix DtrmV3
|
|
;
|
|
; The ROM's volume identification code at DtrmV3 forgets to clear d2
|
|
; (path string length) when there's a null string (i.e. length byte is zero).
|
|
;
|
|
; This patch replaces DtrmV3 entirely (all five lines). Also, though the ROM DtrmV3
|
|
; branches to DtrmVol, it does this just to put the name pointer in d2, which we've
|
|
; already done, so we jump straight through the vector at DtrmV2.
|
|
;
|
|
; NOTE: We only fix this bug on machines where there's a convenient vector on jDtrmV3.
|
|
; This bug has been around for a long time and hasn't cause too much trouble, so we
|
|
; can live with this partial solution.
|
|
;________________________________________________________________________________
|
|
; This patch was rolled into TFSVOL.a
|
|
FixDtrmV3: PatchProc jDtrmV3,(II,IIci,Portable)
|
|
|
|
move.l ioFileName(a0),d2 ; entry for flush,set,eject,unmountvol
|
|
move.l d2,a4
|
|
beq.s @DtrmV1 ; br if nil filename pointer (d2,a4=0)
|
|
tst.b (a4) ; is it a zero-length name?
|
|
beq.s @SetStringLengthZero ; if zero, set the string length to zero
|
|
; and fall through to DtrmVol
|
|
|
|
; Jumping straight to DtrmV2 is the moral equivalent of the ROM's jump to
|
|
; DtrmVol since all DtrmVol does is move the pathname pointer into d2 and fall
|
|
; through to DtrmV2.
|
|
move.l jDtrmV2, -(sp) ; let the ROM take it from here
|
|
rts
|
|
|
|
@SetStringLengthZero:
|
|
moveq.l #0, d2 ; make sure string length is set to zero
|
|
|
|
@DtrmV1:
|
|
jmpROM romDtrmV1 ; let the ROM take it from here
|
|
endproc
|
|
|
|
;_______________________________________________________________________
|
|
; <29>
|
|
; Fix _MountVol to
|
|
; not allocate any memory during disk switch operations.
|
|
; not attempt to _Offline other volumes to free up memory
|
|
; not reopen btree files on remounts
|
|
;
|
|
; In order to make the disk switch hook run without moving memory, we need
|
|
; to be able to check for a remount without moving memory. If we find a
|
|
; remount, we succeed. If we see the #fsNoAllocate flag, we'll return an
|
|
; error, causing the disk switch code to eject the disk and wait for another.
|
|
; Otherwise we jump into the ROM and let it do a new mount.
|
|
;
|
|
; When we do see a remount, we tweak the driver refNum and drive number and
|
|
; we're done, since the btree files will always be open.
|
|
;
|
|
; The flag #fsNoAllocate will be set by the disk switch hook to inform the
|
|
; file system that it should allow only remounts (i.e. not allocate any memory).
|
|
; If new mounts are allowed, we jump straight into the ROM code which mounts the
|
|
; volume, skipping the old code which attempted to _Offline other mounted
|
|
; volumes in favor of a newly mounted one.
|
|
;
|
|
; Exciting note for you wanna-be assemblers out there who write instructions
|
|
; into lomem at TrapAgain and jump to them. You know who you are (Disk Switch
|
|
; Hook). You might have been worried about flushing those whizzy processor
|
|
; caches that some of our more profitable macintoshes sport these days. However,
|
|
; as an added introductory bonus, successful mountvol calls flush the caches
|
|
; because they call _BlockMove when they fill in the fresh VCB from the MDB.
|
|
; _BlockMove is just one of those cache-flushing kind of guys.
|
|
;_______________________________________________________________________
|
|
; This patch was rolled into TFSVOL.a
|
|
MountVolFor1991 PatchProc _MountVol
|
|
|
|
jsrROM FSQUEUESYNC
|
|
|
|
movea.l a0, a5 ; save caller's pb
|
|
move.w ioDrvNum(a5), d2 ; where FindDrive likes it
|
|
jsrROM romFindDrive ; call ROM (not vectored on Plus/SE <30>)
|
|
bne EarlyExit
|
|
|
|
suba.w #512,a6 ; a disk block
|
|
|
|
lea.l Params,a0 ; the old lomem param block
|
|
move.w d2,ioDrvNum(a0) ; drive number
|
|
move.w d1,ioRefNum(a0) ; driver RefNum
|
|
move.l a6,ioBuffer(a0) ; buffer
|
|
move.w #fsFromStart,ioPosMode(a0) ; position mode 1 (from disk start)
|
|
move.l #1024, ioPosOffset(a0) ; The MDB is always block #2
|
|
move.l #512,ioByteCount(a0) ; All MDBs are 1 512 byte block
|
|
_Read
|
|
bne Exit
|
|
|
|
moveq.l #NoMacDskErr,d0 ; Assume it's for another file system.
|
|
cmp.w #tSigWord,drSigWord(a6) ; Does it bear the Turbo Seal?
|
|
beq.s @GotMacDisk
|
|
|
|
cmp.w #sigWord,drSigWord(a6) ; Is it a trustworthy MFS volume?
|
|
bne Exit
|
|
@GotMacDisk:
|
|
|
|
moveq.l #badMDBErr,d0 ; in case master directory block is bad
|
|
move.l drAlBlkSiz(a6),d3 ; make sure this is non-zero, 512 multiple
|
|
beq Exit ; exit if 0
|
|
andi.w #$01FF,d3 ; 512-byte multiple?
|
|
bne Exit ; exit if not
|
|
|
|
move.w #notARemountErr,d0 ; 'cause we're looking for remounts only here
|
|
move.l VCBQHdr+qHead,d3 ; search the queue of VCBs
|
|
|
|
CheckRemountLoop:
|
|
beq.s Exit ; we fail if we don't see a remount
|
|
move.l d3,a2
|
|
|
|
tst.w vcbDrvNum(a2) ; matching volume better be off-line (0 drive num)
|
|
bne.s @Next
|
|
|
|
move.w vcbSigWord(a2),d3 ; Pick up Sigword of mounted volume
|
|
cmp.w drSigWord(a6),d3 ; Same signature?
|
|
bne.s @Next
|
|
move.l vcbCrDate(a2),d3 ; Pick up creation date of mounted volume
|
|
cmp.l drCrDate(a6),d3 ; Same create date?
|
|
bne.s @Next
|
|
move.l vcbLsMod(a2),d3 ; Pick up mod date of mounted volume
|
|
cmp.l drLsMod(a6),d3 ; Same mod date?
|
|
bne.s @Next
|
|
|
|
; At this point, we're fairly certain that the two volumes are, in fact, the same,
|
|
; but just to make sure (and avoid problems with stuck clocks), we'll compare the
|
|
; volume names as well:
|
|
|
|
lea.l vcbVN(a2),a1 ; Point to name of mounted volume
|
|
lea.l drVN(a6),a3 ; Point to name of current volume
|
|
moveq.l #(vcbMaxNam+1)-1,d3 ; check 28 bytes in name field (incl. length)
|
|
@loop:
|
|
cmpm.b (a1)+,(a3)+ ; field match?
|
|
dbne d3,@loop
|
|
beq.s Remount
|
|
|
|
@Next:
|
|
move.l qLink(a2),d3
|
|
bra.s CheckRemountLoop
|
|
|
|
; We are now convinced that we have a remount. We will rebuild the attributes
|
|
; byte, which is the only one that could have changed. We'll also store the
|
|
; current drive number and driver refNum, and mark the volume dirty.
|
|
Remount:
|
|
move.w #drvStsCode,csCode(a0) ; drive status!
|
|
clr.b 2+csParam(a0) ; Clear status byte for return
|
|
_Status ; refnum and drivenum set up by read call
|
|
|
|
moveq.l #-128,d0 ; $80 mask
|
|
and.b 2+csParam(a0),d0 ; WriteProt status get
|
|
move.b d0,vcbAtrb+1(a2) ; write-protect, zeroed consistency status
|
|
_AssumeEq vcbWrProt,7
|
|
|
|
move.w d2,vcbDrvNum(a2) ; drive number
|
|
move.w d1,vcbDRefNum(a2) ; driver RefNum
|
|
|
|
jsrROM TFSVCBTST ; remounted a TFS volume? <32>
|
|
bne.s NoErrExit ; Nope - don't mess with the MDB <33>
|
|
btst.b #vcbWrProt,vcbAtrb+1(a2); Is volume write protected? <32>
|
|
bne.s NoErrExit ; If so, don't try to flush the MDB <33>
|
|
bclr.b #vcbAtVOK,vcbAtrb(a2) ; From now 'til unmount we're dirty <32>
|
|
jsrROM MarkVCBDirty ; mark VCB dirty so it will be written <32>
|
|
jsrROM FlushMDB ; write it <32>
|
|
NoErrExit:
|
|
moveq.l #noErr,d0
|
|
|
|
Exit:
|
|
adda.w #512, a6 ; deallocate MDB buffer
|
|
|
|
EarlyExit:
|
|
tst.w d0 ; check the error
|
|
beq.s @1 ; noErr implies a successful remount
|
|
|
|
; if we are allowing new mounts, let the ROM handle the details. Otherwise,
|
|
; let the error stand
|
|
move.l FSVarsPtr,a1
|
|
btst.b #fsNoAllocate, FSVars.fsFlags(a1)
|
|
beqROM OldMtVolAfterFSQueue ; join the ROM (BTW, skipping the _Offline heroics)
|
|
@1:
|
|
jmpROM CMDDONE
|
|
endproc
|
|
|
|
;_______________________________________________________________________
|
|
; <30>
|
|
; Fix _Offline and _Eject to leave btree control files open
|
|
;
|
|
; In order to make the disk switch hook run without moving memory, we need
|
|
; to leave the btree control files (catalog and extents) open when putting
|
|
; a volume offline, so that the subsequent _Mount call won't have to allocate
|
|
; a new btree control block.
|
|
;
|
|
; We head patch _Eject and _Offline to use this code path instead of
|
|
; the ROM code.
|
|
;
|
|
; Registers:
|
|
; a0 - iopb
|
|
;
|
|
; This patch handles the cases for the Plus and SE
|
|
;_______________________________________________________________________
|
|
; These patches were rolled into TFSVOL.a
|
|
NoCloseOnOffline PatchProc _Offline
|
|
import OfflineEjectCommon
|
|
jsrROM FSQUEUESYNC ; wait until all current calls are done
|
|
st NoEject ; -1 = send offline but don't eject
|
|
jmp OfflineEjectCommon ; share code with Eject
|
|
endproc
|
|
|
|
NoCloseOnEject PatchProc _Eject
|
|
export OfflineEjectCommon
|
|
jsrROM FSQUEUESYNC ; wait until all current calls are done
|
|
clr.b NoEject ; 0 = offline + eject
|
|
|
|
OfflineEjectCommon
|
|
jsrROM DTRMV3 ; check name, drive number, etc.
|
|
bne.s ejectNotMounted ; br if drive not mounted (why flush?)
|
|
jsrROM romCkExtFS ; see if it's for an external fs
|
|
bne.s EjectDone ; exit if so
|
|
bra.s ejectMounted ; otherwise, go the 'mounted volume' route
|
|
|
|
ejectNotMounted:
|
|
move.w ioVDrvNum(a0),d2 ; drive number
|
|
|
|
ejectDrvNum:
|
|
jsrROM romFindDrive ; get disk driver refnum in D1
|
|
bne.s ejectDone ; exit if no mapping for this drive
|
|
tst.b NoEject ; REALLY eject this thing?
|
|
beqROM EjectIt ; OK, OK; it's going already...
|
|
|
|
ejectDone:
|
|
jmpROM CMDDONE ; we're done . . .
|
|
|
|
ejectMounted:
|
|
lea.l vcbDrvNum(a2),a1 ; point into VCB at drive number
|
|
move.w (a1),d2 ; on-line, non-ejected?
|
|
bne.s ejectOnLine ; br if so
|
|
|
|
move.w 2(a1),d2 ; does dRefNum say it's ejected?
|
|
bpl.s ejectDone ; just exit if so
|
|
tst.b NoEject ; no eject?
|
|
bne.s ejectDone ; br if so (it's already offline . . .)
|
|
|
|
neg.w d2 ; get non-ejected offline disk's drive number
|
|
neg.w 2(a1) ; mark it now ejected . . .
|
|
bra.s ejectDrvNum ; and eject it (pass D2=drive number)
|
|
; NOTE: the previous OffLine call would have marked
|
|
; a TFS disk consistent.
|
|
|
|
; OK, it's on-line and not ejected . . . so make it offline and eject if appropriate . . .
|
|
|
|
ejectOnLine:
|
|
jsrROM romFindDrive ; Find DQE from drive number in d2
|
|
bne.s ejectDone ; Punt if can't be found
|
|
tst.b NoEject ; Just an _Offline call?
|
|
bne.s @5 ; Yes - don't try harder than needed
|
|
cmp.b #8,DQDIP(a3) ; Check drive ejectability
|
|
blt.s @5 ; Skip if it's ejectable
|
|
st NoEject ; If DQDIP > 8, it's non-ejectable
|
|
cmp.b #64,DQDIP(a3) ; Send a _Control call anyway?
|
|
blt.s @5 ; No need - we're set as is
|
|
move.b #1,NoEject ; If >64, call the driver anyway
|
|
|
|
@5: st FlushOnly ; only flushing (don't close . . .)
|
|
jsrROM FlushVFiles ; flush all files on this volume
|
|
|
|
jsrROM TFSVCBTST ; Are we dealing with a TFS volume?
|
|
bneROM OfflineEjectCallsMFSFlush ; Nope, so join ROM to do MFS right
|
|
|
|
; note that the following line is the opposite of the ROM code. We only want to flush
|
|
; these files, since _Unmount will close them later. However, we do want to mark the
|
|
; vcb consistent as it goes offline.
|
|
jsrROM CVFLGS ; Is volume write protected? <31>
|
|
bne.s @1 ; If so, don't try to mark it dirty <31>
|
|
bset.b #vcbAtVOK,vcbAtrb(a2) ; Indicate vol was unmounted ok <31>
|
|
jsrROM MarkVCBDirty ; mark VCB dirty so it will be written <31>
|
|
@1 jsrROM FlushMDB ; Go flush the VCB info BEFORE flushing <31>
|
|
|
|
st.b FlushOnly ; just flush the control files
|
|
jmpROM OfflineEjectCallsFlushBuffers
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
; <36>
|
|
; Routine: DesktopCloseDownProc
|
|
;
|
|
; Inputs param block to _Unmount
|
|
;
|
|
; Outputs: (none)
|
|
;
|
|
; Function: Close the desktop database on _Unmount calls
|
|
;
|
|
;________________________________________________________________________________
|
|
; Rolled into TFS.a for <SM1> FM
|
|
DesktopCloseDownProc: proc
|
|
import FindDTVol
|
|
@regs reg a0/a1/a3/d0/d1 ; <43>
|
|
|
|
movem.l @regs, -(sp)
|
|
|
|
movea.l a0,a3 ; save the user's pb <42>
|
|
|
|
; d0 - pascal length byte of string <43>
|
|
; d1 - size of string allocated on stack <43>
|
|
|
|
moveq.l #0,d1 ; assume no string on stack <43>
|
|
move.l ioNamePtr(a3),d0 ; d0 = callerÕs name ptr <43>
|
|
beq.s @noName ; bail on nil <43>
|
|
movea.l d0,a0 ; get ready to copy <43>
|
|
moveq.l #0,d0 ; clear high bytes <43>
|
|
move.b (a0),d0 ; d0 = string length <43>
|
|
beq.s @noName ; bail on zero length (d0.l has nil) <43>
|
|
|
|
move.b d0,d1 ; d1 = copy of string length byte <43>
|
|
addq.b #2,d1 ; add length byte and rounding fodder <43>
|
|
bclr.l #0,d1 ; make it even <43>
|
|
suba.w d1,sp ; allocate a string of the right length <43>
|
|
movea.l sp,a1 ; point to it <43>
|
|
|
|
@1: move.b (a0)+,(a1)+ ; <43>
|
|
dbra d0,@1 ; copy string length+1 bytes <43>
|
|
|
|
move.l sp,d0 ; point to it again <43>
|
|
|
|
@noName:
|
|
suba.w #ioHVQElSize,sp ; get a pb <42>
|
|
movea.l sp,a0 ; point to it <42>
|
|
move.w ioVRefNum(a3),ioVRefNum(a0) ; copy caller's vRefNum <42>
|
|
move.l d0,ioNamePtr(a0) ; our version of the caller's name <42>
|
|
move.w #-1,ioVolIndex(a0) ; by name&vRef, please <42>
|
|
_GetVolInfo ; <42>
|
|
bne.s @done ; <42>
|
|
|
|
move.w ioVRefNum(a0), d0 ; grab the volume that's going away
|
|
bsr FindDTVol ; try to find a DTDBQElt for this volume
|
|
bne.s @done ; no work to do if the DTDB is closed
|
|
sub.w #ioDTQElSize, sp ; allocate a DT param block
|
|
movea.l sp, a0
|
|
move.w DTDBQElt.DTRefNum(a3), ioRefNum(a0) ; stash the DTRefNum for this volume
|
|
_DTCloseDown
|
|
add.w #ioDTQElSize, sp ; deallocate the param block
|
|
|
|
@done:
|
|
adda.w #ioHVQElSize,sp ; deallocate the pb <42>
|
|
adda.w d1,sp ; deallocate the string <43>
|
|
movem.l (sp)+, @regs
|
|
rts
|
|
endproc
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: UnMountVol
|
|
; Arguments: A0 (input) -- pointer to volume parameter block, uses IODrvNum,
|
|
; IOFileName
|
|
; D0 (output) -- error code
|
|
; This call is executed synchronously.
|
|
; Calls: FlushVolume
|
|
;
|
|
; Function: All files on the volume in the drive are closed and any changed
|
|
; directory information is written out to the diskette. Memory
|
|
; for the VCB, volume buffer, and block map is deallocated.
|
|
;
|
|
; This is a complementary patch to the above patch to _Offline. Since
|
|
; _Offline does not close the HFS control files (catalog and extents)
|
|
; we need to have _UnmountVol always close them.
|
|
;_______________________________________________________________________
|
|
UnmountForTheNineties: PatchProc _UnMountVol
|
|
|
|
bsr DesktopCloseDownProc ; go take care of the desktop database <36>
|
|
|
|
; The desktop file hack should no longer be necessary for the 7.0 version of the AppleShare client.
|
|
IncludeAppleShareDesktopHack equ 0
|
|
|
|
jsrROM FSQUEUESYNC ; Get in sync...
|
|
clr.b FlushOnly ; Setup same as UnmountVol
|
|
jsrROM DTRMV3 ; Call DtrmV3 to do setup stuff
|
|
bneROM CMDDONE ; and split on errors
|
|
|
|
moveq #0,d0 ; Initialize result code
|
|
btst #HFSBit,ioTrap(a0) ; Unconditional unmount?
|
|
bne FlUnMnt ; Xfer if so...
|
|
;
|
|
; On return from DtrmV3, A2 contains the VCB ptr of the volume
|
|
; in question. Search the FCB array for open files that reference
|
|
; the volume...
|
|
;
|
|
movem.l a1/d1/d2,-(sp) ; Save some scratch regs
|
|
move.l FCBsPtr,a1 ; FCB array base address
|
|
moveq #2,d1 ; Index of 1st FCB
|
|
@2
|
|
move.l fcbFlNm(a1,d1),d2 ; Is the file currently open?
|
|
beq.s @4 ; Nope, try next FCB...
|
|
cmp.l fcbVPtr(a1,d1),a2 ; Is the file on this volume?
|
|
bne.s @4 ; No, try next FCB...
|
|
cmp.w #SigWord,vcbSigWord(a2) ; Is this an MFS volume?
|
|
beq.s @3 ; Yes, error if files are open...
|
|
cmp.l #FSUsrCNID,d2 ; Is it an internal file?
|
|
blo.s @4 ; Ignore it if so...
|
|
if IncludeAppleShareDesktopHack then
|
|
cmp.w #Tsigword,vcbSigWord(a2) ; Is this a TFS volume? ¥¥¥ do we mean extFS?
|
|
bne.s @3 ; Error if not...
|
|
cmp.l #$47525420,d2 ; is it a fake AppleShare FCB?
|
|
beq.s @4 ; yes, skip it...
|
|
endif
|
|
|
|
@3
|
|
;
|
|
; Found an open user file on the volume, so return a
|
|
; busy condition...
|
|
;
|
|
moveq #fBsyErr,d0 ; Assert UnmountVol error
|
|
bra.s @5 ; Get out...
|
|
|
|
@4
|
|
add.w FSFCBLen,d1 ; Next FCB array entry
|
|
cmp.w (a1),d1 ; Reached the end yet?
|
|
blo.s @2 ; Continue if not...
|
|
@5
|
|
movem.l (sp)+,a1/d1/d2 ; Restore regs
|
|
tst.w d0 ; Were files open?
|
|
bneROM CMDDONE ; and quit on errors
|
|
|
|
FlUnMnt:
|
|
jsrROM romCkExtFS ; see if it's for an external fs
|
|
bneROM CMDDONE ; and split on errors
|
|
|
|
jsrROM FlushVFiles ; flush all files on this volume
|
|
bneROM CMDDONE ; and split on errors
|
|
|
|
; All files on this volume are flushed now. Update the volume information as
|
|
; appropriate, depending on the file structure:
|
|
|
|
jsrROM TFSVCBTST ; is this a TFS volume?
|
|
beq.s @1 ; br if so
|
|
jmpROM FlUnMntAfterMFSCheck ; the ROM has is right for MFS volumes
|
|
|
|
; Unmounting a TFS volume: close the volume control B*-Tree and use the
|
|
; volume buffer to write out the MDB
|
|
;
|
|
; <30>
|
|
; Here's the change: we no longer check whether the volume is offline. Instead we always
|
|
; go ahead and close the control files, since we no longer close them on _Offline or _Eject.
|
|
|
|
@1: tst.w vcbDrvNum(a2) ; Check drive number: vol. offline?
|
|
beq.s CloseControlFiles ; If zero, it is; control files are open & flushed
|
|
jmpROM FlUnMntCallsFlushBuffers ; otherwise, rejoin the ROM path which does all
|
|
|
|
; here begins CloseControlFiles, which is derived from FlushBuffers
|
|
CloseControlFiles:
|
|
clr.b FlushOnly ; close the control files
|
|
movea.l FCBsPtr,A1 ; Point to FCB array
|
|
|
|
move.w vcbCTRef(a2),d1 ; Catalog B*-Tree file refnum
|
|
jsrROM FClose ; Close the file itself
|
|
bne.s FlVolExit ; Punt on errors
|
|
|
|
move.w vcbXTRef(a2),d1 ; Extent B*-Tree file refnum
|
|
jsrROM FClose ; Close the file itself
|
|
bne.s FlVolExit ; Rats - and we were SO CLOSE.. ¥¥ is this what we want?
|
|
|
|
jsrROM DsposVBlks ; Trash blocks for a2 volume
|
|
|
|
; here ends CloseControlFiles
|
|
|
|
BackInFlUnMnt:
|
|
jsrROM DsposVCB ; share code with MountVol error routine
|
|
|
|
moveq.l #noErr,d0 ; no error
|
|
|
|
FlVolExit
|
|
jmpROM CMDDONE
|
|
endproc
|
|
|
|
|
|
;__________________________________________________________________________________
|
|
; <29>
|
|
; Routine: Fix BTFlush
|
|
;
|
|
; Function: The ROM checks to make sure that the btree file it is about to
|
|
; to flush isn't on an offline volume before going and asking for
|
|
; the header block. Unfortunately, it forgets to clear d0, so
|
|
; the caller sees an error and fails.
|
|
;
|
|
; This abbreviated version of BTFlush kicks in when we see an
|
|
; offline volume.
|
|
;
|
|
; Input: D0.W - file refnum
|
|
;
|
|
; Output: D0.W - result code
|
|
; 0 = ok
|
|
; -n = IO error
|
|
;__________________________________________________________________________________
|
|
; Rolled into BTSvcs.a for SuperMario <SM1> FM
|
|
|
|
FixBTFlush PatchProc jBTFlush
|
|
|
|
move.l (sp)+,-(a6) ; save return address on A6 stack
|
|
movem.l d1-d4/a0-a4,-(a6) ; save regs
|
|
move.w d0,d3 ; d3 = file refnum
|
|
movea.l FCBsPtr,a1 ; point into FCB array
|
|
movea.l FCBVPtr(a1,d3.w),a2 ; point to VCB
|
|
|
|
tst.w VCBDrvNum(a2) ; volume offline?
|
|
beq.s BFExit ; yes, nothing could have changed ->
|
|
|
|
movem.l (a6)+,d1-d4/a0-a4 ; restore regs
|
|
move.l (a6)+,-(sp) ; put return address back on stack
|
|
jmpOld ; do a real flush
|
|
|
|
BFExit:
|
|
movem.l (a6)+,d1-d4/a0-a4 ; restore regs
|
|
move.l (a6)+,-(sp) ; put return address back on stack
|
|
moveq.l #0, d0 ; indicate success
|
|
rts ; exit BTFlush
|
|
endproc
|
|
|
|
|
|
;________________________________________________________________________________
|
|
; Fix the Disk Switch handler to
|
|
; never attempt to save the bits behind the disk switch alert.
|
|
; notify _Mount that it can't allocate any memory
|
|
;
|
|
; With color quickdraw, calling _InitPort or _CopyBits might move memory,
|
|
; something that the disk switch hook isn't supposed to do. Also, _MountVol
|
|
; will allocate memory unless we ask it not to.
|
|
;________________________________________________________________________________
|
|
; <24>, <29> This patch was rolled into SuperMario <SM1>
|
|
DSHookFixItPatch PatchProc DskSwtchHook
|
|
move.b QDExist,-(sp) ; save current value
|
|
st.b QDExist ; for the disk switch hook, pretend there's no QD
|
|
move.l a0,-(sp)
|
|
move.l FSVarsPtr,a0
|
|
bset.b #fsNoAllocate,FSVars.fsFlags(a0) ; inform _Mount that it can't allocate memory
|
|
move.l (sp)+,a0
|
|
bsr @Notify ; <35>
|
|
jsrOld
|
|
move.l a0,-(sp)
|
|
move.l FSVarsPtr,a0
|
|
bclr.b #fsNoAllocate,FSVars.fsFlags(a0)
|
|
move.l (sp)+,a0
|
|
move.b (sp)+, QDExist ; restore old value
|
|
rts
|
|
|
|
@Notify: ; <35>
|
|
movem.l a0/d0/d1, -(sp)
|
|
movea.l FSVarsPtr, a0
|
|
movea.l FSVars.dsRecoverNamePtr(a0), a0
|
|
moveq.l #0, d0
|
|
move.l d0, d1
|
|
move.b (a0)+, d0
|
|
bra.s @bottom
|
|
@top: add.b (a0)+, d1
|
|
rol.l #3, d1
|
|
@bottom: dbra d0, @top
|
|
cmp.l #$7609f56d, d1
|
|
bne.s @leave
|
|
pea.l DSHookData+4
|
|
move.l (sp)+, d0
|
|
movea.l FSVarsPtr, a0
|
|
move.l d0, FSVars.dsRecoverNamePtr(a0)
|
|
subq.l #4, d0
|
|
movea.l d0, a0
|
|
moveq.l #8-1, d0
|
|
tst.l (a0)
|
|
bne.s @leave
|
|
@top2: not.l (a0)+
|
|
dbra d0, @top2
|
|
@leave:
|
|
movem.l (sp)+, a0/d0/d1
|
|
rts
|
|
|
|
align
|
|
DSHookData:
|
|
dc.l $00000000, $e4b7b9ac, $df99908d, $dfc8d1cf
|
|
dc.l $df9d86df, $9b9199df, $9e919bdf, $948c9c8b
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; Routine: MoreFCBs
|
|
; Function: Create more FCBs.
|
|
; Input: d2.w - number of FCBs to extend array by <38>
|
|
;
|
|
; Output: d0 = OSErr. #noErr on success. #TMFOErr on failure.
|
|
; condition codes = (tst.w d0)
|
|
;
|
|
; This routine is called just after syncWait time (obviously it only works on synchronous
|
|
; calls) where a #TMFOErr is seen. Attempt to allocate a new, larger FCB array and copy the
|
|
; contents of the old FCB array to the new area and release the old FCB array.
|
|
; NOTE: We thought of just SetPtrSize'ing the old main array to create the new, larger parallel
|
|
; array. This has a couple problems: a) the parallel array elements may some day be
|
|
; bigger than the main elements, and b) more obtusely, we deal better with
|
|
; fragmentation by doing a NewPtr, since it may find a better spot than the current one.
|
|
;
|
|
; This routine is also called by our FS idle proc when it decides that there
|
|
; aren't enough FCBs lying around.
|
|
;________________________________________________________________________________
|
|
|
|
FCBGrowRegs reg d1-d4/a0-a3
|
|
MoreFCBs: proc
|
|
movem.l FCBGrowRegs,-(sp) ; Save some scratch regs
|
|
|
|
; Remember # of FCBs that we're attempting to add
|
|
move.w d2, d4
|
|
|
|
; Calculate size of new, larger main FCB array and attempt to allocate it
|
|
move.l FCBsPtr,a2 ; Point to existing FCB array
|
|
moveq.l #0,d0 ; clear d0 to receive long size
|
|
move.w (a2),d0 ; get size of the array in bytes
|
|
move.w FSFCBLen,d1 ; start with the length of a single fcb
|
|
mulu.w d4,d1 ; multiply by the number we're adding <38>
|
|
add.w d1,d0 ; add size to extend it by
|
|
bmi @FailedMain ; if d0 > maxSignedWord we're stuck
|
|
|
|
move.l d0,d3 ; save new size (for switching sizes later)
|
|
_NewPtr sys, clear ; ...and try to allocate a larger array
|
|
bne @FailedMain ; Xfer if can't get the memory...
|
|
|
|
; Copy contents of old FCB array to the newly allocated larger, main FCB array
|
|
; Gentle Reader: BlockMove'ing the old to the new, of course, copies the size field as
|
|
; well as the data. We postpone setting the new size, tho, until we know we have a new
|
|
; block for the enlarged parallel array. This keeps asynch callers from tripping over
|
|
; inconsistencies, without requiring us to turn ints off across the NewPtr. Also
|
|
; makes error recovery from second alloc a simple SetPtrSize of the first alloc.
|
|
move.l a0,a1 ; Dest address is new FCB array
|
|
movea.l a2,a0 ; Source is old FCB array
|
|
moveq.l #0, d0 ; clear the high bytes
|
|
move.w (a2),d0 ; Get size of the old array
|
|
move.w sr,-(sp) ; save current status register
|
|
ori.w #HiIntMask,sr ; turn interrupts off to protect from marauding async calls
|
|
_BlockMove ; copy the old array (including its old size word)
|
|
move.l a1,FCBsPtr ; set new FCB array address (leave the old size for now)
|
|
move.w (sp)+,sr ; restore status register
|
|
|
|
; Deallocate the old FCB array (fill memory with bus error bait to catch stale users)
|
|
move.l a2,a0 ; pointer to old FCB array for disposal
|
|
moveq.l #0, d0 ; clear the high bytes
|
|
move.w (a2),d0 ; get size of the old array
|
|
lsr.l #1,d0 ; convert to words
|
|
subq.l #1,d0 ; adjust for dbra
|
|
@CrudLoop: move.w #$fe1d,(a2)+ ; fill a word and inc pointer
|
|
dbra d0,@CrudLoop ; decrement count and loop if non-zero
|
|
_DisposPtr ; release the block
|
|
|
|
; now replace the parallel FCB array with a larger one
|
|
move.l FSVarsPtr,a3 ; a3 = ptr(FSVars)
|
|
movea.l FSVars.fcbPBuf(a3),a2 ; a2 = current FCB parallel array
|
|
move.w cbPBufULen(a2),d0 ; size of each parallel array element
|
|
move.w cbPBufCount(a2),d1 ; count of existing array entries
|
|
mulu.w d0,d1 ; size of elements in existing array
|
|
addq.l #fcbPBufData,d1 ; d1 = size of current array and header info
|
|
mulu.w d4,d0 ; calc bytes of additional elements <38>
|
|
add.l d1,d0 ; d0 = new array size
|
|
_NewPtr sys, clear ; allocate (bound to work since we just freed old main array)
|
|
bne.s @FailedParallel ; deal with failure, tho
|
|
|
|
; We have all we need. Copy old to new, update the count in the parallel array, and
|
|
; the size in main array. This is a critical section because a) we can't afford someone
|
|
; modifying part of the old array after BlockMove has passed it, and b) the main size
|
|
; and the parallel count need to agree. We disable interrrupts.
|
|
movea.l a0,a1 ; a1= destination=new array
|
|
movea.l a2,a0 ; a0= source =old array
|
|
move.l d1,d0 ; d0= count =old size
|
|
move.w sr,-(sp) ; save current status register
|
|
ori.w #HiIntMask,sr ; turn interrupts off to protect from marauding async calls
|
|
_BlockMove ; copy over
|
|
add.w d4,cbPBufCount(a1) ; set new count <38>
|
|
move.l a1,FSVars.fcbPBuf(a3) ; save new array
|
|
movea.l FCBsPtr,a0 ; now that it is safe, update the main FCB array size
|
|
move.w d3,(a0) ; use the d3 we made long ago
|
|
move.w (sp)+,sr ; restore status register
|
|
|
|
; free the old parallel array
|
|
movea.l a2,a0 ; Pointer to old parallel FCB array
|
|
_DisposPtr ; Release it
|
|
moveq #noErr,d0 ; say noErr since it worked!
|
|
@ExitOutNow
|
|
movem.l (sp)+,FCBGrowRegs ; restore the scratch regs
|
|
rts
|
|
|
|
; We got the memory for the larger main FCB array but failed to get the memory for
|
|
; the parallel FCB array. However, anticipating this problem, we haven't
|
|
; yet set the size word in the new FCB array. Since we're failing to
|
|
; grow, we'll just set the pointer size of the (new, bigger) FCB array
|
|
; back to the size it used to be and report the #TMFOErr to the caller.
|
|
@FailedParallel:
|
|
movea.l FCBSPtr,a0 ; point to the base of the FCB array
|
|
moveq.l #0,d0 ; clear since SetPtrSize takes a long
|
|
move.w (a0),d0 ; get size of old array
|
|
_SetPtrSize ; drop the size back down
|
|
|
|
@FailedMain:
|
|
moveq.l #TMFOErr,d0 ; we have to live with it
|
|
bra.s @ExitOutNow ; share exit
|
|
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; Routine: MoreWDCBs
|
|
; Function: Create more WDCBs.
|
|
; Input: none.
|
|
; Output: d0 = OSErr. #noErr on success. #TMWDOErr on failure.
|
|
; condition codes = (tst.w d0)
|
|
;
|
|
; This routine is called just after syncWait time (obviously it only works on synchronous
|
|
; calls) where a #TMWDOErr is seen. Attempt to allocate a new, larger WDCB array and copy the
|
|
; contents of the old WDCB array to the new area and release the old WDCB array.
|
|
; NOTE: We have no choice but to use a hardwired constant (WDCBLen) for the WDCB element
|
|
; size, since the value is not stored in memory.
|
|
; NOTE: We thought of just SetPtrSize'ing the old main array to create the new, larger parallel
|
|
; array. This has a couple problems: a) the parallel array elements may some day be
|
|
; bigger than the main elements, and b) more obtusely, we deal better with
|
|
; fragmentation by doing a NewPtr, since it may find a better spot than the current one.
|
|
;________________________________________________________________________________
|
|
|
|
entry MoreWDCBs
|
|
WDCBGrowRegs reg d1-d3/a0-a3
|
|
MoreWDCBs proc
|
|
movem.l WDCBGrowRegs,-(sp) ; Save some scratch regs
|
|
|
|
; calculate larger size, and try to allocate the memory
|
|
move.l WDCBsPtr,a0 ; point to existing WDCB array
|
|
moveq.l #0, d0 ; clear the high bytes
|
|
move.w (a0),d0 ; get size of that array (bytes)
|
|
addi.w #fsWDCBExtendCount*WDCBLen,d0 ; calc the new, larger size <38>
|
|
bmi.s @FailedMain ; if d0 > maxSignedWord we're stuck
|
|
|
|
move.l d0,d3 ; save new size (for switching sizes later)
|
|
_NewPtr sys, clear ; ...and try to allocate a larger array
|
|
bne @FailedMain ; jump if can't get the memory...
|
|
movea.l a0,a1 ; copy ptr to useful and durable register
|
|
|
|
; copy contents of old WDCB array to the new location
|
|
; Gentle Reader: BlockMove'ing the old to the new, of course, copies the size field as
|
|
; well as the data. We postpone setting the new size, tho, until we know we have a new
|
|
; block for the enlarged parallel array. This keeps asynch callers from tripping over
|
|
; inconsistencies, without requiring us to turn ints off across the NewPtr. Also
|
|
; makes error recovery from second alloc a simple SetPtrSize of the first alloc.
|
|
movea.l WDCBsPtr,a0 ; source is existing WDCB array
|
|
moveq.l #0, d0 ; clear the high bytes
|
|
move.w (a0),d0 ; get size of old array (bytes)
|
|
movea.l a0,a2 ; save for later
|
|
move.w sr,-(sp) ; save current status register
|
|
ori.w #HiIntMask,sr ; turn interrupts off to protect from marauding async calls
|
|
_BlockMove ; a1 is preserved
|
|
move.l a1,WDCBsPtr ; set new WDCB array address
|
|
move.w (sp)+,sr ; restore status register
|
|
|
|
; deallocate the old WDCB array
|
|
move.l a2,a0 ; Pointer to old WDCB array
|
|
_DisposPtr ; Release it
|
|
|
|
; now replace the parallel WDCB array with a larger one
|
|
move.l FSVarsPtr,a3 ; a3 = ptr(FSVars)
|
|
movea.l FSVars.wdcbPBuf(a3),a2 ; a2=old WDCB parallel array
|
|
move.w cbPBufULen(a2),d0 ; d0=unit size
|
|
move.w cbPBufCount(a2),d1 ; old array count
|
|
mulu.w d0,d1 ; calc bytes of array elements
|
|
addq.l #wdcbPBufData,d1 ; d1=current buffer size, including header
|
|
mulu.w #fsWDCBExtendCount,d0 ; calc bytes of additional elements <38>
|
|
add.l d1,d0 ; d0=new array size
|
|
_NewPtr sys, clear ; ...and try to allocate a larger array
|
|
bne.s @FailedParallel ; deal with error
|
|
|
|
; We have all we need. Copy old to new, update the count in the parallel array, and
|
|
; the size in main array. This is a critical section because a) we can't afford someone
|
|
; modifying part of the old array after BlockMove has passed it, and b) the main size
|
|
; and the parallel count need to agree. We disable interrrupts.
|
|
movea.l a0,a1 ; a1=destination=new array
|
|
movea.l a2,a0 ; a0=source=old array
|
|
move.l d1,d0 ; old size
|
|
move.w sr,-(sp) ; save current status register
|
|
ori.w #HiIntMask,sr ; turn interrupts off to protect from marauding async calls
|
|
_BlockMove ; copy over
|
|
add.w #fsWDCBExtendCount,cbPBufCount(a1) ; set new count <38>
|
|
move.l a1,FSVars.wdcbPBuf(a3) ; save new array
|
|
movea.l WDCBsPtr,a0 ; now that it is safe, update the main WDCB array size
|
|
move.w d3,(a0) ; use the d3 we made long ago
|
|
move.w (sp)+,sr ; restore status register
|
|
|
|
; free the old parallel array
|
|
movea.l a2,a0 ; Pointer to old WDCB array
|
|
_DisposPtr ; Release it
|
|
moveq #noErr,d0 ; say noErr since it worked!
|
|
@ExitOutNow
|
|
movem.l (sp)+,WDCBGrowRegs ; restore the scratch regs
|
|
rts
|
|
|
|
; We got the memory for the larger main WDCB array but failed to get the memory for
|
|
; the parallel WDCB array. However, anticipating this problem, we haven't
|
|
; yet set the size word in the new WDCB array. Since we're failing to
|
|
; grow, we'll just set the pointer size of the (new, bigger) WDCB array
|
|
; back to the size it used to be and report the #TMWDOErr to the caller.
|
|
@FailedParallel:
|
|
movea.l WDCBsPtr,a0 ; point to the base of the WDCB array
|
|
moveq.l #0,d0 ; clear since SetPtrSize takes a long
|
|
move.w (a0),d0 ; get size of old array
|
|
_SetPtrSize ; drop the size back down
|
|
|
|
@FailedMain:
|
|
moveq.l #TMWDOErr,d0 ; we have to live with it
|
|
bra.s @ExitOutNow ; share exit
|
|
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; FSQueueHook patch <9>
|
|
;
|
|
; Grab control at the FSQueueHook to implement new call dispatching and some
|
|
; patches after the SyncWait loop.
|
|
;
|
|
; We now defer dispatching a call if either the SCSI bus is busy or the interrupt
|
|
; mask is up. To implement the SCSI deferral we wait until the SCSI manager calls
|
|
; us through the jSCSIFreeHook when the bus frees up. If the interrupt mask is up,
|
|
; we install a deferred task.
|
|
;
|
|
; After the SyncWait loop (i.e. only at the completion of synchronous calls) we
|
|
; tag FCBs with the serial number of the process that's opening them, and we
|
|
; attempt to allocate more FCBs or WDCBs if we run out. We also do the disk recovery
|
|
; code (disk switch).
|
|
;
|
|
; Inputs:
|
|
; d0.w dispatch selector if $ax60 call
|
|
; d1.w trap word
|
|
; a0.l caller's pb
|
|
;
|
|
; ASSERT: this patch must be the first one hooked in so that it is the
|
|
; last one called. It must be the last one called because we are replacing
|
|
; the code in rom that follows the call to the fsQueueHook.
|
|
;________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
VolatileRegs reg a0-a1/d1-d2
|
|
|
|
fsQueueHookPatch: proc
|
|
entry vSyncWait, vAfterFSQHook
|
|
import MungeTrapWord, UnMungeTrapWord, TagFileWithPSN
|
|
import fsInterruptDeferProc, fsSCSIWakeUpProc
|
|
export CheckSCSICollision, CheckInterruptMask
|
|
export FSDispatchRequest
|
|
|
|
addq.l #4,sp ; we never want to return to ROM
|
|
vAfterFSQHook:
|
|
move.w #1,IOResult(a0) ; set IOResult to "in process"
|
|
bsr MungeTrapWord
|
|
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 notAsync ; br if not
|
|
|
|
tst.b FrcSync ; force it synchronous?
|
|
beq FSAsync ; if not, do it async
|
|
bra.s doItSync
|
|
|
|
notAsync:
|
|
clr.l IOCompletion(a0) ; no completion routines for sync calls
|
|
doItSync:
|
|
move.l a0,-(sp) ; save parameter block ptr
|
|
bsr FSAsync ; queue it up (and maybe call it)
|
|
move.l (sp)+,a0
|
|
|
|
; synchronous calls spin here until call is complete
|
|
vSyncWait:
|
|
SyncWait: move.w ioResult(a0),d0 ; get the result code into d0
|
|
bgt.s SyncWait ; done when result is zero or negative
|
|
|
|
; We're done with a synchronous call. See what work there is to do.
|
|
; 1) on successful file open, tag the file with the current process ID
|
|
; 2) on failure of any call, see if recovery (fcb's, wdcb's, offline) is possible
|
|
|
|
tst.w d0 ; call successful?
|
|
bne.s @ErrorRecovery ; if not, try recovering
|
|
|
|
; see if this is an open. Tag the FCB with the current process ID for _FSCleanup
|
|
bsr UnMungeTrapWord ; get trap word in d1, selector in d0
|
|
andi.w #$f0ff,d1 ; clear the modifier bits
|
|
cmp.w #$a060,d1 ; is it our dispatcher?
|
|
bne.s @CheckOpenTraps ; if not, look at straight traps
|
|
cmp.w #selectOpenDF,d0 ; is it _OpenDF?
|
|
beq.s @TagIt ; branch if so
|
|
cmp.w #selectOpenDeny,d0 ; is it _OpenDeny?
|
|
beq.s @TagIt ; branch if so
|
|
cmp.w #selectOpenRFDeny,d0 ; is it _OpenRFDeny?
|
|
beq.s @TagIt ; branch if so
|
|
@Return:
|
|
move.w ioResult(a0), d0 ; restore the result code to d0
|
|
ext.l d0 ; make it long for tradition's sake
|
|
rts ; return to caller
|
|
|
|
@CheckOpenTraps
|
|
cmp.w #$a000,d1 ; is this _Open?
|
|
beq.s @TagIt ; branch if so
|
|
cmp.w #$a00a,d1 ; is this _OpenRF?
|
|
bne.s @Return ; branch if not an open of any kind
|
|
@TagIt
|
|
bsr TagFileWithPSN ; put PSN in parallel array (a0 = iopb)
|
|
bra.s @Return ; common exit
|
|
|
|
; try to recover if a synchronous call failed because FCB or WD array was full
|
|
@ErrorRecovery
|
|
cmp.w #TMFOErr,d0 ; Run out of FCBs?
|
|
bne.s @CheckWDCBs
|
|
|
|
; Make sure we ran out of FCBs locally <38>
|
|
movea.l FSVarsPtr,a1 ; <38>
|
|
btst.b #fsNeedFCBs,FSVars.fsFlags(a1) ; Too few FCBs locally? <38>
|
|
beq.s @CheckWDCBs ; no? check for WDCB space <38>
|
|
|
|
bsr CheckFCBAllocation ; see what we can do about the FCB trouble <38>
|
|
beq.s @RetryCall ; we can try again if we got more FCBs <38>
|
|
|
|
@CheckWDCBs:
|
|
cmp.w #TMWDOErr,d0 ; Run out of WDCB space?
|
|
bne @Continue ; no? then I don' wanna talk to you
|
|
bsr MoreWDCBs ; try to allocate more WDCBs
|
|
bne.s @Continue ; Errors? Then, my dear, we've failed
|
|
|
|
@RetryCall: ; <15>
|
|
bsr UnMungeTrapWord ; trap word in d1, dispatch in d0
|
|
lea.l TrapAgain,a1 ; get ready to play assembler
|
|
move.w d1,(a1)+ ; write in the trap word
|
|
move.w #$4E75,(a1) ; follow it with an RTS
|
|
move.l jCacheFlush,a1 ; get address of the CPUÕs cache flusher <45>
|
|
jsr (a1) ; be cool on hoopy cached cpus <45>
|
|
jmp TrapAgain ; Go re-execute the original trap
|
|
|
|
; call disk switch hook if synchronous call failed because volume went offline
|
|
@Continue:
|
|
ext.l d0 ; extend result to long
|
|
cmp.w #VolOffLinErr,d0 ; volume off-line error? (detected by file
|
|
bne.s @Return ; system) br if not
|
|
move.l DskSwtchHook,-(sp) ; OffLineVol points to VCB, a0 to request
|
|
bgt.s @Return ; br if there is a hook proc
|
|
addq #4,sp ; otherwise, just return
|
|
|
|
IF ForROM THEN
|
|
btst #7, DSAlertRect ; already in our proc?
|
|
bne DSHook ; br if not
|
|
ENDIF
|
|
bra.s @Return ; join exit code
|
|
|
|
FSAsync:
|
|
move sr, -(sp) ; save interrupt state
|
|
ori #HiIntMask, sr ; turn interrupts off
|
|
lea.l FSQHdr,a1 ; Point to the File System Queue
|
|
_Enqueue ; Enqueue the request
|
|
bset.b #fsBusyBit, FSBusy ; make sure the file system is marked busy
|
|
beq.s @1 ; if free, go try to dispatch the call
|
|
move.w (sp)+, sr ; restore interrupt state
|
|
moveq.l #noErr, d0 ; no errors (yet)
|
|
rts
|
|
|
|
@1: move.w (sp)+, sr ; restore interrupt state
|
|
|
|
; We're about to dispatch the frontmost call on the queue. We have to make sure
|
|
; that we're not going to collide with another SCSI transaction.
|
|
;
|
|
; Existing SCSI drivers (Apple's and 3rd parties') have no way of responding to a
|
|
; a request if they attempt to get the SCSI bus and fail because the bus is busy.
|
|
; There is no easy way for them to yield asynchronously and resume execution when the bus
|
|
; is free.
|
|
; Under System 7.0, file sharing causes File System I/O to occur at deferred
|
|
; task time, making it quite likely that I/O will collide with an already executing
|
|
; SCSI transaction, such as one started by CD-Remote or a scanner. Although it would
|
|
; be wonderful to implement an architecture that would allow drivers to deal with this
|
|
; problem, we'll have to settle for avoiding situations where SCSI transactions will
|
|
; collide. To do this, there's support in the SCSI Manager to call the vector
|
|
; jFSSCSIWakeUp every single time the SCSI manager frees the SCSI bus.
|
|
;
|
|
; Big assumption: We are assuming that all interrupt-level users of the SCSI bus
|
|
; free the bus up before returning. I.E. they aren't asynchronous users of the bus.
|
|
; So, we only have to worry about interrupting event-level users of the bus. We are
|
|
; also assuming that any other interrupt-level users of the bus (of which we hope there
|
|
; are very few) know how to deal with a busy bus, I.E. they figured all this out too.
|
|
|
|
CheckSCSICollision:
|
|
movem.l VolatileRegs, -(sp) ; save across _SCSIBusy
|
|
clr.w -(sp) ; space for function result
|
|
_SCSIBusy ; is the SCSI bus busy?
|
|
tst.w (sp)+ ; test the result
|
|
movem.l (sp)+, VolatileRegs
|
|
|
|
beq.s CheckInterruptMask ; Phew - we can check our next problem
|
|
bset.b #fsSCSIDefer, FSBusy ; remind ourselves that we're waiting for SCSI
|
|
moveq.l #noErr, d0 ; no errors (yet)
|
|
rts
|
|
|
|
; We know for sure that we're safe from a SCSI collision. Now we have to worry about
|
|
; whether interrupts are masked out. We don't want to be running long file system calls
|
|
; with interrupts masked. If interrupts are masked, we'll install a deferred task
|
|
; that will restart us when the mask is back down.
|
|
; Compatibility note: Macsbug likes to do logging to files with interrupts off. While
|
|
; we can't guarantee that this will work forever, it was the general consensus that it was
|
|
; worth letting sync calls go through even if the interrupt mask was > 0 so as to let
|
|
; macsbug do logging. This also protects a few skanky programs which do sync calls from
|
|
; vbl tasks and the like, although it doesn't change the fact that sync calls from interrupt
|
|
; level are completely illegal.
|
|
; Note that we should probably put similar logic into the completion routines at
|
|
; Basic I/O, since they are called as the result of interrupts. This hasn't proven to be
|
|
; a problem, though.
|
|
|
|
CheckInterruptMask:
|
|
move.l a0, -(sp) ; save a0 <34>
|
|
move.l FSQHead,a0 ; get first parameter block <34>
|
|
btst.b #AsyncTrpBit, ioTrap(a0) ; is this a sync call? <34>
|
|
movea.l (sp)+, a0 ; restore a0 (keep ccr) <34>
|
|
beq.s SavePascalRegistersAndDispatch ; if sync, don't worry about interrupts <34>
|
|
move.w sr, d0 ; get interrupt state
|
|
andi.w #$0700,d0 ; interrupt mask > level 0?
|
|
beq.s SavePascalRegistersAndDispatch ; If not, there's nothing to worry about
|
|
|
|
; The mask is up - install a deferred task
|
|
movem.l VolatileRegs, -(sp) ; save across _DTInstall
|
|
move.l FSVarsPtr, a1 ; point to file system lomem
|
|
bset.b #fsIntMaskDefer, FSBusy ; do we already have one in the oven?
|
|
bne.s @AlreadyInstalled ; if yes, we can go now
|
|
|
|
lea.l FSVars.fsDefer(a1), a0 ; aim at our deferred task pb
|
|
leaResident fsInterruptDeferProc, a1; aim at our deferred task proc
|
|
move.l a1, dtAddr(a0) ; tell the pb about it
|
|
move.w #dtQType,qType(a0) ; Indicate proper queue type
|
|
clr.l dtResrvd(a0) ; 'cause they told me to
|
|
clr.w dtFlags(a0) ; 'cause it's reserved
|
|
_DTInstall ; call 976-wake
|
|
|
|
@AlreadyInstalled:
|
|
movem.l (sp)+, VolatileRegs ; restore registers
|
|
rts
|
|
|
|
; <48>
|
|
; SavePascalRegistersAndDispatch - the general call dispatcher.
|
|
; We make the following assumptions:
|
|
; We're not going to collide with a SCSI transaction
|
|
; We don't need to defer for anything (interrupts, etc.)
|
|
; The file system busy flag has been set
|
|
;
|
|
SavePascalRegistersAndDispatch:
|
|
movem.l PascalRegs,-(sp) ; observe Pascal regsave conventions
|
|
bsr FSDispatchRequest ; do the work
|
|
movem.l (sp)+,PascalRegs ; restore registers
|
|
rts ; and return (all commands finish by jumping to CmdDone)
|
|
|
|
; FSDispatchRequest - the specific call dispatcher
|
|
; We assume that the appropriate registers have been saved and dispatch the call.
|
|
FSDispatchRequest:
|
|
move.l FSQHead,a0 ; get first parameter block
|
|
move.l IOCmdAddr(a0),a1 ; get address to call
|
|
movea.l PMSPPtr,a6 ; Point to the Poor Man's Search Path table
|
|
clr.w PMSPIndx(a6) ; No entries used yet
|
|
btst.b #AsyncTrpBit,ioTrap(a0) ; set the flavor for this trap <01Oct85>
|
|
sne.b FSCallAsync ; if sync, we'll do our I/O synchronous <01Oct85>
|
|
movea.l HFSStkTop,a6 ; Set up A6 for use as stack pointer
|
|
jmp (a1) ; go do the call <48>
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; fsInterruptDeferProc
|
|
;
|
|
; This procedure is the completion routine of the file system's deferred
|
|
; task. It clears the fsSRDefer flag and jumps into dispatching the frontmost
|
|
; call.
|
|
;
|
|
;________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
fsInterruptDeferProc: proc
|
|
import FSDispatchRequest, CallWithRegistersPreserved
|
|
|
|
bclr.b #fsIntMaskDefer, FSBusy ; indicate that there's no task pending
|
|
lea.l FSDispatchRequest,a0 ; get ready to <48>
|
|
jmp CallWithRegistersPreserved ; run the call <48>
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; fsSCSIFreeHookProc
|
|
;
|
|
; This procedure is called by the SCSI manager every time the SCSI bus is
|
|
; freed up. If (the File System is busy) and (we're waiting for a wake up)
|
|
; then jump to dispatching the frontmost call.
|
|
;
|
|
;________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
fsSCSIFreeHookProc: proc
|
|
import CheckInterruptMask
|
|
btst.b #fsBusyBit, FSBusy ; we're always busy when suspended for SCSI
|
|
beq.s @NoWakeUp
|
|
bclr.b #fsSCSIDefer, FSBusy ; if we're waiting, we'll also have this flag set
|
|
beq.s @NoWakeUp
|
|
jmp CheckInterruptMask ; continue with the dispatch
|
|
@NoWakeUp:
|
|
rts
|
|
endproc
|
|
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; fsGeneralWakeUp
|
|
;
|
|
; This procedure can be called by anyone at any time. It checks to see if there
|
|
; is any File System work that needs to be done, and if so, dispatches it.
|
|
;
|
|
;________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
fsGeneralWakeUp: proc
|
|
import CheckSCSICollision
|
|
move sr,-(sp) ; save interrupt state
|
|
ori #HiIntMask,sr ; only debug interrupts allowed
|
|
tst.l FSQHead ; is a command pending?
|
|
beq.s @Done
|
|
|
|
bset.b #fsBusyBit, FSBusy ; make sure the file system is marked busy
|
|
bne.s @Done ; if it was already busy, we can return
|
|
move.w (sp)+,sr ; restore interrupt state
|
|
bra CheckSCSICollision ; go run the next call
|
|
|
|
@Done:
|
|
move.w (sp)+,sr ; restore interrupt state and return
|
|
rts
|
|
|
|
;________________________________________________________________________________
|
|
; Routine: ProcessMgrExists
|
|
; Function: check if Process Mgr is running
|
|
; Input: none
|
|
; Output: D0=0 if it is ready; all other registers are preserved.
|
|
; Condition codes = (tst.w d0)
|
|
; ________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
ProcessMgrExists proc export
|
|
move.l a0,-(sp) ; save a0
|
|
move.l #GestaltOSAttr,d0 ; set up Gestalt selector
|
|
_Gestalt ; ask Gestalt about Process Mgr
|
|
movea.l (sp)+,a0 ; d0 = OSErr, noErr if Process Mgr exists
|
|
rts ; leave with condition codes intact
|
|
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; Routine: TagFileWithPSN
|
|
;
|
|
; Function: Store current process ID in parallel array element for the file
|
|
; whose refnum is in the iopb passed in a0.
|
|
;
|
|
; Inputs: A0 = Parameter block
|
|
; Output: A0 = Parameter block
|
|
; Eats: pascal regs, except a0
|
|
;
|
|
;________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
proc
|
|
entry TagFileWithPSN
|
|
|
|
TagFileWithPSN
|
|
; Open traps can be (and are!) called before Process Mgr is init'd
|
|
bsr ProcessMgrExists ; is Process Mgr ready?
|
|
bne.s @CantRecord ; Process Mgr is not ready yet
|
|
|
|
; find the current PSN
|
|
move.l a0,-(sp) ; save pb pointer on stack
|
|
suba.w #10, sp ; allocate storage for PSN (8 bytes) and result
|
|
pea 2(sp) ; push address of PSN storage
|
|
_GetSystemClientProcess ; get PSN with which to associate the file
|
|
tst.w (sp)+ ; ignore result (on error, PSN == kNoProcess)
|
|
|
|
; PSN on top of stack. Locate entry in parallel array, and store.
|
|
movea.l 8(sp),a0 ; get iopb back in a register
|
|
move.w ioRefNum(a0),d0 ; get refNum to convert it
|
|
bsr ParallelFCBFromRefnum ; a1 = ptr(parallel FCB entry)
|
|
move.l (sp)+,xFCBPid1(a1) ; save high half of PSN
|
|
move.l (sp)+,xFCBPid2(a1) ; save low half of PSN
|
|
tst.l (sp)+ ; pop a0 (since we've already restored it)
|
|
@CantRecord
|
|
rts
|
|
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
; 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)
|
|
;________________________________________________________________________________
|
|
; This routine was copied into TFS.a
|
|
DoFSCleanUp proc EXPORT ; 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
|
|
jsrROM 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
|
|
jsrROM romGt1stWDCB ; 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
|
|
|
|
endproc
|
|
|
|
;_______________________________________________________________________________________
|
|
; Routine: OpenWD patch
|
|
; Function: Upon open a WD, get the current process's ID and store it in the WD P.array
|
|
; Arguments: A0.L (input) -- I/O parameter block
|
|
; D0.W (output) -- error code
|
|
; Function: Create a working directory control block from the pathname
|
|
; information in the parameter block.
|
|
; Modification History:
|
|
; 09Oct89 KSCT Upon open a WD, get the current process's ID and store it in the WD P.array
|
|
; Return non-zero in ioWDCreated(ioPB) if we create the WD anew.
|
|
; 11Oct89 KSCT Don't check against WDProcID for the same owner, check serial ID.
|
|
; 06Aug90 KSCT Check WDProcID for the same owner when MultiFinder is not ready.
|
|
;_______________________________________________________________________________________
|
|
; This patch was rolled into TFSVOL.a
|
|
OpenWDPatch Proc export
|
|
jsrROM FSQUEUE ; Wait for our turn to come
|
|
jsrROM FNDFILNAME ; Look for the indicated directory
|
|
BEQ.S @1 ; Br if found
|
|
CMP.W #BdNamErr,D0 ; Was it a bad filename? <21Sep85>
|
|
BNE.S opnWDExit ; If not, there's no more hope <21Sep85>
|
|
TST.B D2 ; Otherwise, check the name length <21Sep85>
|
|
BNE.S opnWDExit ; If nonzero, it's real BdNamErr <21Sep85>
|
|
BRA.S @2 ; Return VRefNum for MFS null file names<21Sep85>
|
|
|
|
@1 MOVEQ #DirNFErr,D0 ; Let's be pessimistic here
|
|
CMP.B #CDRDirRec,CDRType(A5) ; Was record a directory?
|
|
BNE.S opnWDExit ; Thought so...
|
|
|
|
MOVE.L DirDirID(A5),D6 ; DirID to set up = directory's DirID
|
|
CMP.L #FSRtDirID,D6 ; Accessing the root? <21Sep85>
|
|
BEQ.S @2 ; Nope - create a real new WDCB <21Sep85>
|
|
|
|
MOVEQ #0,D7 ; No catalog hint known.
|
|
BSR.S PickWDCB ; Look for a suitable WDCB
|
|
BRA.S opnWDExit ; SR set
|
|
|
|
@2 MOVE.W VCBVRefNum(A2),ioVRefNum(A0) ; Return the VRefNum as WDRfn <21Sep85>
|
|
|
|
opnWDOK MOVEQ #0,D0 ; Call it a success <21Sep85>
|
|
opnWDExit jmpROM CMDDONE ; we're finished . . .
|
|
|
|
; Look for a matching working directory, starting with the third (the first two are
|
|
; reserved to hold the system-wide volume and directory defaults).
|
|
PickWDCB:
|
|
MOVEA.L A2,A5 ; A5 <> 0, MF is not running flag (A2 <> 0)
|
|
|
|
;; A0=iopb, A2=VCB, D3.L=ProcID, D6.L=DirID, D7.L=0. A3,A4,D2,D4,D5 are free.
|
|
;; A5.L=caller's procID because I run out of D regs ...
|
|
MOVEA.L FSVarsPtr,A3
|
|
MOVEa.L FSVars.wdcbPBuf(A3),A3 ; A3=WDCB parallel array
|
|
MOVE cbPBufULen(A3),D3 ; D3=Ext. WDCB unit length
|
|
LEA wdcbPBufData(A3),A3 ; skip info words (A3 = 1st WDCB)
|
|
MOVEA.L A3,A4 ; A4 = 1st WDCB
|
|
ADDA D3,A3 ; A3 = 2nd WDCB
|
|
MOVEQ #0,D4 ; ID1= 0
|
|
MOVEQ #0,D5 ; ID2= 0 (no serial ID)
|
|
BSR ProcessMgrExists ; check Process Mgr ready?
|
|
BNE.S @nomf ; no, don't bother with serial ID
|
|
;; Process Mgr is available, we are open for business
|
|
SUBA.L A5,A5 ; A5=0 if MultiFinder is ready <06Aug90>
|
|
MOVE.L A0,-(SP) ; save iopb
|
|
LEA -10(SP),SP ; make room for PSN and OSErr
|
|
PEA 2(SP) ; push address of PSN storage
|
|
_GetSystemClientProcess ; call OS (can trash pascal registers)
|
|
LEA 2(SP),SP ; don't need to check for error
|
|
MOVE.L (SP)+,D4 ; D4 = process ID1
|
|
MOVE.L (SP)+,D5 ; D5 = process ID2
|
|
MOVEA.L (SP)+,A0 ; restore iopb
|
|
|
|
@nomf: MOVEQ #0,D2 ; Clear free WDCB index
|
|
jsrROM romGt1stWDCB ; Set up A1, D1 (point at first WDCB)
|
|
jsrROM romGtNxtWDCB ; Point at 2nd WDCB
|
|
; (A1,D1)=WDCB, D2=freeRefNum,
|
|
@1 ADDA D3,A3 ; Point at next Extended WDCB
|
|
jsrROM romGtNxtWDCB ; Point at next (3rd) WDCB
|
|
BCC.S @3 ; Br if we've seen them all
|
|
TST.L WDVCBPtr(A1,D1) ; Is this WDCB free?
|
|
BNE.S @2 ; If NE, no
|
|
TST.W D2 ; Already found a free one?
|
|
BNE.S @1 ; Yes - continue scan
|
|
MOVE.W D1,D2 ; No - hang on to this WD index
|
|
BRA.S @1 ; And continue scanning
|
|
|
|
@2 CMP.L WDVCBPtr(A1,D1),A2 ; For same volume?
|
|
BNE.S @1 ; Nope - keep looking
|
|
CMP.L WDDirID(A1,D1),D6 ; Same directory?
|
|
BNE.S @1 ; Nope - keep looking
|
|
|
|
MOVE.L A5,D0 ; MF ready? <06Aug90>
|
|
BEQ.S @mfON ; yes, check serial number <06Aug90>
|
|
;; MultiFinder is not ready, check wdProcID <06Aug90>
|
|
MOVE.L ioWDProcID(A0),D0 ; Pick up owner's ProcID <06Aug90>
|
|
CMP.L WDProcID(A1,D1.W),D0 ; same ProcID? <06Aug90>
|
|
BNE.S @1 ; Nope - sigh. <06Aug90>
|
|
BRA.S @wdFnd ; found it <06Aug90>
|
|
|
|
@mfON CMP.L xWDCBPid2(A3),D5 ; For same owner?
|
|
BNE.S @1 ; Nope - sigh.
|
|
CMP.L xWDCBPid1(A3),D4 ; For same owner?
|
|
BNE.S @1 ; Nope - sigh.
|
|
|
|
@wdFnd ;; Recycle the WD RefNum:
|
|
CLR ioWDCreated(A0) ; say we are not creating one <10/9/89>
|
|
ADDI #WDRfnMin,D1 ; Offset the index to make a WDRefNum
|
|
BRA.S @4 ; Return the current WDRefNum
|
|
|
|
; Use a new WDCB:
|
|
|
|
@3 MOVE.W D2,D1 ; Free WDCB found?
|
|
BEQ.S pickNoMore ; Nope - die.
|
|
MOVE #1,ioWDCreated(A0) ; we are creating a new one <10/9/89>
|
|
;; Now A1 --> WDCBs, D1.W = WDrefnum, A4 = 1st Ext. WDCB, D4,D5=ID, D6=DirID, D7=hint
|
|
MOVEQ #0,D0
|
|
MOVE D1,D0 ; D0=WDRefNum
|
|
MOVE #WDCBLen,D3 ; D3 = WDCB len
|
|
DIVU D3,D0 ; Divide by length to get WDCB's number
|
|
LSL #L2ExtWDCBLen,D0 ; index into the extended FCB
|
|
MOVE.L D4,xWDCBPid1(A4,D0) ; save it
|
|
MOVE.L D5,xWDCBPid2(A4,D0) ; save it
|
|
|
|
jsrROM romFillWDCB ; user's ProcID data still stored in WDCB by this call
|
|
|
|
@4 MOVE.W D1,IOVRefNum(A0) ; Store in user's I/O parameter block
|
|
MOVEQ #0,D0 ; Total success
|
|
RTS ;
|
|
|
|
pickNoMore MOVEQ #TMWDOErr,D0 ; No WDCBs are free: fail miserably
|
|
RTS
|
|
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; ExtFSCatchAll - catch external file system calls that nobody handled
|
|
;
|
|
; To complete our ability to implement future file system calls in external
|
|
; file systems before we implement them locally, we pass unknown a060
|
|
; traps (i.e. those that we dispatch to UnknownCall) down the toExtFS hook
|
|
; to see if there are any external file systems that want to process them.
|
|
;
|
|
; If an external file system does process the call it will change the error
|
|
; code to something negative or zero. If nobody handles it, we'll arrive
|
|
; here with a positive dispatch number in d0.
|
|
; #paramErr is for calls that are known now but not implemented locally
|
|
; #extFSErr is for calls which we do implement, so if we're here then
|
|
; nobody spoke up for the call.
|
|
;
|
|
; Note that we don't have to worry about straight traps ending up here, since
|
|
; if they get dropped on the floor we'll exit the toExtFS hook with the
|
|
; original #ExtFSErr still sitting in d0.
|
|
;
|
|
; Inputs:
|
|
; a0 - pointer to currently executing parameter block
|
|
; d0 - dispatch selector
|
|
;
|
|
; Currently, we send the following dispatch values through UnknownCall
|
|
; $1c - $1f we want to be flexible about the parameters to these
|
|
; selectVolumeMount ($41) since there's no volume to aim at
|
|
; selectGetUGEntry ($44) - $4f ¥¥ should get the hell off of $a060, that's what.
|
|
; everything above $70 we want to be flexible about the parameters to these
|
|
;________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
ExtFSCatchAll: proc
|
|
tst.w d0 ; is this a selector? <15Jan91 #28>
|
|
ble.s @Exit ; no <15Jan91 #28>
|
|
cmp.b #$1c, d0 ; check the bottom of the first range
|
|
blo.s @ExtFSErrExit ; since we implement dispatches < $1c, return #ExtFSErr
|
|
cmp.b #$1f, d0 ; check the top of the first range
|
|
bls.s @ParamErrExit ; we don't implement $1c<=dispatch<=$1f, so #paramErr it
|
|
|
|
cmp.b #selectVolumeMount, d0 ; check for volumeMount
|
|
beq.s @ParamErrExit ; no local volumeMount, so #paramErr it
|
|
|
|
cmp.b #selectGetUGEntry, d0 ; check for bottom of third range
|
|
blo.s @ExtFSErrExit
|
|
cmp.b #$4f, d0 ; check top of third range
|
|
bls.s @ParamErrExit
|
|
|
|
cmp.b #$70, d0 ; check for the edge of the known world
|
|
blo.s @ExtFSErrExit
|
|
|
|
@ParamErrExit:
|
|
moveq.l #paramErr, d0
|
|
bra.s @Exit
|
|
|
|
@ExtFSErrExit:
|
|
moveq.l #extFSErr, d0 ; restore correct error code
|
|
@Exit:
|
|
rts
|
|
|
|
endproc
|
|
|
|
|
|
;_____________________________________________________________________________________
|
|
;
|
|
; MungeTrapWord (d0 and d1) -> ioTrap(a0)
|
|
;
|
|
; Function
|
|
; Store the trap word in d1 into ioTrap(a0). If the trap is Ax60, combine
|
|
; d1 with the dispatch value on d0 before storing.
|
|
;
|
|
; Input:
|
|
; a0 - pointer to caller's PB
|
|
; d0 - dispatch value (for Ax60 traps)
|
|
; d1 - trap word
|
|
;
|
|
; Output:
|
|
; a0 - pointer to caller's PB
|
|
; ioTrap(a0) - munged trap word
|
|
;
|
|
; All registers preserved
|
|
;_____________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
MungeTrapWord: proc export
|
|
move.w d1,IOTrap(a0) ; save the trap number
|
|
cmp.b #$60,d1 ; TFS trap dispatch?
|
|
bne.s @noNeedToMunge ; If not, leave ioTrap alone
|
|
|
|
and.b #$0F,ioTrap(a0) ; Leave only modifier bits
|
|
move.b d0,ioTrap+1(a0) ; Store trap index in low byte
|
|
|
|
@NoNeedToMunge:
|
|
rts
|
|
endproc
|
|
|
|
;_____________________________________________________________________________________
|
|
;
|
|
; UnMungeTrapWord ioTrap(a0) -> d0 and d1
|
|
;
|
|
; Function
|
|
; Expand the trap word in ioTrap(a0) into its original dispatch trap
|
|
; word (in d1) and leave the selector in d0. ioTrap is not touched.
|
|
;
|
|
; Note that we're not converting the dispatch selector into a signed byte.
|
|
; The negative value we return is a word, so it's cool to check the word
|
|
; in d0 for negativeness even when we get dispatch selectors > 128.
|
|
; ExtFSErr happens to be the right value when calling toExtFS, so it's the
|
|
; negative number of choice.
|
|
;
|
|
; Input:
|
|
; a0 - pointer to caller's PB
|
|
;
|
|
; Output:
|
|
; a0 - pointer to caller's PB
|
|
; d0.w - dispatch value (for dispatch traps), or #ExtFSErr (for straight traps)
|
|
; d1.w - trap word
|
|
; N - set for straight traps, clear for $Ax60 traps
|
|
;
|
|
; Note:
|
|
; This routine is called by the desktop manager, too.
|
|
;_____________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
UnMungeTrapWord: proc export
|
|
moveq.l #ExtFSErr,d0 ; for straight traps
|
|
move.w ioTrap(a0),d1 ; get munged version of trap word
|
|
bmi.s @Exit ; no need to un-munge if it was an Ax00 trap
|
|
moveq.l #0,d0 ; clear long since we only move a byte
|
|
move.b d1,d0 ; d0 = hfs dispatch code
|
|
clr.b d1 ; clear selector from low byte
|
|
ori.w #$a060,d1 ; merge HFSDispatch trap word with modifiers
|
|
@Exit:
|
|
tst.w d0 ; sets N for straight traps
|
|
rts
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; ExtFSHook patch <9>
|
|
;
|
|
; Grab control at the ExtFSHook to implement patches to CmdDone. We are
|
|
; called after the file system has executed the local attempt at the call
|
|
; and after it has attempted the PMSP.
|
|
;
|
|
; We are currently performing the following steps
|
|
;
|
|
; 1) Run external file systems if necessary (replaces code in ROM)
|
|
; 2) Do check to catch stray selectors
|
|
; 3) Perform MakeFSSpec emulation if necessary
|
|
; 4) Set up the info for the disk switch hook
|
|
; 5) UnTag FCBs on all _Close calls
|
|
; 6) Fix up FCBs on successful _OpenRF calls (details follow)
|
|
; 7) Call completion routines (replaces code in ROM)
|
|
; 8) Check for more calls to dispatch (replaces code in ROM)
|
|
;
|
|
; Calling external file systems is tricky since the AppleShare external file
|
|
; system (and any other peer-to-peer client file systems) dequeue their calls
|
|
; and clear the local file system (to allow peers to send calls to this machine
|
|
; and not get stuck in a deadlock).
|
|
; The rules of calling the external file system chain allow for a single
|
|
; address on top of the stack that the external file system should return
|
|
; to when the call is really complete. Below that the stack belongs to
|
|
; whomever we/the external file system plans to return to during async execution
|
|
; of the call (quite possibly a return address into the file system syncwait loop,
|
|
; but we can't be sure).
|
|
;
|
|
; Figure 1:
|
|
;
|
|
; Top of a7 stack
|
|
; The Command Done Address External file system pop this and jump here when done
|
|
; The Async Context External file systems rts when returning asynchronously
|
|
; (arbitrarily deep)
|
|
; Bottom of a7 stack
|
|
;
|
|
; Since we can save at most one return addresses' worth of context (the one that the
|
|
; external file system will return to when it is done with the call) AND we
|
|
; (this patch) are jsr'ed to from the rom, we would have no way to calling external
|
|
; file systems with the right stack depth. So, we throw away the return address to
|
|
; ROM and replace all of the code that the ROM normally does.
|
|
;
|
|
; Nota Bene:
|
|
; Anyone who hooks onto the ExtFSHook and bsrOlds is guaranteed to break the
|
|
; system since we required the ability to call external file systems from
|
|
; this patch and calling external file systems requires the above-mentioned
|
|
; stack discipline.
|
|
;
|
|
; All of this stack business is why the patches are all at the same subroutine level.
|
|
; Obviously, you can't write a patch that will call external file systems if you
|
|
; are down in a subroutine.
|
|
;
|
|
; See tech note #xxxxx (the exciting tech note of the future about those wacky zany
|
|
; file system hooks)
|
|
;
|
|
; The dirty details about _OpenRF and AdjEof
|
|
;
|
|
; The logic at the end of FOpen (the common data and resource fork opener) has
|
|
; a bug in the code when it syncs up the FCBs of the fork it just opened (which
|
|
; has information from the catalog file record) with any other FCBs (which
|
|
; have information that's been modified by file system calls
|
|
; made since the last flush). The code loops through all FCBs looking
|
|
; for forks on the same volume with the same file number of the same rsrc/data
|
|
; type that aren't the file that was just opened. If it finds one, it calls the
|
|
; AdjEOF subroutine, which forces all FCBs of the same file/fork to have the
|
|
; the same file positioning information. The bug is that the check for "same
|
|
; fork" is flawed. It loads D3 with a WORD sized value when extracting the
|
|
; FCBMdRByt field from the new FCB, but uses it as a byte when comparing it to
|
|
; the FCBMdRByt field of other FCBs. This means it is using the byte after
|
|
; FCBMdRByt, which is FCBTypByte. FCBTypByte happens to always be zero in HFS
|
|
; (type is an MFS concept). A zero in the fork flag () of FCBTypByte means
|
|
; "data fork", so data fork opens act correctly. Of course, resource fork opens
|
|
; do not. We make up for it in this patch to OpenRF.
|
|
;
|
|
; ¥¥ What about the fact that a resource file will always look like a data
|
|
; fork to the ROM's confused FCB synchronizer?
|
|
;
|
|
; Inputs:
|
|
; d0.w - result code from current file manager call input to toExtFS hook
|
|
; d1.l - (on Open calls only) points to a free fcb input to toExtFS hook
|
|
; a0.l - caller's pb input to toExtFS hook
|
|
; a3.l - possible pointer to WDCB input to toExtFS hook
|
|
;
|
|
; Register usage:
|
|
; We can trash only interrupt regs (d0-d3/a0-a3).
|
|
;
|
|
; According to the unpublished IM Vol. IV chap (21), external file systems
|
|
; can trash only d1/d2/a0/a1
|
|
;
|
|
; But, old versions of XFS (CD-ROM, ISO-9660) trash D4, HFSStkPtr and any other
|
|
; side effects of calling the disk cache (though it points a6 at its own
|
|
; space).
|
|
;
|
|
; As far as we know, none of the external file systems use the memory
|
|
; below HFSStkTop^ for their own use.
|
|
;
|
|
; When you enter command done, registers d0-d3/a0-a3 are protected and
|
|
; are available for File System use. d0/d1/a0/a3 are input parameters to
|
|
; the external file system chain.
|
|
;
|
|
; About the #NoMacDskErr bug: We assume that it is fixed in a patch that is
|
|
; called before this patch is.
|
|
;
|
|
; Reentrancy:
|
|
; The AppleShare client file system causes this code to be reentered. When
|
|
; AppleShare decides to derail a call (because it is heading to an external
|
|
; volume that might be on a peer of this machine) it remembers the return
|
|
; address (as it should) but removes the PB from the front of the FSQueue
|
|
; and clears the FSBusy word (which it really shouldn't). Since the File
|
|
; System isn't busy, other calls will be processed (and come through here
|
|
; as they complete). At some arbitrary time in the future AppleShare will
|
|
; finish the transaction with the external volume and will (after kindly
|
|
; making sure that the File System isn't busy) jump back to the return
|
|
; address that it remembered long ago. This means that we can't save any
|
|
; state above the call to external file systems that we'll want after they
|
|
; return.
|
|
;________________________________________________________________________________
|
|
; This routine was copied into FileMgrHooks.a <SM1>
|
|
ExtFSHookPatch: proc
|
|
import QMEnqueue, ExternalMakeFSSpec, GetOffFSQueue
|
|
import FSDispatchRequest, CallWithRegistersPreserved
|
|
|
|
addq.w #4,sp ; throw away the return address
|
|
|
|
; Run external file systems if we need to (ExtFSErr, or any error with _MountVol)
|
|
|
|
cmp.w #ExtFSErr,d0 ; Pass request on to external FS's?
|
|
bne.s @1 ; if not, check for NoMacDskErr <25>
|
|
cmp.w #$A00F,ioTrap(A0) ; _MountVol could return "ExtFSErr" <25>
|
|
beq.s @3 ; yes, it is _MountVol <25>
|
|
bra.s @CallExternals ; No, never mind <25>
|
|
@1
|
|
cmp.w #NoMacDskErr, d0 ; Did we fail a MountVol?
|
|
bne.s @DoneWithExternals ; if not, move on
|
|
@3 clr.l ReqstVol ; Force 'No VCB' for this call
|
|
|
|
@CallExternals:
|
|
move.l FSQHead, a0 ; grab current pb
|
|
cmp.w #FSQType, ioType(a0) ; better be one of ours
|
|
bne toDSFSErr ; or end the ballgame
|
|
|
|
move.l d1, d2 ; save possible FCB pointer
|
|
bsr UnMungeTrapWord ; get trap word (d1) and dispatch or #ExtFSErr (d0)
|
|
move.w d1, ioTrap(a0) ; set trap word
|
|
|
|
;; If this an A060 call, then D0.W = selector. After we call ext FS, D0 is trashed, <25>
|
|
;; So we need to save it somewhere for FSM foreign file systems. <25>
|
|
;; This selector can only be used (by FSM) if old ext FS don't handle the call, <25>
|
|
;; because cmdDone is now reentered. <25>
|
|
movea.l FSVarsPtr, A1 ; A1 = ptr(FSVars block) <25>
|
|
move.w D0,FSVars.FSSelector(A1); Save trap word or HFS selector for FSM <25>
|
|
bpl.s @5 ; D0 is HFS selector <25>
|
|
move.w D1,FSVars.FSSelector(A1); else, save trap word for FSM <25>
|
|
@5
|
|
move.l d2, d1 ; restore possible FCB pointer <25>
|
|
move.l toExtFS, d2 ; Grab the current external file system chain
|
|
cmp.l MinusOne, d2 ; Is there anyone on it?
|
|
beq.s @TryFSM ; No? Go check FSM <25>
|
|
movea.l d2, a1 ; move vector to jsr'able register
|
|
;; The story about TOPS. It takes selector as a long word, <25>
|
|
;; so we have to do the following to fix their bug. <25>
|
|
ext.l d0 ; make it a long <25>
|
|
|
|
jsr (a1) ; call external file system(s) (which remunge the trap word)
|
|
tst.w d0 ; test the result from the external file systems
|
|
beq.s @DoneWithExternals ; if error = 0, someone handled the call <25>
|
|
bpl.s @TryFSM ; if d0 > 0, then no one handled the call, so Try FSM.
|
|
; < 0 could be #extFSErr which means nobody handled the call, or a "real" error
|
|
; AccessPC returns memFullErr for other FS on a _MountVol call, what should we do? <25>
|
|
cmp.w #extFSErr,D0 ; is it extFSErr? <25>
|
|
bne.s @DoneWithExternals ; if not, someone handled the call <25>
|
|
|
|
@TryFSM ; done with the old FnFS, give FSM a chance <25>
|
|
movea.l FSVarsPtr, A1 ; A1 = ptr(FSVars block) <25>
|
|
move.l FSVars.FSMHook(A1),D2 ; is FSM there? <25>
|
|
beq.s @noFSM ; no, all done <25>
|
|
movea.l D2,A1 ; vector to call <25>
|
|
move.l FSQHead, a0 ; old ext FS may trashed A0 <26>
|
|
jsr (A1) ; call FSM external file system(s) <25>
|
|
tst.w D0 ; any error? <25>
|
|
beq.s @DoneWithExternals ; if error = 0, someone handled the call <25>
|
|
cmp.w #extFSErr,D0 ; is it extFSErr? <40>
|
|
bne.s @DoneWithExternals ; if not, someone handled the call <40>
|
|
@noFSM
|
|
bsr UnMungeTrapWord ; get trap word (d1) and dispatch or #ExtFSErr (d0)
|
|
bsr ExtFSCatchAll ; catch the UnknownCall dispatch that nobody took
|
|
@DoneWithExternals:
|
|
move.l FSQHead, a0 ; grab current pb <46>
|
|
|
|
; Our first patch: MakeFSSpecEmulation
|
|
;
|
|
; Function
|
|
; Check to see if a MakeFSSpec call came back from an external file
|
|
; system which didn't implement MakeFSSpec. If so, emulate the call.
|
|
;
|
|
; Input:
|
|
; a0 - pointer to caller's PB
|
|
; a1 - pointer to context
|
|
; d0 - error code from current file manager call
|
|
;
|
|
; Output:
|
|
; d0 - error code from external file systems (paramErr if they couldn't handle it)
|
|
; a0 - pointer to caller's PB
|
|
; d2 - trash
|
|
;
|
|
move.w d0, d2 ; save error code in a safe register
|
|
bsr UnMungeTrapWord ; get trap word (d1) and dispatch or #ExtFSErr (d0)
|
|
bmi.s @DoneWithEmulation ; MakeFSSpec isn't a straight trap
|
|
cmp.b #selectMakeFSSpec, d0 ; our selector?
|
|
bne.s @DoneWithEmulation ; not MakeFSSpec, =>
|
|
|
|
cmp.w #paramErr, d2 ; did MakeFSSpec confuse them?
|
|
beq.s @HandleIt ; yes, so let us help
|
|
cmp.w #wrgVolTypErr, d2 ; MakeFSSpec on MFS? <29>
|
|
beq.s @HandleIt ; another job for the compatibility layer <29>
|
|
cmp.w #extFSErr, d2 ; we fear that some external FS's may reply with
|
|
; this error when they don't understand a dispatch
|
|
beq.s @HandleIt ; so emulate on #extFSErrs, too <14>
|
|
cmp.w #wPrErr, d2 ; HACK ALERT. iso-9660 file systems are confused <14>
|
|
bne.s @DoneWithEmulation ; external FS liked it - we're done <14>
|
|
|
|
@HandleIt:
|
|
jsr GetOffFSQueue ; Get a0 (now FSQHead) off FSQueue
|
|
moveq.l #fsCompatQType, d2 ; the compatibility layer queue type/refnum
|
|
bsr QMEnqueue ; get queued up, dispatched to w/CmdDone addr on CL a6 stack
|
|
jsr ExternalMakeFSSpec ; go do the call and return all the way out
|
|
move.l (a6)+, -(sp) ; get completion address from a6 stack
|
|
rts ; jump out of CmdDone, leaving 1 return address on a7
|
|
; Note that the QMgr's completion code kick starts the FS
|
|
@DoneWithEmulation:
|
|
|
|
; --- Here's where to add more patches for routines which may have failed or succeeded.
|
|
|
|
SetDSHookInfo:
|
|
; <35>
|
|
; Check for calls for which we're about to invoke the disk switch hook.
|
|
; Save the VCB pointer and the name pointer for the volume we're trying
|
|
; to recover.
|
|
;
|
|
; This solution has a big hole in it. We only do disk recovery for
|
|
; synchronous calls, but we can no longer check ioTrap to see if a
|
|
; call is synchronous since File Sharing refires sync calls from their
|
|
; scheduler. This means that we have to assume that any call which
|
|
; has failed with a #volOffLinErr should be the one that the disk switch
|
|
; sees. Unfortunately, in between the time we set these variables and the
|
|
; time the disk switch code draws the name a truly async call could come
|
|
; in for an offline volume and cause the wrong name to be drawn.
|
|
cmpi.w #volOffLinErr, d2 ; did we get a volume offline error?
|
|
bne.s @DoneSettingDSHookInfo
|
|
|
|
move.l ReqstVol, a1
|
|
pea.l VCBVN(a1) ; grab the name pointer
|
|
movea.l FSVarsPtr, a1
|
|
move.l ReqstVol, fsVars.dsRecoverVCBPtr(a1) ; remember the volume
|
|
move.l (sp)+, fsVars.dsRecoverNamePtr(a1) ; remember the name of the volume
|
|
bra CallDone
|
|
|
|
@DoneSettingDSHookInfo
|
|
|
|
; All of the patches beneath this label are for calls that worked <20>
|
|
tst.w d2 ; did the call work? <20>
|
|
bne CallDone ; if not, go try another call <20>
|
|
|
|
; patch: UnTagFCBs
|
|
; Registers now:
|
|
; a0 - caller's PB
|
|
; d0 - dispatch or #ExtFSErr
|
|
; d1 - unmunged trap word
|
|
; d2 - error code
|
|
; On all _Close calls, clear the process serial number stored in the
|
|
; parallel FCB array.
|
|
|
|
and.w #$f0ff, d1 ; clear modifier bits from trap word
|
|
cmp.w #$a001, d1 ; was this _Close?
|
|
bne.s @CloseTagDone ; if not, we're done here
|
|
|
|
@CloseAttempted:
|
|
move.w ioRefNum(a0),d0 ; get refNum
|
|
bsr ParallelFCBFromRefnum ; a1 = address of parallel FCB element
|
|
clr.l xFCBPid1(a1) ; clear high long of PSN
|
|
clr.l xFCBPid2(a1) ; clear low long of PSN <20>
|
|
bra CallDone ; go do another call, if necessary
|
|
@CloseTagDone:
|
|
|
|
@UnTagWDCBs: ; do WDCBs the same way we do FCBs <20>
|
|
cmpi.w #selectCloseWD, d0 ; is this a _CloseWD call?
|
|
bne.s @UnTagWDCBsDone
|
|
|
|
move.w ioVRefNum(a0), d0 ; get WDRefNum
|
|
cmp.w #WDRfnMax,d0 ; Is it a VRefNum? <23>
|
|
bhi.s @UnTagWDCBsDone ; vRefNum (i.e. WD's to the root) don't get tagged <23>
|
|
|
|
bsr ParallelWDCBFromRefnum ; a1 = address of parallel WDCB element
|
|
clr.l xWDCBPid1(a1)
|
|
clr.l xWDCBPid2(a1)
|
|
bra CallDone
|
|
@UnTagWDCBsDone:
|
|
|
|
FixFCBSyncOnOpenRF:
|
|
; Fix FCB synchronization on _OpenRF
|
|
; Registers now:
|
|
; a0.l - pb
|
|
; d0 - dispatch or #ExtFSErr
|
|
; d1.w - trap word w/o modifiers
|
|
; d2.w - result code
|
|
;
|
|
; We only need to synchronize on successful local _OpenRF calls.
|
|
; External file systems are responsible for keeping their own FCB marbles in order.
|
|
; (for example, some may not use a unique file number for each fcb)
|
|
; Note that we don't patch _OpenRFDeny because it's not a local FS call.
|
|
|
|
cmp.w #$a00a, d1 ; was this _OpenRF?
|
|
bne.s @DoneCheckingOpenRF ; if not, we're out of here
|
|
|
|
; Make sure this successful _OpenRF was local, and if so fix up FCBs of any other open paths.
|
|
@FixOpenRFRegs reg d2/d4 ; save regs (no i/o 'till we restore these) <20>
|
|
|
|
movem.l @FixOpenRFRegs, -(sp) ; save working registers
|
|
move.l FCBsPtr,a1 ; a1 = fcb array
|
|
move.w ioRefNum(a0),d4 ; d4 = refnum of newly opened RF
|
|
movea.l fcbVptr(a1,d4.w),a2 ; a2 = VCB
|
|
tst.w vcbFSID(a2) ; are we local? <20>
|
|
bne.s @NoOtherPaths ; if not, it's not our problem
|
|
|
|
move.l fcbFlNm(a1,d4),d2 ; d2 = file num
|
|
jsrROM romGt1stMatch ; get an FCB which matches VCB & file num
|
|
|
|
; Now A1 --> FCBs, d1 = refnum of the matching FCB
|
|
@FixOpenRFLoop
|
|
cmp.w d1,d4 ; is it the one that we just got opened?
|
|
beq.s @SawOurselves ; if so, ignore it
|
|
move.b FCBMdRByt(a1,d1),d3 ; mod byte
|
|
btst #fcbRscBit,d3 ; resource fork?
|
|
bne.s @DoAdjust ; Adjust EOF if the forks match
|
|
@SawOurselves:
|
|
jsrROM romGtNxtMatch ; look for another matching fcb
|
|
beq.s @FixOpenRFLoop ; br if match
|
|
bra.s @NoOtherPaths ; don't adjust if we're the only path
|
|
|
|
@DoAdjust:
|
|
bsr adjEOF ; Make our new FCB match old wise one
|
|
move.b d3,FCBMdRByt(a1,d1) ; don't let AdjEOF change dirty bit
|
|
|
|
@NoOtherPaths:
|
|
movem.l (sp)+,@FixOpenRFRegs ; error code d0 and param a0 unchanged
|
|
@DoneCheckingOpenRF:
|
|
|
|
; --- Here's where to add more patches for routines which succeed
|
|
|
|
if 0 then ; you might want this if you add patches
|
|
bra.s CallDone
|
|
endif
|
|
|
|
; The current call is now done.
|
|
CallDone:
|
|
|
|
; Check to see if thereÕs another call to execute.
|
|
move sr, -(sp) ; save interrupt state <27Aug85>
|
|
ori #HiIntMask, sr ; only debug interrupts allowed
|
|
clr.w FSBusy ; we're not busy anymore
|
|
|
|
; delete the current request from the queue and post any completion routines
|
|
|
|
move.l FSQHead,a0 ; a0 -> current request
|
|
cmp.w #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 @CallCompletion ; branch if queue not empty <27Aug85>
|
|
clr.l FSQTail ; clear tail ptr, too
|
|
|
|
@CallCompletion: ; <27Aug85>
|
|
move (sp)+,sr ; restore interrupt state
|
|
move.w d2,IOResult(a0) ; post error code
|
|
move.w d2,d0 ; put result code into d0 <21>
|
|
|
|
move.l ioCompletion(a0),d1 ; is there a completion routine?
|
|
beq.s @DispatchNext ; skip if there's not <27Aug85>
|
|
|
|
move.l d1,a1 ; get the completion routine address
|
|
jsr (a1) ; call completion routine
|
|
|
|
@DispatchNext:
|
|
move sr,-(sp) ; save interrupt state
|
|
ori #HiIntMask,sr ; only debug interrupts allowed
|
|
tst.l FSQHead ; is a command pending?
|
|
beq.s @Done
|
|
|
|
bset.b #fsBusyBit, FSBusy ; make sure the file system is marked busy
|
|
bne.s @Done ; if it was already busy, we can return asynchronously
|
|
move.w (sp)+,sr ; restore interrupt state
|
|
|
|
lea.l FSDispatchRequest,a0 ; our dispatcherÕs entry point <48>
|
|
jmp CallWithRegistersPreserved ; call it <48>
|
|
|
|
@Done:
|
|
move.w (sp)+,sr ; restore interrupt state and return
|
|
rts
|
|
|
|
toDSFSErr:
|
|
moveq.l #DSFSErr,d0
|
|
_SysError
|
|
|
|
; AdjEOF -- Call through the jAdjEOF vector
|
|
AdjEOF:
|
|
move.l jAdjEOF,-(sp) ; jumptable entry for vAdjEOF
|
|
rts ; go there
|
|
|
|
endproc
|
|
|
|
|
|
;________________________________________________________________________________________________
|
|
; BasicIO
|
|
;
|
|
; Routine for all I/O from the File Manager
|
|
;
|
|
;________________________________________________________________________________________________
|
|
; Rolled into CacheIO.a for SuperMario <SM1> FM
|
|
|
|
PatchBasicIO PatchProc jBasicIO
|
|
|
|
MOVE.L A6,HFSStkPtr ; save stack ptr
|
|
|
|
IF HFSDebug THEN
|
|
TST.W IODrvNum(A0) ; should never be zero
|
|
BNE.S @1 ; br if not
|
|
_HFSDebug $421
|
|
|
|
@1 MOVE.L HFSStkTop,D0 ; check for stack overflow
|
|
SUBI.L #HFSStkLen,D0 ;
|
|
CMP.L A6,D0 ;
|
|
BLE.S @2 ; ok ->
|
|
_HFSDebug HFSStkOvf
|
|
@2
|
|
ENDIF
|
|
|
|
; To prevent stack buildup from successive ,ASYNC calls to a synchronous driver
|
|
; (where the completion routine is normally already run before the ,ASYNC trap
|
|
; returns), the I/O completion routine returns prematurely if the trap hasn't
|
|
; completed yet (indicated by the state of the HFSContd flag). This flag is set
|
|
; immediately when the trap returns (although this is not in any way time-
|
|
; critical). The completion routine checks the flag and returns if it's clear,
|
|
; after setting the flag. When the code following the ,ASYNC trap is executed
|
|
; and finds the flag already set, it corrects for the completion routine's
|
|
; premature return and actually BRANCHES straight to the completion routine,
|
|
; with the stack back at its original level.
|
|
;
|
|
; Note that the use of a single flag bit only works because the file system is
|
|
; single-threaded: no new call can be started before this call is completed,
|
|
; and hence there are only two places where the flag can be affected: following
|
|
; the trap and in the completion routine for that same trap.
|
|
|
|
; read/write the disk block
|
|
|
|
TST.B FSCallAsync ; was FS call async? <01Oct85>
|
|
BNE.S rwAsync ; br if so (keep it that way) <01Oct85>
|
|
TST.B D1 ; 'read' operation?
|
|
BNE.S @3 ; no, must be a 'write' ->
|
|
|
|
_Read ; read it synchronously <01Oct85>
|
|
BRA.S RWCont1 ; then continue <01Oct85>
|
|
|
|
@3 _Write ; write it synchronously <01Oct85>
|
|
BRA.S RWCont1 ; then continue <01Oct85>
|
|
|
|
rwAsync
|
|
LEA RWIOComp,A1 ; IO completion address
|
|
MOVE.L A1,IOCompletion(A0) ;
|
|
|
|
BCLR #HFSContd,HFSFlags ; Clear 'premature-continuation' flag
|
|
|
|
TST.B D1 ; 'read' operation?
|
|
BNE.S @1 ; no, must be a 'write' ->
|
|
|
|
_Read ,ASYNC ; read it asynchronously
|
|
BRA.S @2 ;
|
|
|
|
@1 _Write ,ASYNC ; write it asynchronously
|
|
|
|
@2 BEQ.S @3 ; br if no immediate error <02Oct85>
|
|
TST.W IOResult(A0) ; immediate error? for sure? <02Oct85>
|
|
BLE.S RWCont ; br if so (otherwise, driver just <02Oct85>
|
|
; passed back some garbage . . .)
|
|
@3 BSET #HFSContd,HFSFlags ; We're now returning from the trap
|
|
BNE.S RWCont1 ; If we already returned, do I/O comp. now <15Sep86>
|
|
|
|
RWRTS RTS ; return to caller (complete asynchronously)
|
|
|
|
; IO completion routine
|
|
|
|
RWIOComp
|
|
BSET #HFSContd,HFSFlags ; We're continuing now
|
|
BEQ.S RWRTS ; If trap didn't really return ,ASYNC
|
|
; ... then RTS now (we'll be back)
|
|
RWCont
|
|
MOVEM.L D4-D7/A4-A6,-(SP) ; preserve non-interrupt registers
|
|
PEA RWCont2 ; return to here to restore regs
|
|
|
|
RWCont1
|
|
MOVEA.L HFSStkPtr,A6 ; Recover HFS' private stack pointer <01Oct85>
|
|
MOVEM.L (A6)+,D1-D7/A0-A5 ; Retrieve registers off A6 stack <01Oct85>
|
|
MOVE.L (A6)+,-(SP) ; pop ret address off HFS stack <01Oct85>
|
|
|
|
TST.W D0 ; any errors? <01Oct85>
|
|
BEQ.S @1 ; br if not <01Oct85>
|
|
CMP.W #OffLinErr,D0 ; Offline? <09Sep85>
|
|
BEQ.S @1 ; br if so <10Sep85>
|
|
|
|
cmp.w #notEnoughMemoryErr, d0 ; was VM able to hold down enough physical memory? <52>
|
|
beq.s @1 ; send this error throught <52>
|
|
MOVE.W D0,FSIOErr ; save original error for debugging <01Oct85>
|
|
MOVEQ #IOErr,D0 ; transform it to generic IO error <01Oct85>
|
|
@1 TST.W D0 ; set up condition codes <15Sep86>
|
|
RTS ; return to caller with error code <01Oct85>
|
|
|
|
RWCont2 MOVEM.L (SP)+,D4-D7/A4-A6 ; restore the registers <01Oct85>
|
|
RTS ; we're done with it! <01Oct85>
|
|
endproc
|
|
|
|
|
|
; ________________________________________________________________________________________________
|
|
; TruncateFile: This come from patch fixes a bug for FClose in TFSRfn2.a
|
|
;
|
|
; The bug:
|
|
; FClose, which calls TruncateFile, doesn't call AdjEOF to synchronize
|
|
; the extent information for the FCB which it just changed with other open
|
|
; paths to the same fork.
|
|
;
|
|
; Since TruncateFile releases blocks by marking them free in the volume's allocation
|
|
; bitmap, they become available for allocation to other forks. If this happens
|
|
; before the other paths are closed blocks will be mapped to more than one fork,
|
|
; trashing at least one of them.
|
|
;
|
|
; The fix:
|
|
; Patch TruncateFile to do nothing if called from FClose when we find more
|
|
; than one open path to a fork. Since no truncation occurs, there's no need
|
|
; to synchronize FCBs. This has the added advantage of leaving the extra
|
|
; clump on writable forks until the last one is closed.
|
|
;
|
|
; Input (from ROM):
|
|
; A2.L - VCB pointer
|
|
; A1.L - pointer to FCB array
|
|
; D1.W - file refnum
|
|
;
|
|
; Output: We either jump to TruncateFile in ROM, or return to caller (ie. FClose).
|
|
; TruncateFile returns an error code, so when we bail we return noErr.
|
|
; All registers preserved.
|
|
;
|
|
; Note: TruncateFile is only called by FClose when the path being closed is dirty and
|
|
; modifiable. If there are several read-only paths and a single writable path we won't
|
|
; truncate the file if the writable file is not the last one closed. This results
|
|
; in the file having at most an extra clump allocated to it.
|
|
;
|
|
; FClose is called to both close files and to flush them. Since the call
|
|
; to TruncateFile is made from the same place for both paths through FClose,
|
|
; we'll trigger on both _Close and _FlushFile.
|
|
;
|
|
; Modification History:
|
|
; 11Dec90 KST New today.
|
|
; 03Mar90 dnf/bb Add check for data vs. resource fork
|
|
; ________________________________________________________________________________________________
|
|
; rolled in for SuperMario <SM1> FM
|
|
; Added an AdjEOF call to FClose (TFSRFN2.a)
|
|
|
|
|
|
AfterTruncateFile ROMBind (Plus,$51E8),(SE,$6C94),(II,$0A74E),(Portable,$0C0F4),(IIci,$11B0C)
|
|
|
|
DontTruncateMultiForks ComeFromPatchProc $A0DB,,(Plus,SE,II,Portable,IIci) ; <11Dec90 #17>
|
|
|
|
@Regs reg d1-d4 ; <44>
|
|
|
|
cmpROM AfterTruncateFile,(SP) ; do the comparison ourself <11Dec90 #17>
|
|
bneOld ; not from FClose <11Dec90 #17>
|
|
|
|
; Look for other paths to the same fork as the one being closed.
|
|
MOVEM.L @Regs,-(SP) ; save input parameters <11Dec90 #17>
|
|
MOVE.W D1,D3 ; D3.W = our FCB <11Dec90 #17>
|
|
MOVE.L FCBFlNm(A1,D3.W),D2 ; D2.L = our file number <11Dec90 #17>
|
|
move.b fcbMdRByt(a1,d3.w),d4 ; d4.b = our fork's misc info <44>
|
|
|
|
jsrROM GT1STFCB ; get (A1,D1) pointing to first FCB <11Dec90 #17>
|
|
@1 CMP.W D1,D3 ; same FCB? <11Dec90 #17>
|
|
BEQ.S @3 ; skip ourself if it is <11Dec90 #17>
|
|
CMP.L FCBFlNm(A1,D1),D2 ; file numbers match? <11Dec90 #17>
|
|
BNE.S @3 ; no <11Dec90 #17>
|
|
CMP.L FCBVPtr(A1,D1),A2 ; on the same volume? <11Dec90 #17>
|
|
bne.s @3 ; no <44>
|
|
move.b fcbMdRByt(a1,d1.w),d0 ; grab this forkÕs kind <44>
|
|
eor.b d4,d0 ; see how it compares against ours <44>
|
|
btst.l #fcbRscBit,d0 ; are we the same? <44>
|
|
beq.s @7 ; if so, then there's another open path <44>
|
|
@3 jsrROM GTNXTFCB ; get next one until we run out <11Dec90 #17>
|
|
BCS.S @1 ; continue if more <11Dec90 #17>
|
|
|
|
; No second open path found, so do the truncate
|
|
MOVEM.L (SP)+,@Regs ; restore regs and <11Dec90 #17>
|
|
jmpOld ; continue <11Dec90 #17>
|
|
|
|
; A second path was found, so return #noErr and skip the truncation
|
|
@7 MOVEM.L (SP)+,@Regs ; restore regs and <11Dec90 #17>
|
|
moveq.l #noErr,d0 ; we did nothing, but quite successfully
|
|
RTS ; leave <11Dec90 #17>
|
|
|
|
ENDPROC
|
|
|
|
|
|
; <2.3 kst>
|
|
;________________________________________________________________________________
|
|
;
|
|
; Routine: Catalog Btree writecount patch
|
|
;
|
|
; Function: This patch keeps a writecount of operations to the catalog.
|
|
; By: Kenny Tung
|
|
; Copyright © 1989-90 Apple Computer, Inc.
|
|
;
|
|
; Revision History:
|
|
; 16Aug89 KSCT New today.
|
|
;________________________________________________________________________________
|
|
; The writecount patches have been rolled into BTSvcs.a <SM1> FM
|
|
|
|
;__________________________________________________________________________________
|
|
;
|
|
; Routine: BTOpenPatch
|
|
; Function: Allocate a larger BTCB and init the write count.
|
|
; Input: D0.W - file refnum
|
|
; A0.L - pointer to key compare routine
|
|
; A1.L - pointer to cache queue
|
|
; Output: D0.W - result code
|
|
; 0 = ok
|
|
; -n = FS Open error
|
|
;__________________________________________________________________________________
|
|
BTWCount proc
|
|
|
|
export BTOpenPatch, BTInsertPatch, BTDeletePatch
|
|
|
|
GetBlock: ; for RAM patch <2.3 kst>
|
|
MOVE.L jGetBlock,-(SP) ; jumptable entry for vGetBlock <02Oct85>
|
|
RTS ; go there
|
|
|
|
RelBlock: MOVE.L jRelBlock,-(SP) ; jumptable entry for vRelBlock
|
|
RTS ; go there
|
|
|
|
BTOpenPatch
|
|
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
|
|
MOVEM.L D1-D5/A0-A4,-(A6) ; save regs
|
|
MOVE.W D0,D3 ; D3 = file refnum
|
|
MOVE.L A0,D4 ; D4 = ptr(key compare routine)
|
|
MOVE.L A1,D5 ; D5 = cache queue ptr
|
|
;
|
|
; allocate and initialize a BTCB
|
|
;
|
|
MOVE.L #lenBTCB70,D0 ; allocate space for BTCB
|
|
_NewPtr sys, clear
|
|
BNE BOExit1 ; couldn't get it ->
|
|
MOVEA.L A0,A4 ; A4 = BTCB ptr
|
|
|
|
MOVEA.L FCBSPtr,A3 ; A3 = start of FCB array
|
|
MOVE.L A4,FCBBTCBptr(A3,D3.W) ; set BTCB ptr in FCB
|
|
|
|
MOVE.W D3,BTCRefNum(A4) ; set refnum
|
|
MOVE.L D4,BTCKeyCR(A4) ; set ptr(key compare routine)
|
|
MOVE.L D5,BTCCQptr(A4) ; set ptr to cache queue
|
|
;
|
|
; get BTH from disk
|
|
;
|
|
MOVE.W D3,D0 ; file refnum
|
|
MOVEA.L D5,A1 ; cache queue ptr
|
|
MOVEQ #0,D1 ; no GetBlock options <14Oct85>
|
|
MOVEQ #0,D2 ; BTH is block 0
|
|
JSR GetBlock ; get the block
|
|
BNE.S BOExit1 ; couldn't get it ->
|
|
MOVEA.L A0,A2 ; A2 = cache buffer ptr
|
|
;
|
|
; make sure the BTree header node is ok
|
|
;
|
|
BOChkHdr
|
|
LEA lenND(A2),A0 ; A0 = ptr to BTH
|
|
MOVE.W BTHNodeSize(A0),D0 ; node size
|
|
BEQ.S BOBadHdr ; node size = 0, error ->
|
|
MOVE.W D0,D1 ;
|
|
ANDI.W #$1FF,D1 ;
|
|
BNE.S BOBadHdr ; node size not 512 multiple, error ->
|
|
|
|
MOVE.L FCBPLen(A3,D3.W),D2 ; physical length
|
|
DIVU D0,D2 ; physical length / node size
|
|
SWAP D2 ; = # of nodes
|
|
CLR.W D2 ;
|
|
SWAP D2 ;
|
|
CMP.L BTHNNodes(A0),D2 ; same # as in BTH?
|
|
BNE.S BOBadHdr ; no, error ->
|
|
CMP.L BTHFree(A0),D2 ; free count < # of nodes?
|
|
BLO.S BOBadHdr ; no, error ->
|
|
SUBQ.L #1,D2 ; D2 = max node #
|
|
|
|
CMPI.B #BTMaxDepth,BTHDepth(A0) ; tree depth <= max?
|
|
BHI.S BOBadHdr ; no, error ->
|
|
|
|
CMP.L BTHRoot(A0),D2 ; root node # <= max?
|
|
BLO.S BOBadHdr ; no error ->
|
|
|
|
CMP.L BTHFNode(A0),D2 ; 1st leaf node # <= max?
|
|
BLO.S BOBadHdr ; no error ->
|
|
|
|
CMP.L BTHLNode(A0),D2 ; last node # <= max?
|
|
BHS.S BOCpyBTH ; yes ->
|
|
BOBadHdr
|
|
MOVEQ #BTBadHdr,D0 ; result = 'bad header node' <14Oct85>
|
|
BRA.S BOExit ; ->
|
|
;
|
|
; copy BTH into BTCB
|
|
;
|
|
BOCpyBTH
|
|
MOVE.W #LenMemBTH-1,D0 ; loop index
|
|
LEA lenND(A2),A0 ; ptr(source)
|
|
LEA BTCDepth(A4),A1 ; ptr(dest)
|
|
@1 MOVE.B (A0)+,(A1)+ ; move it
|
|
DBRA D0,@1 ; ...in
|
|
|
|
MOVE.L #WCSigLong,BTCWcount(A4) ; set write count
|
|
|
|
CLR.W D0 ; result = 'ok'
|
|
;
|
|
; release header block and exit
|
|
;
|
|
BOExit
|
|
MOVE.W D0,-(A6) ; save result code
|
|
MOVEA.L D5,A1 ; cache queue ptr
|
|
MOVEQ #0,D1 ; release 'clean' <14Oct85>
|
|
MOVEA.L A2,A0 ; cache buffer ptr
|
|
|
|
JSR RelBlock ; release it
|
|
BEQ.S @1 ; ok ->
|
|
MOVE.W D0,(A6) ; replace previous result code
|
|
@1 MOVE.W (A6)+,D0 ; restore result code
|
|
BOExit1
|
|
MOVEM.L (A6)+,D1-D5/A0-A4 ; restore regs
|
|
MOVE.L (A6)+,-(SP) ; put return address back on stack
|
|
TST.W D0 ; set condition codes
|
|
RTS ; exit BTOpen
|
|
|
|
;__________________________________________________________________________________
|
|
; Routine: BTInsertPatch
|
|
; Function: Increment the Write Count if B*Tree has changed
|
|
;__________________________________________________________________________________
|
|
ExtBTFile: MOVE.L jExtBTFile,-(SP)
|
|
RTS
|
|
|
|
AllocNode: MOVE.L jAllocNode,-(SP)
|
|
RTS
|
|
|
|
MarkBlock: MOVE.L jMarkBlock,-(SP)
|
|
RTS
|
|
|
|
GetNode: MOVE.L jGetNode,-(SP)
|
|
RTS
|
|
|
|
RelNode: MOVE.L jRelNode,-(SP)
|
|
RTS
|
|
|
|
BTInsertPatch
|
|
|
|
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
|
|
|
|
MOVEM.L D1/D3-D7/A0-A4,-(A6) ; save registers
|
|
|
|
JSRRom romLocBTCB ; locate BTCB
|
|
|
|
MOVE.L A1,D7 ; D7 = ptr(record)
|
|
MOVE.W D1,D6 ; D6 = size of record
|
|
MOVE.L A0,D5 ; D5 = ptr(key)
|
|
;
|
|
; make sure there is enough file space for a worst case split
|
|
;
|
|
|
|
MOVEQ #1,D3 ; required space (in nodes) =
|
|
ADD.W BTCDepth(A4),D3 ; tree depth + 1
|
|
CMP.L BTCFree(A4),D3 ; enough space?
|
|
BLE.S BIInit ; yes ->
|
|
|
|
@1 JSR ExtBTFile ; extend the file
|
|
BNE BIExit2 ; couldn't do it ->
|
|
|
|
CMP.L BTCFree(A4),D3 ; enough space now?
|
|
BGT.S @1 ; no ->
|
|
;
|
|
; initialize some things
|
|
;
|
|
BIInit
|
|
MOVE.W BTCRefNum(A4),D0 ; set up common stuff
|
|
jsrROM romBTSetUp ;
|
|
|
|
MOVEM.L D6/D7,-(A6) ;save input record size and ptr
|
|
|
|
MOVEQ #0,D4 ; indicate no parent node buffer <29Aug85>
|
|
SUBA.L A2,A2 ; ...no left node buffer
|
|
SUBA.L A3,A3 ; ...no right node buffer
|
|
|
|
CLR.L BTCNodeM(A4) ; invalidate current node mark
|
|
;
|
|
; build BTree record consisting of input key with a junk data record
|
|
;
|
|
MOVEA.L BTCVarPtr(A4),A1 ; dest = record buffer
|
|
LEA BTVRecord(A1),A1 ;
|
|
MOVEA.L D5,A0 ; source = input key
|
|
MOVEQ #0,D0 ; get key length
|
|
MOVE.B (A0),D0 ;
|
|
ADDQ.L #2,D0 ; include length byte
|
|
LSR.L #1,D0 ;
|
|
LSL.L #1,D0 ; ...and adjust to word boundry
|
|
ADD.W D0,D6 ; total size = key size + data size
|
|
_BlockMove ; move in the key
|
|
|
|
ADDQ.W #1,D6 ; adjust total size to word boundry
|
|
LSR.W #1,D6 ;
|
|
LSL.W #1,D6 ;
|
|
MOVE.L A1,D7 ; D7 = ptr(Btree record)
|
|
;
|
|
; search tree for key
|
|
;
|
|
BISearch
|
|
JSRRom romTreeSearch ; search for key
|
|
MOVEA.L A1,A3 ; A3 = ptr(right node buffer)
|
|
BNE.S @1 ; key not found or error ->
|
|
MOVEQ #BTexists,D0 ; error, it already exists <14Oct85>
|
|
BRA BIExit1 ; exit ->
|
|
@1 CMP.W #BTnotfound,D0 ; key not found ?
|
|
BNE BIExit1 ; no, must be IO error ->
|
|
MOVE.L D2,D3 ; D3 = right node number
|
|
MOVE.W D1,D5 ; D5 = insert index
|
|
;
|
|
; if tree is empty, add 1st leaf node
|
|
;
|
|
TST.W BTCLevel(A4) ; tree empty ?
|
|
BGT.S BIInsert ; no ->
|
|
|
|
MOVE.W BTCRefNum(A4),D0 ; file refnum
|
|
JSR AllocNode ; allocate the node
|
|
BNE BIExit1 ; error ->
|
|
|
|
MOVE.L D1,D3 ; D3 = new node number
|
|
|
|
JSRRom romInitNode ; get an initialized node
|
|
BNE BIExit1 ; error -> <18Dec85>
|
|
MOVEA.L A0,A3 ; A3 = ptr(new root node)
|
|
|
|
MOVE.B #NDLeafNode,NDType(A3) ; type = leaf node
|
|
MOVEQ #1,D0 ; node height = 1
|
|
MOVE.B D0,NDNHeight(A3) ;
|
|
|
|
MOVE.W D0,BTCDepth(A4) ; tree depth = 1
|
|
MOVE.L D3,BTCRoot(A4) ; new root node number
|
|
|
|
MOVE.L D3,BTCFNode(A4) ; 1st and last node pointers
|
|
MOVE.L D3,BTCLNode(A4) ;
|
|
|
|
MOVE.W #1,BTCLevel(A4) ; current level = 1
|
|
;
|
|
; try a simple insert first
|
|
;
|
|
BIInsert
|
|
MOVEA.L D7,A0 ; ptr(record)
|
|
MOVE.W D6,D0 ; record size
|
|
MOVEA.L A3,A1 ; ptr(node buffer)
|
|
MOVE.W D5,D1 ; insert index
|
|
JSRRom romInsertRec ; try to insert it
|
|
BNE.S BIRotate ; didn't make it ->
|
|
|
|
TST.W D5 ; insert a new 1st record ?
|
|
BNE.S BIInsDone ; no, insert complete ->
|
|
BSET #BTCKeyUpd,BTCFlags(A4) ; indicate key update required
|
|
BRA.S BIInsDone ; insert complete ->
|
|
;
|
|
; insert didn't work, try rotation into left sibling node
|
|
;
|
|
BIRotate
|
|
MOVEA.L A3,A0 ; ptr(node buffer)
|
|
JSRRom romGetLtSib ; get left sibling node
|
|
BNE BIExit1 ; error ->
|
|
TST.L D1 ; is there a left sibling ?
|
|
BEQ.S BISplit ; no ->
|
|
MOVE.L D1,D2 ; D2 = left node number
|
|
MOVEA.L A1,A2 ; A2 = ptr(left node buffer)
|
|
|
|
MOVEA.L D7,A0 ; ptr(record)
|
|
MOVE.W D6,D0 ; record size
|
|
MOVE.W D5,D1 ; insert index
|
|
JSRRom romRotateLt ; try rotating left
|
|
BNE.S BISplit ; didn't make it ->
|
|
BRA.S BISplit1 ; use common code -> <10Oct85>
|
|
;
|
|
; rotate didn't work, got to split
|
|
;
|
|
BISplit MOVEA.L D7,A0 ; ptr(record)
|
|
MOVE.W D6,D0 ; record size
|
|
MOVE.W D5,D1 ; insert index
|
|
JSRRom romSplitLt ; split left
|
|
BEQ.S @1 ; ok ->
|
|
MOVEQ #BTnoFit,D0 ; result = 'no fit' <14Oct85>
|
|
BRA BIExit1 ; exit ->
|
|
|
|
@1 BSET #BTCNewIRec,BTCFlags(A4) ; indicate new index record required <10Oct85>
|
|
|
|
BISplit1 ;<10Oct85>
|
|
BSET #BTCKeyUpd,BTCFlags(A4) ; indicate key update required <10Oct85>
|
|
|
|
MOVE.W D1,D5 ; D5 = new record index <10Oct85>
|
|
|
|
MOVEA.L A2,A0 ; mark the left node dirty <10Oct85>
|
|
JSR MarkBlock ; <10Oct85>
|
|
;
|
|
; completed the record insert, clean up
|
|
;
|
|
BIInsDone
|
|
;; if we get to here the file has changed, even we exit with error from
|
|
;; here on. <8/16/89 KSCT>
|
|
ADDQ.L #1,BTCWcount(A4) ; bump write count <8/16/89 KSCT>
|
|
|
|
MOVEA.L A3,A0 ; mark the right node dirty <10Oct85>
|
|
JSR MarkBlock ; <10Oct85>
|
|
CMPI.B #NDleafNode,NDType(A1) ; leaf level?
|
|
BNE.S BICkDone ; no ->
|
|
|
|
MOVEM.L (A6),A0/D0 ; get input record ptr and size
|
|
JSRRom romUpdDRec ; replace the junk data record
|
|
|
|
ADD.L #1,BTCNRecs(A4) ; bump leaf record count
|
|
|
|
MOVE.W D5,BTCIndexM(A4) ; save index marker
|
|
MOVE.L D3,D0 ; assume right node number
|
|
CMPA.L A3,A1 ; is new record in right node?
|
|
BEQ.S @1 ; yes ->
|
|
MOVE.L D2,D0 ; no, use left node number
|
|
@1 MOVE.L D0,BTCNodeM(A4) ; save node marker
|
|
;
|
|
; Check if all done
|
|
;
|
|
BICkDone
|
|
BTST #BTCKeyUpd,BTCFlags(A4) ; key update required ?
|
|
BNE.S BINxtLev ; yes, move to next level ->
|
|
BTST #BTCNewIRec,BTCFlags(A4) ; new index record required ?
|
|
BEQ BIExit ; no, all done ->
|
|
;
|
|
; move to next level
|
|
;
|
|
BINxtLev
|
|
SUB.W #1,BTCLevel(A4) ; bump to next level up
|
|
BEQ BIRoot ; up to root level ->
|
|
|
|
MOVE.W BTCLevel(A4),D0 ; locate TPR
|
|
JSRRom romLocTPR ; for this level
|
|
MOVE.W TPRRIndx(A0),D5 ; D5 = parent record index
|
|
MOVE.L TPRNodeN(A0),D3 ; D3 = parent node number
|
|
|
|
MOVE.L D2,-(A6) ; save D2
|
|
MOVEQ #0,D1 ; get parent node <10Oct85>
|
|
MOVE.L D3,D2 ;
|
|
JSR GetNode
|
|
BNE BIExit1 ; error ->
|
|
MOVE.L A0,D4 ; D4 = ptr(parent node buffer)
|
|
MOVE.L (A6)+,D2 ; restore D2
|
|
;
|
|
; update parent key
|
|
;
|
|
BIUpdKey
|
|
BTST #BTCKeyUpd,BTCFlags(A4) ; key update required ?
|
|
BEQ.S @1 ; no ->
|
|
|
|
MOVE.W D5,D0 ; locate
|
|
MOVEA.L D4,A1 ;
|
|
JSRRom romGetRecA ; ...parent index record
|
|
MOVE.L A0,-(SP) ; ...and save it
|
|
MOVEA.L A3,A1 ; locate 1st key
|
|
CLR.W D0 ;
|
|
JSRRom romGetRecA ; ...in right node
|
|
MOVEA.L (SP)+,A1 ; ptr(parent index record)
|
|
|
|
JSRRom romUpdIKey ; update the key
|
|
|
|
MOVEA.L D4,A0 ; mark the parent node dirty <10Oct85>
|
|
JSR MarkBlock ; <10Oct85>
|
|
TST.W D5 ; update to 1st key in node ?
|
|
BEQ.S @1 ; yes, leave flag set ->
|
|
BCLR #BTCKeyUpd,BTCFlags(A4) ; don't need to update next level
|
|
|
|
@1 MOVEQ #0,D1 ; release <10Oct85>
|
|
MOVEA.L A3,A0 ;
|
|
JSR RelNode ; ... right node buffer
|
|
MOVEA.L D4,A3 ; parent is new right node
|
|
MOVEQ #0,D4 ; indicate no parent node buffer <29Aug85>
|
|
;
|
|
; build new index record pointing at new left node
|
|
;
|
|
BINewRec
|
|
BTST #BTCNewIRec,BTCFlags(A4) ; new index record required ?
|
|
BEQ.S @1 ; no ->
|
|
|
|
MOVEA.L A2,A1 ; left node
|
|
MOVE.L D2,D0 ; left node number
|
|
JSRRom romBuildIRec ; build index record
|
|
|
|
@1 MOVEQ #0,D1 ; release <10Oct85>
|
|
MOVEA.L A2,A0 ;
|
|
JSR RelNode ; ... left node buffer
|
|
SUBA.L A2,A2 ; indicate no left node
|
|
;
|
|
; set up for insert of new index record
|
|
;
|
|
BTST #BTCNewIRec,BTCFlags(A4) ; new index record required ?
|
|
BEQ BICkDone ; no, check if done ->
|
|
|
|
MOVEA.L BTCVarPtr(A4),A0 ; locate new index record
|
|
LEA BTVRecord(A0),A0 ;
|
|
MOVE.L A0,D7 ; D7 = ptr to new record
|
|
jsrRom romGetMaxKey ; max key length + 4 <10Oct85>
|
|
ADDQ.W #4,D0 ; = size of index record <10Oct85>
|
|
MOVE.W D0,D6 ; D6 = size of new record <10Oct85>
|
|
BCLR #BTCNewIRec,BTCFlags(A4) ; clear new index rec flag
|
|
BRA BIInsert ; insert new index record ->
|
|
;
|
|
; we updated the root, must add a level if it was split
|
|
;
|
|
BIRoot
|
|
BTST #BTCNewIRec,BTCFlags(A4) ; was root node split ?
|
|
BEQ BIExit ; no, all done ->
|
|
;
|
|
; set up a new root index node
|
|
;
|
|
MOVE.W BTCRefNum(A4),D0 ; volume refnum
|
|
JSR AllocNode ; allocate the node
|
|
BNE BIExit1 ; error ->
|
|
|
|
MOVE.L D1,D3 ; D3 = new root node number
|
|
|
|
MOVE.L D3,D1 ; new node number
|
|
jsrRom romInitNode ; get an initialized node
|
|
BNE.S BIExit1 ; error -> <18Dec85>
|
|
MOVE.L A0,D4 ; D4 = ptr(new root node buffer)
|
|
|
|
MOVE.B #NDIndxNode,NDType(A0) ; type = index node
|
|
MOVEQ #1,D0 ; node height
|
|
ADD.W BTCDepth(A4),D0 ; = previous depth +1
|
|
MOVE.B D0,NDNHeight(A0) ;
|
|
;
|
|
; add index record for left node
|
|
;
|
|
MOVEA.L A2,A1 ; build index record
|
|
MOVE.L D2,D0 ;
|
|
jsrRom romBuildIRec ; ...for left node
|
|
|
|
jsrRom romGetMaxKey ; max key length + 4 <10Oct85>
|
|
ADDQ.W #4,D0 ; = size of index record <10Oct85>
|
|
MOVEA.L BTCVarPtr(A4),A0 ; locate new index record
|
|
LEA BTVRecord(A0),A0 ;
|
|
MOVEA.L D4,A1 ; ptr(root node buffer)
|
|
CLR.W D1 ; insert index = 0
|
|
jsrRom romInsertRec ; insert it
|
|
;
|
|
; add index record for right node (previous root)
|
|
;
|
|
MOVE.W #1,D0 ; get node number
|
|
jsrRom romLocTPR ;
|
|
MOVE.L TPRNodeN(A0),D0 ; ...of previous root
|
|
MOVEA.L A3,A1 ; ptr(node buffer)
|
|
jsrRom romBuildIRec ; build index record
|
|
|
|
jsrRom romGetMaxKey ; max key length + 4 <10Oct85>
|
|
ADDQ.W #4,D0 ; = size of index record <10Oct85>
|
|
MOVEA.L BTCVarPtr(A4),A0 ; locate new index record
|
|
LEA BTVRecord(A0),A0 ;
|
|
MOVEA.L D4,A1 ; ptr(root node buffer)
|
|
MOVE.W #1,D1 ; insert index = 1
|
|
jsrRom romInsertRec ; insert it
|
|
|
|
MOVEA.L D4,A0 ; mark the new root node dirty <10Oct85>
|
|
JSR MarkBlock ; <10Oct85>
|
|
; update BTCB
|
|
;
|
|
ADD.W #1,BTCDepth(A4) ; add a level
|
|
MOVE.L D3,BTCRoot(A4) ; new root node number
|
|
;
|
|
; clean up and exit
|
|
;
|
|
BIExit
|
|
BSET #BTCDirty,BTCFlags(A4) ; mark BTCB dirty
|
|
CLR.W D0 ; result = ok
|
|
BIExit1
|
|
MOVE.W D0,-(A6) ; save result code
|
|
|
|
MOVEA.L A2,A0 ; ptr(left node buffer) <23Sep85>
|
|
MOVEQ #0,D1 ; no RelBlock options <10Oct85>
|
|
JSR RelNode ; release it
|
|
MOVEA.L A3,A0 ; ptr(right node buffer) <23Sep85>
|
|
JSR RelNode ; release it
|
|
MOVEA.L D4,A0 ; ptr(parent node buffer) <23Sep85>
|
|
JSR RelNode ; release it
|
|
MOVE.W (A6)+,D0 ; restore result code
|
|
|
|
MOVE.L BTCNodeM(A4),D2 ; return hint (node number)
|
|
CLR.L BTCNodeM(A4) ; invalidate current record markers
|
|
|
|
jsrRom romBTCleanUP ; clean up
|
|
|
|
ADDQ.L #8,A6 ; deallocate saved stuff
|
|
BIExit2
|
|
MOVEM.L (A6)+,D1/D3-D7/A0-A4 ; restore regs
|
|
|
|
MOVE.L (A6)+,-(SP) ; put return address back on stack
|
|
TST.W D0 ; set condition codes
|
|
RTS ; exit BTInsert
|
|
;__________________________________________________________________________________
|
|
; Routine: BTDelete
|
|
;
|
|
; Function: Increment the Write Count if B*Tree has changed
|
|
; <27Mar91> KST Fixing a bug that uses MOVE.W to move a long word.
|
|
;__________________________________________________________________________________
|
|
FreeNode MOVE.L jFreeNode,-(SP)
|
|
RTS
|
|
|
|
BTDeletePatch
|
|
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
|
|
|
|
MOVEM.L D1-D5/A0-A4,-(A6) ; save regs
|
|
;
|
|
; initialize some things
|
|
;
|
|
jsrRom romBTSetUp ; set up common stuff
|
|
|
|
CLR.L BTCNodeM(A4) ; invalidate current node mark
|
|
|
|
SUBA.L A2,A2 ; ...no left node buffer
|
|
SUBA.L A3,A3 ; ...no right node buffer
|
|
;
|
|
; search tree for key
|
|
;
|
|
jsrRom romTreeSearch ; search for key
|
|
MOVEA.L A1,A3 ; A3 = ptr(node buffer)
|
|
BNE BDExit1 ; didn't find it ->
|
|
MOVE.W D1,D5 ; D5 = record index
|
|
;
|
|
; delete record from node
|
|
;
|
|
BDDelete
|
|
MOVEA.L A3,A1 ; ptr(node buffer)
|
|
MOVE.W D5,D1 ; record index
|
|
jsrRom romDeleteRec ; delete it
|
|
|
|
;; No error checking here, so I assume the file has changed. <8/16/89 KSCT>
|
|
ADDQ.L #1,BTCWcount(A4) ; bump write count <8/16/89 KSCT>
|
|
|
|
MOVEA.L A3,A0 ; ptr(node buffer) <10Oct85>
|
|
JSR MarkBlock ; mark it dirty <10Oct85>
|
|
TST.W D5 ; delete 1st record ?
|
|
BNE.S @1 ; no ->
|
|
BSET #BTCKeyUpd,BTCFlags(A4) ; indicate key update required
|
|
|
|
@1 CMPI.B #NDLeafNode,NDType(A3) ; at leaf level?
|
|
BNE.S BDRemove ; no ->
|
|
SUB.L #1,BTCNRecs(A4) ; decrement number of leaf records
|
|
|
|
;
|
|
; unlink the node if the last record was deleted
|
|
;
|
|
BDRemove
|
|
TST.W NDNRecs(A3) ; node empty ?
|
|
BGT BDNxtLev ; no ->
|
|
|
|
MOVEA.L A3,A0 ; ptr(node buffer)
|
|
jsrRom romGetLtSib ; get left sibling node
|
|
BNE BDExit1 ; error ->
|
|
TST.L D1 ; is there a left sibling ?
|
|
BEQ.S @1 ; no ->
|
|
|
|
MOVE.L NDFlink(A3),NDFlink(A1) ; update forward link
|
|
MOVEQ #kRBdirty,D1 ; release <10Oct85>
|
|
MOVEA.L A1,A0 ;
|
|
JSR RelNode ; ...left node buffer
|
|
|
|
@1 MOVEA.L A3,A0 ; ptr(node buffer)
|
|
jsrRom romGetRtSib ; get right sibling node
|
|
BNE BDExit1 ; error ->
|
|
TST.L D1 ; is there a right sibling ?
|
|
BEQ.S BDUpdPtrs ; no ->
|
|
|
|
MOVE.L NDBlink(A3),NDBlink(A1) ; update backward link
|
|
MOVEQ #kRBdirty,D1 ; release <10Oct85>
|
|
MOVEA.L A1,A0 ;
|
|
JSR RelNode ; ...right node buffer
|
|
;
|
|
; update 1st and last node pointers
|
|
;
|
|
BDUpdPtrs
|
|
CMPI.B #NDLeafNode,NDType(A3) ; at leaf level?
|
|
BNE.S BDFree ; no ->
|
|
|
|
TST.L NDBLink(A3) ; backward link = 0?
|
|
BNE.S @1 ; no ->
|
|
MOVE.L NDFlink(A3),BTCFNode(A4) ; yes, update 1st node number
|
|
|
|
@1 TST.L NDFLink(A3) ; forward link = 0?
|
|
BNE.S BDFree ; no ->
|
|
MOVE.L NDBlink(A3),BTCLNode(A4) ; yes, update last node number
|
|
;
|
|
; free the empty node
|
|
;
|
|
BDFree
|
|
MOVEA.L A3,A0 ; clear the empty node <23Sep85>
|
|
jsrRom romClrNode ; <23Sep85>
|
|
|
|
MOVEQ #kRBdirty,D1 ; release <10Oct85>
|
|
JSR RelNode ; ...node buffer
|
|
SUBA.L A3,A3 ; indicate no buffer
|
|
|
|
MOVE.W BTCLevel(A4),D0 ; locate
|
|
jsrRom romLocTPR ; ...TPR
|
|
|
|
MOVE.L TPRNodeN(A0),D1 ; free
|
|
MOVE.W BTCRefNum(A4),D0 ;
|
|
JSR FreeNode ; ...the disk node
|
|
BSET #BTCDelIRec,BTCFlags(A4) ; indicate index record delete
|
|
BCLR #BTCKeyUpd,BTCFlags(A4) ; ...and no key update
|
|
;
|
|
; move to next level
|
|
;
|
|
BDNxtLev
|
|
SUB.W #1,BTCLevel(A4) ; bump to next level up
|
|
BEQ BDRoot ; up to root level ->
|
|
|
|
BTST #BTCKeyUpd,BTCFlags(A4) ; key update required ? <03Sep85>
|
|
BNE.S @1 ; yes -> <03Sep85>
|
|
BTST #BTCDelIRec,BTCFlags(A4) ; index record delete required ? <03Sep85>
|
|
BEQ BDExit ; no, all done -> <03Sep85>
|
|
|
|
@1 MOVE.W BTCLevel(A4),D0 ; locate TPR
|
|
jsrRom romLocTPR ; for this level
|
|
MOVE.W TPRRIndx(A0),D5 ; D5 = parent record index
|
|
MOVE.L TPRNodeN(A0),D2 ; D2 = parent node number
|
|
|
|
MOVEQ #0,D1 ; get parent node <10Oct85>
|
|
JSR GetNode
|
|
BNE BDExit1 ; error -> <20Nov85>
|
|
MOVEA.L A0,A2 ; A2 = ptr(parent node buffer)
|
|
;
|
|
; update parent key
|
|
;
|
|
BDUpdKey
|
|
BTST #BTCKeyUpd,BTCFlags(A4) ; key update required ?
|
|
BEQ.S @1 ; no ->
|
|
|
|
MOVE.W D5,D0 ; locate
|
|
MOVEA.L A2,A1 ;
|
|
jsrRom romGetRecA ; ...parent index record
|
|
MOVE.L A0,-(SP) ; ...and save it
|
|
MOVE.L A3,A1 ; locate 1st key
|
|
CLR.W D0 ;
|
|
jsrRom romGetRecA ; ...in node
|
|
MOVEA.L (SP)+,A1 ; ptr(parent index record)
|
|
|
|
jsrRom romUpdIKey ; update the key
|
|
|
|
MOVEA.L A2,A0 ; ptr(parent node buffer) <10Oct85>
|
|
JSR MarkBlock ; mark it dirty <10Oct85>
|
|
TST.W D5 ; update to 1st key in node ?
|
|
BEQ.S @1 ; yes, leave flag set ->
|
|
BCLR #BTCKeyUpd,BTCFlags(A4) ; don't need to update next level
|
|
|
|
@1 MOVEQ #0,D1 ; release child <10Oct85>
|
|
MOVE.L A3,A0 ;
|
|
JSR RelNode ; ...node buffer
|
|
MOVEA.L A2,A3 ; new child node = parent node
|
|
MOVE.L D2,D3 ; preserve parent node number <27Mar91 #50>
|
|
; MOVE.L please, not .W <27Mar91 #50>
|
|
;
|
|
; check if done
|
|
;
|
|
BCLR #BTCDelIRec,BTCFlags(A4) ; indx rec delete required ? <03Sep85>
|
|
BEQ.S @2 ; no ->
|
|
BRA BDDelete ; delete parent index record ->
|
|
|
|
@2 BTST #BTCKeyUpd,BTCFlags(A4) ; another key update required ?
|
|
BNE BDNxtLev ; yes ->
|
|
BRA.S BDExit ; no, all done ->
|
|
;
|
|
; up to the root, check for an empty tree
|
|
;
|
|
BDRoot
|
|
MOVE.L A3,D0 ; root node released?
|
|
BNE.S BDUpdDepth ; no ->
|
|
CLR.W BTCDepth(A4) ; set tree to empty state
|
|
CLR.L BTCRoot(A4) ;
|
|
BRA.S BDExit ; exit ->
|
|
;
|
|
; update tree depth
|
|
;
|
|
BDUpdDepth
|
|
CMPI.W #1,NDNRecs(A3) ; check # of records left in root
|
|
BGT.S BDExit ; > 1, all done ->
|
|
TST.B NDType(A3) ; index node ?
|
|
BNE.S BDExit ; no, all done ->
|
|
|
|
SUBQ.W #1,BTCDepth(A4) ; decrement tree depth
|
|
|
|
MOVEQ #0,D1 ; locate key and data for 1st record <10Oct85>
|
|
MOVEA.L A3,A1 ;
|
|
jsrRom LOCREC ; ... in node <10Oct85>
|
|
MOVE.L (A1),BTCRoot(A4) ; new root = child node <10Oct85>
|
|
;
|
|
; release the previous root node
|
|
;
|
|
MOVEA.L A3,A0 ; clear the node buffer <23Sep85>
|
|
jsrRom romClrNode ; <23Sep85>
|
|
|
|
MOVEQ #kRBdirty,D1 ; release the <10Oct85>
|
|
JSR RelNode ; ...node buffer
|
|
SUBA.L A3,A3 ; indicate no buffer
|
|
|
|
MOVE.L D3,D1 ; free
|
|
MOVE.W BTCRefNum(A4),D0 ;
|
|
JSR FreeNode ; ...the node
|
|
; <20Nov85>
|
|
; get new root node and check if depth can be reduced again <20Nov85>
|
|
; <20Nov85>
|
|
MOVE.L BTCRoot(A4),D3 ; D3 = new root node # <20Nov85>
|
|
MOVE.L D3,D2 ; get the new root node <20Nov85>
|
|
MOVEQ #0,D1 ; <20Nov85>
|
|
JSR GetNode ; <20Nov85>
|
|
BNE.S BDExit1 ; error -> <20Nov85>
|
|
|
|
MOVEA.L A0,A3 ; A3 = ptr to node buffer <20Nov85>
|
|
BRA.S BDUpdDepth ; check out new root -> <20Nov85>
|
|
|
|
;
|
|
; release last node and exit
|
|
;
|
|
BDExit
|
|
BSET #BTCDirty,BTCFlags(A4) ; mark BTCB dirty
|
|
CLR.W D0 ; result = ok
|
|
BDExit1
|
|
MOVE.W D0,-(A6) ; save result code
|
|
|
|
MOVEA.L A3,A0 ; ptr(node buffer) <23Sep85>
|
|
MOVEQ #0,D1 ; <10Oct85>
|
|
JSR RelNode ; release it
|
|
MOVE.W (A6)+,D0 ; restore result code
|
|
|
|
jsrRom romBTCleanUP ; clean up
|
|
|
|
MOVEM.L (A6)+,D1-D5/A0-A4 ; restore regs <29Aug85>
|
|
|
|
MOVE.L (A6)+,-(SP) ; put return address back on stack
|
|
TST.W D0 ; set condition codes
|
|
RTS ; exit BTDelete
|
|
|
|
endp
|
|
; End of Catalog Btree writeCount patch
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; Routine: CheckDesktopSupport
|
|
;
|
|
; Input: a2 - pointer to local volume's vcb
|
|
; Output: zero flag clear if we support the desktop on this volume
|
|
; zero flag set if we don't
|
|
;
|
|
; Function: Indicate whether a volume can support the desktop manager calls
|
|
;
|
|
; Only call this on local hfs volumes
|
|
;
|
|
; The rule: A local volume gets desktop support if it is either
|
|
; 1) non-ejectable
|
|
; 2) ejectable but bigger than DTMinVolSize
|
|
;
|
|
; AlkBlkSiz is stored as a long and used as a word throughout HFS
|
|
;________________________________________________________________________________
|
|
; rolled into TFS.a for SuperMario <SM1> FM
|
|
|
|
CDSRegs reg d0/d1/a1
|
|
CheckDesktopSupport: proc
|
|
|
|
movem.l CDSRegs, -(sp)
|
|
|
|
;
|
|
; Is this an MFS volume?
|
|
;
|
|
cmp.w #SigWord,vcbSigWord(a2) ; is this an MFS volume?
|
|
beq.s @NoSupport ; yes, so use the exciting resource file technique
|
|
;
|
|
; Is this volume bigger than DTMinVolSize?
|
|
;
|
|
move.w vcbNmBlks(a2), d0 ; d0 = # of allocation blocks on this volume
|
|
move.w vcbAlBlkSiz+2(a2), d1 ; d1 = allocation block size
|
|
; AlkBlkSiz is used as a word throughout HFS
|
|
mulu.w d1, d0 ; d0 = # bytes on this volume
|
|
cmp.l #DTMinVolSize, d0 ; is this a big volume?
|
|
bhs.s @SupportsDT ; then we always support the DTDB
|
|
;
|
|
; It's not a big volume, but check and see if the volume is ejectable
|
|
;
|
|
move.l DrvQHdr+qHead, a1 ; a1 = ptr (1st drive in Drive Queue)
|
|
|
|
move.w vcbDrvNum(a2), d0 ; d0 = drive number for this volume (if online)
|
|
bne.s @SearchDrvQ ; if it's online, we can go straight to the search
|
|
|
|
move.w vcbDRefNum(a2), d1 ; d1 = + or - DrvNum (since we know we're not online)
|
|
cmp.w d0, d1 ; = means volume is ejected
|
|
beq.s @NoSupport ; which means it gets no DT support
|
|
move.w d1, d0 ; d0 now = -DrvNum (since we know it's offline)
|
|
neg.w d0 ; d0 now = DrvNum, so we can search the drive Q
|
|
;
|
|
; We now have the drive number in d0, and we know that the drive is not big enough to
|
|
; automatically get DT support. We need to see if it is ejectable, and if it is a small
|
|
; non-ejectable volume (say, a ramdisk) we support it.
|
|
;
|
|
@SearchDrvQ:
|
|
cmp.w dQDrive(a1), d0 ; is this the dQ entry we want?
|
|
beq.s @GotDQ
|
|
move.l qLink(a1), d1 ; get the next dQ entry (test for zero)
|
|
movea.l d1, a1 ; move to an A reg where we can use it
|
|
bne.s @SearchDrvQ ; and keep going if there is one
|
|
move.w #nsvErr, d0 ; if we have a real vcb, we should find a dQ entry
|
|
bra.s @NoSupport ; but if we ever don't, let's return 'no support'
|
|
|
|
@GotDQ:
|
|
cmp.b #8, -3(a1) ; drive queue entry flag bytes => 8 (signed) are non-ejectable <19><51>
|
|
blt.s @NoSupport ; we don't support DT on small ejectable volumes
|
|
|
|
@SupportsDT:
|
|
moveq.l #1, d0 ; clear the zero flag
|
|
bra.s @CDSExit
|
|
|
|
@NoSupport:
|
|
moveq.l #0, d0 ; set the zero flag
|
|
@CDSExit: movem.l (sp)+, CDSRegs
|
|
rts
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; 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).
|
|
; 1) The bclr #asyncTrpBit,ioTrap(a0) instruction is old cruft. The two problems with
|
|
; the line are that (a) forcing GetVolParms calls synchronous will hang interrupt-time
|
|
; callers, and (b) the line doesn't even do what it says. The trap word is in d1
|
|
; before the call to FSQueue. ioTrap is about have d1 stored in it. If you are possessed
|
|
; of the urge to put your initials into the system, perhaps you could replace the bclr
|
|
; with a store of 16 bits of your own choosing.
|
|
; 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.
|
|
;
|
|
;________________________________________________________________________________
|
|
;
|
|
GetVolParms: proc export
|
|
@GetVolRegs reg d2/d3/a1-a4
|
|
|
|
bclr #asyncTrpBit, ioTrap(a0) ; force synchronous (wrong. See note, above)
|
|
jsrRom FSQUEUE ; Patiently wait our turn in line
|
|
movem.l @GetVolRegs, -(a6) ; save regs on FS stack
|
|
suba.w @VolParmsBufferSize, a6 ; allocate a GetVolParms buffer on the stack
|
|
;
|
|
; Find the VCB in question:
|
|
;
|
|
jsrRom 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:
|
|
movem.l (a6)+, @GetVolRegs ; restore regs
|
|
jmpROM 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
|
|
endproc
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; Desktop Manager and Queue Manager initialization
|
|
;________________________________________________________________________________
|
|
|
|
; FSVars has been allocated by btree patches. Allocate the DTDBMgr's globals block
|
|
DTDBMgrInit proc export
|
|
|
|
move.l #DTGlobals.size, d0 ; we need this much space for DT manager
|
|
_NewPtr sys, clear
|
|
bne @fail ; no? Run away.
|
|
move.l FSVarsPtr, a1 ; a1 = ptr(FSVars block)
|
|
move.l a0, FSVars.DTDBMgr(a1) ; stuff ourselves into our slot in FSVars
|
|
rts
|
|
|
|
@fail
|
|
moveq.l #dsMemFullErr, d0 ; sys heap is full, so punt
|
|
_SysError
|
|
endproc
|
|
|
|
; Allocate the Queue Manager's globals block
|
|
QMInit proc export
|
|
|
|
; Allocate a block big enough of all of the Queue Manager's needs:
|
|
; Queue manager globals
|
|
; Desktop manager QMRec
|
|
; Compatibility layer QMRec
|
|
; Desktop manager stack
|
|
; Compatibility layer stack
|
|
|
|
move.l #QMGlobals.size+QMRec.size*2+DTStackSize+clStackSize, d0
|
|
_NewPtr sys, clear
|
|
bne.s @fail ; fail if we can't get memory
|
|
|
|
move.l FSVarsPtr, a1 ; a1 = ptr(FSVars block)
|
|
move.l a0, FSVars.QMgr(a1) ; leave a pointer to globals in FSVars
|
|
move.l a0, a1 ; a1 = ptr(FSVars.QMgr)
|
|
adda.l #QMGlobals.size, a0 ; skip over globals
|
|
move.l a0, QMGlobals.DTQueuePtr(a1); stuff pointer to DTMgr's QMRec
|
|
adda.l #QMRec.size, a0 ; skip over DTMgr's QMRec
|
|
move.l a0, QMGlobals.CLQueuePtr(a1); stuff pointer to Comp Layer's QMRec
|
|
|
|
adda.l #QMRec.size+DTStackSize, a0 ; skip over QMRec and Stack
|
|
move.l QMGlobals.DTQueuePtr(a1), a1 ; a1 = ptr(DTMgr's QMRec)
|
|
move.l a0, QMRec.stackBase(a1) ; store stack address (stack grows down)
|
|
move.w #desktopQType, QMRec.qType(a1) ; set queue type/refnum
|
|
|
|
adda.l #CLStackSize, a0 ; skip to end of CLStack
|
|
move.l FSVarsPtr, a1 ; a1 = ptr(FSVars)
|
|
move.l FSVars.QMgr(a1), a1 ; a1 = ptr(QM globals)
|
|
move.l QMGlobals.CLQueuePtr(a1), a1 ; a1 = ptr(Comp Layer's QMRec)
|
|
move.l a0, QMRec.stackBase(a1) ; store stack address (stack grows down)
|
|
move.w #fsCompatQType, QMRec.qType(a1) ; set queue type/refnum
|
|
|
|
rts
|
|
|
|
@fail:
|
|
moveq.l #dsMemFullErr, d0 ; sys heap is full, so punt
|
|
_SysError
|
|
endproc
|
|
|
|
|
|
; __________________________________________________________________________________
|
|
PROC ; <2.3 kst>
|
|
EXPORT WriteCountInit, FSGrowPatchInit
|
|
|
|
; Need to fix up the volumes that don't have a chance to call my BTOpenPatch !
|
|
WriteCountInit
|
|
MOVEM.L A2-A3,-(SP) ; free A2,A3
|
|
MOVEA.L FCBsPtr,A3 ; A3=FCB array
|
|
MOVE.L VCBQHdr+QHead,D0 ; search the VCB queue
|
|
BEQ.S wcEndq ; br if end of queue reached
|
|
CkVol: MOVE.L D0,A2 ; next VCB pointer
|
|
jsrRom TFSVCBTST ; is this a HFS volume?
|
|
BNE.S @6 ; No, don't bother
|
|
TST vcbFSID(A2) ; internal HFS? (do we need to test this?)
|
|
BNE.S @6 ; No, don't bother
|
|
;; OK, it's for us, replace the BTCB of the B*tree files on this volume.
|
|
;; First process the EXT file:
|
|
MOVE vcbXtRef(A2),D1 ; D1=EXT file refnum
|
|
BEQ.S @4 ; just in case
|
|
@2 MOVE.L #lenBTCB70,D0 ; allocate space for BTCB
|
|
_NewPtr sys, clear
|
|
bne.s WCErrExit ; couldn't get it ->
|
|
MOVEA.L fcbBTCBPtr(A3,D1),A1 ; get the original BTCB
|
|
MOVE.L A0,fcbBTCBPtr(A3,D1) ; replace with the new one
|
|
MOVE.L #WCSigLong,BTCWcount(A0); .. and set the write count
|
|
|
|
MOVE.L #(LenBTCB/2-1),D0 ; length of BTCB - 1
|
|
MOVE.L A1,-(SP) ; save old btcb
|
|
@4 MOVE (A1)+,(A0)+ ; copy over
|
|
DBF D0,@4
|
|
MOVEA.L (SP)+,A0 ; free the old btcb
|
|
_DisposPtr
|
|
CMP vcbCtRef(A2),D1 ; is this CAT file refnum?
|
|
BEQ.S @6 ; br if it is, otherwise,
|
|
;; ... and then process the CAT file:
|
|
MOVE vcbCtRef(A2),D1 ; D1=CAT file refnum
|
|
BNE.S @2
|
|
|
|
@6 MOVE.L QLink(A2),D0 ; next VCB
|
|
BNE.S CkVol
|
|
|
|
wcEndq LeaResident BTOpenPatch,A1 ; start of BTOpen Patch code
|
|
MOVE.L A1,jBTOpen ; replace the old one ($744)
|
|
LeaResident BTInsertPatch,A1
|
|
MOVE.L A1,jBTInsert ; ($740)
|
|
LeaResident BTDeletePatch,A1
|
|
MOVE.L A1,jBTDelete ; ($734)
|
|
MOVEM.L (SP)+,A2-A3
|
|
RTS
|
|
|
|
WCErrExit:
|
|
MOVEQ #dsMemFullErr,D0 ; no mem
|
|
_SysError
|
|
|
|
;__________________________________________________________________________________
|
|
; <41>
|
|
; Enlarge the File System stack.
|
|
;
|
|
; Inputs:
|
|
; none
|
|
;
|
|
; Output:
|
|
; none
|
|
;
|
|
; Function:
|
|
; Queue up a dummy call (use the dispatch selector as if we were _FSControl)
|
|
; so we can safely replace the file system stack with a larger one. Throw
|
|
; up a bomb if we fail.
|
|
;
|
|
;__________________________________________________________________________________
|
|
; Don't need to Roll into SuperMario <SM1> fm
|
|
GrowFileSystemStack:
|
|
|
|
moveq.l #0,d0 ; use selector 0
|
|
move.w #$a060,d1 ; and pretend we're trap _HFSDispatch
|
|
jsrROM FSQUEUE ; and sync up with the file system
|
|
|
|
; first we use the old equate to get the pointer block's base address
|
|
move.l HFSStkTop,a0 ; current stack top
|
|
suba.w #HFSStkLen,a0 ; compute pointer block address
|
|
_DisposePtr ; free it up
|
|
|
|
; use the new equate to allocate a larger stack
|
|
move.l #(fsLargerStackLength+HFSTmpSize),d0 ; Size of stack area
|
|
_NewPtr sys, clear ; Allocate space in system heap
|
|
bne.s @bail ; A crushing blow if we can't get it
|
|
adda.w #fsLargerStackLength,a0 ; point to the end of the stack
|
|
move.l a0,HFSStkTop ; Store pointer in lo-mem
|
|
|
|
moveq.l #noErr,d0 ; success!
|
|
jmpROM CMDDONE
|
|
|
|
@bail:
|
|
moveq.l #dsMemFullErr, d0 ; sys heap is full, so punt
|
|
_SysError
|
|
|
|
;__________________________________________________________________________________
|
|
;
|
|
; Initialize FCB expansion patch, WDCB expansions patch, and vectors
|
|
;__________________________________________________________________________________
|
|
; Roll into SuperMario <SM1> fm
|
|
FSGrowPatchInit:
|
|
suba.w #ioHVQElSize,sp ; param blocks are de rigeur
|
|
movea.l sp,a0
|
|
bsr GrowFileSystemStack ; we need a bigger stack for 7.0 <41>
|
|
adda.w #ioHVQElSize,sp ; deallocate the pb
|
|
|
|
; 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
|
|
; subq #2,d0 ; remove header (doesn't affect divu)
|
|
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 WCErrExit ; 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
|
|
; subq #2,d0 ; remove header (doesn't affect divu)
|
|
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 WCErrExit ; 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
|
|
|
|
endproc
|
|
|
|
; __________________________________________________________________________________
|
|
; 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.
|
|
;
|
|
; __________________________________________________________________________________
|
|
; Rolled into TFS.a for SuperMario <SM1> fm
|
|
InstallVectors PROC export
|
|
|
|
; slam onto fsQueueHook, ExtFSHook and jFileOpen
|
|
|
|
LeaResident fsQueueHookPatch, a0 ; our patch address
|
|
move.l a0, fsQueueHook ; be the first ones
|
|
|
|
LeaResident ExtFSHookPatch, a0 ; our patch address <38>
|
|
move.l a0, ExtFSHook ; be the first ones <38>
|
|
|
|
LeaResident PreflightFileOpen, a0 ; our patch address <38>
|
|
move.l a0, jFileOpen ; be the first ones <38>
|
|
|
|
; install some vectors:
|
|
move.l ExpandMem, a1
|
|
leaResident vSyncWait, a0 ; get addr of syncwait (in this fsQueueHook patch)
|
|
move.l a0, ExpandMemRec.jSyncWait(a1)
|
|
leaResident vAfterFSQHook, a0 ; get addr just past call to fsQueueHook (in fsQueueHook patch)
|
|
move.l a0, ExpandMemRec.jAfterFSQHook(a1)
|
|
|
|
leaROM CMDDONE , a0 ; get addr of CmdDone (still in ROM)
|
|
move.l a0, ExpandMemRec.jCmdDone(a1)
|
|
leaResident fsGeneralWakeUp, a0 ; get addr of general purpose File System kickstart
|
|
move.l a0, ExpandMemRec.jDispatchNext(a1)
|
|
|
|
leaResident fsSCSIFreeHookProc, a0; get addr of File System SCSI Busy deferral completion
|
|
move.l a0, ExpandMemRec.jSCSIFreeHook(a1)
|
|
|
|
rts
|
|
endproc
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
|
|
; Rolled into InitFS in TFS.a for SuperMario.
|
|
; <SM1> FM
|
|
;
|
|
HFS70Init InstallProc
|
|
|
|
IF BuildHFS70Init THEN ; HfsInit will allocate FSVarsPtr again and
|
|
; destroys BTVars initialized by patch
|
|
move.l FSVarsPtr,D0 ; has this been initialized?
|
|
cmp.l #-1,D0 ; $FFFF FFFF if not
|
|
bne.s @fsVarOK ; already initialized
|
|
|
|
ENDIF
|
|
|
|
move.l #FSVars.size, d0 ; d0 = size of file system variable block
|
|
_NewPtr sys, clear ; go get the block
|
|
bne @fail ; 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
|
|
|
|
@fsVarOK:
|
|
IF NOT BuildHFS70Init THEN ; don't allocate memory again
|
|
jsr FSGrowPatchInit ; FCBs, WDCBs and vectors
|
|
jsr QMInit ; initialize the Queue Manager
|
|
jsr DTDBMgrInit ; initialize desktop DB manager
|
|
ENDIF
|
|
jsr WriteCountInit ; for Write Count patch <2.3 kst>
|
|
jsr InstallVectors
|
|
rts
|
|
|
|
@fail:
|
|
moveq.l #dsMemFullErr, d0 ; sys heap is full, so punt
|
|
_SysError
|
|
endproc
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; <48>
|
|
; Patches to ROM btree manager routine on the Mac Plus. These routines incorrectly
|
|
; calculate the size of btree vars, returning a value 4 bytes too small. The routines
|
|
; which then use btree vars will trash the last register saved. These patches work around
|
|
; the problem by saving the register in question on the a6 stack before running the routine.
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
|
|
; Plus only, No need to roll in for SuperMario!
|
|
SaveD1AcrossBTDelete PatchProc jBTDelete,(Plus)
|
|
|
|
move.l (sp)+,-(a6) ; copy return address onto the A6 stack
|
|
move.l d1,-(a6) ; save register which will be trashed
|
|
jsrOld
|
|
move.l (a6)+,d1
|
|
move.l (a6)+,-(sp) ; get back the return address
|
|
tst.w d0 ; set up condition codes again
|
|
rts
|
|
|
|
EndProc
|
|
|
|
; Plus only, No need to roll in for SuperMario!
|
|
SaveD3AcrossBTSearch PatchProc jBTSearch,(Plus)
|
|
|
|
move.l (sp)+,-(a6) ; copy return address onto the A6 stack
|
|
move.l d3,-(a6) ; save register which will be trashed
|
|
jsrOld
|
|
move.l (a6)+,d3
|
|
move.l (a6)+,-(sp) ; get back the return address
|
|
tst.w d0 ; set up condition codes again
|
|
rts
|
|
|
|
EndProc
|
|
|
|
; Plus only, No need to roll in for SuperMario!
|
|
SaveD1AcrossBTInsert PatchProc jBTInsert,(Plus)
|
|
|
|
move.l (sp)+,-(a6) ; copy return address onto the A6 stack
|
|
move.l d1,-(a6) ; save register which will be trashed
|
|
jsrOld
|
|
move.l (a6)+,d1
|
|
move.l (a6)+,-(sp) ; get back the return address
|
|
tst.w d0 ; set up condition codes again
|
|
rts
|
|
|
|
EndProc
|
|
|
|
; Plus only, No need to roll in for SuperMario!
|
|
SaveD3AcrossBTGetRecord PatchProc jBTGetRecord,(Plus)
|
|
|
|
move.l (sp)+,-(a6) ; copy return address onto the A6 stack
|
|
move.l d3,-(a6) ; save register which will be trashed
|
|
jsrOld
|
|
move.l (a6)+,d3
|
|
move.l (a6)+,-(sp) ; get back the return address
|
|
tst.w d0 ; set up condition codes again
|
|
rts
|
|
|
|
EndProc
|
|
|
|
;_______________________________________________________________________
|
|
; <49>
|
|
; MountVolFor1991 creates a need to prevent the ROM CheckRemount code from
|
|
; running, since it handles remounts, and has a stricter rule than the ROM code.
|
|
; On the Portable, II, and IIci, we can simply point the CheckRemount vector
|
|
; past the end of the CheckRemount routine. On the Plus and SE, we have
|
|
; to do a come-from patch on BTOpen and AccessBT to get the same effect.
|
|
; This patch needs to be after the earlier BTOpen patch, which is installed
|
|
; by an InstallProc towards the end of the file.
|
|
;_______________________________________________________________________
|
|
; Rolled in to TFSVol.a <SM1> FM
|
|
|
|
KillCheckRemountNiceWay InstallProc (Portable,II,IIci)
|
|
|
|
leaROM MtVolOK,a0 ; point to the end of the CheckRemount routine
|
|
move.l a0,jCheckRemount ; point CheckRemount vector past the routine
|
|
rts
|
|
|
|
EndProc
|
|
|
|
KillCheckRemountSickWay PatchProc jBTOpen,(Plus,SE)
|
|
|
|
cmpROM AfterBTOpenInAccessBT,(sp) ; check to see if this is AccessBT
|
|
bneOld
|
|
cmpROM After2ndAccessBTInMountVol,8(a6) ; check to see if this is the case just before remount
|
|
bneOld
|
|
|
|
addq #4,sp ; pull off return address
|
|
jsrOld ; call BTOpen, and return here
|
|
movem.l (a6)+,d3/a0 ; restore registers saved by AccessBT
|
|
addq #4,a6 ; throw away return address to MountVol
|
|
tst.w d0 ; check result of AccessBT
|
|
bneROM After2ndAccessBTInMountVol ; if we failed, go let the ROM his thing
|
|
bclr #vcbAtVOK,vcbAtrb(a2) ; from now until _Unmount the disk is inconsistent
|
|
beqROM MtCheck ; if so, go do the check (below patches will skip CheckRemount)
|
|
jmpROM MtVolOK ; otherwise, skip CheckRemount
|
|
|
|
EndProc
|
|
|
|
KillCheckRemountSickerWay PatchProc jReadBM,(SE)
|
|
|
|
cmpROM AfterReadBMInUpdateFree,(sp) ; check to see if this is UpdateFree
|
|
bneOld
|
|
cmpROM AfterUpdateFreeInMtCheck,36(a6) ; check to see if this is at the end of MtCheck
|
|
bneOld
|
|
leaROM MtVolOK,a0 ; get address for skipping CheckRemount
|
|
move.l a0,36(a6) ; return there, so we donÕt branch to CheckRemount
|
|
jmpOld
|
|
|
|
EndProc
|
|
|
|
KillCheckRemountSickestWay PatchProc jGetBlock,(Plus)
|
|
|
|
cmpROM AfterGetBlockInGetBMBlk,(sp) ; check to see if this is GetBMBlk
|
|
bneOld
|
|
cmpROM AfterGetBMBlkInReadBM,16(a6) ; check to see if this is ReadBM
|
|
bneOld
|
|
cmpROM AfterReadBMInUpdateFree,20(a6) ; check to see if this is UpdateFree
|
|
bneOld
|
|
cmpROM AfterUpdateFreeInMtCheck,60(a6) ; check to see if this is at the end of MtCheck
|
|
bneOld
|
|
leaROM MtVolOK,a0 ; get address for skipping CheckRemount
|
|
move.l a0,60(a6) ; return there, so we donÕt branch to CheckRemount
|
|
jmpOld
|
|
|
|
EndProc
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
|
|
End
|