; ; Hacks to match MacOS (most recent first): ; ; 8/3/92 Reverted by putting back the "ROM" prefixes. Rolled in the 6/22/92 ; change that was made to the TFSRFN2.a version of ClosePatch: ; namely, disabled the patch with a short branch. ; 9/2/94 SuperMario ROM source dump (header preserved below) ; ; ; File: FileMgrPatches.a ; ; Contains: Patches to the file system. ; ; Copyright: © 1990-1992 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 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) ROMBUILDKEY ROMBind (Plus,$065d8), (SE,$080a0), (II,$0BB64), (IIci,$12f40), (Portable, $0d50a) ;ex Put back "ROM" ROMBTDELETE ROMBind (Plus,$0671c), (SE,$081e6), (II,$0bcaa), (IIci,$13090), (Portable, $0d650) ;ex Put back "ROM" ROMBTGETRECORD ROMBind (Plus,$06928), (SE,$083fc), (II,$0bec0), (IIci,$132A6), (Portable, $0d866) ;ex Put back "ROM" ROMBTINSERT ROMBind (Plus,$069ea), (SE,$084b4), (II,$0bf78), (IIci,$1335E), (Portable, $0d91e) ;ex Put back "ROM" ROMBTSEARCH ROMBind (Plus,$06d4a), (SE,$0880c), (II,$0c2d0), (IIci,$136B6), (Portable, $0dc76) ;ex Put back "ROM" ROMBTUPDATE ROMBind (Plus,$06dd6), (SE,$08896), (II,$0c35a), (IIci,$13740), (Portable, $0dd00) ;ex Put back "ROM" ROMCACHERDIP ROMBind (Plus,$07b2a), (SE,$0967e), (II,$0d13e), (IIci,$1459C), (Portable, $0eb44) ;ex Put back "ROM" romChgMFlLock ROMBind (Plus,$046de), (SE,$06812), (II,$0a2e8), (IIci,$11694), (Portable, $0bc7c) ROMCHKNODE ROMBind (Plus,$072c2), (SE,$08e22), (II,$0c8e6), (IIci,$13D42), (Portable, $0e2ec) ;ex Put back "ROM" romCkExtFS ROMBind (Plus,$03638), (SE,$050be), (II,$08b80), (IIci,$0fefa), (Portable, $0a4e2) romCkFilMod ROMBind (Plus,$0497a), (SE,$06420), (II,$09eec), (IIci,$11298), (Portable, $0b880) ROMCMDDONE ROMBind (Plus,$0295e), (SE,$043a0), (II,$07e48), (IIci,$0f04c), (Portable, $0964c) ;ex Put back "ROM" ROMCMFLUSH ROMBind (Plus,$06606), (SE,$080ce), (II,$0BB92), (IIci,$12f6e), (Portable, $0d538) ;ex Put back "ROM" ROMCMGETCN ROMBind (Plus,$06238), (SE,$07d04), (II,$0b7c8), (IIci,$12ba2), (Portable, $0d16e) ;ex Put back "ROM" ROMCMSETUP ROMBind (Plus,$065a0), (SE,$08068), (II,$0bb2c), (IIci,$12f06), (Portable, $0d4d2) ;ex Put back "ROM" romCMUpdateCN ROMBind (Plus,$0656c), (SE,$08036), (II,$0bafa), (IIci,$12ed4), (Portable, $0d4a0) ROMCVFLGS ROMBind (Plus,$03a76), (SE,$05502), (II,$08FCA), (IIci,$10344), (Portable, $0a92c) ;ex Put back "ROM" romDtrmV1 ROMBind (Plus,$03650), (SE,$050e2), (II,$08ba4), (IIci,$0ff1e), (Portable, $0a50c) ROMDTRMV3 ROMBind (Plus,$03642), (SE,$050ce), (II,$08b90), (IIci,$0ff0a), (Portable, $0a4f8) ;ex Put back "ROM" ROMEXTOFFLINCK ROMBind (Plus,$04aba), (SE,$06560), (II,$0A02C), (IIci,$113d8), (Portable, $0b9c0) ;ex Put back "ROM" romFindDrive ROMBind (Plus,$03414), (SE,$04e9A), (II,$08956), (IIci,$0FC6C), (Portable, $0A258) ROMFNDFILNAME ROMBind (Plus,$04990), (SE,$06436), (II,$09f02), (IIci,$112ae), (Portable, $0b896) ;ex Put back "ROM" romFSAsync ROMBind (Plus,$02912), (SE,$04354), (II,$07dfc), (IIci,$0f000), (Portable, $09600) ROMFSQUEUESYNC ROMBind (Plus,$028a6), (SE,$042e8), (II,$07d90), (IIci,$0ef94), (Portable, $09594) ;ex Put back "ROM" ROMFSQUEUE ROMBind (Plus,$028aa), (SE,$042ec), (II,$07d94), (IIci,$0ef98), (Portable, $09598) ;ex Put back "ROM" romGt1stMatch ROMBind (Plus,$04002), (SE,$05a9c), (II,$0955c), (IIci,$108d6), (Portable, $0aebe) romLocCNode ROMBind (Plus,$06678), (SE,$0813e), (II,$0BC02), (IIci,$12FDE), (Portable, $0d5a8) ROMLOCCREC ROMBind (Plus,$06698), (SE,$0815e), (II,$0bc22), (IIci,$12FFE), (Portable, $0d5c8) ;ex Put back "ROM" ROMLOCREC ROMBind (Plus,$07538), (SE,$0908c), (II,$0cb50), (IIci,$13FAC), (Portable, $0e556) ;ex Put back "ROM" romMarkVCB ROMBind (Plus,$02d1e), (SE,$04766), (II,$0820e), (IIci,$0F524), (Portable, $09b10) romMarkVCBTime ROMBind (Plus,$02d20), (SE,$04768), (II,$08210), (IIci,$0F526), (Portable, $09b12) ROMPOPCNAME ROMBind (Plus,$04288), (SE,$05d28), (II,$097EA), (IIci,$10b96), (Portable, $0b17e) ;ex Put back "ROM" ROMPUSHCNAME ROMBind (Plus,$04258), (SE,$05cf8), (II,$097BA), (IIci,$10b66), (Portable, $0b14e) ;ex Put back "ROM" romRfnCall ROMBind (Plus,$05352), (SE,$06e04), (II,$0a8c8), (IIci,$11C86), (Portable, $0c26e) ROMTFSVCBTST ROMBind (Plus,$04ec6), (SE,$06968), (II,$0a43e), (IIci,$117ea), (Portable, $0bdd2) ;ex Put back "ROM" ROMUPDCNAME ROMBind (Plus,$066c2), (SE,$0818c), (II,$0BC50), (IIci,$1302C), (Portable, $0d5f6) ;ex Put back "ROM" romUpdRtCnts ROMBind (Plus,$065be), (SE,$08086), (II,$0BB4A), (IIci,$12f24), (Portable, $0d4f0) romUpdVCnts ROMBind (Plus,$065ae), (SE,$08076), (II,$0BB3A), (IIci,$12f14), (Portable, $0d4e0) ROMXFFLUSH ROMBind (Plus,$05ed0), (SE,$0799a), (II,$0B45E), (IIci,$1282a), (Portable, $0ce04) ;ex Put back "ROM" ROMGT1STFCB ROMBind (Plus,$03ff2), (SE,$05a8c), (II,$0954c), (IIci,$108c6), (Portable, $0aeae) ;ex Put back "ROM" ROMGTNXTFCB ROMBind (Plus,$03ffa), (SE,$05a94), (II,$09554), (IIci,$108ce), (Portable, $0aeb6) ;ex Put back "ROM" ROMFLUSHCACHE ROMBind (Plus,$076c6), (SE,$0921a), (II,$0ccdc), (IIci,$1413a), (Portable, $0e6e2) ;ex Put back "ROM" ; 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. 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. VolumeCall: proc jsrROM ROMFSQUEUE ; Patiently wait our turn ex Put back "ROM" jsrROM ROMDTRMV3 ; Determine the volume being referred to ex Put back "ROM" 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. entry RefNumCall RefNumCall: import RefNumCheck jsrROM ROMFSQUEUE ; chill in line ex Put back "ROM" 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. entry UnknownCall UnknownCall: jsrROM ROMFSQUEUE ; Wait our turn ex Put back "ROM" ; 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. entry OpenCall OpenCall: import OpenAttemptHook jsrROM ROMFSQUEUE ; Wait our turn ex Put back "ROM" jsrROM ROMDTRMV3 ; Determine the volume being referred to ex Put back "ROM" 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 ROMGT1STFCB ; get (A1,D1) pointing to first FCB ex Put back "ROM" @1 tst.l FCBFlNm(a1,d1) ; FCB unused beq.s @90 ; br if so jsrROM ROMGTNXTFCB ; get next one until we run out ex Put back "ROM" 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 ROMCMDDONE ; And call it a day. ex Put back "ROM" 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. 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. 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 MakePatch SetFilLock,_SetFilLock MakePatch RstFilLock,_RstFilLock SetFilLock: proc export export RstFilLock JSRRom ROMFSQUEUE ; wait our turn ex Put back "ROM" ST FLckUnlck ; want to lock it BRA.S SRFLck RstFilLock: jsrROM ROMFSQUEUE ; ex Put back "ROM" CLR.B FLckUnlck SRFLck jsrROM romCkFilMod ; look for file and see if we can mod it ; (doesn't return on errors) JSRROM ROMTFSVCBTST ; Are we dealing with a TFS volume? <01Oct85> ex Put back "ROM" 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 ROMCMDDONE ; ex Put back "ROM" 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 ROMFSQUEUE ; wait our turn ex Put back "ROM" 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 ROMCMDDONE ; outa here ex Put back "ROM" 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 ; : ; *** NOTE: THIS PATCH IS DISABLED *** ; ; This patch was broken in System 7, and fixed with change <53>. The fix ; ; causes some third-party applications (QuicKeys, Retrospect Remote) to stop ; ; working because they are unable to close files. For Cube-E, we’ll re-break this ; ; patch and revisit the entire issue later. ; ; bra.s @DoClosePop ; <58> Disable this patch ; ; 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 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 FixVolumeRenames PatchProc _Rename jsrROM ROMFSQUEUE ; what a queue command! ex Put back "ROM" 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 ROMCMDDONE ; ex Put back "ROM" 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 ROMCMDDONE ; ex Put back "ROM" jsrROM ROMDTRMV3 ; Check source volume ex Put back "ROM" bneROM ROMCMDDONE ; Punt if no such thing ex Put back "ROM" jsrROM ROMCVFLGS ; Can it be modified? ex Put back "ROM" bneROM ROMCMDDONE ; Nope - punt now. ex Put back "ROM" jsrROM ROMTFSVCBTST ; Is it a TFS volume? ex Put back "ROM" beq.s @checkExtFS ; Yes - make sure it's not ext. FS tst.w vcbDrvNum(a2) ; Volume on-line? beqROM ROMCMDDONE ; No - just forget it ex Put back "ROM" jmpROM RNMVol@70 ; Yes - go and rename it @checkExtFS: jsrROM ROMEXTOFFLINCK ; Our file system, on-line volume? ex Put back "ROM" bneROM ROMCMDDONE ; If not, get out now ex Put back "ROM" jmpROM RNMVol@70 ; Otherwise, same as ever BadNewNam: moveq.l #bdNamErr,d0 ; get the error code jmpROM ROMCMDDONE ; outa here ex Put back "ROM" 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 ROMFSQUEUE ; Wait our turn ex Put back "ROM" jsrROM romDtrmV1 ; Determine volume by drvnum/refnum bne SVIDone ; Punt on errors jsrROM ROMCVFLGS ; Check if volume can be modified ex Put back "ROM" bne SVIDone ; Give up easily jsrROM ROMEXTOFFLINCK ; Check if volume is on-line, non ext. FS ex Put back "ROM" 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 ROMTFSVCBTST ; Is it a TFS volume? ex Put back "ROM" 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 ROMTFSVCBTST ; Are we dealing with an MFS volume? ex Put back "ROM" 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 ROMCMDDONE ; ex Put back "ROM" 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 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 ROMPOPCNAME ; remove name from A6 stack ex Put back "ROM" @RNmExit cmp.w #BTExists,D0 ; B*-Tree error? bne.s @FinalExit moveq #dupFNErr,D0 ; If entry exists, give better error code @FinalExit jmpRom ROMCMDDONE ; and now back to our regularly scheduled broadcast... ex Put back "ROM" ; 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 ;; 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 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 ; 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 ; 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 ; 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 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 ROMLOCCREC ; ex Put back "ROM" 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 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 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 ROMFSQUEUE ; serialize things ex Put back "ROM" 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 ROMFSQUEUE ; serialize things ex Put back "ROM" 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 ROMFSQUEUE ; wait our turn ex Put back "ROM" 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: jsr MoreFCBs ; try to get the FCBs ex Put back "ROM" 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 ROMCMDDONE ; ex Put back "ROM" @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 ROMFSQUEUESYNC ; ex Put back "ROM" 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 ROMTFSVCBTST ; remounted a TFS volume? <32> ex Put back "ROM" 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 ROMCMDDONE ; ex Put back "ROM" 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 ROMFSQUEUESYNC ; wait until all current calls are done ex Put back "ROM" st NoEject ; -1 = send offline but don't eject jmp OfflineEjectCommon ; share code with Eject endproc NoCloseOnEject PatchProc _Eject export OfflineEjectCommon jsrROM ROMFSQUEUESYNC ; wait until all current calls are done ex Put back "ROM" clr.b NoEject ; 0 = offline + eject OfflineEjectCommon jsrROM ROMDTRMV3 ; check name, drive number, etc. ex Put back "ROM" 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 ROMCMDDONE ; we're done . . . ex Put back "ROM" 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 ROMTFSVCBTST ; Are we dealing with a TFS volume? ex Put back "ROM" 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 ROMCVFLGS ; Is volume write protected? <31> ex Put back "ROM" 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 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 jsr DesktopCloseDownProc ; go take care of the desktop database <36> ex ; The desktop file hack should no longer be necessary for the 7.0 version of the AppleShare client. IncludeAppleShareDesktopHack equ 0 jsrROM ROMFSQUEUESYNC ; Get in sync... ex Put back "ROM" clr.b FlushOnly ; Setup same as UnmountVol jsrROM ROMDTRMV3 ; Call DtrmV3 to do setup stuff ex Put back "ROM" bneROM ROMCMDDONE ; and split on errors ex Put back "ROM" 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 ROMCMDDONE ; and quit on errors ex Put back "ROM" FlUnMnt: jsrROM romCkExtFS ; see if it's for an external fs bneROM ROMCMDDONE ; and split on errors ex Put back "ROM" jsrROM FlushVFiles ; flush all files on this volume bneROM ROMCMDDONE ; and split on errors ex Put back "ROM" ; All files on this volume are flushed now. Update the volume information as ; appropriate, depending on the file structure: jsrROM ROMTFSVCBTST ; is this a TFS volume? ex Put back "ROM" 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 ROMCMDDONE ; ex Put back "ROM" 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 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 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 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 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 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 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 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 proc entry TagFileWithPSN TagFileWithPSN ; Open traps can be (and are!) called before Process Mgr is init'd jsr ProcessMgrExists ; is Process Mgr ready? ex Put back "ROM" 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 ROMGT1STFCB ; A1=FCB, D1=1st RefNum ex Put back "ROM" ; 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 ROMFSQUEUE ; Wait for our turn to come ex Put back "ROM" jsrROM ROMFNDFILNAME ; Look for the indicated directory ex Put back "ROM" 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 ROMCMDDONE ; we're finished . . . ex Put back "ROM" ; 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 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 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 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 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 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 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 ROMGT1STFCB ; get (A1,D1) pointing to first FCB <11Dec90 #17> ex Put back "ROM" @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 ROMGTNXTFCB ; get next one until we run out <11Dec90 #17> ex Put back "ROM" 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 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 ROMLOCREC ; ... in node <10Oct85> ex Put back "ROM" 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 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 ROMFSQUEUE ; Patiently wait our turn in line ex Put back "ROM" 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 ROMDTRMV3 ; find vol using ioNamePtr & ioVRefNum (D023/A234 trashed) ex Put back "ROM" 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 ROMCMDDONE ; Go home ex Put back "ROM" ; 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 ROMTFSVCBTST ; is this a HFS volume? ex Put back "ROM" 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 fm GrowFileSystemStack: moveq.l #0,d0 ; use selector 0 move.w #$a060,d1 ; and pretend we're trap _HFSDispatch jsrROM ROMFSQUEUE ; and sync up with the file system ex Put back "ROM" ; 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 ROMCMDDONE ; ex Put back "ROM" @bail: moveq.l #dsMemFullErr, d0 ; sys heap is full, so punt _SysError ;__________________________________________________________________________________ ; ; Initialize FCB expansion patch, WDCB expansions patch, and vectors ;__________________________________________________________________________________ ; Roll into SuperMario 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 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 ROMCMDDONE, a0 ; get addr of CmdDone (still in ROM) ex Put back "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. ; 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 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