mac-rom/OS/HFS/TFSVOL.a
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

2922 lines
126 KiB
Plaintext

;
; 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):
;
; <SM8> 8/27/93 BH Backed out SetVolInfo changes from <SM7>. The flushing stuff is
; now in CmdDone.
; <SM7> 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.
; <SM5> 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).
; <SM4> 12/1/92 RB Exported PickWDCB so it can be vectorized for FSM use.
; <SM3> 10/22/92 CSS Change some branch short instructions to branches.
; <SM2> 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.
; <SM1> 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.
; <C193> 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 <SM1>
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 <SM3> 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 ; <SM7> <BH 03Aug93>
BSR SetVCBManEject ; set vcb maneject flag appropriately <SM7> <BH 03Aug93>
ENDIF ; <SM7> <BH 03Aug93>
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 ; <SM7> <BH 03Aug93>
BSR SetVCBManEject ; set vcb maneject flag appropriately <SM7> <BH 03Aug93>
ENDIF ; <SM7> <BH 03Aug93>
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 <SM1>
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) <PWD 07Oct85>
BLE CmdDone ; Yes - We're all done, then. <PWD 07Oct85>
MOVE.L FSQHead,A0 ; A0 -> current request <PWD 07Oct85>
BRA mv_Start ; So start all over again, but don't even THINK <PWD 07Oct85>
; about the possibility of a ReMount this time. <PWD 07Oct85>
; 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>
; <Use catalog hint still in D2>
; 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 ; <SM7> <BH 03Aug93>
;--------------------------------------------------------------------------------------
; 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 <SM1>
OffLine:
BSR FSQueueSync ; wait until all current calls are done <SM1>
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 <SM1>
; 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 <SM1>
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><v1.4>
BSR.L EnQueueTrap ; the end for round-robin offline scheme <29Aug85><v1.4>
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:
; <SM1> 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 ; <SM1> 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 <SM1>
@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 <SM5> CSS
bne.s FLVolOK ; just a flush <SM5> 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:<dirname:><dirname:><etc>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 <SM1>
; (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:<dirname:>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 <PWD 06Oct85>
BSR.S SetVolName ; Update name in VCB <PWD 06Oct85>
@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 <PWD 06Oct85>
MOVEQ #1,D0 ; set up to copy 1st character in name <PWD 06Oct85>
@1 CMP.B (A1),D0 ; Exceeded source length? <PWD 06Oct85>
BGT.S @5 ; If so, call it off <PWD 06Oct85>
CMP.B #':',0(A1,D0) ; Hit a colon? <PWD 06Oct85>
BEQ.S @5 ; Yes - punt. <PWD 06Oct85>
CMP.B #VCBMaxNam,D0 ; Exceeded the max. length? <PWD 06Oct85>
BGT.S @5 ; Yes - stop here. <PWD 06Oct85>
MOVE.B 0(A1,D0),0(A2,D0) ; move in new name <PWD 06Oct85>
ADDQ.W #1,D0 ; Advance to the next character <PWD 06Oct85>
BRA.S @1 ; And try again <PWD 06Oct85>
@5 SUBQ.W #1,D0 ; Back up to real # characters copied <PWD 06Oct85>
MOVE.B D0,(A2) ; Set new name length <PWD 06Oct85>
MOVEM.L (SP)+,A1/A2 ; Reset pointer to VCB <PWD 06Oct85>
BSR MarkVCB ; mark VCB info changed <PWD 06Oct85>
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 <PWD 14Oct85>
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 ; <SM4> 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 <PWD 14Oct85>
BNE.S GtWDIExit ; Punt on errors <PWD 14Oct85>
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? <PWD 14Oct85>
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. <PWD 14Oct85>
;
; Subroutine shared between _GetWDInfo (queuing) and _ReadWDCB (non-queueing): <PWD 14Oct85>
;
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) <PWD 14Oct85>
GetWDIExit TST.W D0 ; Set condition codes <PWD 14Oct85>
RTS ; And call it a day. <PWD 14Oct85>
ReadWDCB: MOVEM.L D3-D7/A1-A6,-(SP) ; Save registers [normally done in FSQueue] <PWD 14Oct85>
MOVEA.L HFSStkTop,A6 ; Set up A6 for use as stack pointer <PWD 14Oct85>
BSR GetWDCBInfo ; Pick up the WDCB information requested <PWD 14Oct85>
MOVEM.L (SP)+,D3-D7/A1-A6 ; Restore scratch registers [normally CmdDone] <PWD 14Oct85>
MOVE.W D0,IOResult(A0) ; post result code <PWD 14Oct85>
RTS ; Call it a day <PWD 14Oct85>
; 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 <C193>
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 <PWD 14Oct85>
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 <PWD 14Oct85>
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 <PWD 14Oct85>
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>