; ; File: TFSVOL.a ; ; Contains: This file contains mostly volume-level routines for the Turbo ; File System. ; ; Copyright: © 1984-1993 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 8/27/93 BH Backed out SetVolInfo changes from . The flushing stuff is ; now in CmdDone. ; 8/3/93 BH Changed MountVol to set the manual-eject flag in the VCB for ; volumes mounted in manual-eject drives. Changed SetVolInfo to ; flush changed critical volume info for manual-eject drives. ; <6> 3/10/93 gs Fix bug #1063340 in MountVol MtCheck to prevent an overflow when ; determining the maximum number of leaf records for the Catalog ; and Extents b*trees. ; 3/9/93 CSS Fix Radar bug #1059140. The patch for UnmountForTheNineties ; was applied incorrectly. The patch only closed the control files ; on Unmounting the volume. They did this by patching only the ; _Unmount trap. SuperMario rolled it in line with FlUnMnt which is ; shared by _FlushVol and _Unmount. Rather than roll it only into ; _Unmountvol, I coditionalized the new code with a test against FlushOnly ; this should keep the code from executing in the Flush case. This is ; a lower risk solution than moving code around now (Cyclone is beta). ; 12/1/92 RB Exported PickWDCB so it can be vectorized for FSM use. ; 10/22/92 CSS Change some branch short instructions to branches. ; 5/21/92 kc Append "Trap" to the names of Dequeue, EnQueue, Eject, ; UnMountVol, FlushVol, GetVol, SetVol, OpenWD, CloseWD and ; GetWDInfo to avoid name conflict with the glue. ; 4/1/92 kc Rolled in OpenWDPatch, FixDtrmV3, MountVolFor1991, KillCheckRemountNiceWay ; NoCloseOnOffline and NoCloseOnEject and UnmountForTheNineties ; from FileMgrPatches.a ; • Pre-SuperMario comments follow • ; <2> 9/13/91 JSM Add a header. ; <1.6> 6/12/89 JB Changed UnmountVol to disallow unmounting of volumes with open ; files EXCEPT FOR the following: files with FNum < $10 (internal ; system files), files with FNum == 'GRT ' (AppleShare hack). ; External file system "internal files" are now included in the ; check such that they may unmount sucessfully with internal files ; left open. ; <1.5> 4/3/89 MSH Put in the AppleShare hack for unmount. ; <1.4> 3/21/89 CSL change JSR to DEQueue and EnQueue to BSR.L to fix link error. ; <1.3> 3/2/89 DNF removed references to forROM; HFS now builds identically for ram ; or rom ; <1.2> 11/16/88 CCH Took out include of "nTraps.a" ; <1.1> 11/10/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <1.0> 2/11/88 BBM Adding file for the first time into EASE… ; 11/4/87 JB (C958) Rolled in changes to UnmountVol from the following ; patches: PM243, PA244, PB245, and PMAB271. Moved the label ; 'FlUnMnt' 2 instructions forward (branched to only from ; UnMountVol). ; 2/19/87 BB Vectored MtCheck, FindDrive, CheckReMount, and DtrmV2. ; 12/10/86 BB Removed range check in XferVName, neither BufPtr or MemTop are ; valid upper limits in the Twitcher environment. Also added use ; of StripAddress in XferVName. [SHF: added include for ntraps.a ; for _StripAddress.] ; 10/27/86 BB Vectored DtrmV3,CkExtFS, and BMChk routines. ; 10/24/86 BB Changed range check in XferVName to use MemTop rather than ; BufPtr. ; 10/2/86 BB Fixed bug in MountVol (wasn't saving D0 accross a CmpString ; call. ; 10/1/86 WRL Set offset to zero before doing VCB pointer check in routine ; CkWDRefnum in TFSVOL.a. ; 9/16/86 BB Fixed rename problem in MountVol (use of pointer to a cache ; buffer). ; 9/15/86 BB Added check for a zero VCB pointer in CkWDRefNum indicating that ; the WD is already closed. ; 4/15/86 PWD fix bug in GetWDRefNum (one path forgot to init high word of D1 ; before doing a DIVU. ; 1/13/86 LAK Incorporated fix to remount check from ROM75Fix. ; 10/29/85 LAK Vectored DtrmV1 routine. ; 10/28/85 PWD Changed to pass control call to drivers anyway if 64 <= DIP <= ; 127 mung VCB as for _Offline call for these drivers. Changed ; NoEject from byte-boolean to a tri-state flag: -1 [offline], 0 ; [eject], or +1[special eject call]. ; 10/27/85 PWD Changed _GetVolInfo to ignore volume control files in ; determining volume busy status. Set attributes bit 5 if default ; on this volume. ; 10/24/85 LAK Fixed Eject bug (FlushBuffers wasn't preserving D2 which FClose ; clobbers). ; 10/20/85 LAK Added LEOF remount checking for MFS volumes. ; 10/14/85 PWD Added ReadWDCB routine for external file system support. Moved ; remount check to last step in MountVol. Added DumpCaches routine ; to dispose of cache blocks with defunct VRefNum/VCBPtr [on ; remount]. Added LEOF check again. ; 10/13/85 PWD Fixed bug in GetVolInfo: don't try to read working directory ; valence for external FS volumes. ; 10/11/85 PWD Changed GetVolInfo to pin NmAlBlks and NmFrBlks at ; (32767*1000)/1024 instead of 32767 for programs that figure in ; 'decimal K' ; 10/11/85 PWD Backed out of LEOF check on remount for Beta-ROMs. The current ; algorithm fails to correctly back out of a remount attempt, ; leaving the original VCB changed. Maybe we can dispose of it ; somehow?? Restore its original state?? ; 10/10/85 LAK Call new routine MarkVCBDirty for Eject/Unmount and Mount to ; avoid changing the modification date for just the consistency ; bit (Finder gets infinitely confused otherwise in resync loop on ; single-drive system). ; 10/7/85 PWD Changed to separate out BMChk routine, use it to check 1st ; B*-Tree extent allocation status. Added code to check LEOF of ; open file on remount. ; 10/6/85 PWD Threw in SetVolName for use in SetVolInfo (from TFSDir2). ; 10/4/85 PWD Fixed bug in GetVol, SetVol (test D1 bit rather than IOTrap(A0) ; bit). ; 10/1/85 LAK Munged MountVol a lot to share code with MFS mount (which now ; uses the volume cache). Removed AdjustIntErr: this function is ; now done in CmdDone. MountVol modified to test for ; Offline/Ejected vol after call to GetVCBDrv which now also looks ; for these. No longer save first 4 bytes of non-Mac disk in ; FSTemp4 for Format package since it can't tell anyways. Call ; Offline on TMFOErr also at MountVol. ; 9/30/85 PWD Move PMSP hook to correct place. If HFSBit is set in GetVol ; call, go to GetDir. ; 9/26/85 PWD Added SetupDef entry point for raw internal access from external ; FS. ; 9/25/85 PWD Overhauled PMSP: removed root from directories considered; added ; support for PMSPHook and PMSP Enable/Disable calls. Left ; interrupts enabled during search of FCB table. ; 9/24/85 PWD Fixed bug (MOVE.L vs. MOVEM.L) in directory valence lookup in ; GetVolInfo ; 9/24/85 PWD Changed SetVol to branch to SetDir when TFS bit is set. ; 9/22/85 PWD Fixed setting of DefVRefNum in SetVol, changed OpenWD to allow ; MFS volumes as argument if directory is root, changed HSetVol ; (a.k.a. SetDir) to allow MFS volumes specified by name, changed ; MountVol to set up new VCB fields for B*-Tree allocation sizes, ; changed GetVolInfo to subtract B*-Tree allocation from NmAlBlks, ; and return directory valence instead of root valence if ; directory referenced is not the root. ; 9/21/85 LAK Call FlushCache with D0=volume refnum, not 0 (this option no ; longer supported). This is more efficient (we used to trash all ; cache blocks for all volumes when we ejected or unmounted a ; volume) as well as being easier on the cache. ; 9/8/85 LAK Don't mount the volume if a catalog loop is detected. Call ; UpdateFree as part of MountVol consistency check. Zero roving ; allocation ptr on mount. Save first 4 bytes of non-Mac disk in ; FSTemp4 for Format package so it can discern Apple II diskettes. ; 9/6/85 LAK Slight modification to DtrmV3 prefix to prevent passing to ; DtrmVol if IOFileName points to a zero-length string (for the ; dubious result of making CatMove work with a zero-length string ; . . .). ; 9/5/85 LAK Set CacheFlag before flushing control cache. ; 8/31/85 LAK Made XferVName a bit more robust. Fixed GetWDInfo call bug. ; Mount scan now sets an inconsistent bit if it had to mark a bit ; in the allocation map . . . ; 8/30/85 LAK Added calls to TrashVBlks for Mount/UnmountVol. Rewrote ; DtrmVl/3. Fixed bug causing extents tree scan to be skipped. ; 8/29/85 LAK Call FlushMDB BEFORE closing the catalog and extents file FCBs ; in UnMountVol. Rewrote Eject mess . . . it's always synchronous ; now. ; 8/28/85 LAK Some changes to use WDCB lookup routines in TFSDir2. ; 8/27/85 LAK Much munging and saving in the InitCache, RelCache stuff. ; 8/22/85 PWD Changed _HGetVolInfo to return VRefNum in ioVRefNum field. ; 8/15/85 PWD Changed _GetVolInfo to return ioVFilCnt and ioVDirCnt. ; 8/6/85 PWD Fixed bugs in external FS treatment: changed _(TF)GetVolInfo to ; pass control to external FS AFTER stuffing I/O PB fields. ; 7/12/85 PWD Added MarkVCB routine to set VCB dirty instantly ; 7/11/85 PWD Moved FlushMDB routine into TFSCommon ; 6/29/85 PWD Fixed bug in mount to set up default WDCB when first volume is ; mounted in addition to setting DefVCBPtr. ; 6/20/85 PWD Changed to use combined file/directory CNode numbering Changed ; to return volRefNum on GetVolInfo and GetWDInfo ONLY if no WDCB ; was specified, or if a volume name was used. ; 6/19/85 PWD Changed non-hardware internal errors to FSDSIntErr instead of ; IOErr. ; 5/14/85 PWD Added SetVolInfo trap. ; 5/11/85 PWD Changed MountVol to share caches between volumes in a system to ; allow use on 128K machines ; 5/10/85 PWD Added TFGetVolInfo ; 5/1/85 PWD Added GetWDInfo ; 4/25/85 PWD Changed _Eject to leave non-ejectable volumes online, but call ; the driver anyway. Fixed code to turn all disk errors into IOErr ; before returning to the user. ; 4/25/85 PWD Fixed bug in OpenWD due to missing BRA to successful completion ; Fixed bug in GetWDCBRfn from double offset. ; 4/22/85 PWD Fixed FlushVol to write VCBLsMod date. ; 3/14/85 PWD Added WD code (OpenWD, CloseWD, SetDir, GetDir). ; 3/12/85 LAK FSVol/Eject: save and restore IOCompletion address over async ; FlushVol call (so Eject part of Eject may be done ; asynchronously). ; 2/12/85 PWD Adapted for use in Turbo FS from original Mac FS code: split ; MFS-specific code off into MFSVol, changed MountVol, UnMountVol, ; FlushVol, OffLine and Eject to handle TFS volumes and pass MFS ; volume matters to appropriate MFSVol entries. Added ; FindFCB,AccessBT, and FreeFCB routines ; 1/25/85 LAK Uncommented status call in MountVol. Use EnQueue, DeQueue ; routines directly. ; 8/7/84 GSS New today. ; ; ;_______________________________________________________________________ ; ; External Routines: MountVol,UnMountVol,GetVol,SetVol, ; FlushVol,GetVolInfo,SetVolInfo,Eject,Offline, ; OpenWD,CloseWD,SetDir,GetDir ; ; Internal Routines: DtrmVol,FindDrive,CVFlgs,CkExtFS, ; FindFCB,AccessBT ; ;_______________________________________________________________________ ;_______________________________________; ; ; ; MakeStkPB utility . . . ; ;_______________________________________; BLANKS ON STRING ASIS MakeStkPB MOVE.L (SP)+,A0 MOVEQ #(IOVQElSize/2)-1,D0 @1 CLR.W -(SP) ; get IO param block off stack DBRA D0,@1 ; (with IOFileName zeroed) MOVE.L A0,-(SP) MOVE.L SP,A0 ADDQ #4,A0 RTS ;_______________________________________________________________________ ; ; Routine: MountVol ; Arguments: A0 (input) -- pointer to volume parameter block, uses: ; IOVDrvNum (name not allowed) ; D0 (output) -- error code ; This call is executed synchronously. ; Calls: FSQueueSync,GetVCBDrv,GetVCBRfn,FindDrive,CmdDone, ; ; Function: The VCB pointers are checked to see if a volume in the ; specified drive is already on-line (error if so). Reads in the ; directory master block and allocates memory for VCB and additional ; data structures, depending on the volume type: ; ; - For MFS volumes (handled in MFSVol), space is allocated for ; a volume buffer, as well as the block map, which is read in ; from disk). ; ; - For TFS volumes, space is allocated for a bitmap cache, a volume ; control cache (for B*-Tree use), and a volume cache. In addition, ; two FCBs are used by the B*-Trees. ; ; No new VCB storage is allocated for remounts. ; ; 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. ; ; Modification History: ; ; 07 Aug 84 GSS New today ; 26 Oct 84 RFA Commented out Status call since Ron's driver doesn't support it ; 25 Jan 85 LAK Uncommented above call for Mac. ; 12 Feb 85 PWD Adapted for use with TFS Volumes; pass control to MFSMount ; for MFS volumes. ; 14 Feb 85 PWD Changed to link VCB into VCB queue immediately (it's needed ; for GetBlock to work. Unlink before passing control to MFSVol ; 27-Feb-85 PWD Fixed cache release code: use RelCache to dispose of vol. cache, ; and removed vol. cache code from DsposCaches (vol. cache is ; released in DsposBuf). ; 25-Apr-85 PWD Changed to return IOErr on internal errors. ; 11-MAy-85 PWD Changed to allocate caches only for first TFS volume, and share ; the caches on a system-wide basis with subsequently mounted volumes. ; 24-Jun-85 PWD Changed to update root name from volume name in VCB on mount ; 23-Jul-85 PWD Changed disk recognition algorithm to use only SigWord, ; CrDate, and volume name. ; 24-Jul-85 PWD Added increment of VCBWrCnt on mount to account for last ; write of MDB. Changed to copy information fresh from MDB ; into existing VCB on remount. ; 22-Aug-85 PWD Changed to flush MDB after mount with consistency flag cleared. ; <27Aug85> LAK Got rid of all calls to InitCache, RelCache. Added subroutine ; AdjustIntErr. Removed support for SysCRefcnt. Minor cleanup. ; <30Aug85> LAK Fixed bug causing extents tree scan to be skipped. ; <08Sep85> LAK Don't mount the volume if a catalog loop is detected. Call UpdateFree ; as part of MountVol consistency check. Zero roving allocation ptr on ; mount. ; 22-Sep-85 PWD Added code at mount to compute VCBXTAlBks and VCBCTAlBks. ; <01Oct85> LAK Removed AdjustIntErr: this function is now done in CmdDone. ; <07Oct85> PWD Changed to check 1st B*-Tree extent allocations status in cons. check ; Changed to check LEOF of open files on remount. ; <11Oct85> PWD Backed out of LEOF check on remount for Beta-ROMs. ; <14Oct85> PWD Changed to do all remount checking (including LEOF) immediately before ; a successful return. ; <03Nov85> LAK Fixed bug in MountVol out-of-memory (Mountvol has replaced IODrvNum in ; user parameter block with bogus vrefnum). ; This helps us in tight memory situations. ;_______________________________________________________________________ ; Rolled in MountVolFor1991 patch from FileMgrPatches.a MountVol: bsr FSQueueSync ; wait until all current calls are done movea.l a0, a5 ; save caller's pb move.w ioDrvNum(a5), d2 ; where FindDrive likes it bsr FindDrive ; get driver refnum in D1 (drive num still in D2) bne MtVolDone 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 RemountExit 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 RemountExit @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 RemountExit ; exit if 0 andi.w #$01FF,d3 ; 512-byte multiple? bne RemountExit ; 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 RemountExit ; we fail if we don't see a remount CSS 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 IF hasManEject THEN ; BSR SetVCBManEject ; set vcb maneject flag appropriately ENDIF ; jsr TFSVCBTst ; remounted a TFS volume? <32> bne.s NoRemountErrExit ; Nope - don't mess with the MDB <33> btst.b #vcbWrProt,vcbAtrb+1(a2); Is volume write protected? <32> bne.s NoRemountErrExit ; If so, don't try to flush the MDB <33> bclr.b #vcbAtVOK,vcbAtrb(a2) ; From now 'til unmount we're dirty <32> jsr MarkVCBDirty ; mark VCB dirty so it will be written <32> jsr FlushMDB ; write it <32> NoRemountErrExit: moveq.l #noErr,d0 RemountExit: adda.w #512, a6 ; deallocate MDB buffer tst.w d0 ; check the error beq.s CmdDone ; 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) bne CmdDone ; let the error stand ST NewMount ; assume now that it's a new volume ; First see if the disk is already mounted. mv_Start MOVEQ #ParamErr,D0 MOVE.W IOVDrvNum(A0),D2 ; drive number BLE.S toMVDone ; br if none specified MOVE.W D2,D0 ; see if there's a vol already mounted BSR GetVCBDrv ; BNE.S mv_getDrive ; br if not TST.W VCBDrvNum(A2) ; is it offline? <01Oct85> BEQ.S mv_getDrive ; br if so . . . (probably a remount) <01Oct85> MOVEQ #VolOnLinErr,D0 ; report an error toMVDone BRA MtVolDone ; Find the appropriate drive queue entry and allocate a VCB. mv_getDrive: BSR FindDrive ; get driver refnum in D1 (drive num still in D2) BNE.S toMVDone ; br if not found or for external FS MOVE.L A0,A2 ; preserve A0 a bit MOVE.L #VCBLength,D0 ; get memory for VCB _NewPtr ,SYS,CLEAR ; off the system heap, zeroed ; Note: VCBFSID,VCBDirIndex,VCBFlags are 0, as well as VCBXTRef, VCBCTRef, ; VCBMAdr, VCBCtlBuf, and VCBBufAdr. BNE.S toMVDone ; exit if we got no memory LEA VCBQHdr,A1 ; Point to head of VCB queue TST.L QHead(A1) ; Check: is queue empty right now? BNE.S @1 ; If not, never mind MOVE.L A0,DefVCBPtr ; If empty, this is now default, too. MOVE.L WDCBsPtr,A1 ; Point to WDCB array MOVE.L A0,WDVCBPtr+2(A1) ; Set default VCB pointer in default WDCB MOVEQ #FSRtDirID,D0 ; Default to root directory MOVE.L D0,WDDirID+2(A1) ; Set directory to default to CLR.L WDCatHint+2(A1) ; Clear catalog hint CLR.L WDProcID+2(A1) ; And procID of WDCB 'owner' LEA VCBQHdr,A1 ; Reset A1 for VCB insertion @1 JSR EnqueueTrap ; Insert the new VCB in the queue EXG A0,A2 ; VCB ptr MOVE.W D2,VCBDrvNum(A2) ; put drive number MOVE.W D1,VCBDRefNum(A2) ; and driver refnum into VCB IF hasManEject THEN ; BSR SetVCBManEject ; set vcb maneject flag appropriately ENDIF ; MOVEA.L SysVolCPtr,A1 ; set up A1 MOVE.L A1,VCBBufAdr(A2) ; always use system-wide cache . . . ; Assign a refNum to this new volume. MOVEQ #0,D0 ; Begin with a clean slate mv_GetVRef SUBQ.W #1,D0 ; Start with -1 and count down MOVEM.L D0/A2,-(SP) BSR GetVCBRfn ; Check if already assigned MOVEM.L (SP)+,D0/A2 ; BEQ.S mv_GetVRef ; If EQ, VRefNum already assigned MOVE.W D0,VCBVRefNum(A2) ; note for us CMP.L DefVCBPtr,A2 ; Are we supposedly the default? BNE.S mv_GetMDB ; Nope - don't worry about it. MOVE.W D0,DefVRefNum ; Set up default VRefNum now, too ; Now try reading in the master directory block. mv_GetMDB: MOVEQ #0,D1 ; Clear flag bytes MOVEQ #2,D2 ; MDB is always block 2 (third block on disk) JSR GetBlock ; With A1 still pointing to volume CQH. BNE MtVolEr2 ; Quit & Release VCB on errors <02Sep85> MOVE.L A0,A5 ; Save buffer ptr for later <01Oct85> ; Now check what manner of animal we have before us: MOVEQ #kRBTrash,D1 ; trash it in case VCB gets reused . . .<01Oct85> JSR RelBlock ; Release hold on cache block <02Sep85> CMP.W #TSigWord,DrSigWord(A5) ; Does it bear the Turbo Seal? <08Sep85> BEQ.S mv_GotMDB ; If so, give it the full treatment <01Oct85> MOVEQ #NoMacDskErr,D0 ; Assume it's for another file system. <01Oct85> CMP.W #SigWord,DrSigWord(A5) ; Is it a trustworthy MFS volume? <08Sep85> BNE MtVolEr2 ; br if not <01Oct85> ; Now do a little more checking before starting to use the data. mv_GotMDB: MOVEQ #BadMDBErr,D0 ; in case master directory block is bad MOVE.L DrAlBlkSiz(A5),D1 ; make sure this is non-zero, 512 multiple BEQ MtVolEr1 ; exit if 0 (shared MFS/TFS exit) AND.W #$01FF,D1 ; 512-byte multiple? BNE MtVolEr1 ; exit if not (shared MFS/TFS exit) ; The MDB seems OK: transfer all master directory info from buffer into VCB. LEA VCBDInfoSt(A2),A1 ; Destination is in VCB MOVEQ #VCBDILen,D0 ; Length of MFS/TFS info in MDB _BlockMove ; Copy the information MV_GetWPStatus: MOVE.L FSQHead,A0 ; A0 -> current request MOVE.W VCBVRefNum(A2),IOVRefNum(A0) ; return volume refnum to user LEA Params,A0 ; general purpose I/O param block 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 #-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 ; Now the MFS code diverges from the TFS code. BSR TFSVCBTst ; Is it an MFS volume? <01Oct85> BNE MV_GetMFSMap ; Br if so (do the MFS-specific stuff) <01Oct85> LEA DrTInfoSt(A5),A0 ; Advance pointer to additional TFS stuff LEA VCBTDInfoSt(A2),A1 ; Point to additional TFS-specific info MOVEQ #VCBTDILen,D0 ; Length of additional information _BlockMove ; Copy the additional information in MOVE.L VCBAlBlkSiz(A2),D1 ; Pick up allocation block size <22Sep85> MOVE.L DrXTFlSize(A5),D0 ; Pick up PEOF of extent B*-Tree <22Sep85> JSR DivUp ; Divide (AlBlkSiz MUST BE <64KB!) <22Sep85> MOVE.W D0,VCBXTAlBks(A2) ; Store result for use in GetVolInfo <22Sep85> MOVE.L DrCTFlSize(A5),D0 ; Pick up PEOF of catalog B*-Tree <22Sep85> JSR DivUp ; Compute its allocation similarly <22Sep85> MOVE.W D0,VCBCTAlBks(A2) ; And store the result for later use <22Sep85> CLR.W VCBAllocPtr(A2) ; Restart the roving allocation ptr <08Sep85> ADDQ.L #1,VCBWrCnt(A2) ; Compensate for write of MDB on last flush ; Try to find two free FCBs for use by the volume control B*-Trees: BSR FindFCB ; Try to find a free FCB (set up D0/D1/A1) BNE MtVolErr ; Br if we failed to find one <01Oct85> MOVE.W D1,VCBXTRef(A2) ; Set Extents B*-Tree file RefNum MOVE.L DrXTFlSize(A5),FCBEOF(A1,D1) ; Set extent tree's LEOF <01Oct85> MOVE.L DrXTFlSize(A5),FCBPLen(A1,D1) ; Set extent tree's PEOF <01Oct85> MOVEQ #lenXDR,D0 ; Length of extent record LEA DrXTExtRec(A5),A0 ; Point to only XT extent record LEA FCBExtRec(A1,D1),A1 ; Point to extent record in FCB <01Oct85> _BlockMove ; Copy in the extent record BSR FindFCB ; Try to find another FCB (set up D0/D1/A1) BNE MtVolErr ; Punt on error MOVE.W D1,VCBCTRef(A2) ; Save catalog file refNum MOVE.L DrCTFlSize(A5),FCBEOF(A1,D1) ; Set catalog tree's LEOF <01Oct85> MOVE.L DrCTFlSize(A5),FCBPLen(A1,D1) ; Set catalog tree's PEOF <01Oct85> MOVEQ #lenXDR,D0 ; Length of extent record LEA DrCTExtRec(A5),A0 ; Point to first catalog extent record LEA FCBExtRec(A1,D1),A1 ; Point to extent record in FCB <01Oct85> _BlockMove ; Copy in the extent record MOVE.L SysBMCPtr,VCBMAdr(A2) ; Set up the volume bitmap cache MOVE.L SysCtlCPtr,VCBCtlBuf(A2) ; Set up the volume control cache ; Finish setting up the FCBs for the extent B*-Tree and the catalog B*-Tree: MOVE.W VCBXTRef(A2),D0 ; Get extent-tree refNum MOVEQ #FSXTCNID,D1 ; extent-tree file ID MOVE.L VCBXTClpSiz(A2),D2 ; clump size MOVE.L VCBCtlBuf(A2),A1 ; extent-tree cache LEA FXMKeyCmp,A3 ; Key comparison routine for extent tree BSR AccessBT ; Set up access to B*-Tree file BNE MtChkErr ; Exit on errors <01Oct85> MOVE.W VCBCTRef(A2),D0 ; Get catalog-tree refNum MOVEQ #FSCTCNID,D1 ; catalog-tree file ID MOVE.L VCBCTClpSiz(A2),D2 ; clump size MOVE.L VCBCtlBuf(A2),A1 ; catalog-tree cache LEA CMKeyCmp,A3 ; Key comparison routine for catalog tree BSR AccessBT ; Set up access to B*-Tree file BNE MtChkErr ; Exit on errors <01Oct85> BCLR #VCBAtVOK,VCBAtrb(A2) ; From now until _Unmount <22Aug85> ; ... the disk is inconsistent <22Aug85> BEQ MtCheck ; If it was clear, do the time consuming <01Oct85> ; disk check ; NOTE: The MFS code re-joins this common thread of execution here: CheckRemount: MOVE.L jCheckRemount,-(SP) ; jump table entry for vCheckRemount <19Feb87> RTS ; go there <19Feb87> vCheckRemount ; 'vectored' CheckRemount routine <19Feb87> ; Deleted stuff patched out by KillCheckRemountNiceWay in FileMgrPatches.a MtVolOK MOVEQ #0,D0 ; no errors MtVolDone TST.W D0 ; Any errors encountered? BNE.S @1 ; Yes - leave well enough alone, then BSR TFSVCBTst ; Mounted a TFS volume? BNE.S @1 ; Nope - don't mess with the MDB BTST #VCBWrProt,VCBAtrb+1(A2) ; Is volume write protected? BNE.S @1 ; If so, don't try to flush the MDB BSR MarkVCBDirty ; Make sure it's marked dirty <10Oct85> BSR FlushMDB ; Flush the MDB out to mark the volume inconsistent @1 BRA CmdDone ; return to command finish MtChkErr MOVE.W D0,HFSDSErr ; Save the error code for debugging <01Oct85> MOVEQ #badMDBErr,D0 ; Indicate the MDB is bad for all internal errors ; Release any resources allocated so far before exiting with an error: MtVolErr BSR DsposFCBs ; deallocate control file FCBs ; The following two exits are shared with MFS mount code . . . MtVolEr1 BSR DsposVBlks ; invalidate any cache blocks for this volume MtVolEr2 TST.B NewMount ; only deallocate VCB for new mounts BEQ.S @1 ; remount case BSR DsposVCB ; new mount -- get rid of VCB @0 TST.W D0 ; Check: was this a real error? (or OK Mount) BLE CmdDone ; Yes - We're all done, then. MOVE.L FSQHead,A0 ; A0 -> current request BRA mv_Start ; So start all over again, but don't even THINK ; about the possibility of a ReMount this time. ; Remount case -- Must zero buffer and map ptrs in old VCB. ; Restore VCB to its original off-line state (ie clear VCBDrvNum, ; and move drive number to VCBDRefNum field) @1 ADDA #VCBDrvNum, A2 ; A2 --> drive number field of VCB MOVE.W (A2),D3 ; D3 = drive number CLR.W (A2)+ ; clear drive number field of VCB MOVE.W D3,(A2)+ ; write drv number to VCBDRefNum field ADDQ #4,A2 ; A2 --> VCB's buffptr field CLR.L (A2)+ ; clear buffptr in VCB CLR.L (A2)+ ; clear mapptr in VCB BRA.S @0 ; <27Aug85> ; Before releasing the volume to the world, do some quick consistency checks ; (and possibly some patch-ups) on the volume: ; ; 1. Make sure the name of the root reflects the volume name in the VCB: MtCheck: MOVE.L jMtCheck,-(SP) ; jump table entry for vMtCheck <19Feb87> RTS ; go there <19Feb87> vMtCheck ; 'vectored' MtCheck routine <19Feb87> MOVEQ #FSRtDirID,D0 ; Root directory ID MOVEQ #0,D2 ; No catalog hint MOVE.L D2,A0 ; Nil CName JSR CMGetCN ; Look up the root directory BNE.S MtChkErr ; Punt on errors MOVEQ #0,D0 ; Clear all unused bytes LEA ckrCName(A0),A1 ; Point to CName in key MOVE.B (A1)+,D0 ; Pick up length byte SWAP D0 ; Stash 'second' string length LEA VCBVN(A2),A0 ; Source is volume name MOVE.B (A0)+,D0 ; Pick up 'first' string length SWAP D0 ; Put things in order for _CmpString _CmpString ,MARKS,CASE ; EVERYTHING counts here... BEQ.S BMScan ; If this is OK, check the rest of the catalog ; the names don't match, check length of volume name SUBQ.L #1,A1 ; Point back to root name again <16Sep86> SUBQ.L #1,A0 ; Point back to volume name again <16Sep86> MOVEQ #0,D0 ; Pick up length byte <02Oct86> MOVE.B (A0),D0 ; <02Oct86> BEQ.S @2 ; use root name if zero -> <16Sep86> CMPI.W #VCBMaxNam,D0 ; check if length greater than max <16Sep86> BLE.S @1 ; br if not -> <16Sep86> MOVE.B #VCBMaxNam,(A0) ; truncate it to max length <16Sep86> ; the length of volume name is ok, rename the root directory @1 MOVEQ #FSRtDirID,D0 ; root DirID <16Sep86> MOVEA.L A0,A1 ; volume name is new name <16Sep86> SUBA.L A0,A0 ; use only the DirID to identify root <16Sep86> MOVEQ #0,D2 ; no hint <16Sep86> JSR CMRenameCN ; rename the root directory <16Sep86> BNE.S MtChkErr ; punt on errors <16Sep86> BRA.S BMScan ; continue with bit map check <16Sep86> ; the length of the volume name is zero, check root name length @2 MOVEQ #0,D0 ; Pick up length byte <02Oct86> MOVE.B (A1),D0 ; <02Oct86> BEQ MtChkErr ; give up if root name is zero also <16Sep86> CMPI.W #VCBMaxNam,D0 ; check if length greater than max <16Sep86> BLE.S @3 ; br if not -> <16Sep86> MOVEQ #VCBMaxNam,D0 ; truncate it to max length <16Sep86> ; the root name length is ok, change volume name to root name @3 MOVE.B D0,(A0)+ ; move in the length byte <16Sep86> SUBQ.W #1,D0 ; adjust D0 for DBRA <16Sep86> ADDQ.L #1,A1 ; position pass root name length byte <16Sep86> @4 MOVE.B (A1)+,(A0)+ ; move in <16Sep86> DBRA D0,@4 ; .. the name <16Sep86> ; EXG A0,A1 ; Sigh - CMRename likes 'em differently <16Sep86> ; MOVEQ #FSRtParID,D0 ; This directory exists in the root parent <16Sep86> ; ; JSR CMRenameCN ; Change the name <16Sep86> ; BNE MtChkErr ; Punt on errors <16Sep86> ; 2. Make sure the bitmap reflects the allocation status of all extent records: BMScan: MOVE.L FCBsPtr,A1 ; Point to FCB table <07Oct85> MOVE.W VCBXTRef(A2),D1 ; Pick up extent B*-tree refNum <07Oct85> LEA FCBExtRec(A1,D1),A0 ; Point to extent record there <07Oct85> BSR BMChk ; Check this extent record <07Oct85> MOVE.W VCBCTRef(A2),D1 ; Pick up catalog B*-Tree refNum <07Oct85> LEA FCBExtRec(A1,D1),A0 ; Point to extent record for B*-Tree <07Oct85> BSR BMChk ; Check this extent's allocation status <07Oct85> ; Start by scanning the remainder of the catalog to verify all extent ; records in the catalog: MOVEQ #FSRtDirID,D0 ; Root directory ID ; Use catalog hint in D2 SUBA.L A0,A0 ; Generate a nil CName JSR CMGetCN ; Look up the root directory BNE MtChkErr ; Punt on errors MOVEA.L FCBsPtr,A1 ; Point to the FCBs MOVE.W VCBCTRef(A2),D1 ; Pick up the catalog refNum ; Before starting a scan of the catalog, make a conservative estimate of the ; upper limit of B*-Tree records that could conceivably be encountered in a ; scan of all leaf nodes by dividing the catalog's PEOF by the size of the ; smalles CNode (a directory entry): MOVE.L FCBPLen(A1,D1),D0 ; Pick up the catalog size in bytes LSR.L #6,D0 ; divide by 64 (less than smallest record size) MOVE.L D0,D2 ; D2 = max. number of CNodes possible MOVEQ #FSUsrCNID-1,D4 ; Reset largest CNID found <29Aug85> MOVEQ #0,D3 ; Clear inconsistency flag MOVEQ #0,D5 ; Clear file count MOVEQ #0,D6 ; Clear directory count MOVEQ #0,D7 ; Clear root content counts (high & low) CTScan: SUBQ.L #1,D2 ; Count down by ones BLT MtChkErr ; No mounting on loop errors <08Sep85> @10 MOVE.W VCBCTRef(A2),D0 ; Catalog tree refNum MOVEQ #1,D1 ; Get first record following current record MOVE.L D2,-(A6) ; Save record count across call JSR BTGetRecord ; MOVE.L (A6)+,D2 ; Restore record count, destroying hint. TST.W D0 ; Check for error on BTGetRecord BNE.S @90 ; Punt on errors CMP.B #cdrDirRec,cdrType(A1) ; Is this a directory? BNE.S @25 ; If not, check for files ADDQ.L #1,D6 ; Bump the total directory count CMP.L #FSRtDirID,ckrParID(A0) ; Is this directory in the root? BNE.S @15 ; If not, nothing special SWAP D7 ; Get access to the high word ADDQ.W #1,D7 ; Bump the root directory count SWAP D7 ; And store it back. @15 CMP.L dirDirID(A1),D4 ; Is this DirID bigger than cur. maximum? BHS.S CTScan ; If not, keep looking MOVE.L dirDirID(A1),D4 ; Otherwise, retain this new high BRA.S CTScan ; And ignore directories otherwise @25 CMP.B #cdrFilRec,cdrType(A1) ; Is this a file? BNE.S CTScan ; If not, just keep on looking ADDQ.L #1,D5 ; Bump the total file count CMP.L #FSRtDirID,ckrParID(A0) ; Is this directory in the root? BNE.S @30 ; If not, nothing special ADDQ.W #1,D7 ; Bump the root file count @30 CMP.L filFlNum(A1),D4 ; Is this file number a new maximum? BCC.S @50 ; If not, just check its allocation MOVE.L filFlNum(A1),D4 ; Otherwise, remember this peak ; Check the blocks allocated to this file (both forks): @50 LEA filExtRec(A1),A0 ; Point to extent record for data fork BSR BMChk ; Check its allocation status <07Oct85> LEA filRExtRec(A1),A0 ; Point to extent record for resource fork BSR BMChk ; Check its allocation status <07Oct85> BRA.S CTScan ; Go for the next record @90 CMP.W #BTNotFound,D0 ; Was record not found? BNE MtChkErr ; Punt on other errors VCBChk: CMP.L VCBNxtCNID(A2),D4 ; Is the maximum found in scan consistent? BCS.S @10 ; If so, that's nice [expected] ADDQ.L #1,D4 ; Otherwise, THIS is the next CNode ID MOVE.L D4,VCBNxtCNID(A2) ; Record the new maximum BSET #0,VCBAtrb+1(A2) ; Mark error in VCB attributes MOVEQ #-1,D3 ; Mark a scan error @10 CMP.L VCBFilCnt(A2),D5 ; Check total number of files on volume BEQ.S @20 ; If same, continue MOVE.L D5,VCBFilCnt(A2) ; Otherwise, fix the inconsistency BSET #1,VCBAtrb+1(A2) ; Mark error in VCB attributes MOVEQ #-1,D3 ; But mark the scan error @20 CMP.L VCBDirCnt(A2),D6 ; Check total number of directories on volume BEQ.S @30 ; If same, continue MOVE.L D6,VCBDirCnt(A2) ; Fix the inconsistency BSET #1,VCBAtrb+1(A2) ; Mark the error in VCB attributes MOVEQ #-1,D3 ; Mark the scan error @30 CMP.W VCBNmFls(A2),D7 ; Check the number of files in the root BEQ.S @40 ; If that's OK, continue MOVE.W D7,VCBNmFls(A2) ; Otherwise, overwrite the VCB info. BSET #1,VCBAtrb+1(A2) ; Mark error in VCB attributes MOVEQ #-1,D3 ; And mark a scan error @40 SWAP D7 ; Get the root directory count in low word CMP.W VCBNmRtDirs(A2),D7 ; Check the number of root directories BEQ.S @90 ; Continue if all seems well MOVE.W D7,VCBNmRtDirs(A2) ; Otherwise, update the VCB info. BSET #1,VCBAtrb+1(A2) ; Mark error in VCB attributes MOVEQ #-1,D3 ; And mark a scan error @90 ; Next, scan the extent tree to make sure all extent records are actually ; marked as allocated: XTScan: ; Before starting a scan of the extenbt tree, make a conservative estimate of the ; upper limit of B*-Tree records that could conceivably be encountered in a ; scan of all leaf nodes by dividing the catalog's PEOF by the size of an extent ; record: MOVEA.L FCBsPtr,A1 ; Point to the FCB array MOVE.W VCBXTRef(A2),D1 ; Pick up the extent tree refNum MOVE.L FCBPLen(A1,D1),D0 ; Pick up the extent tree size in bytes LSR.L #4,D0 ; divide by 16 (less than smallest record size) MOVE.L D0,D5 ; D5 = max. number of extent records MOVE.W VCBXTRef(A2),D0 ; Extent tree refNum SUB.W #lenXKR,A6 ; Allocate an extent tree key on the stack MOVEA.L A6,A0 ; Set up pointer to extent key MOVE.W #$0700,xkrKeyLen(A0); Set up key length & fork type CLR.L xkrFNum(A0) ; Clear file number in key CLR.W xkrFABN(A0) ; Clear starting allocation block in key MOVEQ #0,D2 ; Clear B*-Tree hint JSR BTSearch ; Look for this key [which cannot exist] ADD.W #lenXKR,A6 ; Deallocate key from stack MOVEQ #0,D1 ; Select record right of insertion point @10 SUBQ.L #1,D5 ; Count down by one BLT MtChkErr ; No mounting on loop errors <08Sep85> @20 MOVE.W VCBXTRef(A2),D0 ; Set up extent tree RefNum again JSR BTGetRecord ; Try to get it BNE.S @90 ; Stop on errors ; Check the allocation status of this extent record: MOVEA.L A1,A0 ; Point to extent record BSR.S BMChk ; Check the allocation status <07Oct85> MOVEQ #1,D1 ; Set up to get next record @50 BRA.S @10 ; And go for it @90 CMP.W #BTNotFound,D0 ; No more records to be found? BNE MtChkErr ; If not, that's serious trouble ; Finally, refigure the free block count by counting all zero bits in allocation map JSR UpdateFree ; VSM routine does this for us . . . <08Sep85> BRA CheckRemount ; This mount is OK: Check for remount <14Oct85> BMChk MOVE.L jBMChk,-(SP) ; jump table entry for vBMChk <27Oct86> RTS ; go there <27Oct86> vBMChk ; 'vectored' BMChk routine <27Oct86> MOVE.L (SP)+,-(A6) ; Save return address <09Oct85> BSR CVFlgs ; Can we write the volume? <18Oct85> BNE.S @10 ; If not, no point fixing the bitmap <18Oct85> JSR BlkChk ; Check the allocation status <07Oct85> BEQ.S @10 ; Continue if all was well <07Oct85> MOVEQ #-1,D3 ; Make a note of the inconsistency <07Oct85> BSET #2,VCBAtrb+1(A2) ; Mark error in allocation map <07Oct85> @10 MOVE.L (A6)+,-(SP) ; Restore original return address <09Oct85> RTS ; <07Oct85> IF hasManEject THEN ; ;-------------------------------------------------------------------------------------- ; Routine: SetVCBManEject ; Input: A2 = VCB ptr ; Called by: MountVol ; Function: Sets or clears the manual-eject bit in the flags word of the input VCB ; based on the type of the drive indicated by vcbDrvNum. All registers ; are preserved. The manual-eject flag should only be changed at MountVol ; time. ;-------------------------------------------------------------------------------------- SetVCBManEject MOVEM.L A0/D0,-(SP) ; save regs MOVE.W vcbDrvNum(A2),D0 ; get drive num MOVEA.L DrvQHdr+qHead,A0 ; get first DQE @check CMP.W dqDrive(A0),D0 ; match? BEQ.S @found ; yep: go set the flag MOVEA.L qLink(A0),A0 ; no: check the next one BRA.S @check @found MOVE.W vcbFlags(A2),D0 ; get flags word BTST #dqManEjBit,dqInstall(A0) ; is this a manual-eject drive? BEQ.S @no ; no: clear the flag BSET #vcbManEjBit,D0 ; yes: set it BRA.S @exit @no BCLR #vcbManEjBit,D0 ; clear the flag @exit MOVE.W D0,vcbFlags(A2) ; store flags MOVEM.L (SP)+,A0/D0 ; restore regs RTS ; goodbye ENDIF ;________________________________________________________________________________ ; ; Routines: DsposFCBs, DsposVCB, DsposVBlks ; Function: Shared routines for tearing down volume structures. ;________________________________________________________________________________ DsposFCBs MOVEM.L D0-D1/A1,-(SP) ; preserve all regs <01Oct85> MOVEA.L FCBsPtr,A1 ; Point to FCB table <01Oct85> MOVE.W VCBXTRef(A2),D1 ; Get Extent B*-Tree refNum BEQ.S @1 ; br if unallocated CLR.L FCBFlNm(A1,D1) ; Clear file number to FCB as unused <01Oct85> @1 MOVE.W VCBCTRef(A2),D1 ; Get catalog refnum BEQ.S @2 ; If zero, it's unallocated CLR.L FCBFlNm(A1,D1) ; Clear file number to FCB as unused <01Oct85> @2 MOVEM.L (SP)+,D0-D1/A1 ; restore all regs <01Oct85> RTS ; DsposVCB MOVE.L D0,-(SP) ; preserve error code ; Close any working directories left open for this volume (the VCB is about to ; disappear): BSR Gt1stWDVMatch ; sets up A1, D1 <28Aug85> @1 BNE.S @2 ; br if no more WDCBs <28Aug85> CLR.L WDVCBPtr(A1,D1) ; free the WDCB <28Aug85> CLR.L WDDirID(A1,D1) ; <30Aug85> BSR GtNxtWDVMatch ; <28Aug85> BRA.S @1 ; <28Aug85> @2 MOVE.L A2,A0 ; dequeue this VCB LEA VCBQHdr,A1 ; ptr to VCB queue header JSR DequeueTrap ; unlink this VCB from the VCB queue CMP.L DefVCBPtr,A2 ; did we unmount our default? <30Aug85> BNE.S @3 ; br if not <30Aug85> CLR.L DefVCBPtr ; if so, no more default <30Aug85> CLR.W DefVRefNum ; And no more default VRefNum <30Aug85> @3 _DisposPtr ; dispose VCB and buffer memory <30Aug85> DsposExit MOVE.L (SP)+,D0 ; restore error code RTS ; DsposVBlks trashes all cache blocks for a given volume (specified by A2=VCB ptr). ; It is called on mount errs and when unmounting a volume. DsposVBlks MOVE.L A1,-(SP) ; save all regs <30Aug85> MOVE.L SysBMCPtr,A1 ; System-wide bitmap cache pointer <30Aug85> JSR TrashVBlks ; A2=VCB ptr <30Aug85> MOVE.L SysVolCPtr,A1 ; System-wide volume cache pointer <30Aug85> JSR TrashVBlks ; A2=VCB ptr <30Aug85> MOVE.L SysCtlCPtr,A1 ; System-wide control cache pointer <30Aug85> JSR TrashVBlks ; A2=VCB ptr <30Aug85> MOVE.L (SP)+,A1 ; <30Aug85> RTS ; <30Aug85> ;________________________________________________________________________________ ; ; Routine: FindFCB ; ; Arguments: D1.W (out) - FCB index (suitable for use as File RefNum). ; A1.L (out) - FCB ptr ; D0.W (out) - TMFOErr or 0 if ok. ; All other regs preserved. ; ; Function: Find an unused FCB ; ; Modification history: ; 22-Jul-85 PWD Changed to skip first FCB (#2), left free for system file. ; <01Oct85> LAK Rewrote to use Gt1stFCB, GtNxtFCB routines, and to return A1/D0/D1. ;________________________________________________________________________________ FindFCB: BSR Gt1stFCB ; get (A1,D1) pointing to first FCB <01Oct85> BRA.S @2 ; skip first FCB (save for System file) <01Oct85> @1 TST.L FCBFlNm(A1,D1) ; FCB unused? <01Oct85> BNE.S @2 ; br if so <01Oct85> MOVEQ #-1,D0 ; get -1 <01Oct85> MOVE.L D0,FCBFlNm(A1,D1) ; Found a free one: mark as in-use <01Oct85> MOVEQ #0,D0 ; no error <01Oct85> BRA.S @3 ; <01Oct85> @2 BSR GtNxtFCB ; get next one until we run out <01Oct85> BCS.S @1 ; <01Oct85> MOVEQ #TMFOErr,D0 ; too many files open <01Oct85> @3 RTS ; <01Oct85> ;________________________________________________________________________________ ; ; Routine: AccessBT ; ; Function: Create an access path for a B*-Tree file: ; 1. Initialize the FCB ; 2. Attach a B*-Tree control block ; ; Inputs: ; D0.W - File FCB ; D1.L - File ID ; D2.L - File clump size ; A1 - Cache buffer ; A2 - VCB pointer ; A3 - Address of key comparison routine ; ; Outputs: ; D0.W - I/O result from BTOpen ;________________________________________________________________________________ AccessBT: MOVE.L (SP)+,-(A6) ; Save return address MOVEM.L D3/A0,-(A6) ; Save scratch registers MOVEA.L FCBsPtr,A0 ; Point to FCB table LEA 0(A0,D0.W),A0 ; Point to FCB itself CLR.W FCBFlags(A0) ; Clear flag bytes CLR.W FCBSBlk(A0) ; Start block is undefined CLR.L FCBCrPs(A0) ; Current position is undefined MOVE.L D1,FCBFlNm(A0) ; Set file ID MOVE.L A2,FCBVPtr(A0) ; Set VCB pointer MOVE.L D2,FCBClmpSize(A0) ; Set File Clump Size MOVEA.L A3,A0 ; Key comparison routine JSR BTOpen ; Open file for B*-Tree access MOVEM.L (A6)+,D3/A0 ; Restore registers MOVE.L (A6)+,-(SP) ; Restore return address TST.W D0 RTS ;_______________________________________________________________________ ; ; Routine: FindDrive ; Arguments: D2.W (input) -- drive number ; D1.W (output) -- driver refnum for this drive number ; D2.W (output) -- drive number ; D0.W (output) -- error code (no such drive) ; A3.L (output) -- pointer to DQE for drive in question ; All other registers are preserved. ; Calls: QWordSearch ; Called By: Eject,MountVol ; Function: Given a drive number, this routine returns the RefNum ; for the driver by searching the system drive queue. ; ; Modification History: ; 06 Dec 82 LAK New today. ; 13 Jan 83 LAK Removed block offset - now returns drive number in D2 ; 01 Jun 83 LAK Checks added DQFSID field, reporting ExtFSErr if nonzero ; 25 Apr 85 PWD Changed to return DQE pointer in A3 for use in Eject. ;_______________________________________________________________________ FindDrive: MOVE.L jFindDrive,-(SP) ; jump table entry for vFindDrive <19Feb87> RTS ; go there <19Feb87> vFindDrive ; 'vectored' FindDrive routine <19Feb87> MOVE.L A0,-(SP) ; preserve A0 MOVE.W D2,D0 ; search using this drive number as the key LEA DrvQHdr,A0 ; search the queue of drive numbers MOVEQ #DQDrive,D1 ; for drive number BSR QWordSearch BNE.S @2 ; exit if not found MOVEA.L A0,A3 ; Return pointer to DQE MOVE DQRefNum(A0),D1 ; return refnum MOVE.W DQFSID(A0),D0 ; is it for us? BEQ.S @1 ; br if so MOVEQ #ExtFSErr,D0 ; otherwise, report an error @1 MOVEA.L (SP)+,A0 ; restore A0 RTS @2 MOVEQ #NSDrvErr,D0 ; no such drive number BRA.S @1 ;_______________________________________________________________________ ; ; Routine: OffLine ; Arguments: ; Calls: ; Called By: ; Function: ; ; Modification History: ; ; 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. ; ; 5 Jul 84 GSS Added this call to the TFS code ;_______________________________________________________________________ ; Rolled in NoCloseOnOffline patch from FileMgrPatches.a OffLine: BSR FSQueueSync ; wait until all current calls are done ST NoEject ; NoEject.B = -1: mark vol. offline but ; don't eject the diskette BRA Eject1 ; share code with Eject ;_______________________________________________________________________ ; ; Routine: Eject ; Arguments: A0 (input) -- pointer to volume parameter block, uses IODrvNum, ; IOFileName ; D0 (output) -- error code ; This call is executed synchronously until the eject call is ; actually made. ; Calls: _FlushVol,_Control ; ; Function: The volume in the drive is flushed and its block map and buffer ; block are deallocated. A control call to the disk driver ; is made to eject the diskette. ; ; Modification History: ; 06-Dec-82 LAK New today. ; 13-Jan-83 LAK Disk control call now uses drive number parameter. Completion ; routine is now just CmdDone. ; 01-Jun-83 LAK Changed to just flush the volume before ejecting; VCB ; drive number and driver number are zeroed. ; 05-Jul-84 GSS Patched from MSFileFix code ; 12-Feb-85 PWD Split off MFS code and adapted for use in Turbo FS. ; 25-Apr-85 PWD Changed to leave non-ejectable volumes online. ; 26-Jun-85 PWD Changed to not call driver for non-ejectable disks ; <30Aug85> LAK Changed to force Eject to be synchronous since FlushMDB must be ; done BEFORE closing of volume B-tree files. Why not use ; a separate parameter block for Eject so we can return immediately? ; <14Oct85> PWD Added DumpCaches routine for use by MountVol on remount. ; <28Oct85> PWD Changed to pass control call to drivers anyway if 64 <= DIP <= 127 ; mung VCB as for _Offline call for these drivers. Changed to ; interpret NoEject as tri-state flag: -1[offline], 0[eject], or ; +1 [offline w. special eject control call]. ; ; Notes: ; - CmdDone gets result code from D0 and assumes it is being called when the ; first routine on the queue is satisfied, so it all works . . . ; - Should the diskette still be ejected if the flush does not work? ; Should directory writes be verified for paranoid users? ; ;_______________________________________________________________________ ; Rolled in NoCloseOnEject patch from FileMgrPatches.a ; DumpCaches is called by MountVol when a remount is detected to flush out any <14Oct85> ; changes the consistency check may have brought [part. in the bitmap cache], <14Oct85> ; and trash the cache blocks marked with the now-defunct VRefNum/VCBPtr <14Oct85> ; <14Oct85> ; Called by: MountVol <14Oct85> DumpCaches: MOVE.L (SP)+,-(A6) ; Save return address across ,ASYNC I/O <14Oct85> MOVEM.L A1/D1-D2,-(A6) ; Free same scratch registers as below <24Oct85> CLR.B FlushOnly ; Trash cache blocks after flushing <14Oct85> BRA.S flVCaches ; Go flush the cache buffers <14Oct85> ; FlushBuffers is a code-sharing routine used by Eject and Flush/UnMountVol to flush the ; MDB (marking the volume consistent for Eject and UnMount), and flushing (and ; closing for Eject and UnMount) the volume control files . . . it likes to have ; the FlushOnly flag and A2 set appropriately on entry . . . It also flushes all buffers ; (and invalidates all cache blocks for the volume if FlushOnly=0). ; ; Called By: Eject, FlushVol, MFSFlush FlushBuffers: ; <01Oct85> MOVE.L (SP)+,-(A6) ; Save return address for ,ASYNC calls <29Aug85> MOVEM.L A1/D1-D2,-(A6) ; Save all regs except D0 <24Oct85> BSR TFSVCBTst ; Is it an MFS volume? <01Oct85> BNE.S flVCaches ; Br if so (just flush caches) <01Oct85> TST.B FlushOnly ; Just flushing? <29Aug85> BNE.S @1 ; Br if so <29Aug85> BSR CVFlgs ; Is volume write protected? <01Oct85> BNE.S @1 ; If so, don't try to mark it dirty <01Oct85> BSET #VCBAtVOK,VCBAtrb(A2) ; Indicate vol was unmounted ok <29Aug85> BSR MarkVCBDirty ; mark VCB dirty so it will be written <10Oct85> @1 JSR FlushMDB ; Go flush the VCB info BEFORE close <29Aug85> MOVEA.L FCBsPtr,A1 ; Point to FCB array <29Aug85> MOVE.W VCBCTRef(A2),D1 ; Catalog B*-Tree file refnum <29Aug85> BSR FClose ; Close the file itself <29Aug85> BNE.S flBufExit ; Punt on errors <29Aug85> TST.B FlushOnly ; Just flushing? <29Aug85> BNE.S @2 ; If so, the FCB's still 'live' <29Aug85> CLR.W VCBCTRef(A2) ; Indicate it's gone <29Aug85> @2 MOVE.W VCBXTRef(A2),D1 ; Extent B*-Tree file refnum <29Aug85> BSR FClose ; Close the file itself <29Aug85> BNE.S flBufExit ; Rats - and we were SO CLOSE... <29Aug85> TST.B FlushOnly ; Just flushing? <29Aug85> BNE.S flVCaches ; If so, there's still data in the FCB <29Aug85> CLR.W VCBCTRef(A2) ; It's a goner now... <29Aug85> ; Flush the volume caches (this code is shared with MFSFlush) flVCaches: MOVEQ #0,D1 ; Clear options byte (we'll trash later) ST CacheFlag ; Yes, REALLY flush . . . <05Sep85> MOVE.L SysBMCPtr,A1 ; System-wide bitmap cache pointer <30Aug85> MOVE.W VCBVRefNum(A2),D0 ; Volume refnum <21Sep85> JSR FlushCache ; A2=VCB ptr <30Aug85> MOVE.L SysCtlCPtr,A1 ; System-wide control cache pointer <30Aug85> MOVE.W VCBVRefNum(A2),D0 ; Volume refnum <21Sep85> JSR FlushCache ; A2=VCB ptr <30Aug85> MOVE.L SysVolCPtr,A1 ; System-wide volume cache pointer <30Aug85> MOVE.W VCBVRefNum(A2),D0 ; Volume refnum <21Sep85> JSR FlushCache ; A2=VCB ptr <30Aug85> TST.B FlushOnly ; Just flushing? <30Aug85> BNE.S flBufOK ; If so, that's all we ask <30Aug85> BSR DsposVBlks ; Otherwise, trash blocks for A2 volume <30Aug85> flBufOK MOVEQ #0,D0 ; it's cool <29Aug85> flBufExit MOVEM.L (A6)+,A1/D1-D2 ; Restore regs <24Oct85> MOVE.L (A6)+,-(SP) ; Restore the return address <29Aug85> TST.W D0 ; <29Aug85> RTS ; <29Aug85> EjectTrap: BSR FSQueueSync ; wait until all current calls are done CLR.B NoEject ; want to really eject here . . . Eject1: BSR DtrmV3 ; check name, drive number, etc. <30Aug85> BNE.S @1 ; br if drive not mounted (why flush?) <30Aug85> BSR CkExtFS ; see if it's for an external fs <30Aug85> BNE.S EjectDone ; exit if so <30Aug85> BRA.S ejectMnted ; otherwise, go the 'mounted volume' route <30Aug85> @1 MOVE.W IOVDrvNum(A0),D2 ; drive number ejectDrvNum BSR FindDrive ; get disk driver refnum in D1 BNE.S ejectDone ; exit if no mapping for this drive <29Aug85> TST.B NoEject ; REALLY eject this thing? BEQ EjectIt ; OK, OK; it's going already... ejectDone BRA CmdDone ; we're done . . . <29Aug85> ejectMnted LEA VCBDrvNum(A2),A1 MOVE.W (A1),D2 ; on-line, non-ejected? BNE.S @0 ; br if so <29Aug85> MOVE.W 2(A1),D2 ; is it already ejected? BPL.S ejectDone ; just exit if so TST.B NoEject ; no eject? BNE.S ejectDone ; br if so (it's already offline . . .) <29Aug85> 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 . . . @0 BSR FindDrive ; Find DQE from drive number in D2 BNE.S ejectDone ; Punt if can't be found TST.B NoEject ; Just an _Offline call? <28Oct85> BNE.S @5 ; Yes - don't try harder than needed <28Oct85> CMP.B #8,DQDIP(A3) ; Check drive ejectability: <29Aug85> BLT.S @5 ; Skip if it's ejectable <28Oct85> ST NoEject ; If DQDIP > 8, it's non-ejectable <28Oct85> CMP.B #64,DQDIP(A3) ; Send a _Control call anyway? <28Oct85> BLT.S @5 ; No need - we're set as is. <28Oct85> MOVE.B #1,NoEject ; If >64, call the driver anyway. <28Oct85> @5 ST FlushOnly ; only flushing (don't close . . .) <11Sep85> BSR FlushVFiles ; flush all files on this volume <11Sep85> BSR TFSVCBTst ; Are we dealing with a TFS volume? <01Oct85> BNE.S @10 ; Nope. ; note that the following line is the opposite of the OLD 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. BSR CVFlgs ; Is volume write protected? <31> BNE.S @1 ; If so, don't try to mark it dirty <31> BSET.B #vcbAtVOK,vcbAtrb(a2) ; Indicate vol was unmounted ok <31> BSR MarkVCBDirty ; mark VCB dirty so it will be written <31> @1 BSR FlushMDB ; Go flush the VCB info BEFORE flushing <31> ST.B FlushOnly ; just flush the control files BSR FlushBuffers ; and flush MDB as 'consistent' <01Oct85> BRA.S ejectMark ; now go mark it . . . <29Aug85> ; FlushOnly is still set for MFS (otherwise MFSFlush would dispose the VCB) @10 BSR MFSFlush ; flush the MFS allocation map and MDB <11Sep85> BSR MDspsMap ; and dispose MFS map buffer <01Oct85> BSR DsposVBlks ; finally, trash blocks for A2 volume <01Oct85> ; OK, mark it offline by zeroing the drive number field in the VCB. Then, put the ; drive number in the driver refnum field in the VCB and if it's really just Offline, ; negate that field. ejectMark CLR.W (A1)+ ; zero drive number to mark it offline/ejected TST.B NoEject ; Real eject call <28Oct85> BEQ.S @1 ; br if so <28Oct85> NEG.W D2 ; neg drive number for offline indication <29Aug85> @1 MOVE.W D2,(A1)+ ; store drive number here for disk-switch <29Aug85> ; (negated drivenum for offline) TST.B NoEject ; eject or offline? <29Aug85> BEQ.S ejectIt ; go eject it if eject call <29Aug85> ; OffLine calls requeue the VCB for fairness (let some other drive get taken offline next time) MOVE.L A2,A0 ; VCB queue element <29Aug85> LEA VCBQHdr,A1 ; VCB queue header <29Aug85> BSR.L DequeueTrap ; DeQueue then EnQueue to force VCB to <29Aug85> BSR.L EnQueueTrap ; the end for round-robin offline scheme <29Aug85> TST.B NoEject ; Was this a real _Offline call? <28Oct85> BMI ejectDone ; Yes - offline br to command done <29Aug85> ; Here is where it finally gets ejected . . . ejectIt ; shared by MFS and TFS eject code . . . LEA Params,A0 ; general purpose I/O param block <29Aug85> LEA IODrvNum(A0),A1 ; prepare to fill in 3-in-a-row <29Aug85> MOVE.W D2,(A1)+ ; IODrvNum (the drive) <29Aug85> MOVE.W D1,(A1)+ ; IORefNum (driver handling this drive) <29Aug85> MOVE.W #EjectCode,(A1) ; CSCode (eject it!) <29Aug85> LEA CmdDone,A1 ; completion routine just says done <29Aug85> MOVE.L A1,IOCompletion(A0) ; <29Aug85> _Control ,ASYNC ; asynchronous call <29Aug85> RTS ; always return at this level <29Aug85> ;_______________________________________________________________________ ; ; 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. ; ; Modification History: ; 06 Dec 82 LAK No longer ejects the diskette (This combination function ; is now done by calling Eject). If the default volume is ; unmounted, the default volume pointer is set to the first ; VCB in the VCB queue. ; 21 Dec 82 LAK Rewrote to share code with FlushVol; now calls DtrmVol to ; figure out the VCB pointer. ; 22 Apr 85 PWD Fixed to write VCBLsMod field. ; 22-Aug-85 PWD Changed to set 'volume consistent' flag in volume attributes ; before flushing MDB. ; <04Nov87> JB (C958) Rolled in UnMountVol patches PM243, PA244, PB245, and PMAB271. ; Two functional changes: 1) disallow unmount if files are ; open, and 2) allow unconditional unmount (HFS bit set) ; for the shutdown case. ; 09Jun89 BB/JB Reorder the comparison for "internal file" and "HFS vol" when ; determining whether to ignore opened FCB's. External FS's now ; can have UnMount succeed if they have "internal" files open. ; Inserted a check for MFS volumes before using file number as ; a qualifier for unmount with files open. MFS volumes will not ; allow unmount with any files open. NOTE: MultiFinder makes sure ; that the 'Desktop' file is closed before UnmountVol is called. ;_______________________________________________________________________ UnMountVolTrap: ; FM rolled in for SuperMario, DesktopCloseDownProc closes the catalog ; and extents files. Since _Offline now no longer does this, we must make sure ; that UnMountVol always does. bsr DesktopCloseDownProc ; FM go take care of the desktop database <36> bsr.s FSQueueSync ; Get in sync... <04Nov87> clr.b FlushOnly ; Setup same as UnmountVol <04Nov87> bsr DtrmV3 ; Call DtrmV3 to do setup stuff <04Nov87> bne FlVolExit ; Xfer if error... <04Nov87> moveq #0,d0 ; Initialize result code <04Nov87> btst #HFSBit,ioTrap(a0) ; Unconditional unmount? <04Nov87> bne FlUnMnt ; Xfer if so... <04Nov87> ; ; 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 <04Nov87> move.l FCBsPtr,a1 ; FCB array base address <04Nov87> moveq #2,d1 ; Index of 1st FCB <04Nov87> @2 move.l fcbFlNm(a1,d1),d2 ; Is the file currently open? <04Nov87> beq.s @4 ; Nope, try next FCB... <04Nov87> cmp.l fcbVPtr(a1,d1),a2 ; Is the file on this volume? <04Nov87> bne.s @4 ; No, try next FCB... <04Nov87> cmp.w #SigWord,vcbSigWord(a2) ; Is this an MFS volume? <1.6> beq.s @3 ; Yes, error if files are open... <1.6> cmp.l #FSUsrCNID,d2 ; Is it an internal file? <1.6> blo.s @4 ; Ignore it if so... <1.6> ; dead code stripped @3 ; ; Found an open user file on the volume, so return a ; busy condition... ; moveq #fBsyErr,d0 ; Assert UnmountVol error <04Nov87> bra.s @5 ; Get out... <04Nov87> @4 add.w FSFCBLen,d1 ; Next FCB array entry <04Nov87> cmp.w (a1),d1 ; Reached the end yet? <04Nov87> blo.s @2 ; Continue if not... <04Nov87> @5 movem.l (sp)+,a1/d1/d2 ; Restore regs <04Nov87> tst.w d0 ; Were files open? <04Nov87> bne FlVolExit ; Xfer if error... <04Nov87> bra.s FlUnMnt ; Else, go unmount... <04Nov87> ;_______________________________________________________________________ ; ; Routine: FlushVolume ; Arguments: A0 (input) -- VCB pointer to volume to flush ; D0 (output) -- error code ; Calls: FClose,MyWriteDB ; Called By: UnMountVol ; Function: All file buffers on the volume are flushed and any changed ; directory information is written out to the diskette. ; ; Modification History: ; 20 Nov 82 LAK Clears the modified bit after writing out the VCB. ; Removed logic to get rid of a file's own buffer after closing ; it (should be done by close routine; also changing open to ; get a pointer to a buffer from the user -> so user would ; deallocate after a close or an eject . . . ; Removed logic to deallocate the VCB buffers: this is now done ; by unmount volume . . . ; 06 Dec 82 LAK Modified for new file system data structures . . . ; 07 Dec 82 LAK Made into an external procedure. ; 21 Dec 82 LAK Changed to flush file buffers but not close the files; now ; combines code of both unmountvol and flushvol. ; 13 Jan 83 LAK Zeros rest of last block map block before writing it out; ; some cosmetic and minor changes. Fills in IODrvNum field. ; 26 Jan 83 LAK Doesn't read in the master block first anymore; always ; flushes dirty volume buffer. ; 02 Jun 83 LAK Made flush of off-line volume a no-op; also allows unmount ; of an off-line volume. ; 11 Mar 85 PWD Changed to call BTClose for files with non-nil FCBBTCBPtrs as ; a temporary patch (eventually this will be part of FlClose). ; 4 Apr 85 PWD B*-Tree are now handled by FClose; removed calls to BTClose. ; 1 May 85 PWD Added code to free WDCBs pointing to unmounted volume ; on UnMount ; 4-Jun-85 PWD Changed to write MDB as last block (should always have highest ; sequence number in tags). ; <29Aug85> LAK MDB cannot be written after control files are closed. ;_______________________________________________________________________ FlushVFiles: MOVE.L (SP)+,-(A6) ; Save return address for ,ASYNC calls <30Aug85> MOVEM.L A0-A5/D1-D7,-(A6) ; Save all regs except D0 <11Sep85> ; scan through the FCBs and flush any files on this volume that are open ; (also close them if we are unmounting the volume . . .) BSR Gt1stFCB ckNxtFCB TST.L FCBFlNm(A1,D1) ; file open? BEQ.S ckNxtF1 ; br if not CMP.L FCBVPtr(A1,D1),A2 ; pointing at this VCB? BNE.S ckNxtF1 ; nope. BSR TFSVCBTst ; Are we dealing with a TFS volume? <01Oct85> BNE.S @1 ; Nope - all's safe <28Aug85> CMP.L #FSUsrCNID,FCBFlNm(A1,D1) ; Check file id - internal file? BCS.S ckNxtF1 ; If LO, yes - wait until later <28Aug85> @1 BSR FClose ; file is on this volume so flush it BNE.S fvFilesExit ; report any errors ckNxtF1 BSR GtNxtFCB ; look at next file BCS.S ckNxtFCB ; until we have looked at them all MOVEQ #0,D0 ; we're cool fvFilesExit MOVEM.L (A6)+,A0-A5/D1-D7 ; Restore regs <11Sep85> MOVE.L (A6)+,-(SP) ; restore return address TST.W D0 RTS FlushVolTrap: BSR FSQueue ; wait our turn ST FlushOnly ; only flushing . . . ; first, find the appropriate VCB in our queue BSR.S DtrmV3 ; check name, drive number, etc. BNE.S FlVolExit ; exit if no such volume FlUnMnt: ; <04Nov87> BSR.S CkExtFS ; see if it's for an external fs BNE.S FlVolExit ; exit if so BSR.S FlushVFiles ; flush all files on this volume BNE.S FlVolExit ; All files on this volume are flushed now. Update the volume information as ; appropriate, depending on the file structure: BSR TFSVCBTst ; is this a TFS volume? <01Oct85> BEQ.S @1 ; br if so <11Sep85> BSR MFSFlush ; flush the MFS allocation map and MDB <11Sep85> BRA.S FlVolExit ; and exit . . . <11Sep85> ; Unmounting a TFS volume: close the volume control B*-Tree and use the ; volume buffer to write out the MDB ; ; From UnmountForTheNineties in FileMgrPatches.a ; 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 BSR FlushBuffers ; share routine with Eject to do it all <01Oct85> BNE.S FlIOErrExit ; Punt on errors BRA.S FlVolDone ; ; here begins CloseControlFiles, which is derived from FlushBuffers ; Now we have to close the control files because we no longer close them ; in Eject and Offline CloseControlFiles tst.b FlushOnly ; only do this if we are in fact unmounting the volume CSS bne.s FLVolOK ; just a flush CSS movea.l FCBsPtr,A1 ; Point to FCB array move.w vcbCTRef(a2),d1 ; Catalog B*-Tree file refnum jsr FClose ; Close the file itself bne.s FlVolExit ; Punt on errors move.w vcbXTRef(a2),d1 ; Extent B*-Tree file refnum jsr FClose ; Close the file itself bne.s FlVolExit ; Rats - and we were SO CLOSE.. •• is this what we want? jsr DsposVBlks ; Trash blocks for a2 volume FlVolDone TST.B FlushOnly ; only flushing? BNE.S FlVolOK ; br if so ; For UnMountVol, dequeue the VCB and trash any WDCBs for this volume . . . BSR DsposVCB ; share code with MountVol error routine <30Aug85> FlVolOK MOVEQ #0,D0 ; no error FlIOErrExit ; FlVolExit BRA CmdDone ;_______________________________________________________________________ ; ; Routine: CkExtFS ; Arguments: A2.L (input) -- VCB pointer ; D0.W (output) -- 0=belongs to us, ExtFSErr=belongs to another ; Called By: ; Function: Simple routine to separate out calls to be handled by an ; external file system. ; ; Modification History: ; 06 Dec 82 LAK New today. ;_______________________________________________________________________ CkExtFS: MOVE.L jCkExtFS,-(SP) ; jump table entry for vCkExtFS <27Oct86> RTS ; go there <27Oct86> vCkExtFS ; 'vectored' CkExtFS routine <27Oct86> MOVE.W VCBFSID(A2),D0 ; is this VCB for us? BEQ.S @1 ; br if so MOVEQ #ExtFSErr,D0 @1 RTS ;_______________________________________________________________________ ; ; Routine: DtrmVol,DtrmV1,DtrmV2,DtrmV3 ; Arguments: HFSFlags (input) -- who really sets this up??? <29Aug85> ; A0.L (input) -- IOFileName(A0) = ptr to path name ; D0.W (output) -- 0 or error code: NSVErr ; D2.W (output) -- pathname length (not including any vol prefix) ; D3.W (output) -- 0 if no vol name specified, non-zero otherwise ; A2.L (output) -- VCB pointer ; A3.L (output) -- WDCB pointer or zero (if none specified) ; A4.L (output) -- pathname ptr (not including any vol prefix) ; All other regs are preserved ; Makes use of the fact that all IO parameter blocks have ; their filename pointers and drive numbers in the same spot. ; Calls: _CmpString,QWordSearch,GetVCBDrv,GetVCBRfn ; Called By: SetVol,UnMountVol,FlushVol,Open,Create,Delete,Rename, ; GetFileInfo(DtrmV1),GetVolInfo(DtrmV1,DtrmV3) ; Function: Determine what volume is being used in a name. Main entry ; requires a name pointer; DtrmV2 also does, but the pointer is ; passed in D2. DtrmV1 just looks at drive number; DtrmV3 ; looks at name field if not nil, otherwise drive number. ; ; Modification History: ; 02 Dec 82 LAK Changed to set CCR when done. Changed to reflect that volumes ; off-line have a zero VCB pointer. Preserves non-interface ; regs. Searches thru VCB queue as mountVol, unmountVol do. ; 10 Dec 82 LAK Changed to look at drive number field when there is no ; volume prefix. Now uses global string compare proc. ; 13 Dec 82 LAK Added entry point DtrmVol1 for GetFileInfo. ; 13 Jan 83 LAK Calls OS _CmpString proc. Don't ignore parity bit when looking ; for colon in name. ; 23 Jan 83 LAK Changed DtrmV2 entrypoint to have pointer already; report ; error at DtrmVol and DtrmV2 entrys if name ptr is nil; ; deleted DtrmV1 (just call GetDrvVCB). ; 25 May 83 LAK A4 points to first filename byte now. ; 02 Jun 83 LAK Changed to support VRefNum: GetDrvVCB has been factored ; out and made into GetVCBDrv, GetVCBRfn ; 23 Feb 85 GJC added TFS support for pathnames of the form ; volname:filename (scan filename from ; left to right). ; also, added support for working directory queue and ; WDRefnums (search WDCB queue for VRefNums < WDRfnMax). ; 28-Feb-85 PWD Changed to stash WDCB pointers in A3, always return VCB pointer ; in A2. Note that A3 is CLEARED in cases where no WDCB is ; specified, INCLUDING MFS CALLS. ; 1-Mar-85 PWD Changed to check for and ignore zero-length volume names ; (possible if WDCB/partial pathname is specified). Name pointer ; is left pointing AFTER leading colon at first pathname element. ; 22-Aug-85 PWD Changed to skip search path if requested through lo-mem flag ; (for GetFileInfo/GetCatInfo by index). ; <29Aug85> LAK Rewrote in a more straightforward fashion. Only error returned ; now is NSVErr. ; <06Sep85> LAK Slight modification to DtrmV3 prefix to prevent passing to DtrmVol ; if IOFileName points to a zero-length string (for the dubious ; result of making CatMove work with a zero-length string . . .). ; <25Sep85> PWD Added support for PMSPHook and PMSP Enable/Disable. ; ; Test: no vol name, very short vol names, vol name which is only a colon, ; internal-external-no volume,only drive specified ; ; NOTE: WHY ZERO THE ENTIRE PMSP BLOCK? ;_______________________________________________________________________ DtrmV3: MOVE.L jDtrmV3,-(SP) ; jump table entry for vDtrmV3 <27Oct86> RTS ; go there <27Oct86> vDtrmV3 ; 'vectored' DtrmV3 routine <27Oct86> MOVE.L IOFileName(A0),D2 ; entry for flush,set,eject,unmountvol <06Sep85> MOVE.L D2,A4 ; <06Sep85> BEQ.S DtrmV1 ; br if nil filename pointer (D2,A4=0) <06Sep85> TST.B (A4) ; is it a zero-length name? <06Sep85> BNE DtrmVol ; if non-zero, check for vol prefix <06Sep85> MOVEQ #0, d2 ; make sure string length is set to zero ; (this is from FixDtrmV3 in FileMgrPatches.a) DtrmV1: MOVE.L jDtrmV1,-(SP) ; jumptable entry for vDtrmV1 <29Oct85> RTS ; go there <29Oct85> vDtrmV1 ; 'vectored' DtrmV1 routine <29Oct85> MOVEQ #0,D3 ; No volume name specified <29Aug85> SUB.L A3,A3 ; Assume no WDCB spec'd for now... <29Aug85> MOVE.W IOVRefNum(A0),D0 ; volume refnum BEQ.S dtrmDeflt ; br if no drive/vrefnum specified <29Aug85> BMI.S dtrmVRef ; br if volume refnum <29Aug85> BSR GetVCBDrv ; try to figure VCB by drive number <29Aug85> BRA.S dtrmGotCk ; <29Aug85> dtrmVRef CMP.W #WDRfnMax,D0 ; Check against max. WDRefNum <29Aug85> BLE.S @1 ; If LE, it's a working directory RefNum <29Aug85> BSR GetVCBRfn ; try to figure VCB by volume refnum <29Aug85> BRA.S dtrmGotCk ; <29Aug85> @1 BSR GetWDCBRfn ; search WDCB queue for WD entry <29Aug85> dtrmGotCk BEQ.S dtrmGotVol ; br if A2->VCB <29Aug85> dtrmErrRTS MOVEQ #NSVErr,D0 ; let's be consistent nowadays . . . <29Aug85> RTS dtrmDeflt MOVE.L DefVCBPtr,D0 ; Is a default set up? <29Aug85> BEQ.S dtrmErrRTS ; br if no name, no drive, no refnum, no default MOVEA.L D0,A2 ; Otherwise, set it up for use MOVEA.L WDCBsPtr,A3 ; Point to the WDCB array ADDQ.L #2,A3 ; Point to the default WDCB there ; OK, we have A2 set up with the VCB pointer, and A3 -> WDCB if specified by WDCB or default dtrmGotVol MOVEQ #0,D0 ; All's well so far MOVE.L A2,ReqstVol ; save in case of offline, ext fs vols ; Now that we've determined a volume to work with, check to make sure some ; defaults are set up to deal with the possibility that the file we're looking ; for doesn't appear in the first directory tried (if none was specified ; explicitly): BTST #NoPMSP,HFSFlags ; PMSP disabled? <25Sep85> BNE.S @0 ; If set, don't search any other directories <25Sep85> BTST #SkipPMSP,HFSFlags ; Don't bother with PMSP for this operation? <22Aug85> BEQ.S dtrmPath ; If flag isn't set, give it a chance <22Aug85> ; Zero the search path: @0 MOVE.L A4,-(SP) ; Create scratch registers <22Aug85> MOVEA.L PMSPPtr,A4 ; Point to the search path <22Aug85> ADDQ.L #2,A4 ; Point to first entry <22Aug85> MOVEQ #((PMSPSize-SPHdrSize-2)/2)-1,D0 ; Pick up length of PMSP <22Aug85> @1 CLR.W (A4)+ ; Clear out the search path <22Aug85> DBRA D0,@1 ; <22Aug85> MOVE.L (SP)+,A4 ; Restore the original A4 <22Aug85> dtrmExOK MOVEQ #0,D0 ; All's well so far <29Aug85> RTS ; So quit while we're ahead. <29Aug85> dtrmPath BTST #HFSBit,ioTrap(A0) ; Use of HFSBit (9) mod 8 is OK on high byte BEQ.S @1 ; If no TFS trap, there's no DirID TST.L ioDirID(A0) ; Otherwise, was one specified? BNE.S dtrmExOK ; Yes - there'll be no defaulting. @1 MOVEM.L A4/A1/D2/D4,-(SP) ; Save scratch registers from all this wickedness ; for use as PMSP pointers... MOVEA.L PMSPPtr,A4 ; Point off to the Poor Man's Search Path MOVE.W PMSPIndx(A4),D4 ; Pick up the default volume index BGT.S dtrmPthUse ; If it's initialized, go for it ; Initialize the search path list: MOVEQ #2,D4 ; Index beyond the size word to set up 1st entry MOVE.W VCBVRefNum(A2),D2 ; Pick up the volume's VRefNum for use ; The first entry is the default volume/directory: MOVE.L A3,D0 ; Was a WDCB [or default] specified? BEQ.S @2 ; Nope - use the root MOVE.L WDDirID(A3),D0 ; Otherwise, we want the default DirID BRA.S @3 ; [A3 points to a WDCB] @2 MOVEQ #FSRtDirID,D0 ; No WDCB - use the root @3 BSR.S AddSPEntry ; Add this entry to the search path ; The remainder only makes sense for TFS volumes, which actually have ; distinguishable directories: BSR TFSVCBTst ; is this a TFS volume? <01Oct85> BNE.S dtrmPthEnd ; Nope - put an end to it all ; The second entry is the directory referred to by BootDrive, if it's ; a working directory on the same volume: dtrmPth2 MOVE.W BootDrive,D0 ; Pick up BootDrive BGE.S dtrmPth3 ; If it's a real DriveNum, forget it ; (it would just refer to the root, anyways) CMP.W #WDRfnMax,D0 ; Is it a working directory? BGT.S dtrmPth3 ; If not, forget it BSR GetWDCBRfn ; Look up the VCB (sets A2 and A3) BNE.S dtrmPth3 ; Punt on errors CMP.W VCBVRefNum(A2),D2 ; Same volume? BNE.S dtrmPth3 ; If not, forget it MOVE.L WDDirID(A3),D0 ; Pick up the DirID from the WDCB BSR.S AddSPEntry ; And add the entry to the PMSP ; The third entry is the system directory on the same volume: dtrmPth3 MOVEA.L ReqstVol,A2 ; Revert back to the requested volume MOVE.L VCBFndrInfo(A2),D0 ; Pick up the system DirID BEQ.S dtrmPthEnd ; If it doesn't exist, just skip it. BSR.S AddSPEntry ; Add this to the search path, too ; The fourth entry is the root of the volume: <25Sep85> *EX-CODE:* MOVEQ #FSRtDirID,D0 ; Pick up the root directory ID <25Sep85> *EX-CODE:* BSR.S AddSPEntry ; And add it to the search path <25Sep85> ; *Add directories on the boot drive, too? (a setup FROUGHT with peril!)* dtrmPthEnd CLR.W SPVRefNum(A4,D4) ; Zero last VRefNum to indicate end of PMSP. MOVEQ #2,D4 ; Set up to point to first entry in PMSP MOVE.W D4,PMSPIndx(A4) ; Store it for future reference ; Check if a PMSP hook was defined, and give it a chance to change the PMSP table <30Sep85> ; (pointed to by A4), and/or the PMSP index (D4) using the VCB (A2) and IOPB (A0) <30Sep85> MOVE.L PMSPHook(A4),D0 ; Pick up the hook, if any <30Sep85> BEQ.S dtrmPthUse ; If zero, no hook is currently installed <30Sep85> MOVEA.L D0,A1 ; Shift hook address over for dispatch <30Sep85> JSR (A1) ; Call the PMSP hook <30Sep85> dtrmPthUse MOVE.W SPVRefNum(A4,D4),D0 ; Pick up the default VRefNum BSR GetVCBRfn ; Find the corresponding VCB BNE.S @1 ; Br if found no more MOVEA.L WDCBsPtr,A3 ; Point to WDCB table ADDA.W #(2+WDCBLen),A3 ; Point A3 off to newly created default MOVE.L A2,WDVCBPtr(A3) ; Set up second WDCB VCB pointer MOVE.L SPDirID(A4,D4),WDDirID(A3) ; Set up second WDCB DirID CLR.L WDCatHint(A3) ; No catalog hint CLR.L WDProcID(A3) ; No ProcID MOVEQ #0,D0 ; We're all set, and all is well. @1 MOVEM.L (SP)+,A4/A1/D2/D4 ; Restore scratch registers to original state <25Sep85> RTS ;_______________________________________________________________________ ; ; Add an entry to the Poor Man's Search path ; ; Input: D0 = DirID ; D2 = VRefNum ; D4 = PMSP index of next free entry ; A4 = PMSP table pointer ; ; Output: D4 = updated to point to next entry if entry is used. ; ; D0 is clobbered. ;_______________________________________________________________________ AddSPEntry: ; Look for an existing entry in the PMSP with the same VRefNum/DirID combination: MOVE.L D4,-(SP) ; Save PMSP index across search MOVEQ #2,D4 ; Index D4 to first entry in PMSP @10 CMP.L (SP),D4 ; Reached the free slot already? BCC.S @60 ; Yes - fill in the entry CMP.W SPVRefNum(A4,D4),D2 ; Match on VRefNum? BNE.S @40 ; If not, give up CMP.L SPDirID(A4,D4),D0 ; Match on DirID? BEQ.S @50 ; Yes - No need to fill this one in again @40 ADDQ.W #SPEntLen,D4 ; Point to the next entry CMP.W (A4),D4 ; Exceeded the table size? BLO.S @10 ; Nope - continue @50 MOVEQ #0,D0 ; Yes - no more room @60 MOVE.L (SP)+,D4 ; Restore D4 to index to free entry again ; Now consider adding the new entry: TST.L D0 ; Check the DirID: still want to use it? BEQ.S @90 ; If it's zeroed, there's no point MOVE.W D2,SPVRefNum(A4,D4) ; Otherwise, set up the VRefNum MOVE.L D0,SPDirID(A4,D4) ; And the new DirID ADDQ.W #SPEntLen,D4 ; Advance to the next entry @90 RTS DtrmVol: MOVE.L IOFileName(A0),D2 ; get pointer to 'volume:filename' DtrmV2: MOVE.L jDtrmV2,-(SP) ; jump table entry for vDtrmV2 <19Feb87> RTS ; go there <19Feb87> vDtrmV2 ; 'vectored' DtrmV2 routine <19Feb87> MOVEM.L D4-D6/A0-A1,-(SP) ; save regs TST.L D2 ; Name specified? BEQ.S NoNameErr ; need a name this entrypoint MOVE.L D2,A4 MOVEQ #0,D2 ; clear index into name (long for later add) MOVEA.L D2,A3 ; Clear WDCB pointer (never specified) MOVE.B (A4)+,D2 ; len of file name BEQ.S NoNameErr ; no zero-length names MOVEQ #0,D3 ; initialize loop count to zero @1 MOVE.B 0(A4,D3),D4 ; watch for colons in the name CMP.B #$3A,D4 ; ':'? BEQ.S @2 ; found possible volume name ADDQ.W #1,D3 ; scan entire name from front to back CMP.W D3,D2 ; have we scanned the entire length yet? BNE.S @1 ; If more to scan, go for it BRA.S @3 ; Otherwise, go look by DrvNum/VRefNum @2 SUB.L D3,D2 ; file name len excluding volume part SUBQ.W #1,D2 ; and the colon MOVE.L A4,A1 ; ptr to 1st char of vol name string ADD.L D3,A4 ; ptr to first colon in pathname string ADDA.L #1,A4 ; now pointing to the pathname TST.W D3 ; Have we scanned over any characters? BGT.S VolSpcfd ; Yes - go look for volume by name @3 BSR DtrmV1 ; no volume prefix; use DrvNum/VRefNum DtrmDone MOVEM.L (SP)+,D4-D6/A0-A1 ; restore regs TST.W D0 ; set condition codes RTS NoNameErr MOVEQ #BdNamErr,D0 ; zero name pointer BRA.S DtrmDone ; A volume name was specified. figure out which one (if any) VolSpcfd MOVE.L VCBQHdr+QHead,D0 ; search the VCB queue CkVol: BEQ.S @2 ; br if end of queue reached MOVE.L D0,A2 ; next VCB pointer LEA VCBVN(A2),A0 ; string pointer MOVEQ #0,D0 MOVE.B (A0)+,D0 ; length of (A0) string SWAP D0 MOVE.W D3,D0 ; length of (A1) string _CmpString ; compare strings @A0, @A1 BNE.S @1 ; br if not equal MOVE.L A2,ReqstVol ; note the requested volume BRA.S DtrmDone ; br if it compares @1 MOVE.L QLink(A2),D0 BNE.S CkVol @2 MOVEQ #NSVErr,D0 ; no volume name match, so volname must BRA.S DtrmDone ; be dir name, so use drvnum/vrefnum ;_______________________________________________________________________ ; ; Routine: SetPMSP ; Arguments: A0.L (input) -- I/O volume parameter block: uses ioCompletion ; and ioMisc ($1C). ; D0.W (output) -- error code ; Calls: FSQueue,CmdDone ; ; Function: Specify the behavior of TFS' Poor Man's Search Path. ; ; ioCompletion(A0) is the address of a hook procedure (zero to disable) ; which is called when TFS has just initialized the PMSP table. ; The hook is called with (A4,D4) pointing to the first PMSP entry. ; ; ioMisc(A0) is a word, the LSB of which determines whether the PMSP is ; used at all (if set) or ignored alltogether (if clear). ; ; Modification History: ; <25Sep85> PWD New today. ;_______________________________________________________________________ SetPMSP: BSR FSQueue ; Patiently wait our turn MOVE.L ioPMSPHook(A0),D0 ; Pick up the hook procedure BMI.S @1 ; If negative, don't install it MOVEA.L PMSPPtr,A1 ; Point to the PMSP table MOVE.L D0,PMSPHook(A1) ; Install the new hook @1 MOVE.W ioPMSPFlg(A0),D0 ; Pick up the accompanying boolean BCLR #NoPMSP,HFSFlags ; Clear flag, enabling PMSP BTST #0,D0 ; Test the LDB [a la Pascal] BNE.S SetPMSPOK ; If enabled, we're set BSET #NoPMSP,HFSFlags ; If flag is clear, PMSP is off SetPMSPOK MOVEQ #0,D0 ; Always a big hit BRA CmdDone ; So let's just call it a day here ;_______________________________________________________________________ ; ; Routine: GetVolInfo ; Arguments: A0.L (input) -- I/O volume parameter block: uses all volume ; fields. ; D0.W (output) -- error code ; Calls: FSQueue,CmdDone ; ; Function: Return information about the volume in a mounted drive. ; If the IOVolIndex field is 0, ; the name of the default volume is returned; if non-zero, the ; name of the nth mounted volume is returned. The maximum length ; of a volume name is 27 bytes. The drive number for the volume ; is also returned. ; ; Modification History: ; 07 Dec 82 LAK Changed to support new file system data structures. ; 16 Dec 82 LAK Removed backup file lgth subtract in free blk determination. ; 21 Dec 82 LAK Changed to call DtrmVol to figure the volume name. Free ; blocks comes from VCB info already stored. ; 14 Jan 83 LAK The latest changes. ; 23 Jan 83 LAK Changed to use the volindex field, call XferVName. ; 03 Jun 83 LAK Added in-use bit: true if any files on the volume are open; ; returns volume refnum now instead of drive number. ; 6-Aug-85 PWD Changed to call external file system for non-Macintosh volumes ; AFTER filling in the I/O parameter block information. ; 15-Aug-85 PWD Changed to add ioVFilCnt and ioVDirCnt fields ; 21-Sep-85 PWD Changed to exclude B*-Tree file allocations from NmAlBlks ; 21-Sep-85 PWD Changed to return directory valence instead of VCBNmFls if ; ioVRefNum is a working directory refNum. ; 24-Sep-85 PWD Fixed bug (MOVE.L vs. MOVEM.L) in directory valence lookup ; 11-Oct-85 PWD Changed to pin NmAlBlks and NmFrBlks at (32767*1000)/1024 ; instead of 32767 for programs that figure in 'decimal K' ; 13-Oct-85 PWD Fixed bug: don't try to read working directory valence for ; external FS volumes. ; 27-Oct-85 PWD Changed to ignore volume control files in determining vol. busy ; Changed to set bit 5 in attributes if volume is default ; ; - if this was the twin of GetFileInfo, the volume really shouldn't have to ; be mounted . . . if it is, get the info from the VCB and block map: if ; not, read the drive's master block into a stack buffer (would have to ; read the block map, tho, to determine the number of free blocks) . . . ;_______________________________________________________________________ GetVolInfo: BSR FSQueue ; queue up the request MOVE.W IOVolIndex(A0),D2 ; if positive, BGT.S @3 ; go search by index BEQ.S @1 ; if zero, go by drive number/default BSR DtrmV3 ; if negative, go by name BRA.S @2 @1 BSR DtrmV1 ; figure by drvnum, vrefnum, or default @2 BNE TGVIDone BRA.S RetVolInfo @3 MOVEQ #0,D3 ; Never any name specified <25Sep85> ; (ioFileName is output arg) <25Sep85> CLR.W ioVRefNum(A0) ; make sure this gets filled in later <25Sep85> MOVE.L VCBQHdr+QHead,D1 ; we want nth VCB in queue @4 BEQ NSVErrXit ; exit with err at end of queue SUBQ.W #1,D2 ; the one we want? MOVE.L D1,A2 BEQ.S RetVolInfo ; br if so MOVE.L QLink(A2),D1 ; if not, keep traversing the queue BRA.S @4 ; first copy the heart of the VCB into the parameter block RetVolInfo MOVEQ #IOVDirLen-2,D0 ; number of bytes to straight copy @4 MOVE.W VCBCrDate(A2,D0.W),IOVCrDate(A0,D0.W) SUBQ #2,D0 BPL.S @4 BSET #6,ioVAtrb+1(A0) ; set if any files are opened <28Oct85> BSR Gt1stFCB ; get (A1,D1) pointing to first FCB @0 CMP.L FCBVPtr(A1,D1),A2 ; file open on this volume? BNE.S @1 ; br if so BSR TFSVCBTst ; Are we looking at a TFS VCB? <27Oct85> BNE.S @2 ; Nope - all files are fair game <27Oct85> MOVE.L FCBFlNm(A1,D1),D0 ; Check the file number <27Oct85> CMP.L #FSUsrCNID,D0 ; Is it a system control file? <27Oct85> BHS.S @2 ; Accept only the highest quality... <27Oct85> @1 BSR GtNxtFCB ; get next one until we run out BCS.S @0 BCLR #6,ioVAtrb+1(A0) ; 0 if no open files match <28Oct85> @2 BCLR #5,ioVAtrb+1(A0) ; Assume this volume is not the default.<27Oct85> CMPA.L DefVCBPtr,A2 ; Check the default volume pointer <27Oct85> BNE.S @3 ; If this isn't it . . . <27Oct85> BSET #5,ioVAtrb+1(A0) ; If this is default, drop a hint. <27Oct85> @3 SUBA.L A3,A3 ; Clear WDCB pointer <14Oct85> TST.W ioVolIndex(A0) ; Check volIndex: <21Sep85> BGT.S retVRef ; If vol was indexed, leave things be <21Sep85> TST.W D3 ; Was a volume name specified? <21Sep85> BNE.S retVRef ; If so, always return real file count <21Sep85> MOVE.W ioVRefNum(A0),D1 ; Check VRefNum supplied: <21Sep85> BGT.S retVRef ; If driveNum, ignore it <21Sep85> BLT.S @5 ; If negative, might be a WDRefNum <21Sep85> MOVEQ #2,D1 ; If 0, look at default WDCB <21Sep85> BRA.S @7 ; <21Sep85> @5 CMP.W #WDRfnMax,D1 ; Otherwise, compare to max WDRefNum <21Sep85> BGT.S retVRef ; If it's a real VRefNum, we're OK <21Sep85> ; a WDRefNum was supplied as VRefNum: change the number of files to be the <21Sep85> ; valence of the directory in question: <21Sep85> SUB.W #WDRfnMin,D1 ; Change WDRefNum to index <21Sep85> @7 MOVE.L WDCBsPtr,A3 ; Point to WDCB array <12Oct85> ADD.W D1,A3 ; Point A3 to WDCB for ext. FS <13Oct85> BSR ExtOffLinCk ; Is this an external file system vol? <13Oct85> BNE.S retVRef ; Yes - don't try to read the catalog <13Oct85> MOVEM.L A0-A1,-(A6) ; Use A0,A1 as scratch registers <21Sep85> MOVEA.L WDCBsPtr,A1 ; Point to WDCB array <21Sep85> MOVE.L WDDirID(A1,D1),D0 ; Pick up the DirID in question <21Sep85> CMP.L #FSRtDirID,D0 ; Is it the root directory anyway? <21Sep85> BEQ.S @8 ; If so, don't make special efforts <21Sep85> MOVE.L WDCatHint(A1,D1),D2 ; Pick up directory hint <21Sep85> SUBA.L A0,A0 ; CName = Nil <21Sep85> JSR CMGetCN ; Look up the directory <21Sep85> BNE.S @8 ; If can't find it, forget it. <21Sep85> MOVE.W dirVal(A1),D0 ; Store directory valence <21Sep85> MOVEM.L (A6)+,A0-A1 ; Restore scratch regs <21Sep85> MOVE.W D0,ioVNmFls(A0) ; Replace file count w. dir. valence <21Sep85> BRA.S retVRef ; And continue <21Sep85> @8 MOVEM.L (A6)+,A0-A1 ; Continue without changing file count <24Sep85> ; Do some hairy checking: if a working directory was specified, it shouldn't ; be overwritten by the volRefNum. However, if a volume NAME was used, the ; volRefNum field is ignored, and SHOULD be filled in with the volume's VRefNum. retVRef TST.W D3 ; Was a volume name specified? BNE.S @10 ; If so, always return volRefNum TST.W IOVRefNum(A0) ; VRefNum or WDRefNum supplied? BLT.S @20 ; If so, leave it alone @10 MOVE.W VCBVRefNum(A2),IOVRefNum(A0) ; return volume refnum @20 BSR XferVName ; copy volume name retAlBks BSR TFSVCBTst ; Are we dealing with a TFS volume? <13Oct85> BNE.S @25 ; If not, don't fiddle with NmAlBlks<21Sep85> ; Subtract the physical sizes of the extent B*-Tree and the catalog B*-Tree <21Sep85> ; from the volume size, so that the difference between the volume size and <21Sep85> ; the free space reflects only the user's allocations: <21Sep85> MOVE.W VCBXTAlBks(A2),D0 ; Pick up extent B*-Tree size <21Sep85> SUB.W D0,ioVNmAlBlks(A0) ; Take out XT allocation <21Sep85> MOVE.W VCBCTAlBks(A2),D0 ; Pick up catalog B*-Tree size <21Sep85> SUB.W D0,ioVNmAlBlks(A0) ; Take out CT allocation <21Sep85> @25 BTST #HFSBit,ioTrap(A0) ; TFGetVolInfo vs. plain GetVolInfo? BNE.S @40 ; Br if it's TGetVolInfo MOVE.W #AlBlkLim,D0 ; Pick up our favorite constant, 32767 <11Oct85> CMP.W ioVNmAlBlks(A0),D0 ; Check the number of allocation blocks: <11Oct85> BHI.S @30 ; If we're under the limit, we're fine. <11Oct85> MOVE.W D0,ioVNmAlBlks(A0) ; Otherwise, pin the value there <11Oct85> CMP.W ioVFrBlk(A0),D0 ; Check the number of free blocks: <11Oct85> BHI.S @30 ; If we're under the limit, we're fine. <11Oct85> MOVE.W D0,ioVFrBlk(A0) ; Otherwise, pin the value there <11Oct85> @30 BRA.S GVIDone ; Return some additional information for TGetVolInfo requests: @40 MOVE.W VCBVRefNum(A2),ioVRefNum(A0) ; ALWAYS return VRefNum <25Sep85> MOVE.W VCBSigWord(A2),ioVSigWord(A0) ; Volume signature MOVE.W VCBDrvNum(A2),ioVDrvInfo(A0) ; Driver number MOVE.W VCBDRefNum(A2),ioVDRefNum(A0) ; Driver RefNum MOVE.W VCBFSID(A2),ioVFSID(A0) ; File System ID CLR.L ioVFilCnt(A0) ; Clear top word MOVE.W VCBNmFls(A2),ioVFilCnt+2(A0) ; Stuff low word as if MFS CLR.L ioVDirCnt(A0) ; Clear top word MOVE.W #1,ioVDirCnt+2(A0) ; Stuff low word as if MFS BSR TFSVCBTst ; Are we dealing with a TFS volume? <01Oct85> BNE.S TGVIOK ; No - the information below doesn't exist MOVE.L VCBVolBkup(A2),ioVBkup(A0) ; Last backup date MOVE.W VCBVSeqNum(A2),ioVSeqNum(A0) ; Volume sequence number MOVE.L VCBWrCnt(A2),ioVWrCnt(A0) ; Volume write count MOVE.L VCBFilCnt(A2),ioVFilCnt(A0) ; Files count for volume MOVE.L VCBDirCnt(A2),ioVDirCnt(A0) ; Directory count for volume MOVE.L A0,-(SP) ; Free up A0 as a scratch register LEA ioVFndrInfo(A0),A1 ; Destination finder info LEA VCBFndrInfo(A2),A0 ; Volume's finder info MOVEQ #32,D0 ; Length of finder info _BlockMove ; Copy finder info MOVE.L (SP)+,A0 ; Restore original A0 GVIDone MOVE.L A2,ReqstVol ; Make sure ReqstVol is set up BSR TFSVCBTst ; Are we dealing with a TFS volume? <01Oct85> BNE.S TGVIOK ; No - dont' pass to unsuspecting ext. FS BSR CkExtFS BNE.S TGVIDone TGVIOK MOVEQ #0,D0 ; No errors TGVIDone BRA CmdDone ;_______________________________________________________________________ ; ; Routine: SetVolInfo ; Arguments: A0.L (input) -- I/O PB pointer ; D0.W (output) -- error code (volume locked, wr prot error) ; Called By: ; Function: Change certain user-alterable fields in the VCB ; ; Modification History: ; 14-May-85 PWD New today. ; 6-Oct-85 PWD Moved SetVolName here from TFSDir2. Changed SetVolInfo to ; use SetVolName. ;_______________________________________________________________________ SetVolInfo: BSR FSQueue ; Wait our turn BSR DtrmV1 ; Determine volume by drvnum/refnum BNE.S SVIDone ; Punt on errors BSR CVFlgs ; Check if volume can be modified BNE.S SVIDone ; Give up easily BSR ExtOffLinCk ; Check if volume is on-line, non ext. FS BNE.S SVIDone ; Be a wimp - give up now. ; Set user-modifiable fields in the VCB: 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 BSR TFSVCBTst ; Is it a TFS volume? <01Oct85> BNE.S @3 ; br if not - MFS VCBs don't have <01Oct85> ; 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 MOVE.L A0,-(SP) ; Save IOPB pointer LEA IOVFndrInfo(A0),A0 ; Point to finder info source LEA VCBFndrInfo(A2),A1 ; Finder info in VCB MOVEQ #32,D0 ; Length of finder info _BlockMove ; Copy it in MOVEA.L (SP)+,A0 ; Restore IOPB pointer @3 MOVE.L IOVNPtr(A0),D0 ; New name specified? BEQ.S @10 ; If not, forget it MOVEA.L D0,A1 ; Point to new name BSR.S SetVolName ; Update name in VCB @10 BSR MarkVCB MOVEQ #0,D0 ; All went well... SVIDone BRA CmdDone SetVolName MOVEM.L A1/A2,-(SP) ; Save original VCB pointer LEA VCBVN(A2),A2 ; point to 1st char in name destination MOVEQ #1,D0 ; set up to copy 1st character in name @1 CMP.B (A1),D0 ; Exceeded source length? BGT.S @5 ; If so, call it off CMP.B #':',0(A1,D0) ; Hit a colon? BEQ.S @5 ; Yes - punt. CMP.B #VCBMaxNam,D0 ; Exceeded the max. length? BGT.S @5 ; Yes - stop here. MOVE.B 0(A1,D0),0(A2,D0) ; move in new name ADDQ.W #1,D0 ; Advance to the next character BRA.S @1 ; And try again @5 SUBQ.W #1,D0 ; Back up to real # characters copied MOVE.B D0,(A2) ; Set new name length MOVEM.L (SP)+,A1/A2 ; Reset pointer to VCB BSR MarkVCB ; mark VCB info changed RTS ; And call it a day ;_______________________________________________________________________ ; ; Routine: CVFlgs ; Arguments: A2.L (input) -- VCB pointer ; D0.W (output) -- error code (volume locked, wr prot error) ; Called By: ; Function: Check the volume's flags to see if modify requests are allowed. ; ; Modification History: ; 08 Dec 82 LAK Changed to support new file system data structures. ; ;_______________________________________________________________________ CVFlgs MOVEQ #VLckdErr,D0 ; assume volume locked TST.W VCBAtrb(A2) ; volume locked? BMI.S CVExit ; br if so MOVEQ #WPrErr,D0 ; assume diskette is write protected TST.B VCBAtrb+1(A2) ; bit 7=1 means write protected BMI.S CVExit ; br if so MOVEQ #0,D0 ; otherwise, no error CVExit RTS ; that's all folks (BEQ FOR OK) ;_______________________________________________________________________ ; ; Routine: GetVol ; Arguments: A0.L (input) -- ptr to volume parameter block, uses IOVNPtr, ; IOVDrvNum ; D0.W (output) -- error code ; Calls: FSQueue,CmdDone ; Function: Find out what the name of the default volume is. The volume ; name is stored at IOVNPtr(A0). The maximum length ; of a volume name is 27 bytes. The drive number for the volume ; is also returned. ; ; Modification History: ; 06 Dec 82 LAK Rewrote to reflect file system data structure changes. ; Changed to return name of nth volume (0=default). ; 21 Dec 82 LAK Returns drive number, too. ; 23 Jan 83 LAK Changed to just return the name of the default volume. ; 02 Jun 83 LAK Changed to return volume refnum instead of drive number. ; 30-May-85 PWD Changed to return VRefNum only if drive number of volindex given ; ; Test: existing vol name, illegal vol name, etc. ;_______________________________________________________________________ GetVolTrap: BTST #HFSBit,D1 ; Check if request is TFS-flavor <04Oct85> PWD BNE GetDir ; If so, go to different code altogether<01oct85> BBM BSR FSQueue ; wait for my turn MOVE.L DefVCBPtr,D0 ; ptr to default VCB BEQ.S NSVErrXit ; error if no default volume MOVEA.L D0,A2 ; MOVE.W DefVRefNum,ioVRefNum(A0) ; Return the original default RefNum ; (which could be a WDRefNum) BSR.S XferVName ; Go copy volume name and set D0=0 GetVolDone BRA CmdDone NSVErrXit MOVEQ #NSVErr,D0 BRA.S GetVolDone ; Quick little routine shared by GetVol, GetVolInfo, GetWDCBInfo: returns ; the volume name if IOVNPtr(A0) is not zero . . . ; Returns: D0=0 always . . . XferVName MOVEM.L A1-A2,-(SP) ; Save regs except D0 <31Aug85> LEA VCBVN(A2),A2 ; ptr to vol name MOVE.L IOVNPtr(A0),D0 ; ptr to return name buffer BEQ.S @3 ; don't return name if pointer is nil ; AND.L Lo3Bytes,D0 ; let's add in a range check cause <10Dec86> ; CMP.L MemTop,D0 ; it's a common error to forget to <10Dec86> ; BGT.S @3 ; fill in the name ptr . . . <10Dec86> _StripAddress ; clean up the address before using it <10Dec86> MOVE.L D0,A1 ; A1 = cleaned up name buffer ptr MOVEQ #0,D0 ; Clear upper bytes MOVE.B (A2),D0 ; len of volume name @2 MOVE.B (A2)+,(A1)+ ; move a char of name DBRA D0,@2 ; loop until all + 1 done (length too) @3 MOVEM.L (SP)+,A1-A2 ; Restore regs <31Aug85> MOVEQ #0,D0 ; Always a success RTS ;_______________________________________________________________________ ; ; Routine: SetVol ; Arguments: A0.L (input) -- ptr to volume parameter block: volume may be ; specified by either IODrvNum or IOFileName ; D0.W (output) -- error code ; All other regs are preserved ; Calls: DtrmV3 ; Function: Set the current default volume. The volume must be mounted ; and may be specified by either name or drive number. If neither ; is specified, the default volume is set to the current value ; if there is a current default (otherwise an error is reported). ; The volume name may be followed by a filename (for convenience). ; ; Modification History: ; 06 Dec 82 LAK Rewrote to reflect file system data structure changes. ; 14 Jan 83 LAK Minor rework. ; 14-Mar-85 PWD Changed to set up default WDCB ; 9-Jul-85 PWD Changed to preserve default VRefNum (or WDRefNum) in DefVRefNum ; 20-Sep-85 PWD Fixed bug in determination of new DefVRefNum when vol. spec'd by name ; 24-Sep-85 PWD Changed to branch to SetDir when TFS bit is set on trap ; ; Test: existing vol name, illegal vol name, etc. ;_______________________________________________________________________ SetVolTrap: BTST #HFSBit,D1 ; Check if request is TFS-flavor <02Oct85> BNE.S SetDir ; If so, go to different code altogether<24Sep85> BSR FSQueue ; wait for my turn BSR DtrmV3 ; determine the volume being asked for BNE.S @20 ; br if we couldn't <31Aug85> MOVE.W VCBVRefNum(A2),D0 ; Pick up the new default vol's refNum <20Sep85> TST.W D3 ; Was a volume name spec'd? <20Sep85> BNE.S @3 ; If so, use its VRefNum straight <20Sep85> TST.W ioVRefNum(A0) ; Otherwise, was a driveNum given? <20Sep85> BGT.S @3 ; If so, use the VRefNum from the VCB <20Sep85> MOVE.W ioVRefNum(A0),D0 ; Pick up the VRefNum supplied BEQ.S @5 ; If none was supplied, leave the world as is @3 MOVE.W D0,DefVRefNum ; Save this VRefNum/WDRefNum for posterity ; ... but mostly for GetVol's use @5 MOVEQ #FSRtDirID,D6 ; Default directory is the volume's root MOVE.L A3,D7 ; Working directory specified (may zero hint) BEQ.S @10 ; If not, hint is zeroed, we're all set MOVE.L WDDirID(A3),D6 ; Directory ID of working directory MOVE.L WDCatHint(A3),D7 ; Catalog hint @10 BSR SetDefWDCB ; And go fill in the default WDCB MOVEQ #0,D0 ; Return success @20 BRA CmdDone ; And call it a day. ;_______________________________________________________________________ ; ; Routine: SetDir ; Arguments: A0.L (input) -- I/O parameter block ; D0.W (output) -- error code ; Called By: ; Function: Set the default directory (and, implicitly, the default volume). ; ; Modification History: ; ; 14-Mar-85 PWD New today. ; 21-Sep-85 PWD Changed to alloc null file names (or just 'vol name:') as well ; as Nil file name pointers. ; ;_______________________________________________________________________ SetDir: BSR FSQueue ; Wait for our turn to come BSR FndFilName ; Look for the indicated directory BEQ.S @0 ; continue if all went well ; Special hack to allow MFS volumes to be specified by volume name only (which ; normally causes FndFilName to choke on the zero-length file name remaining): CMP.W #BdNamErr,D0 ; Was it a bad name? <21Sep85> BNE.S SetDirExit ; Nope - give up <21Sep85> TST.B D2 ; Yes - 'cuz there wasn't one? <21Sep85> BNE.S SetDirExit ; Nope - give up after all <21Sep85> MOVEQ #FSRtDirID,D6 ; Yes - OK, use the root on MFS <21Sep85> BRA.S SetDefDir ; Yes - that's OK here... <21Sep85> @0 MOVEQ #DirNFErr,D0 ; Let's be pessimistic here CMP.B #CDRDirRec,CDRType(A5) ; Was record a directory? BNE.S SetDirExit ; Thought so... MOVE.L DirDirID(A5),D6 ; DirID to set up = directory's DirID ; ; Since SetDir may arrive at the final directory from a pathname relative to a ; working directory, SetDir cannot simply set DefVRefNum to the WDRefNum supplied, ; to be returned by GetVol. SetDir ALWAYS stores the real VRefNum, therefore... ; SetDefDir MOVE.W VCBVRefNum(A2),DefVRefNum ; Save this VRefNum for posterity ; ... but mostly for GetVol's use MOVEQ #0,D7 ; No catalog hint known. BSR SetDefWDCB ; Set up the default WDCB SetDirOK MOVEQ #0,D0 ; Return success SetDirExit BRA CmdDone ; And that's all, folks! ;_______________________________________________________________________ ; ; Routine: GetDir ; Arguments: A0.L (input) -- I/O parameter block ; D0.W (output) -- error code ; Called By: ; Function: Get the default volume's name and the current default directory. ; ; Modification History: ; ; 14-Mar-85 PWD New today. ; 14-Oct-85 PWD Added call to XferVName now that RetDefInfo doesn't do it anymore ;_______________________________________________________________________ GetDir: BSR FSQueue ; Wait our turn BSR Gt1stWDCB ; Set up A1, D1 to point at first WDCB <28Aug85> MOVEQ #NSVErr,D0 ; Assume no default directory set TST.L WDVCBPtr(A1,D1) ; Is this entry actually set up? BEQ.S @1 ; If not, we're finished right here & now <28Aug85> BSR RetDefInfo ; Otherwise - return the WDCB information BSR XferVName ; Return the name of the associated volume MOVE.W DefVRefNum,ioVRefNum(A0) ; Return the original default RefNum MOVEQ #0,D0 ; A totally stunning success @1 BRA CmdDone ; Call it a day. ;_______________________________________________________________________ ; ; Routine: OpenWD ; Arguments: A0.L (input) -- I/O parameter block ; D0.W (output) -- error code ; Called By: ; Function: Create a working directory control block from the pathname ; information in the parameter block. ; ; Modification History: ; ; 14-Mar-85 PWD New today. ; 1-Jul-85 PWD Changed to recycle WDRefNums for callers with same procID ; and return WDRefNum in ioVRefNum field. ; 21-Sep-85 PWD Changed to allow opening of root of MFS volumes with DirID=2 ; and null or nil filename. ;_______________________________________________________________________ OpenWDTrap: BSR FSQueue ; Wait for our turn to come BSR FndFilName ; Look for the indicated directory BEQ.S @1 ; Br if found CMP.W #BdNamErr,D0 ; Was it a bad filename? <21Sep85> BNE.S opnWDExit ; If not, there's no more hope <21Sep85> TST.B D2 ; Otherwise, check the name length <21Sep85> BNE.S opnWDExit ; If nonzero, it's real BdNamErr <21Sep85> BRA.S @2 ; Return VRefNum for MFS null file names<21Sep85> @1 MOVEQ #DirNFErr,D0 ; Let's be pessimistic here CMP.B #CDRDirRec,CDRType(A5) ; Was record a directory? BNE.S opnWDExit ; Thought so... MOVE.L DirDirID(A5),D6 ; DirID to set up = directory's DirID CMP.L #FSRtDirID,D6 ; Accessing the root? <21Sep85> BEQ.S @2 ; Nope - create a real new WDCB <21Sep85> MOVEQ #0,D7 ; No catalog hint known. BSR.S PickWDCB ; Look for a suitable WDCB BRA.S opnWDExit @2 MOVE.W VCBVRefNum(A2),ioVRefNum(A0) ; Return the VRefNum as WDRfn <21Sep85> opnWDOK MOVEQ #0,D0 ; Call it a success <21Sep85> opnWDExit BRA CmdDone ; we're finished . . . SetDefWDCB MOVE.L A2,DefVCBPtr ; set the (new?) default MOVEQ #2,D1 ; Pick the default-WDCB FillWDCB MOVE.L WDCBsPtr,A1 ; Point to the WDCB array MOVE.L A2,WDVCBPtr(A1,D1.W) ; Set the default VCB MOVE.L D6,WDDirID(A1,D1.W) ; In the default WDCB MOVE.L D7,WDCatHint(A1,D1.W) ; Catalog hint for this directory MOVE.L ioWDProcID(A0),D0 ; Pick up caller's procID MOVE.L D0,WDProcID(A1,D1.W) ; Mark WDCB with it ADD.W #WDRfnMin,D1 ; Offset into the WDCB Refnum range RTS ; And return it to the caller ; Look for a matching working directory, starting with the third (the first two are ; reserved to hold the system-wide volume and directory defaults). EXPORT PickWDCB ; rb 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 jsr Gt1stWDCB ; Set up A1, D1 (point at first WDCB) jsr GtNxtWDCB ; Point at 2nd WDCB ; (A1,D1)=WDCB, D2=freeRefNum, @1 ADDA D3,A3 ; Point at next Extended WDCB jsr GtNxtWDCB ; 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 jsr FillWDCB ; 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 ;_______________________________________________________________________ ; ; Routine: CloseWD ; Arguments: A0.L (input) -- I/O parameter block ; D0.W (output) -- error code ; Called By: ; Function: Release the storage used for a working directory control block. ; ; Modification History: ; ; 14-Mar-85 PWD New today. ; 1-Jul-85 PWD Changed to do away with VCBWDCnt maintenance ; Changed to take WDRefNum in ioVRefNum field. ; 6-Aug-85 PWD Changed to call external FS (WITHOUT clearing WDCB!) ; 20-Aug-85 PWD Changed to make VRefNum arg a no-op. ; ;_______________________________________________________________________ CloseWDTrap: BSR FSQueue ; Wait for our turn to come MOVEQ #0,D1 ; Clear top half of D1 MOVE.W IOVRefNum(A0),D1 ; Pick up the WDRefNum BSR CkWDRefNum ; Check if it's OK for use, set up A1=WDCBSptr <31Aug85> BEQ.S @1 ; Br if so CMP.W #WDRfnMax,D1 ; Is it a VRefNum? <20Sep85> BHI.S clsWDOK ; OK HI ($F000-$FFFF) . . . (assume valid VRefNum) BRA.S clsWDExit ; Punt on errors ; The refnum provided checked out OK: @1 SUB.W #WDRfnMin,D1 ; Offset to change to WD array index MOVEA.L WDVCBPtr(A1,D1),A2 ; Pick up volume referred to TST.W VCBFSID(A2) ; Mac FS? BEQ.S @2 ; Yes - please continue MOVE.L A2,ReqstVol ; No - indicate such to the external FS ADD.L A1,D1 ; Point D1 to WDCB MOVEQ #ExtFSErr,D0 ; And leave this one alone BRA.S clsWDExit ; @2 CLR.L WDVCBPtr(A1,D1) ; Clear the VCB pointer to free the WDCB clsWDOK MOVEQ #0,D0 ; Success at last! clsWDExit BRA CmdDone ; Leave by common exit ;_______________________________________________________________________ ; ; Routine: GetWDInfo ; Arguments: A0.L (input) -- I/O parameter block ; D0.W (output) -- error code NSVErr = couldn't find it ; Called By: ; Function: Read the information in a WDCB for a given volume. ; ; Modification History: ; ; 1-May-85 PWD New today. ; 1-Jul-85 PWD Changed to match procID on indexed requests. ; 6-Aug-85 PWD Changed to call external FS for ext. FS volumes AFTER ; copying volume information. ; 22-Aug-85 PWD Changed to return root information for requests by RefNum ; <28Aug85> LAK Fixed bug in indexed get. Now allows specification by ; default volume even, or drive number . . . why not? No ; more ParamErr, it's NSVErr or it's ok. ;_______________________________________________________________________ GetWDInfoTrap: BSR FSQueue ; Wait our turn BSR.S GetWDCBInfo ; Return the WDCB information BNE.S GtWDIExit ; Punt on errors EXT.L D1 ADD.L A1,D1 ; Point D1 to WDCB for extFS MOVE.L A2,ReqstVol ; in case of extFSErr BSR CkExtFS ; Is this an external file system volume? BNE.S GtWDIExit ; br if not (pass D1=WDCB ptr or 0 if not a WDCB) GtWDIOK MOVEQ #0,D0 ; Otherwise, a total success GtWDIExit BRA CmdDone ; And call it a day. ; ; Subroutine shared between _GetWDInfo (queuing) and _ReadWDCB (non-queueing): ; GetWDCBInfo TST.W ioWDIndex(A0) ; Test working dir index BGT.S IndxWDInfo ; If positive, look up WD by index/volume ; Return information for a specific Working Directory, indicated by RefNum: MOVEQ #0,D1 ; CkWDRefNum needs high word of D1 inited to zero <15APR86> PWD MOVE.W IOVRefNum(A0),D1 ; Pick up a WDRefNum/VRefNum BSR CkWDRefNum ; Check its integrity (trashes D0, sets A1=WDCBsPtr) BEQ.S getWD_1 ; br if it's a valid WDCB refnum <22Aug85> BSR DtrmV1 ; Does VRefNum specify a valid volume? <22Aug85> BNE.S GetWDIExit ; Give up easily <22Aug85> ; By special arrangement, calling _GetWDInfo with a VRefNum will fill out <22Aug85> ; a working directory arrangement for the root: <22Aug85> CLR.L ioWDProcID(A0) ; No proc. id's defined for system <22Aug85> MOVEQ #FSRtDirID,D0 ; <22Aug85> MOVE.L D0,ioWDDirID(A0) ; Pick up the volume's root directory ID<22Aug85> MOVE.W VCBVRefNum(A2),ioWDVRefNum(A0) ; Return the volume's refNum <22Aug85> MOVE.W VCBVRefNum(A2),ioVRefNum(A0) ; for both fields . . . <22Aug85> MOVEQ #0,D1 ; no WDCB ptr for extFS . . . <28Aug85> BRA.S XferVN ; proceed to return the name (pass A2) <22Aug85> ; WD refnum was supplied and ioWDIndex<=0, so return a specific entry . . . getWD_1 MOVEQ #NSVErr,D0 ; Let's just assume thing's aren't cool SUB.W #WDRfnMin,D1 ; Change refNum to index TST.L WDVCBPtr(A1,D1) ; This entry really in use? BEQ.S GetWDIExit ; Nope - too bad. BRA.S XferWDInfo ; Yes - fill in the info (pass A1, D1) IndxWDInfo MOVEQ #NSVErr,D0 ; Let's be pessimistic for a moment... MOVEQ #0,D2 ; assume no volume match TST.W IOVRefNum(A0) ; Was a VRefNum supplied? BEQ.S @1 ; Nope - go for it BSR DtrmV3 ; Find the VCB BNE.S GetWDIExit ; Punt if no volume found MOVE.L A2,D2 ; Stash VCB pointer ; Try to find the requested WDCB: @1 MOVE.W ioWDIndex(A0),D4 ; Get a hold of the working dir. index MOVE.L ioWDProcID(A0),D3 ; Pick up the caller's procID, if any MOVEQ #NSVErr,D0 ; Start out pessimistic BSR Gt1stWDCB ; Set up A1, D1 (point at first WDCB) BSR GtNxtWDCB ; Point at 2nd WDCB getWDLoop BSR GtNxtWDCB ; Point at next WDCB (the first two WDCBs are not counted) BCC.S GetWDIExit ; Br if we've seen them all TST.L WDVCBPtr(A1,D1) ; Is this WDCB in use? BEQ.S getWDLoop ; If EQ, it's not (only count the used ones) TST.L D3 ; Match on procID? BEQ.S @1 ; If not, don't bother checking CMP.L WDProcID(A1,D1),D3 ; Is it for this caller? BNE.S getWDLoop ; If no match, it's not @1 TST.L D2 ; Match on volume? BEQ.S @2 ; No - this WDCB is OK CMP.L WDVCBPtr(A1,D1),D2 ; Yes - for requested volume? BNE.S getWDLoop ; If not, skip it. @2 SUBQ.W #1,D4 ; Count down: one done BGT.S getWDLoop ; Keep going until the right one's found XferWDInfo BSR.S RetWDInfo ; Copy out the Working directory information XferVN BSR XferVName ; Copy volume name (sets D0) GetWDIExit TST.W D0 ; Set condition codes RTS ; And call it a day. ReadWDCB: MOVEM.L D3-D7/A1-A6,-(SP) ; Save registers [normally done in FSQueue] MOVEA.L HFSStkTop,A6 ; Set up A6 for use as stack pointer BSR GetWDCBInfo ; Pick up the WDCB information requested MOVEM.L (SP)+,D3-D7/A1-A6 ; Restore scratch registers [normally CmdDone] MOVE.W D0,IOResult(A0) ; post result code RTS ; Call it a day ; Small routine to transfer the information of interest: ; (RetDefInfo called by GetDir) ; Expects: A1,D1 ; Returns: A2=WDVCBPtr(A1,D1) ; Blows: D0 RetWDInfo: ; GetWDInfo entry MOVE.L WDProcID(A1,D1),ioWDProcID(A0) ; Copy ProcID (NOT FOR GETDIR . . .) RetDefInfo: ; GetDir entry MOVEA.L WDVCBPtr(A1,D1),A2 ; Point to VCB for associated volume MOVE.W VCBVRefNum(A2),ioWDVRefNum(A0) ; Copy VRefNum MOVE.L WDDirID(A1,D1),ioWDDirID(A0) ; Copy WD's DirID MOVE.W D1,D0 ; use D0 as scratch <31Aug85> ADD.W #WDRfnMin,D0 ; Convert index back to WD RefNum <31Aug85> MOVE.W D0,ioVRefNum(A0) ; And return it to the user <31Aug85> RTS ; Call it a day <14Oct85> ;_______________________________________________________________________ ; ; Routine: CkWDRefNum ; Arguments: D1.L (input) -- WDCB RefNum (top half should be 0) ; D0.W (output) -- 0 for success, or RFNumErr ; A1.L (output) -- WDCBsPtr ; Called By: ; Function: A quick common routine to check a WDCB refnum for validity. ; ; Modification History: ; ; 1-May-85 PWD New today. ; <28Aug85> LAK Some short branches, please. Also removed redundant check ; against min and max (this is accomplished by the unsigned ; compare against index bounds). ; <15Sep86> BB Added check for a zero VCB pointer in the WDCB indicating ; that the WD is already closed. ;_______________________________________________________________________ ; CkWDRefNum MOVE.L D1,-(SP) ; Save D1 across the call <29Aug85> MOVEQ #RFNumErr,D0 ; Let's just assume thing's aren't cool SUB.W #WDRfnMin,D1 ; Offset to zero MOVEA.L WDCBsPtr,A1 ; Point to the WDCB array CMP.W (A1),D1 ; Pointing beyond the end? BCC.S WDRfnCkExit ; Yes - bad news. <28Aug85> SUBQ.W #2,D1 ; Compensate for the length word DIVU #WDCBLen,D1 ; Divide by the length of a WDCB SWAP D1 ; Get a hold of the remainder TST.W D1 ; Check if it's zero BNE.S WDRfnCkExit ; Unmasked at last! <28Aug85> MOVE.L (SP),D1 ; WD RefNum <15Sep86> SUB.W #WDRfnMin,D1 ; Offset to zero TST.L WDVCBPtr(A1,D1) ; check VCB pointer <15Sep86> BEQ.S WDRfnCkExit ; its zero, WD is aready closed <15Sep86> MOVEQ #0,D0 ; OK - all seems well. WDRfnCkExit MOVE.L (SP)+,D1 ; Restore original D1 value <29Aug85> TST.W D0 ; Set CCR <28Aug85> RTS ;_______________________________________________________________________ ; ; Routine: SetUpWDCB, SetupDef ; Arguments: A0.L (input) -- I/O Parameter block ; Uses: ioVRefNum - Volume to refer to ; ioDirID - Directory of choice ; ioWDProcID - Caller's procID ; ; D0.W (output) -- error code, or 0 for success ; ioVRefNum(A0) -- Updated with WDRefNum if D0 = 0 on output. ; (from SetUpWDCB) ; Called By: ; Function: A low-level routine to set up a WDCB, or the default WDCB ; in particular ; ; Modification History: ; ; 22-May-85 PWD New today. ; 26-Sep-85 PWD Added SetupDef entry point for external FS support. ;_______________________________________________________________________ ; NOTE: This code executes under special conditions: since it does NOT call ; FSQueue on entry, A6 is never set up; any code called from this routine ; cannot rely on A6 being set. Furthermore, it does NOT provide the ; standard full-fledged file finding: VRefNum/DirID is the ONLY valid input. SetUpWDCB: MOVEM.L D3-D7/A1-A6,-(SP) ; Save registers (not done in FSQueue now...) MOVEA.L HFSStkTop,A6 ; Set up A6 for use as stack pointer BSR DtrmV1 ; Determine the volume of choice BNE.S SetWDExit ; Punt on errors MOVE.L ioDirID(A0),D6 ; Requested DirID MOVEQ #0,D7 ; No known catalog hint BSR PickWDCB ; Select and fill a WDCB, or BNE.S SetWDExit ; ... bail out with an error MOVE.W D1,ioVRefNum(A0) ; Return a WDRefNum, because SetWDOK MOVEQ #0,D0 ; ... All went well SetWDExit MOVEM.L (SP)+,D3-D7/A1-A6 ; Restore scratch registers MOVE.W D0,ioResult(A0) ; Set up result code RTS ; And call it a day. ; [returns directly to trap dispatcher] SetupDef: MOVEM.L D3-D7/A1-A6,-(SP) ; Save registers, same as SetUpWDCB <26Sep85> MOVEA.L HFSStkTop,A6 ; Set up A6 for use as stack pointer BSR DtrmV1 ; Determine volume by refNum/driveNum <26Sep85> BNE.S SetWDExit ; Punt on errors <26Sep85> MOVE.W VCBVRefNum(A2),DefVRefNum ; Save this one for posterity <26Sep85> MOVE.L ioDirID(A0),D6 ; Requested DirID <26Sep85> MOVEQ #0,D7 ; No hint known <26Sep85> BSR SetDefWDCB ; Set up the full default WDCB <26Sep85> BRA.S SetWDOK ; And call it a day <26Sep85> ; [returns directly to trap dispatcher] <26Sep85>