sys7.1-doc-wip/OS/HFS/Extensions/BTPScan.a

467 lines
18 KiB
Plaintext
Raw Normal View History

2020-03-22 08:44:21 +00:00
;
; Hacks to match MacOS (most recent first):
;
; <Sys7.1> 8/3/92 Reverted <SM1> by putting back the "ROM" prefixes.
; 9/2/94 SuperMario ROM source dump (header preserved below)
;
2019-07-27 14:37:48 +00:00
;
; File: BTPScan.a
;
; Written by: David Feldman
;
; Copyright: © 1988-1992 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM1> 4/15/92 kc Removed the "ROM" prefix from the RomBind routines.
; • Pre-SuperMario comments follow •
; <13> 9/13/91 JSM Cleanup header.
; <12> 3/11/91 dnf dba, #83780: Remove HFS stack overflow check from BTPScan, which
; isnt the right place for such a check. Also, this was left over
; debugging code which should be removed. Also, this code didnt
; really help because it checks the stack depth at the wrong time.
; <11> 2/12/91 dnf gbm, #RemoveDebuggerStatements: Change _Debugger break on stack
; overflow to a call to _SysErr with #dsFSErr.
; <10> 1/17/91 dnf (kst) Turn on the “please cache this” advisory bit when reading
; catalog nodes. Do a FlushVFiles before we start parsing records
; <9> 11/06/90 dnf (with dba) Remove explicit noCache setting on _Reads. Kenny's
; spiffy new cache code makes the cache case better.
; <8> 10/30/90 dnf (with dba) Fix off-by-one bug that was screwing up handling of
; the noMoreReads bit (showed up in timed CatSearch).
; <7> 9/22/90 dnf Add error check to #FirstTime case through ValidateNode
; <6> 9/10/90 dnf Fix incorrect handling of catPositionChangedErr.
; <5> 8/20/90 gbm (dnf and gbm, actually) Fix overcounting of nodes on search
; exit/restart.
; <4> 7/30/90 dnf convert to linked patch; change rom reference names and use
; jsrRom macro.
; <3> 2/26/90 dnf Add support for NoMoreReads bit and LastTime bit
; <2> 2/4/90 dnf Get rid of include of HFS70Equ.a
; <1.3> 9/7/89 dnf Rewrote BTIPScan and BTEndPScan to support CatPosition record
; <1.2> 8/26/89 dnf Put in temporary code to check for stack high water mark
; <1.1> 7/31/89 dnf Change cache bypass to per-call, redo BTGetPhys
; <1.0> 5/30/89 dnf Integrate CatSearch, FileID's and Desktop Database Mgr into one
; ptch
; 12/20/88 dnf Broke off from CatSearch
;
; BTree Manager routines
; Function: These routines provide rapid access to unordered BTree records
;
; External BTIPScan - Initializes state info for a physical file scan, returns 1st record
; Routines: BTEndPScan - Cleans state off of A6 stack, returns hint
; BTGetPhys - Increments current record, gets it
;
; Internal GetMultNodes - Reads disk-order sequential Btree nodes
; Subroutines: ValidateNode - Validates PSR.curNodePtr
; ValidateRec - Finds next valid record at or after PSR.curRec
;
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'BTScanPriv.a'
Include 'FileMgrPrivate.a'
Include 'LinkedPatchMacros.a'
PRINT ON
export BTGetPhys
;__________________________________________________________________________________
;
; Routine: BTIPScan
;
; Function: Initializes PScan state record on A6 stack.
; Checks CatPosition record
; Returns 1st record from btree
;
; Input: D0.W - Btree reference number
; D3.L - Length of read buffer
; A0.L - Pointer to CatPos record
; A1.L - Address of read buffer
;
; Output: D0.L - result code (CatPosChanged or result from BTFirstPhys)
; D1.W - size of record
; A0.L - ptr(key)
; A1.L - ptr(data record)
; A4.L - pointer to PScan state record
; A6.L - lower by size of PScan state record
; Called by: CMCatSearch
;__________________________________________________________________________________
BTIPScanRegs reg a2
BTIPScan: proc export
SUBA.W #PSR.size, A6 ; allocate a state record on A6 stack
MOVEA.L A6, A4 ; save pointer to state record
MOVE.L (SP)+, -(A6) ; move return address to file system stack
MOVE.L A2, -(A6) ; save a2
with CatPosition
MOVEA.L FCBSPtr, A2 ; A2 = ptr(base of FCB array)
ADDA.W D0, A2 ; A2 = ptr(Btree FCB)
MOVE.L A2, PSR.fcbPtr(A4) ; hold on to fcbPtr
st FlushOnly ; only flushing . . .
move.l fcbVPtr(a2), a2 ; vcb pointer into a2
jsrROM FlushVFiles ; flush all files on this volume
bne.s @BTIExit ; bail on the first hint of trouble
move.l PSR.fcbPtr(a4), a2 ; a2 = ptr(Catalog FCB)
MOVE.L fcbBTCBPtr(A2), A2 ; A2 = ptr(Catalog Btree BTCB)
MOVE.L A2, PSR.btcbPtr(A4) ; hold on to btree control block ptr
MOVE.L D3, PSR.readBufLen(A4) ; hold on to length of read buffer
MOVE.L A1, PSR.readBufPtr(A4) ; hold on to address of read buffer
MOVE.L cpNodeNumber(A0), PSR.curNode(A4) ; move 1st btree node # to state record
MOVE.W cpRecNumber(A0), PSR.curRec(A4) ; move 1st record # to state record
MOVE.L cpGoodNodeCount(A0), PSR.goodCount(A4) ; move count to state record
MOVE.L btcNNodes(A2), D0 ; D0 = total # of nodes in catalog btree
SUB.L btcFree(A2), D0 ; D0 = total # - free nodes. ( = # allocated)
MOVE.L D0, PSR.maxNodes(A4) ; D0 = max # nodes we need to look at
CLR.B PSR.flags(A4) ; clear the flags
MOVE.L cpWriteCount(A0), D0 ; D0 = user's expected writecount
BNE.S @UserWriteCount
; the user put a zero in the writecount, indicating that we should
; start at the beginning of the catalog.
CLR.L PSR.curNode(A4)
CLR.W PSR.curRec(A4)
CLR.L PSR.goodCount(A4)
MOVE.L btcWCount(A2), D0 ; D0 = current catalog writecount
MOVE.L D0, cpWriteCount(A0) ; validate the user's position
@UserWriteCount:
CMP.L btcWCount(A2), D0 ; does the catalog's writecount match the user's?
BEQ.S @sameCatalog
MOVE.L btcWCount(A2), cpWriteCount(A0) ; store current writecount in case caller really wants it
MOVE.W #catChangedErr, d0 ; report the catalog changed error
BRA.S @BTIExit
@sameCatalog:
BSET #FirstTime, PSR.flags(A4) ; since the buffer is empty, force a read
BSR BTGetPhys ; go get the 1st record
@BTIExit:
MOVE.L (A6)+, A2 ; restore a2
MOVE.L (A6)+, -(SP) ; restore return address
TST.W D0 ; re-test the result code to set flags
RTS
endwith
endproc
;__________________________________________________________________________________
;
; Routine: BTEndPScan
;
; Function: Cleans up PScan state record on A6 stack and transfers btree position
; back into CatPosition record.
;
; Input: A0.L - pointer to CatPos record
; A4.L - pointer to PScan state record
;
; Output: A0.L - pointer to updated CatPos record
; A6.L - higher by size of PScan state record
;
; Called by: CMCatSearch
;__________________________________________________________________________________
BTEndPScan: proc export
with CatPosition
MOVE.L PSR.curNode(A4), cpNodeNumber(A0) ; save node we're on now
MOVE.W PSR.curRec(A4), cpRecNumber(A0) ; save record we're on now
MOVE.L PSR.goodCount(A4), cpGoodNodeCount(A0) ; save how many good nodes we've seen
ADDA.W #PSR.size, A6 ; deallocate state record
RTS
endwith
endproc
;__________________________________________________________________________________
;
; Routine: GetMultNodes
;
; Function: Reads multiple Btree nodes into a buffer.
; Nodes in buffer are "raw", I.E. not ChkNode'd
; GetMultNodes trusts the caller about the size of the read buffer
;
; Input: D1.L - # nodes wanted
; D2.L - 1st btree node wanted
; A1.L - address of read buffer
; A2.L - BTCB ptr
;
; Output: D0.W - result code (from read)
;
; Called by: ValidateNode
;__________________________________________________________________________________
GMRegs reg D1-D6/A0-A3
GetMultNodes: proc
MOVE.L (A7)+, -(A6) ; move return address to HFS stack
MOVEM.L GMRegs, -(A6)
SUBA.W #HIOP.size, A6 ; allocate a param block on A6
MOVEA.L A6, A0 ; A0 = ptr(param block)
MOVE.W btcRefNum(A2), HIOP.ioRefNum(A0) ; refNum of btree file
MULU btcNodeSize(A2), D1 ; D1 = # bytes wanted
MOVE.L D1, HIOP.ioReqCount(A0) ; for consistency, stick in ioReqCount
MOVE.L A1, HIOP.ioBuffer(A0) ; user's buffer
MULU btcNodeSize(A2), D2 ; D2 = byte position of 1st node requested
MOVE.L D2, D5 ; CacheRdIP wants file pos in D5
MOVE.L FCBSPtr, A1 ; A1 = ptr(FCB array)
MOVE.W btcRefNum(A2), D1 ; (A1, D1.W) = FCB ptr
MOVE.L HIOP.ioReqCount(A0), D4 ; D4 = # bytes (for CacheRdIP)
LEA (A1, D1.W), A3 ; A3 = ptr(FCB)
MOVEA.L fcbVPtr(A3), A2 ; A2 = ptr(VCB) (for CacheRdIP)
; Since I don't call seek, I'll set the inputs anyway, for consistency
MOVE.W #fsFromStart, HIOP.ioPosMode(A0) ; we'll set the mark ourselves <1.1> <9>
ori.b #fsCacheAdvise, HIOP.ioPosMode+1(a0); ask for extra caching attention <10>
MOVE.B #fsRdPerm, HIOP.ioPermssn(A0) ; read permission on file
CLR.L ioPosOffset(A0) ; offset = 0 'cus we're doing the mapping
CLR.L ioActCount(A0) ; since we haven't read any bytes yet
MOVE.L D2, fcbCrPs(A3) ; put our current pos back into fcb
@RdTop:
2020-03-22 08:44:21 +00:00
jsrRom ROMCACHERDIP ; go do the read ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
@1: BNE.S @Exit
ADD.L D6, D5 ; advance current file position
ADD.L D6, ioActCount(A0) ; and tally up bytes read
SUB.L D6, D4 ; D4 now has ioReqCount - what was just read
BNE.S @RdTop
@Exit
ADDA.W #HIOP.size, A6 ; deallocate param block
MOVEM.L (A6)+, GMRegs
MOVE.L (A6)+, -(A7) ; restore return address
TST.W D0
RTS
endproc
;__________________________________________________________________________________
;
; Routine: TallyAndCheckNodeCount
;
; Function: Add one to PSR.goodCount. Check PSR.goodCount against PSR.maxNodes
; and if we've seen maxNodes good nodes, set PSR.flags LastGoodNode
;
; When PSR.flags LastGoodNode is set it indicates that we've seen all of
; the allocated nodes in the current btree, and if more nodes are requested
; we should return end of file, since we know no more could possibly be valid.
;
; Input: A4.L - pointer to PScan state record
;
; Output: A4.L - pointer to PScan state record
;
; Called by: ValidateRec, ValidateNode
;__________________________________________________________________________________
TallyAndCheckNodeCount: proc
MOVE.L D1, -(SP) ; save one dirty register
ADD.L #1, PSR.goodCount(A4) ; tally another node
MOVE.L PSR.goodCount(A4), D1
CMP.L PSR.maxNodes(A4), D1 ; have we seen enough?
BLO.S @notDone ; if D1 < maxNodes, we've got lots of nodes left
BSET.B #LastGoodNode, PSR.flags(A4)
@notDone
MOVE.L (SP)+, D1 ; restore one dirty register
RTS
endproc
;__________________________________________________________________________________
;
; Routine: ValidateNode
;
; Function: Validates PSR.curNodePtr by looking for the current node # in the
; read buffer. If it's not there, then a buffer full of nodes
; is read in. Once the node is there, it is checked (with ChkNode)
; and then verified to be a leaf node. If not, the current node # is
; incremented and we try again from the top.
;
; On entry, PSR.curNode must be valid.
; If FirstTime is not set, then PSR.buf1stNode and PSR.bufCount must be valid
; On exit, PSR.curNode, PSR.curNodePtr, PSR.buf1stNode, and PSR.bufCount are all valid
;
; Buffer variables buf1stNode and bufCount:
; buf1stNode = btree node # of the 1st node in the buffer
; bufCount = total # nodes in the buffer
;
; If we find the flag "noMoreReads" set true, we'll return nodes
; until we're forced to go to disk. When we're forced to go to disk
; we return a userCanceledErr, which signals to the caller that
; we're done with the current buffer. This allows a caller to
; ask the bt scanner not to do any more expensive disk reads while
; processing all of the records already read in from disk. A caller
; can set noMoreReads true in between any two calls to BTGetPhys
;
; Input: A4.L - pointer to PScan state record
;
; Output: D0.W - result code (from read)
; A4.L - pointer to PScan state record
;
; Called by: ValidateRec, BTGetPhys
;__________________________________________________________________________________
VNRegs reg A0-A2/D1-D2
ValidateNode: proc
MOVE.L (A7)+, -(A6) ; move return address to HFS stack
MOVEM.L VNRegs, -(A6)
@VNTop MOVE.L PSR.curNode(A4), D0 ; D0 = node # we're looking for
BCLR.B #FirstTime, PSR.flags(A4) ; force a disk read?
BNE.S @read
BTST.B #LastGoodNode, PSR.flags(A4) ; force an eof?
BNE @eofExit
MOVE.L PSR.buf1stNode(A4), D1 ; D1 = 1st node # in buffer
CMP.L D1, D0 ; if (curNode < buf1stNode), read
BLO.S @read
ADD.L PSR.bufCount(A4), D1 ; D1 = 1st + count = last node # in buffer + 1
CMP.L D1, D0 ; if (curNode < last node + 1), don't read
BLO.S @inBuf ; I.E. curNode is already in the buffer
@read MOVEA.L PSR.btcbPtr(A4), A2 ; A2 = ptr(BTCB)
MOVE.L btcNNodes(A2), D1 ; D1 = # nodes in btree
SUB.L D0, D1 ; D1 = # nodes left to process
BHI.S @1 ; any left?
BRA @eofExit
@1: BTST.B #NoMoreReads, PSR.flags(A4) ; Should we do any more reads?
BEQ.S @DoMoreReads
MOVE.W #userCanceledErr, d0 ; set up our signaling error
BRA @done
@DoMoreReads:
MOVE.L PSR.readBufLen(A4), D2 ; D2 = buffer length in bytes
LSR.L #8, D2
LSR.L #1, D2 ; D2 = buffer length in 512-byte nodes
CMP.L D2, D1 ; is buffer big enough for all remaining nodes?
BLS.S @2 ; yup; go ahead and read
MOVE.L D2, D1 ; D1 = size of buffer in nodes
@2 MOVE.L D0, D2 ; D2 = curNode = 1st node to read
MOVE.L PSR.readBufLen(A4), D0 ; buffer length
MOVEA.L PSR.readBufPtr(A4), A1 ; buffer address
BSR GetMultNodes
BNE.S @done ; error?
MOVE.L D2, PSR.buf1stNode(A4) ; curNode is now 1st in read buffer
MOVE.L D1, PSR.bufCount(A4) ; # now in buffer = # nodes read
@inBuf MOVEA.L PSR.readBufPtr(A4), A1 ; A1 = ptr(read buffer)
MOVE.L PSR.curNode(A4), D1 ; D1 = current node
SUB.L PSR.buf1stNode(A4), D1 ; D1 = curNode - buf1stNode
MOVEA.L PSR.btcbPtr(A4), A2 ; A2 = ptr(BTCB)
MULU btcNodeSize(A2), D1 ; D1 = (curNode - buf1stNode) * nodeSize
ADDA.L D1, A1 ; A1 now points to current node in buffer
MOVE.L A1, PSR.curNodePtr(A4) ; and we have a valid curNodePr
MOVE.L A4, D2 ; save PSR around ChkNode
MOVEA.L PSR.btcbPtr(A4), A4 ; A4 = ptr(BTCB)
2020-03-22 08:44:21 +00:00
jsrRom ROMCHKNODE ; is this node valid? ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
MOVEA.L D2, A4 ; restore PSR
BNE.S @more ; not valid, get another node
MOVEA.L PSR.curNodePtr(A4), A0 ; A0 = ptr(current node)
CMP.B #ndLeafNode, ndType(A0) ; is this also a leaf node?
BEQ.S @done ; yes, this is a valid leaf node
BSR TallyAndCheckNodeCount ; count the valid non-leaf node
@more ADDQ.L #1, PSR.curNode(A4) ; let's try the next node
CLR.W PSR.curRec(A4) ; starting at record 0
BRA @VNTop
@eofExit:
MOVEQ.L #eofErr, D0
@done MOVEM.L (A6)+, VNRegs
MOVE.L (A6)+, -(A7) ; restore return address
TST.W D0
RTS
endproc
;__________________________________________________________________________________
;
; Routine: ValidateRec
;
; Function: Looks for PSR.curRec in the current node. If it's not there,
; the node count is advanced and the next node read.
; N records in a node are numbered 0 - (N-1)
;
; PSR.curNodePtr must be valid on entry to ValidateRec
;
; Input: A4.L - pointer to PScan state record
;
; Output: DO.L - result code (from read)
; A4.L - pointer to PScan state record
;
; Called by: BTGetPhys
;__________________________________________________________________________________
ValidateRec: proc
MOVE.L (A7)+, -(A6) ; move return address to HFS stack
MOVE.L A0, -(A6)
@VRTop:
MOVEA.L PSR.curNodePtr(A4), A0 ; A0 = ptr(current node)
MOVE.W ndNRecs(A0), D0 ; D0 = # records in current node
CMP.W PSR.curRec(A4), D0 ; # recs in node >= current rec #?
BHI.S @noErr ; cur rec is in cur node, so exit
BSR TallyAndCheckNodeCount ; count the valid leaf node we're now done with
ADDQ.L #1, PSR.curNode(A4) ; next BTree node
CLR.W PSR.curRec(A4) ; and the 1st record in that node
BSR ValidateNode ; go find new node
BNE.S @1 ; error?
BRA.S @VRTop ; Keep going until you find a good one
@noErr:
SUB.W D0, D0 ; clear result code
@1: MOVEA.L (A6)+, A0
MOVE.L (A6)+, -(A7) ; restore return address
TST.W D0
RTS
endproc
;__________________________________________________________________________________
;
; Routine: BTGetPhys
;
; Function: Returns the next btree record in physical disk order.
;
; Input: A4.L - pointer to PScan state record.
; checks the state of the FirstTime bit in the flags word
;
; Output: D0.W - result code (from read)
; D1.W - size of record
; A0.L - ptr(key)
; A1.L - ptr(data record)
; A4.L - pointer to PScan state record
;
; Called by: CMCatSearch
;__________________________________________________________________________________
BTGetPhys: proc
MOVE.L (A7)+, -(A6) ; move return address to HFS stack
BTST.B #FirstTime, PSR.flags(A4) ; is this the first time through?
BEQ.S @NotFirstTime ; if not, just get the record
; it's the first time through, so do a read before trying
; to get a record from the buffer.
BSR ValidateNode ; get the 1st valid node
BNE.S @Exit ; punt on errors <7>
@NotFirstTime
MOVE.L A4, -(A6) ; save PSR ptr around LocRec call
BSR ValidateRec ; point PSR.curRecPtr at node w/next record
BNE.S @1 ; error?
MOVEA.L PSR.curNodePtr(A4), A1 ; A1 = ptr(node)
MOVE.W PSR.curRec(A4), D1 ; D1 = record we want
ADDQ.W #1, PSR.curRec(A4) ; advance to next record for next time <8>
MOVEA.L PSR.btcbPtr(A4), A4 ; A4 = ptr(BTCB)
2020-03-22 08:44:21 +00:00
jsrRom ROMLOCREC ; ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
@1: MOVEA.L (A6)+, A4 ; restore PSR ptr
@Exit:
MOVE.L (A6)+, -(A7) ; restore return address
TST.W D0
RTS
endproc
end