sys7.1-doc-wip/OS/HFS/Extensions/BTreeMgr/BTreeFuncs.a

2370 lines
94 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, and de-inlining
; romGtNxt/1stFCB. Reverted <SM2> word branches.
; 9/2/94 SuperMario ROM source dump (header preserved below)
;
2019-07-27 14:37:48 +00:00
;
; File: BTreeFuncs.a
;
; Contains: This file contains all the B*Tree interface calls and the dispatcher
; A BTOpen patch is added at the end.
;
; Written by: Kenny SC. Tung
;
; Copyright: © 1988-1993 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM3> 9/3/93 rab Roll in changes from Reality. Fixes AOCE B-Tree trashing
; problem. Comments follow…
; <41> 7/8/92 KST #1030304 <csd>: For fix #39, I have to call SetEOF() to change
; the LEOF, otherwise it does not work on a FileShare server.
; <40> 6/2/92 KST #1030304 <hsK>: For change #39, need to mark the block dirty if
; we change the header node. And make sure that the file has write
; permission. Previous fix did not work with a BTfile opened with
; read only permission.
; <SM2> 10/22/92 CSS Change some branch short instructions to word branches.
; <SM1> 4/1/92 kc Changed the name prefex used to distinguish
; routines used by the external B-Tree manager
; from the versions used by the File System.
; Move romGtNxtFCB and romGt1stFCB inline.
; • Pre-SuperMario comments follow •
; <39> 1/13/92 KST Fixed 2 bugs reported by 20/20 project. And verified by them
; with the fixes.
; <38> 1/12/92 KST Documentation changes only.
; <37> 9/13/91 JSM Cleanup header.
; <36> 2/19/91 KST dfn, #82340: Fixing a bug in BtreeRfncall introduced by #35, it
; didn't set up A2 to VCB.
; <35> 2/6/91 KST dnf, 82340: Do not use ROM rfnCheck code because it changes
; ReqstVol.
; <34> 1/28/91 KST dnf, #DNF-001: Allow openning old btree file which doesn't have
; key descriptor if user pass me his own key comparison routine.
; <33> 1/4/91 KST With dnf: Takes out the 'kdDTString' support and returns error
; if anyone uses 'kdReserved' type.
; <32> 12/18/90 KST With Bill B. Adding DoAlloc back. We do _Allocate and then
; _SetEOF for external file systems.
; <31> 12/11/90 KST BBS messed up the comments.
; <30> 12/11/90 KST With Bill B. BTOpen doesn't call fileClose to close the file.
; Change _Allocate to _SetEOF.In "ExtIsBtree", make sure RefNum in
; the BTCB is the one we are currently accessing.
; And BTUpdateKD should verify this is a B*Tree file before
; changing its KD.
; <29> 9/21/90 BG Removed <22>. 040s are behaving more reliably now.
; <28> 8/22/90 KST If we modified a B*Tree file and its LEOF <> PEOF, then we need
; to set LEOF = PEOF and mark FCB dirty.
; <27> 8/10/90 KST Renaming NuLenBTH and NuLenBTCB.
; <26> 8/3/90 KST Fixing the bug that depends on PEOF = LEOF.
; <25> 7/30/90 dnf Convert to linked patch format.
; <24> 7/23/90 KST Fixing a bug in BTGetUID that wraps around incorrectly.
; <23> 7/18/90 KST BTGetRec will now return eofErr when reading pass EOF and return
; posErr when reading before BOF.
; <22> 6/20/90 CCH Added a NOP for flaky 68040's.
; <21> 6/20/90 KST If the header node is bad, we should release the buffer before
; returning error (ExtBTOpen). <SM1>
; <20> 5/10/90 KST Fixing a minor bug in "BTGetInfo" that uses user's KDbuffer
; length when it is a BIG num.
; <19> 4/26/90 KST btGetUid should clear ioResult from within the routine because
; the call is not queued.
; <18> 4/17/90 KST Adding btDebugSYS conditional in "ExtIsBtree".
; <17> 4/13/90 KST btRelAccess will return "noErr" if the file is not previously
; reserved.
; <16> 4/11/90 KST Use ExtBTMaxDepth and related equates. <SM1>
; <15> 4/9/90 KST User can specify his/her own key comparison procedure in the
; field of ioBTKCProc of BTioParam.
; <14> 4/4/90 KST Bug fix: BTHDepth is a word, not a byte.
; <13> 3/30/90 KST If ioBuffer is NULL in BTSearch and BTGetRec, I will return
; paramErr error.
; <12> 3/28/90 KST BTClose doesn't handle multiple open path correctly.
; <11> 3/13/90 KST Return btVersionErr error if accessing a newer version Btree
; file.
; <10> 2/23/90 KST Return btNoKDErr error if there is no key descriptor in the
; header node.
; <9> 2/22/90 KST Documentation change and cleanup.
; <8> 2/12/90 KST Special case kdDTString type in checkKD. kdDTString cannot be
; used with other types.
; <7> 2/6/90 KST Adding a new call, BTUpdateKD.
; <6> 2/4/90 DNF Add include of FileMgrPrivate.a
; <5> 1/22/90 KST Added 3 access control calls and removed using Hfs70Equ.a
; <3> 12/21/89 BBM bug in script put # instead of ; in comments
; <2> 12/19/89 KST Change DTKeyCmp routine to use the correct key length.
; <3.1> 12/8/89 KST Take out debugger code.
; <3.0> 12/8/89 KST Added special key comparison routine for handling DTDBMgr B*Tree
; key with KD type = 9.
; <2.9> 11/17/89 dnf btRfnCall should ignore volOffLinErr.
; <2.8> 11/6/89 KST Save A0 in BTCleanUp.
; <2.7> 10/16/89 KST Added new call -- BTCleanUp.
; 10/5/89 KST Added BTCleanUp support
; <2.6> 10/3/89 KST AppleShare compatibility problem. No clump size in there header
; node.
; <2.5> 9/25/89 KST Fixed a bug in BTInit, MOVE.L should be MOVE.W
; <2.4> 9/18/89 KST Allowing open a B*Tree file without a KD. AppleShare B*tree file
; don't use KD. A file without KD will be using "kdDTString" key
; comparison routine which was and will be our default.
; <2.3> 9/18/89 KST Added a new type kdDTString to replace default for DTDB.
; 9/18/89 KST Added a "kdDTString" type for DTDB.
; <2.2> 9/17/89 KST New buffer scheme. Revoked default key descriptor.
; <2.1> 8/16/89 KST Fixed a bug in comparing default key, RelString is not the right
; thing to call.
; <2.0> 8/11/89 KST Fixed a bug a BTKcmp, high byte of D3 needs to be cleared in a
; word operation.
; 8/11/89 KST Fixed a bug in "BTKCmp", L.S. Byte of D3 is not cleared if
; returned from a DBRA loop then it is used again as loop index.
; <1.9> 8/7/89 KST Code cleanup.
; 7/27/89 KST BTInit now can initialize huge file (limited by disk space)
; 7/27/89 KST Added btRfnCall and btTstMod, can't use ROM's jRfnCall and
; tstMod because it doesn't work for external FS.
; 7/27/89 KST Use jump table for dispatching calls; Get rid of macro calls
; <1.8> 7/6/89 KST Added BTFlush call.
; <1.7> 7/5/89 KST ioMisc field in the param block has to be NIL for HFS OPEN call.
; Fixed the problem in "ExtCopyParam". Also cleaned up the code.
; 6/30/89 KST Don't copy ioMisc field in "ExtCopyParam".
; <1.6> 6/15/89 KST Created BTreePrivate.a equate file.
; <1.5> 6/14/89 KST Changes made for the new implementation of BTreemgr.
; <1.4> 4/7/89 KST Made necessary tweak to make Btree Manager to work on the PLUS.
; ie, tstMod is not vectored on the PLUS.
; <1.3> 3/21/89 KST Added support for Mac Plus, new KD types, new patch for ExtRelNode
; on three systems.
; 3/16/89 KST Added a patch in ExtRelNode for BTDelete => MOVE.L D2,D3
; 3/15/89 KST Added "checkey" routine to validate user's key before we do
; anything else
; <1.1> 3/13/89 KST made traps as callable routines from file system.
; <1.0> 3/8/89 KST Adding to EASE for the first time.
; 12/4/88 KST New today.
;
;;Bugs fixed:
;; ADD 2,keylen in BTreesvcs.a (BTInsert), BTreemaint2.a (ExtLocRec)
;; 3/16/89 Added a patch in ExtRelNode for BTDelete => MOVE.L D2,D3
;; BTParam is used by xBTInit, xBTGetInfo, and xBTUpdateKD. All other calls
;; use BTioParam. BTClose can use either. xBTCleanUp uses dummy param.
LOAD 'StandardEqu.d'
INCLUDE 'BTreeEqu.a' ; BTManager
Include 'BTreePrivate.a'
Include 'Processes.a'
Include 'FileMgrPrivate.a'
include 'LinkedPatchMacros.a'
include 'DTDBMgrPriv.a' ; Desktop key type format
IF &type('btDebug') = 'UNDEFINED' THEN
btDebug EQU 0
ENDIF
IF (&TYPE('btDebugSYS') = 'UNDEFINED') THEN
btDebugSYS EQU 0
ENDIF
;————————————————————————————————————————————————————————————————————————————————————————————————————
; 15FEB89 KST Boot-time initialization code.
; 04Jan90 KST Added a field "btVNextUID" in btvars to store the next UID.
;————————————————————————————————————————————————————————————————————————————————————————————————————
ExtBTreeInstall InstallProc (Plus,SE,II,IIci,Portable)
MOVEQ #btVtotal,D0 ; 28 bytes
_NewPtr ,SYS ,Clear ; allocate BTVars
BNE errLoad ; exit if no room
MOVEA.L A0,A1 ; save btVars in A1
MOVE.L FSVarsPtr,D0 ; has this been initialized?
CMP.L #-1,D0 ; $FFFF FFFF if not
BNE.S @3 ; initialized
MOVE.L #FSVars.size,D0
_NewPtr ,SYS ,Clear
BNE errLoad ; exit if no room
move.l a0, FSVarsPtr ; stash the address in lomem
move.w #FSVars.size, FSVars.length(a0) ; store length of block in 1st word
BRA.S @4
@3 MOVEA.L D0,A0 ; FSVar already initialized
@4 MOVE.L A1,fsVars.BTMgr(A0) ; save BTVar in fsVars
;; allocate Btree stack, ioParam and read/write Buffer ....
;; A1 = ptr(Btree Vars)
MOVE.L #WCSigLong,btVNextUID(A1) ; UID save area (next UID)
MOVE.L #-1,btVStop(A1) ; no stack yet
MOVE.L #btTmpSize,D0 ; N bytes for stack, private param, and r/w buffers
_NewPtr ,SYS ,Clear
BNE errLoad ; exit if no room
; +-- BT param (Low mem)
; |
; +-- buffer index (word) ; current free buffer index (starts with 0)
; +-- buffer size (word)
; +-- BT buffers ; N buffers follow
; |
; +-- stack top
; |
; +-- stack base (btVSTop)
MOVE.L A0,btVParam(A1) ; ioParam pointer
ADDA.L #btParamLen,A0
MOVE.L A0,btBufQHdr(A1) ; BT buffer QHeader
MOVE #btNodesize,btQBSize(A0); save INIT buffer size
ADDA.L #(btBufLen+btStkLen),A0 ; points to bottom of stack
MOVE.L A0,btVSTop(A1) ; stack base
Rts
errLoad: MOVEQ #dsMemFullErr,D0 ; no mem error
_SysError
EndProc ; for linkpatch
BTFuncs PatchProc $A08E,(Plus,SE,II,IIci,Portable)
EXPORT ExtBtreeDispatch
IMPORT ExtBTQueue, ExtBTCmdDone, ExtDoAOCRWF, ExtCopyParam, ExtIsBtree
IMPORT ExtBTOpen, ExtGetBlock ; <SM1>
IMPORT ExtBTDelete, ExtBTSearch, ExtBTGetRecord ; <SM1>
IMPORT ExtBTFlush, ExtBTClose, ExtBTInsert ; <SM1>
IMPORT ExtBTAdjEOF, ExtckClumpSize ; <20AUG90>
ExtBtreeDispatch ;; Input: D0 = trap index, A0 = ioParam, D1 = trap
TST.W D0 ; Check the trap dispatch
BLT.S @1 ; Negative traps are trouble
CMP.W #MaxBtTrap,D0 ; Compare against our known limits
BLS.S @2 ; Continue if all seems well
@1 BSR ExtBTQueue ; We're doomed, but will wait for our turn
MOVEQ #ParamErr,D0 ; Indicate parameter error
BRA ExtBTCmdDone ; Terminate this call
@2 MOVE.W D0,D2 ; trap index
LEA BtreeTrpTbl,A1 ; Point to the trap table
ADD.W D2,D2 ; double for word index
ADD.W D2,D2 ; double for long index
JMP (A1, D2.W) ; pass control to routine
BtreeTrpTbl
macro
DispatchEntry &where
entry &where
jmp &where
endm
DispatchEntry xBTInit ; 0 initialize Btree file
DispatchEntry xBTOpen ; 1 Open a Btree file
; from 2 to 8 are access controlled <1/5/90>
DispatchEntry xBTClose ; 2 Close a Btree
DispatchEntry xBTInsRec ; 3 insert a record
DispatchEntry xBTSetRec ; 4 set a record
DispatchEntry xBTReplRec ; 5 replace a record
DispatchEntry xBTSearch ; 6 search for a record
DispatchEntry xBTGetRec ; 7 Get record
DispatchEntry xBTDelRec ; 8 delete a record
DispatchEntry xBTGetInfo ; 9 Get Btree file information
DispatchEntry xBTFlush ;10 Flush our buffers
DispatchEntry xBTCleanUp ;11 BT cleanup upon process exit
DispatchEntry xBTRsrvAccess ;12 reserve access priviledge
DispatchEntry xBTRelAccess ;13 release access
DispatchEntry xBTGetUid ;14 assign UID
DispatchEntry xBTUpdateKD ;15 update KD info
;_______________________________________________________________________
;
; Routine: xBTInit
; Arguments: A0.L (input) -- pointer to BT parameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; D3-D7/A2-A6 are saved by ExtBTQueue
; Calls: FSQueue,FndFilName,CVFlgs,CmdDone
; Function: Initializes a new B*Tree file, the file should be already created.
; If not enough disk space allocated, we will do it using SetEOF.
; At the end of this routine, we also force LEOF = PEOF.
; Modification History:
; 03Nov88 KSCT New today
; 17Mar89 KSCT Provided default key descriptor
; 11May89 KSCT Fixed the even maxkeylen restriction in RAM implementation
; 27Jul89 KSCT Use bitmapInit routine to set up the bitmap, the file size
; can be initialized has no limit now
; 22Aug89 KSCT BGT should be BHI
; 31Aug89 KSCT no default case for this release.
; 18Dec90 KSCT Changed _Allocate to _SetEOF to allocate disk space.
; 18Dec90 KSCT After _SetEOF, LEOF may not equal to PEOF because clump size
; is not multiple of allocation block size.
;------------------------------------------------------------------------
xBTInit BSR ExtBTQueue ; wait for our turn
;; first validate user's parameters:
MOVE.W #btKDLenErr,D0 ; preset error code
MOVE.L ioBTKDPtr(A0),D2 ; will allow default in the future
BEQ BTCExit2 ; no KD error
;; There is no default case for this release <8/31/89>
;; BEQ.S @4 ; no KD, default case
MOVEA.L D2,A1 ; A1=key descriptor
BSR checkKD ; validate kd
BNE BTCExit2 ; KD error
@4 MOVE.W #BTKeyLenErr,D0 ; validate max key length
MOVE.W ioBTMaxKLen(A0),D2
BEQ BTCExit2 ; it cannot be zero
CMPI.W #maxKeyLen,D2 ; key too long?
BHI BTCExit2 ; yes, punt <Aug-22-89>
MOVEA.L A0,A4 ; save user ioparam in A4
MOVEQ #0,D7 ; D7 = not open flag
BSR ExtCopyParam ; get and clear BT param in A3 and A0
BSET #fsWrPerm,ioPermssn(A0) ; req for write permssn
MOVEQ #DoOpen,D1 ; indicate this is OPEN
BSR ExtDoAOCRWF ; do the open/close sync/async
BNE BTCExit1 ; error, exit
ST D7 ; set file opened flag
MOVEA.L FCBSptr, A2 ; A2 = ptr to FCBs
MOVE.W ioRefNum(A0),D5 ; D5 = file refnum
MOVE.L ioBTClumpsize(A4),D6; use user's clump size?
MOVEA.L FCBVPtr(A2,D5.W),A1 ; A1 = VCB
CMP.L VCBClpSiz(A1),D6 ; user >= volume clump size
BCC.S @7 ; yes, D6 = clump size
MOVE.L VCBClpSiz(A1),D6 ; no, use volume clump size
MOVE.L D6,ioBTClumpsize(A4); set user's clump size to VC's
@7
MOVE.L FCBPLEN(A2,D5.W),D4 ; test for physical EOF
BEQ.S BTInit3 ; no space allocated
CMP.L D6,D4 ; size >= clump
BCC.S BTInit5 ; user size OK
BTInit3 ;; file empty or too small, need to allocate some disk space up to clump size.
;; A0 = BTParam, A1 = VCB, D4.L = physical EOF, D6.L = clump size and D4 is free.
;; Do _Allocate and then _SetEOF. 'cause many foreign file system such as UNIX and
;; AppleShare doesn't understand _Allocate.
SUB.L D4,D6 ; D6 = bytes to allocate
MOVE.L D6,ioReqCount(A0) ; request so many
;; This (HFS) will try contig first and then non-contig
MOVEQ #DoAlloc,D1 ; indicate this is Allocate
BSR ExtDoAOCRWF ; A1 is free
BNE BTCExit1 ; punt on error
ADD.L ioActCount(A0),D4 ; D4 = new file size
;; In case the file system doesn't handle _Allocate, we do a _SetEOF here:
MOVEA.L FCBVPtr(A2,D5.W),A2 ; A2 = VCB <18Dec90 #32>
MOVE.L D4,D6 ; pass parameter in D6 <18Dec90 #32>
BSR ExtckClumpSize ; make sure there is no conflict <18Dec90 #32>
MOVEA.L FCBSptr,A2 ; A2 = ptr to FCBs <18Dec90 #32>
MOVE.L D6,IOLEOF(A0) ; set new LEOF to D6 <27Nov90 #30>
MOVEQ #DoSetEof,D1 ; indicate this is setEof <27Nov90 #30>
BSR ExtDoAOCRWF ; A1 is free <27Nov90 #30>
BNE BTCExit1 ; punt on error <27Nov90 #30>
MOVE.L D6,D4 ; D4 = PEOF = LEOF <27Nov90 #30>
BTInit5 ;; D4.L = PEOF !
;; BTree opened, space allocated, build and write header block.
BSR GetaCBlock ; get a clear BTbuffer in A0
;; init the ND, A0 = ptr(buffer)
MOVE.B #NdHdrNode,NdType(A0) ; node type
MOVE.W #NRHdrNode,NdNRecs(A0) ; always 3 records in header
;; init the BTHeader
MOVE.L A0,-(SP) ; save buffer(header node) address
ADDA.L #lenND,A0 ; points to BT header
MOVE.W #BTNodeSize,bthNodeSize(A0)
MOVE.W ioBTMaxKLen(A4),D0 ; max key length
MOVE.W D0,bthKeyLen(A0)
DIVU #BTNodeSize,D4 ; divide by node size
SWAP D4 ; to calculate the number of nodes
CLR.W D4 ; PEOF always on block boundary
SWAP D4 ; D4.L = total number of nodes
MOVE.L D4,bthNNodes(A0) ; save in BTHeader
MOVE.L D4,D6 ; also save in D6
MOVEQ #1,D3 ; D3 = # of map nodes
SUBI.L #NHmapnode,D6 ; is header bitmap enough?
BLE.S @2 ; yes
@1 ;; calculate bitmap node, now can handle huge file !
;; only a word in D3 is used for number of map nodes, top word is 0
ADDQ.L #1,D3 ; D3.L = # of map nodes
SUBI.L #NMmapnode,D6 ; is map node bitmap enough?
BHI.S @1 ; still to come
@2 SUB.L D3,D4 ; free node = total - used (map) blocks
MOVE.L D4,bthFree(A0) ; number of free nodes
;; save user's arguments: (B*Tree Manager specific info)
MOVE.L ioBTClumpsize(A4),bthClumpSize(A0)
;; B*Tree Type -- we need a way to identify our B*Tree file.
MOVE.B #userBT1Type,bthBTType(A0) ; set our Btree type (use fixed index keylen)
;; copy key descriptor into the header
ADDA.L #LenBTH,A0 ; A0 = ptr(user area)
MOVE.L ioBTKDPtr(A4),D0
BEQ.S @6 ; no KD
MOVEa.L D0,A1 ; A1 = KD ptr
MOVEQ #0,D0
MOVE.B (A1),D0 ; length of KD
@3 MOVE.B (A1)+,(A0)+ ; copy into BTH
DBF D0,@3
@6 MOVEA.L (SP),A0 ; get hdr buffer
ADDA.L #(lenND+LenBTH+LenUser),A0 ; A0 = ptr(bitmap)
;; init the bitmap of header node, 1 = used, 0 = free
;; D6.L = total number of map nodes needs to be marked in the bitmap record
MOVE.L D3,D6 ; D6 = # of map nodes
MOVE #NHmapnode,D2 ; size of the header bitmap
BSR bitmapInit
initHdrOffset
;; init header node offset to records, there are 3 records in header node:
;; header record, user record, map record.
SUBQ.L #1,D3 ; indicate 1 map node less
MOVEA.L (SP),A0 ; A0 = header node
MOVE.W #(lenND+lenBTH+lenUser+LenBMapHdr),btNodeSize-8(A0) ; offset to free space
MOVE.W #(lenND+lenBTH+lenUser),btNodeSize-6(A0) ; offset to bitmap
MOVE.W #(lenND+lenBTH),btNodeSize-4(A0) ; to user space
MOVE.W #lenND,btNodeSize-2(A0) ; to BTHeader (1st record)
MOVEA.L A3,A0 ; A0=A3=BTParam, A3 should not be changed before here
MOVEA.L (SP)+,A3 ; A3 = restore header node.
MOVE.L A3,IOBuffer(A0) ; buffer to write
MOVE.W #fsFromStart,IOPosMode(A0) ; position mode(from BOF)
MOVE.L #BtnodeSize,IOByteCount(A0) ; always r/w 512 bytes
MOVEQ #1,D5 ; D5.L= next node, D3-D6 been used in this loop !!
MOVEQ #0,D4 ; D4.L= current node #
; D6.L= # of map nodes remain to be marked in bitmap
BTCLoop ;; If more than 1 map node needed, set them up in this loop
TST D3 ; next link?
BEQ.S BTCwrite ; no more
MOVE.L D5,NDFlink(A3) ; points to next MapNode
BTCwrite ;; A0 = our ioParam, A3 = header node
MOVE.L D4,D0 ; current node number
MOVEQ #btNSftCnt,D1 ; shift bit (BTnodesize is a constant)
LSL.L D1,D0 ; ...x 512
MOVE.L D0,IOPosOffset(A0) ; ... gives position offset
MOVEQ #DoWrite,D1 ; indicate this is WRITE
BSR ExtDoAOCRWF
BNE.S BTCExit1 ; error
DBF D3,BLoopEnd ; continue if there are more map nodes
;; all done, make LEOF = PEOF, A2 = FCB array
MOVE.W ioRefNum(A0),D5 ; D5 = file refnum
MOVE.L FCBPLEN(A2,D5.W),FCBEOF(A2,D5.W) ; LEOF = PEOF
BRA.S BTCExit1 ; cool
BLoopEnd ;; clear the buffer and initialize next map node
MOVEA.L A3,A1 ; A1 = header ptr
MOVEQ #0,D0
MOVE #(btnodesize/4 - 1),D1 ; node size in long
@5 MOVE.L D0,(A1)+ ; clear header node
DBRA D1,@5
;; init ND and index, can't use "InitNode" because it calls "GetBlock" !
MOVE.B #NdMapNode,NdType(A3) ; node type
MOVE.W #NRMapnode,NdNRecs(A3) ; always 1 record in map node
MOVE.L D4,NDBlink(A3) ; D4 = previous node
;; init offset
MOVE.W #(btNodeSize-4),btNodeSize-4(A3) ; offset to free <9/21/89>
MOVE.W #lenND,btNodeSize-2(A3) ; offset to 1st record
ADDQ.L #1,D4 ; bump current node #
ADDQ.L #1,D5 ; bump next node #
TST.L D6 ; are all map nodes marked in the bitmap?
BEQ.S BTCLoop ; yes
;; need to indicate how many bits are used for map nodes in this bitmap
MOVE.L A0,-(SP) ; save BT param
MOVEA.L A3,A0
ADDA.L #lenND,A0 ; A0 = ptr(bitmap)
MOVE #NMmapnode,D2 ; size of the map node bitmap
BSR bitmapInit ; init the bitmap
MOVEA.L (SP)+,A0 ; A0, A1 unchanged
BRA.S BTCLoop ; write next map node
BTCExit1 ;; ready to leave, D0 = error code
TST.B D7 ; file still open?
BEQ.S BTCExit2 ; no
MOVE.W D0,-(A6) ; save error code
;; close the file before we leave
MOVEQ #DoClose,D1 ; indicate this is CLOSE
BSR ExtDoAOCRWF
MOVE.W (A6)+,D0 ; restore error code
BTCExit2 BRA ExtBTCmdDone ; exit BTInit
;_______________________________________________________________________
;
; Routine: xBTOpen
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; This call can only be executed synchronously.
; Function: Opens a B*Tree file. If first time open, allocate and init BTCB,
; otherwise, FCBs share the BTCB and bump the reference count.
; Modification History:
; 07Aug89 KSCT Added node size shift count in BTCB
; 12Jan92 KSCT If a B*Tree file has been opened first by a file system open,
; we need to allocate a BTCB for this BTOpened file.
;------------------------------------------------------------------------
xBTOpen ;; BTOpen can only be executed synchronously
BCLR #btAsyncBit,D1 ; sync only
BSR ExtBTQueue ; wait for our turn
MOVEA.L A0,A4 ; save user ioparam
BSR ExtCopyParam ; A0=A3=BTParam
MOVE.B ioPermssn(A4),ioPermssn(A0)
MOVEQ #DoOpen,D1 ; indicate this is OPEN
BSR ExtDoAOCRWF
BNE BOExit ; open error, punt
MOVE.W ioRefNum(A0),ioRefNum(A4)
MOVEA.L FCBsptr,A1
MOVE.W ioRefNum(A0),D3 ; D3 = RefNum, A0=btParam
EXG A0,A4 ; A0 = userParam, A4=btParam <21Nov90 #30>
TST.L FCBPLen(A1,D3) ; has disk space?
BNE.S @openOK ; yes,
;; file has opened but it is empty; close it and return error
MOVE.W #btbadHdr,D0 ; file empty (notBtreeErr)
BRA.S BOExit1 ; return to user
@openOK
MOVE.L FCBFlNm(A1,D3.W),D2 ; D2 = file num
MOVEA.L FCBVPtr(A1,D3.W),A3 ; A3 = vcb
MOVEQ #2,D1 ; index to first FCB
;; check if the BTree file has been opened already. D3.W = our (newly open) FCB.
GNMLoop CMP.W D1,D3 ; same FCB?
BEQ.S GtNxtMatch ; skip ourself
CMP.L FCBFlNm(A1,D1),D2 ; file numbers match?
BNE.S GtNxtMatch ; no, try next FCB <12Jan92 #39>
CMP.L FCBVPtr(A1,D1),A3 ; on the same volume? <12Jan92 #39>
BNE.S GtNxtMatch ; no, try next FCB <12Jan92 #39>
;; This is the same file with 2 open paths, but make sure the <12Jan92 #39>
;; first open is thru B*tree Manager, ie., it has a BTCB. <12Jan92 #39>
MOVE.L FCBBTCBptr(A1,D1),D0; D0 = ptr(BTCB)? <12Jan92 #39>
BNE.S BOpened ; found it <12Jan92 #39>
2020-03-22 08:44:21 +00:00
GtNxtMatch jsrROM ROMGTNXTFCB ; go to next FCB <03Feb87><SM1><Sys7.1> De-inlined and put back "ROM"
2019-07-27 14:37:48 +00:00
BCS.S GNMLoop ; loop thru them all
;; This is the first time open
MOVEM.L A0-A1/A5,-(A6) ; save user ioParam and FCBs <28Mar90>
MOVEA.L A0,A5 ; A5 = ioParam <28Mar90>
MOVEa.L FSVarsPtr,A1
MOVEA.L fsVars.btMgr(A1),A1
MOVEA.L btBufQHdr(A1),A1 ; A1 = ptr(buffer Qheader)
LEA BTKCmp,A0 ; key compare routine
MOVE.L ioBTKCProc(A5),D0 ; does user specify his/her own KC procedure?
BEQ.S @0 ; no, use mine <28Mar90>
MOVEA.L D0,A0 ; otherwise, override <28Mar90>
@0 ;; Need to patch ROM BTOpen for B*Tree Manager <05May89>
JSR ExtBTOpen ; use our BTOpen <05May89><SM1>
MOVEM.L (A6)+,A0-A1/A5 ; restore user ioParam and FCBs
BEQ.S btOpenOK ; no error, continue
BOExit1 ;; file is open, but we got an error => close the file.
;; D0.W = error code, D3.W = Refnum, A0 = userParam, A4=btParam
CLR.W ioRefNum(A0) ; return no RefNum in user param <21Nov90 #30>
MOVE.W D0,-(A6) ; save error code <21Nov90 #30>
MOVEA.L A4,A0 ; get BTparam <21Nov90 #30>
MOVE.W D3,ioRefNum(A0) ; D3=refnum <21Nov90 #30>
MOVEQ #DoClose,D1 ; indicate this is CLOSE <21Nov90 #30>
BSR ExtDoAOCRWF ; close the file <21Nov90 #30>
MOVE.W (A6)+,D0 ; restore error code <21Nov90 #30>
CMPI #eofErr,D0 ; B*tree has at least a header; EOF?
BNE.S @3 ; No, other error
MOVEQ #BTBadHdr,D0 ; Yes, then this is not a B*Tree
@3 TST.W D0 ; any error?
BMI.S BOExit ; branch if already negative
SUBI.W #BTErrConst,D0 ; else, make it negative
BOExit BRA ExtBTCmdDone ; exit BTOpen
BOpened ;; this file is already open, share the BTCB and bump the reference count.
MOVEA.L FCBBTCBptr(A1,D1),A4; A4 = ptr(BTCB)
MOVE.L A4,FCBBTCBptr(A1,D3); share the same BTCB
ADDQ.B #1,BTCRcount(A4) ; bump reference count
BRA.S BOReturn ; skip the conversion, has been done already
btOpenOK
;; B*Tree file 1st time open, convert node size to shift bits
MOVEA.L FCBBTCBptr(A1,D3),A4; A4 = ptr(BTCB)
MOVE.W btcNodeSize(A4),D0 ; D0=nodesize
LSR #8,D0 ; some optimization /256
MOVEQ #7,D1 ; D1 starts from 7
@2 ADDQ.B #1,D1
LSR #1,D0 ; is it a 1?
TST D0
BNE.S @2 ; no, continue
MOVE.B D1,btcL2NSize(A4) ; save it in BTCB
BOReturn MOVEQ #0,D0 ; all done
BRA.S BOExit ; OK
;_______________________________________________________________________
;
; Routine: xBTClose
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; This call can only be executed synchronously.
; Calls: BTClose (btsvcs)
; Function: Closes a BTree file. If this is the last open access path, then
; the BTree Header (BTH) is updated and the cache is flushed and
; trashed for the specified file. The BTCB memory is also released.
;
; Modification History:
;
; Jan/18/89 KSCT New today
; Mar/28/90 KSCT For multiple access file, when closing one file, need to
; replace the RefNum in the BTCB to the open one.
;------------------------------------------------------------------------
xBTClose BCLR #btAsyncBit,D1 ; sync only
BSR ExtBTQueue
MOVEQ #noWrite,D0 ; no write permssn
BSR ExtIsBtree
BNE.S BClExit
MOVEQ #0,D4 ; D4 flag = 0 <28Mar90>
SUBI.B #1,BTCRcount(A4) ; is this the only access path? <28Mar90>
BEQ.S @5 ; yes, release BTCB <28Mar90>
;; no, there are more than 1 access path, before we close this FCB,
;; stick another FCB in the BTCB.
MOVEM.L A0/D1,-(SP) ; save param and refnum <28Mar90>
MOVE.W D1,D3 ; D3 = refnum <28Mar90>
MOVEA.L FCBSptr, A1 ; A1 = ptr to FCBs <28Mar90>
MOVE.L FCBFlNm(A1,D3.W),D2 ; D2 = file num <28Mar90>
MOVEA.L FCBVPtr(A1,D3.W),A3 ; A3 = vcb <28Mar90>
MOVEQ #2,D1 ; index to first FCB <28Mar90>
;; check if the BTree file has been opened already <28Mar90>
@BCLoop CMP.W D1,D3 ; same FCB? <28Mar90>
BEQ.S @NxtMatch ; skip ourself <28Mar90>
CMP.L FCBFlNm(A1,D1),D2 ; file numbers match? <28Mar90>
BNE.S @NxtMatch ; <28Mar90>
CMP.L FCBVPtr(A1,D1),A3 ; on the same volume? <28Mar90>
BEQ.S @BCOpened ; found it <28Mar90>
2020-03-22 08:44:21 +00:00
@NxtMatch jsrROM ROMGTNXTFCB ; go to next FCB <SM1><Sys7.1> De-inlined and put back "ROM"
2019-07-27 14:37:48 +00:00
BCS.S @BCLoop ; loop thru them all <28Mar90>
IF btDebug THEN ; no match ??!! <28Mar90>
_Debugger ; can't be happening <28Mar90>
ENDIF
@BCOpened MOVE.W D1,D4 ; another access path <28Mar90>
MOVEM.L (SP)+,A0/D1 ; restore param and refnum <28Mar90>
MOVE.W D1,D0 ; D0 = RefNum
MOVEQ #0,D5 ; clear flag so that it will not flush fs cache
BSR ExtBTFlush ; just flush (will not write to disk)<30Jul90><SM1>
BRA.S BClCommon
@5 ;; close the file, BTflush and release BTCB and KD buffer
MOVE.L btcKDPtr(A4),D0 ; default case?
BEQ.S @7 ; yes, don't dispose
MOVEa.L D0,A0 ; A0 = KD ptr
_DisposPtr ; else, free the memory
@7 MOVE.W D1,D0 ; D0 = RefNum
JSR ExtBTClose ; use only D0, BTCB will be cleared !<SM1>
; will not flush the cache <30Jul90>
BClCommon ;; join here to close a file
MOVE D1,-(A6) ; save refnum
BSR ExtCopyParam ; get and clear BT param in A3=A0
MOVE (A6)+,ioRefNum(A0) ; this file to close
MOVEQ #DoClose,D1 ; indicate this is CLOSE
BSR ExtDoAOCRWF ; close will flush DiskCache <30Jul90>
TST.W D4 ; is there another access path? <28Mar90>
BEQ.S BClExit ; NO <28Mar90>
MOVE.W D4,BTCRefNum(A4) ; set new refnum <28Mar90>
BClExit BRA ExtBTCmdDone
;_______________________________________________________________________
;
; Routine: xBTInsRec
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; Function: Insert a record in the BTree file.
; Modification History:
; Jan-18-89 KSCT New today
;
;------------------------------------------------------------------------
xBTInsRec BSR ExtBTQueue
MOVEA.L A0,A3 ; A3=ioParam
MOVEQ #write,D0 ; request for write permssn
BSR ExtIsBtree ; is this a BTree?
BNE.S @8 ; no, fatal error
BSR checkey ; is key correct?
BNE.S @8 ; no, syntax error
MOVEA.L ioBTKeyPtr(A3),A0 ; A0=addr of key
MOVE.L ioReqCount(A3),D1 ; D1=size of data
BSR ChkSize
BGT.S @8 ; key length or size error
MOVEA.L ioBuffer(A3),A1 ; A1=addr of data
MOVE.W ioRefNum(A3),D0 ; D0=RefNum
MOVE.L D1,ioActCount(A3) ; assume it works
JSR ExtBTInsert ; <SM1>
@8 BRA.S BTSExit1
;_______________________________________________________________________
;
; Routine: xBTSetRec
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; Calls: BTInsert (BTreesvcs.a)
; Function: Insert/overwrite a record in the BTree file.
;
; Modification History:
;
; Jan-30-89 KSCT New today
;
;------------------------------------------------------------------------
xBTSetRec BSR ExtBTQueue
MOVEA.L A0,A3 ; A3=ioParam
MOVEQ #write,D0 ; request for write permssn
BSR ExtIsBtree ; is this a BTree?
BNE.S BTSExit1 ; no, fatal error
BSR checkey ; is key correct?
BNE.S BTSexit1 ; no, syntax error
MOVEA.L ioBTKeyPtr(A3),A0 ; A0=addr of key
MOVE.L ioReqCount(A3),D1 ; D1=size of data
BSR ChkSize
BGT.S BTSExit1 ; record too big
MOVE.L D1,ioActCount(A3) ; assume it works
BTSet1
MOVEA.L ioBuffer(A3),A1 ; A1=addr of data
MOVE.W ioRefNum(A3),D0 ; D0=RefNum
JSR ExtBTInsert ; <SM1>
BEQ.S BTSExit1 ; br if no error
CMPI.W #BTexists,D0 ; record already exist?
BNE.S BTSExit1 ; no, other error
;; here, record already exist, overwrite if possible
MOVEA.L ioBTKeyPtr(A3),A0 ; A0=addr of key
MOVE.W ioRefNum(A3),D0 ; D0=RefNum
JSR ExtBTDelete ; <SM1>
BNE.S BTSExit1 ; punt on error
MOVEA.L ioBTKeyPtr(A3),A0 ; A0=addr of key
BRA.S BTSet1 ; try insert again
BTSExit1
TST.W D0
SEQ D1 ; set if no error
BRA BTReturn
;_______________________________________________________________________
;
; Routine: xBTReplRec
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; Calls: BTInsert (BTreesvcs.a)
; Function: replace a record in the BTree file.
;
; Modification History:
;
; Jan-30-89 KSCT New today
;
;------------------------------------------------------------------------
xBTReplRec BSR ExtBTQueue
MOVEA.L A0,A3 ; A3=ioParam
MOVEQ #write,D0 ; request for write permssn
BSR ExtIsBtree ; is this a BTree?
BNE.S BTRExit ; no, fatal error
BSR checkey ; is key correct?
BNE.S BTRexit ; no, syntax error
MOVEA.L ioBTKeyPtr(A3),A0 ; A0=addr of key
MOVE.L ioReqCount(A3),D1 ; D1=size of data
BSR ChkSize
BGT.S BTRExit ; record or key size error
BTRepl1
MOVE.W ioRefNum(A3),D0 ; D0=RefNum
JSR ExtBTDelete ; <SM1>
BNE.S BTRExit ; punt on error
MOVEA.L ioBTKeyPtr(A3),A0 ; A0=addr of key
MOVEA.L ioBuffer(A3),A1 ; A1=addr of data
MOVE.W ioRefNum(A3),D0 ; D0=RefNum
MOVE.L ioReqCount(A3),ioActCount(A3) ; assume it works
JSR ExtBTInsert ; <SM1>
BTRExit BRA.S BTSExit1
;_______________________________________________________________________
;
; Routine: xBTSearch
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; Calls: BTInsert (BTreesvcs.a)
; Function: search for a record in the BTree file.
;
; Modification History:
;
; Jan-30-89 KSCT New today
;
;------------------------------------------------------------------------
xBTSearch BSR ExtBTQueue
MOVEA.L A0,A3 ; A3=ioParam
MOVEQ #noWrite,D0 ; no write permssn flag
BSR ExtIsBtree ; is this a BTree?
BNE.S SearchExit ; no, fatal error
BSR checkey ; is key correct?
BNE.S SearchExit ; no, syntax error
MOVEA.L ioBTKeyPtr(A3),A0 ; A0=addr of key
MOVEQ #0,D2 ; no hint
MOVE.L ioBTHint1(A3),D1 ; write count
CMP.L btcWcount(A4),D1 ; validate it
BNE.S @1 ; bad hint
MOVE.L ioBTHint2(A3),D2 ; good node hint
@1 MOVE.W ioRefNum(A3),D0 ; D0=RefNum
JSR ExtBTSearch ; <SM1>
@3 BNE.S RecNotFound ; punt on error
; Record found => A1.L - pointer to data record,
; D1.W - size of data record,
; D2.L - new BTree hint, must preserve
EXT.L D1 ; make D1 long
CLR.L ioActCount(A3) ; assume 0 <30Mar90>
MOVE.L ioReqCount(A3),D0 ; D0=size of user data buffer
BEQ.S SearchExit ; no data requested <30Mar90>
CMP.L D0,D1 ; D1=size of data on disk
BGE.S BTSrch2 ; use user buffer size
MOVE.L D1,D0 ; data < user, use exact datasize
BTSrch2 MOVE.L ioBuffer(A3),D3 ; D3=user buffer (dest) <30Mar90>
; is there a buffer? <30Mar90>
BNE.S @6 ; yes <30Mar90>
MOVE.W #paramErr,D0 ; NULL pointer <30Mar90>
BRA.S SearchExit ; punt => <30Mar90>
@6 MOVEA.L D3,A0 ; A0=user buffer (dest) <30Mar90>
MOVE.L D0,ioActCount(A3) ; actual count
EXG A0,A1 ; exchange dest and source buffer
_BlockMove ; copy data byte by byte
MOVEQ #0,D0 ; perfect ending
SearchExit MOVEQ #0,D1 ; clear flag, search never changes Btree
BRA BTReturn
RecNotFound CMP.W #BTnotfound,D0 ; key not found error ?
BNE.S SearchExit ; no, must be IO error ->
;; D0=BTnotFound(32), make it negative
SUBI.W #BTErrConst,D0 ; make it negative
;; If search failed, return correct HINT to caller. <5/31/89 Tung>
MOVE.L btcWcount(A4),ioBTHint1(A3) ; writecount
MOVE.L BTCNodeM(A4),ioBTHint2(A3) ; node #
MOVE.W BTCIndexM(A4),ioBTHint3(A3) ; index #
BRA ExtBTCmdDone
;_______________________________________________________________________
;
; Routine: xBTGetRec
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; Calls: BTInsert (BTreesvcs.a)
; Function: search for a record using cookies.
; Output: If hint is invalid, the correct write count is returned
; node number and node index is cleared.
; Modification History:
;
; Jan-31-89 KSCT New today
; Jul-17-90 KSCT Return eofErr when reading pass EOF and return posErr when
; reading before BOF. Return btnotfound if get current record.
;------------------------------------------------------------------------
xBTGetRec BSR ExtBTQueue
MOVEA.L A0,A3 ; A3=ioParam
MOVEQ #noWrite,D0 ; not write permssn
BSR ExtIsBtree ; is this a BTree?
BNE GetExit ; no, fatal error
MOVE.W #BTPMInvalid,D0 ; set error code
BSR Zerohints ; all hints are 0?
BEQ.S @2 ; yes (D1.L=write count; D2.L=Node #; D3.W=Index#)
CMP.L BTCWcount(A4),D1 ; validate it
BEQ.S @GetRec2 ; OK
MOVE.L BTCWcount(A4),ioBTHint1(A3) ; return current Wcount
2020-03-22 08:44:21 +00:00
BRA.S GetExit ; invalid marker <SM2> CSS <Sys7.1>
2019-07-27 14:37:48 +00:00
@2
MOVE.L btcFNode(A4),D2 ; user wants to read the 1st record
@GetRec2 MOVE.L D2,btcNodeM(A4) ; get record in this node, (change the node marker)
MOVE.W D3,btcIndexM(A4) ; and this index (and change the node index to read from)
MOVE.W ioRefNum(A3),D0 ; D0=RefNum
MOVE.W ioBTPosMode(A3),D1 ; D1=position mode
MOVE.W D1,D3 ; save in D3
JSR ExtBTGetRecord ; <SM1>
BNE.S GetExitChk ; check special error
; A0.L - pointer to key, A1.L - pointer to data record
; D1.W - size of data record, D2.L - new BTree hint, must preserve
EXT.L D1
CLR.L ioActCount(A3) ; assume 0 <30Mar90>
MOVE.L ioReqCount(A3),D0 ; D0=size of user data buffer
BEQ.S @GetRec5 ; data buffer = 0
;; copy data back to user ...
MOVE.L A0,-(A6) ; save key buffer
CMP.L D0,D1
BCC.S @GetRec3 ; use user buffer size
MOVE.L D1,D0 ; data < user
@GetRec3 MOVE.L ioBuffer(A3),D3 ; D3=user buffer
; is there a buffer? <30Mar90>
BNE.S @4 ; yes <30Mar90>
MOVE.W #paramErr,D0 ; NULL pointer <30Mar90>
BRA.S GetExit ; punt => <30Mar90>
@4 MOVEA.L D3,A0 ; A0=user buffer (dest) <30Mar90>
MOVE.L D0,ioActCount(A3) ; actual count
EXG A0,A1 ; exchange dest and source buffer
_BlockMove ; copy data byte by byte
MOVEA.L (A6)+,A0 ; restore A0
@GetRec5 ;; ;; copy key back to user ...
MOVEQ #0,D0
MOVE D0,D1
MOVE.W ioKReqCount(A3),D0 ; D0=size of user KEY buffer
BEQ.S @GetRec7 ; don't copy key if user key buffer len = 0
MOVE.B (A0),D1 ; record key size
CMP.W D0,D1
BCC.S @GetRec7 ; key>=user, use user buffer size
;; Note: return key length includes length byte !!
ADDQ.W #1,D1 ; include length byte
MOVE.W D1,D0 ; key < user, use key
@GetRec7 MOVE.W D0,ioKActCount(A3) ; actual count
BEQ.S GetExit ; don't copy key
MOVEA.L ioBTKeyPtr(A3),A1 ; A1=user key buffer
_BlockMove ; copy key byte by byte
MOVEQ #0,D0 ; perfect ending
GetExit MOVEQ #0,D1 ; clear flag
BRA BTReturn
GetExitChk ; D0.W=error code, D3.W=position mode
CMPI.W #btnotfound,D0 ; is this the special case that we're looking for?
BNE.S GetExit ; branch if not
; if it is btnotfound error, then we don't change the HINTs,
; and we'll also change the error code to a more meaning code.
TST.W D3 ; are we reading forward?
BEQ.S GetExit ; can't find the current node, this HINT must be bad
; so we'll invalidate the HINT.
BMI.S @2 ; no, =>
MOVE.W #btEofErr,D0 ; move forward pass EOF
BRA.S @4 ; all done
@2 MOVE.W #btBofErr,D0 ; attempt to position to before start of file
@4 CLR.L ioActCount(A3) ; no data is written
BRA ExtBTCmdDone ; error code is negative now
;_______________________________________________________________________
;
; Routine: xBTDelRec
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; Calls: BTDelete (BTreesvcs.a)
; Function: search for a record using cookies.
;
; Modification History:
;
; Feb-1-89 KSCT New today
;
;------------------------------------------------------------------------
xBTDelRec BSR ExtBTQueue
MOVEA.L A0,A3 ; A3=ioParam
MOVEQ #write,D0 ; request for write permssn
BSR ExtIsBtree ; is this a BTree?
BNE.S DelExit ; no, fatal error
BSR checkey ; is key correct?
BNE.S DelExit ; no, syntax error
MOVEA.L ioBTKeyPtr(A3),A0 ; A0=addr of key
MOVE.W ioRefNum(A3),D0 ; D0=RefNum
JSR ExtBTDelete ; <SM1>
DelExit TST.W D0
SEQ D1 ; set if no error
MOVEQ #0,D2 ; zero out node hint
BRA BTReturn
;_______________________________________________________________________
;
; Routine: xBTGetInfo
; Arguments: A0.L (input) -- pointer to BT parameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; Calls: BTDelete (BTreesvcs.a)
; Function: search for a record using cookies.
;
; Modification History:
;
; Feb-01-89 KSCT New today
; May-10-90 KSCT KDlen is a word in paramblock, a byte in KDptr.
; To compare them we have to use word comparison.
;------------------------------------------------------------------------
xBTGetInfo BSR ExtBTQueue
MOVEA.L A0,A3 ; A3=ioParam
MOVEQ #noWrite,D0 ; not write permssn
BSR ExtIsBtree ; is this a BTree?
BNE.S GInfoExit ; no, fatal error
MOVE.W ioRefNum(A3),D0 ; D0=RefNum
MOVE.L FCBClmpSize(A1,D0),ioBTClumpSize(A3); clumpsize
MOVE.W btcNodeSize(A4),ioBTNodesize(A3) ; node size
MOVE.W btcKeyLen(A4),ioBTMaxKLen(A3) ; key len
MOVE.W btcDepth(A4),ioBTDepth(A3) ; tree depth
MOVE.L btcNRecs(A4),ioBTRecNum(A3) ; total records
MOVE.L btcNNodes(A4),ioBTNNodes(A3) ; total number of nodes
MOVE.L btcFree(A4),ioBTFreeNode(A3) ; number of free nodes
CLR.W ioBTKDActCount(A3) ; clear ActCount
MOVE.L ioBTKDPtr(A3),D0 ; is there a buffer?
BEQ.S GInfoExit ; no buffer
MOVEA.L D0,A1 ; A1 = user KD ptr
MOVE.L btcKDPtr(A4),D0 ; D0 = btree kd
BEQ.S GInfoExit ; no KD, default case
MOVEA.L D0,A0 ; A0 = Btree KD ptr
MOVEQ #0,D0
MOVE.W ioBTKDReqCount(A3),D0 ; D0 = user kd buffer len
BEQ.S GInfoExit ; buffer len = 0 ?
MOVEQ #0,D1 ; clear D1 <10May90>
MOVE.B (A0),D1 ; D1.W = KD length <10May90>
CMP.W D1,D0 ; D0.W = buffer len <10May90>
BLE.S @2 ; user <= btree, use user buffer size
MOVE.W D1,D0 ; use btree's
ADDQ.W #1,D0 ; include length byte
@2 MOVE.W D0,ioBTKDActCount(A3)
_BlockMove
MOVEQ #0,D0 ; perfect
GInfoExit
BRA ExtBTCmdDone
;_______________________________________________________________________
;
; Routine: xBTFlush
; Arguments: A0.L (input) -- pointer to BT parameter block.
; D1.W (input) -- trap word
; D0 (output) -- error code
; Function: Flush cache buffers associated with the Btree file.
; If ioWriteFlag is clear, then this is a delayed write to fs's cache.
; Modification History:
;
; 06Jul89 KST New today
; 01Aug90 KST Adding a new field ioBTWriteFlag in BTioParam.
;------------------------------------------------------------------------
xBTFlush
BSR ExtBTQueue
MOVEQ #noWrite,D0 ; not write permssn
BSR ExtIsBtree ; is this a BTree?
BNE.S @2
MOVE.W ioRefNum(A0),D0 ; D0.W = RefNum
MOVE.B ioBTWriteFlag(A0),D5; D5.B = write flag
BSR ExtBTFlush ; just flush <SM1>
@2 BRA ExtBTCmdDone
;_______________________________________________________________________
; Routine: xBTCleanUp <2.7>
; Arguments: A0.L (input) -- pointer to (dummy) BT parameter block.
; D1.W (input) -- trap word
; Output: Always return no error (D0 = 0) code
; Function: Close all Btree files associated with a process at process termination.
; This routine is not queued and cannot be called from interrupt !!
; Because, it calls xBTClose which is executed sychronously.
; Modification History:
; Oct-06-89 KSCT New today
;------------------------------------------------------------------------
xBTCleanUp
MOVEM.L A2-A3/D2-D6,-(SP)
MOVE.L A0,-(SP) ; save A0, trashed by _GetCurrentProcess
LEA -10(SP),SP ; get current procID and verify it's for us
PEA 2(SP)
_GetCurrentProcess
LEA 2(SP),SP ; don't need to check for error
MOVE.L (SP)+,D6 ; D6 = process ID1 (network address)
MOVE.L (SP)+,D2 ; D2 = process ID2
MOVEA.L (SP)+,A0 ; restore A0
MOVEA.L FSVarsPtr,A1
MOVEa.L FSVars.fcbPBuf(A1),A2 ; A2=parallel array
MOVE cbPBufCount(A2),D3 ; D3=number of FCBs
SUBQ #1,D3 ; for DBcc
MOVE cbPBufULen(A2),D4 ; D4=ext. FCB unit size
LEA fcbPBufData(A2),A2 ; A2=ext. fcb array
MOVE FSFCBLen,D5 ; D5=FCB len
2020-03-22 08:44:21 +00:00
jsrROM ROMGT1STFCB ; A1=FCB ptrm, D1=FCB index <SM1><Sys7.1> De-inlined and put back "ROM"
2019-07-27 14:37:48 +00:00
; First close all the open files belong to this process:
; A1=FCBptr, A2=Ext. FCBptr, D1.W=RefNum, D2=id2, D3.W=loop index, D4.W=ext FCBlen,
; D5.W=original FCBlen, D6=id1
@cleanLoop MOVE.L FCBBTCBptr(A1,D1),D0; is this B*Tree file?
BEQ.S @3 ; no->
MOVE.L xFCBPid2(A2),D0 ; do the 2nd one first
CMP.L D0,D2 ; FCB belongs to this process?
BNE.S @3 ; no->
MOVE.L xFCBPid1(A2),D0
CMP.L D0,D6 ; FCB belongs to this process?
BNE.S @3 ; no->
;; this open path belongs to this proc, let's close it
BSR.S clearPB ; clear iopb in A0
MOVE D1,ioRefNum(A0) ; close this access path
MOVEM.L A1/D1/D2,-(SP) ; these registers are trashed
BSR xBTClose ; close the file
MOVEM.L (SP)+,A1/D1/D2
@2 CLR.L xFCBPid1(A2) ; clear procID 1
CLR.L xFCBPid2(A2) ; clear procID 2
@3 ADDA D4,A2 ; go to next ext.FCB
ADD.W D5,D1 ; go to next FCB RefNum
DBF D3,@cleanLoop ; process them all …
MOVEM.L (SP)+,A2-A3/D2-D6
MOVEQ #0,D0 ; happy ending
RTS
clearPB MOVEA.L A0,A3 ; A3=A0=iopb
MOVE #(fscPBLen/2)-1,D0 ; iopb len in word -1
@2 CLR (A3)+
DBRA D0,@2 ; clear 26 bytes
RTS
;_______________________________________________________________________
; Routine: xBTRsrvAccess <2.9>
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; Output: D0 = 0 if no error.
; Function: Reserve access for one process.
;
; Modification History:
; 01Dec89 KSCT New today
;------------------------------------------------------------------------
xBTRsrvAccess
BSR ExtBTQueue
MOVEQ #noWrite,D0 ; not write permssn
BSR ExtIsBtree ; is this a BTree?
BNE.S @notBT ; no,
MOVE.L ioBTRsrvUID(A0),D0 ; D0=UID
;; make sure this is a valid UID !! (>=startUid and < currentUid)
CMPI.L #WCSigLong,D0 ; D0 >= start UID?
BLO.S @badUid ; no, error
MOVEA.L FSVarsPtr,A1
MOVEA.L fsVars.BTMgr(A1),A1 ; get BTVar
MOVE.L btVNextUID(A1),D1 ; D1 = next UID
CMP.L D1,D0 ; D0 must < D1
BLO.S @uidok ; OK
@badUid MOVE #btBadUIDErr,D0 ; UID error
BRA.S @notBT
@uidok ; TST.L BTCRsrvUID(A4) ; already reserved?
; BNE.S @rsrved ; yes => (this should not happen now <17Jul90>)
MOVE.L D0,BTCRsrvUID(A4) ; Mark the B*-Tree as in exclusive use
MOVEQ #0,D0 ; successful
@notBT BRA ExtBTCmdDone
;_______________________________________________________________________
; Routine: xBTRelAccess <2.9>
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; Output: D0 = 0 if no error.
; Function: Relinquish exclusive access to the B*-Tree.
;
; Modification History:
; 04Dec89 KSCT New today
;------------------------------------------------------------------------
xBTRelAccess
BSR ExtBTQueue
MOVEQ #noWrite,D0 ; not write permssn
BSR ExtIsBtree ; is this a BTree?
BNE.S @notBT ; no,
MOVE.L BTCRsrvUID(A4),D0 ; D0 = current UID <13Apr90>
BEQ.S @notBT ; not reserved, return OK <13Apr90>
MOVE.L ioBTRsrvUID(A0),D1 ; D1 = user's UID
CMP.L D1,D0 ; D0 must = D1
BEQ.S @uidok ; OK
MOVE #btBadUIDErr,D0 ; UID error
BRA.S @notBT
@uidok CLR.L BTCRsrvUID(A4) ; free access
MOVEQ #0,D0 ; successful
@notBT BRA ExtBTCmdDone
;_______________________________________________________________________
; Routine: xBTGetUid <2.9>
; Arguments: A0.L (input) -- pointer to BT ioParameter block.
; D1.W (input) -- trap word
; Output: D0 = 0 if no error.
; Function: Assign a B*-Tree UID. This routine is not queued!!
;
; Modification History:
; 04Dec89 KSCT New today
; 23Jul90 KSCT ADDQ.W should be ADDQ.L
;------------------------------------------------------------------------
xBTGetUid MOVEA.L FSVarsPtr,A1 ; locate next UID from BTVars
MOVEA.L fsVars.BTMgr(A1),A1 ; get BTVars
MOVE.L btVNextUID(A1),D0 ; D0 = next UID
MOVE.L D0,ioBTRsrvUID(A0) ; return to user
ADDQ.L #1,D0 ; bump UID <23Jul90>
BNE.S @2 ; UID wraps around to 0?
MOVE.L #WCSigLong,D0 ; yes, the system is so robust
@2 MOVE.L D0,btVNextUID(A1) ; and stash in the save area
MOVEQ #0,D0 ; no error
MOVE.W D0,ioResult(A0) ; this call is not queued, so we have to clear it here.
RTS
;_______________________________________________________________________
; Routine: xBTUpdateKD
; Arguments: A0.L (input) -- pointer to BT parameter block.
; D1.W (input) -- trap word
; Output: D0 = 0 if no error.
; Function: Replace Key descriptor into the header!!
;
; Modification History:
; 30Jan90 KSCT New today
;------------------------------------------------------------------------
xBTUpdateKD BSR ExtBTQueue
MOVE.W #btKDLenErr,D0 ; preset error code
MOVE.L ioBTKDPtr(A0),D2
BEQ @ret ; no KD error
MOVEA.L D2,A1 ; A1=key descriptor
BSR checkKD ; validate kd
BNE @ret ; KD error
MOVEA.L A0,A4 ; save user ioparam in A4
MOVEQ #0,D7 ; D7 = not open flag
BSR ExtCopyParam ; get and clear BT param in A3=A0
BSET #fsWrPerm,ioPermssn(A0) ; req for write permssn
MOVEQ #DoOpen,D1 ; indicate this is OPEN
BSR ExtDoAOCRWF ; do the open/close sync/async
BNE @ret ; error, exit
ST D7 ; set file opened flag
MOVEA.L FCBSptr, A2 ; A2 = ptr to FCBs
MOVE.W ioRefNum(A0),D5 ; D5 = file refnum
MOVE.L fcbEof(A2,D5.W),D0 ; logical length <07Dec90 #30>
BEQ.S @badHdr ; LEOF = 0? No way ! <07Dec90 #30>
;; BTree opened, read the header block
BSR GetaCBlock ; get a clear BTbuffer in A0
MOVE.L A0,IOBuffer(A3) ; buffer to read
EXG A3,A0 ; A0= private param block, A3 = buffer
MOVE.L #0,D0 ; header node number = 0
MOVE.L D0,IOPosOffset(A0) ; ... gives position offset
MOVE.W #fsFromStart,IOPosMode(A0) ; position mode(from BOF)
MOVE.L #BtnodeSize,IOByteCount(A0) ; always r/w 512 bytes for header
MOVEQ #DoRead,D1 ; indicate this is READ
BSR ExtDoAOCRWF ; read header node into A3
BNE.S @Exit1 ; error
;; do a simple check of the header in A3 to make sure that this is B*Tree file!
LEA lenND(A3),A2 ; A2 = ptr to BTH
MOVE.W BTHNodeSize(A2),D0 ; node size
BEQ.S @badHdr ; node size = 0, error ->
MOVE.W D0,D1 ; copy into D1
ANDI.W #$1FF,D1 ; clear bits
BNE.S @badHdr ; node size not 512 multiple, error ->
MOVEA.L FCBSptr, A1 ; A1 = ptr to FCBs <26Nov90>
MOVE.L fcbEof(A1,D5.W),D2 ; logical length (will not be 0) <26Nov90>
DIVU D0,D2 ; length / node size <26Nov90>
SWAP D2 ; = # of nodes <26Nov90>
CLR.W D2 ; <26Nov90>
SWAP D2 ; D2.L = total nodes <26Nov90>
CMP.L BTHNNodes(A2),D2 ; same # as in BTH? <26Nov90>
BNE.S @badHdr ; no, error -> <26Nov90>
CMP.L BTHFree(A2),D2 ; # of nodes > free count? <26Nov90>
BHI.S @1 ; yes, looks OK -> <26Nov90>
@badHdr MOVE.W #notBTree,D0 ; result = 'bad header node' <26Nov90>
BRA.S @Exit1 ; and exit <26Nov90>
@1 ;; copy KD into the header then write it back
MOVEA.L ioBTKDPtr(A4),A1 ; A1 = KD buffer
LEA kdPtr(A3),A2 ; A2 is free
MOVEQ #0,D0 ; clear D0
MOVE.B (A1),D0 ; KD length
@2 MOVE.B (A1)+,(A2)+ ; copy over
DBRA D0,@2
MOVE.L #0,D0 ; header node number = 0
MOVE.L D0,IOPosOffset(A0) ; ... gives position offset
MOVEQ #DoWrite,D1 ; indicate this is WRITE
BSR ExtDoAOCRWF ; write the block back
@Exit1 ;; ready to leave, D0 = error code
TST.B D7 ; file still open?
BEQ.S @ret ; no
;; close the file before we leave
MOVE.W D0,-(A6) ; save error code
MOVEQ #DoClose,D1 ; indicate this is CLOSE
BSR ExtDoAOCRWF
MOVE.W (A6)+,D0 ; restore error code
@ret BRA ExtBTCmdDone
;________________________________________________________________________________
;
; Routine: DTKeyCmp
;
; Function: Compare two Desktop B*-Tree keys.
;
; Input: A0.L - search key pointer
; A1.L - trial key pointer
;
; Output: D0.W - result code
; +n search key > trial key
; 0 search key = trial key
; -n search key < trial key
;
; NOTE: The keys in the Desktop B*-Tree are all either numeric or case-sensitive
; strings, differentiated in the first position by the key type. The key
; type will ensure that keys are sorted by type first; beyond that, a
; straight byte comparison may be used to properly differentiate the keys.
;________________________________________________________________________________
IF 0 THEN
DTKeyCmp:
; Figure the trial key length from the search key type; since all index
; keys are padded out to their full length, the trial key length is
; unreliable. The search key length cannot be used because Getxxx routines
; pass shorter keys (Type & Creator only) meant to compare less than any
; key by that creator, but greater than preceding Creators.
MOVE.B (A0)+,D0 ; Pick up length of search key
MOVEQ #IconKey.IKLen-1,D1 ; Figure length of icon key
CMP.B #IconKeyType,(A0) ; Looking for an icon key?
BEQ.S @5 ; Yes - we're in business
MOVEQ #APPLKey.AKLen-1,D1 ; No - try an APPL key
CMP.B #APPLKeyType,(A0) ; Looking for an APPL key?
BEQ.S @5 ; Yes - go with it
MOVEQ #CommentKey.CKLen-1,D1 ; Finally, try a comment key
CMP.B #CommentKeyType,(A0); Looking at a comment?
BEQ.S @5 ; Yes - finally right.
MOVE.B D0,D1 ; No - just use the search key length
;
@5 TST.B (A1)+ ; Ignore length of trial key
@10 CMPM.B (A1)+,(A0)+ ; Compare byte in key
BHI.S DTKCIsGT ; search key > trial key
BLO.S DTKCIsLT ; search key < trial key
SUBQ.B #1,D1 ; Count off one trial key character
SUBQ.B #1,D0 ; Count off one search key character
BEQ.S @20 ; If zero, stop comparison
TST.B D1 ; Reached end of trial key?
BNE.S @10 ; No - keep checking
BRA.S DTKCIsGT ; Yes - search key > trial key
@20 TST.B D1 ; Also reached end of trial key?
BNE.S DTKCIsLT ; No - search key < trial key
DTKCIsEQ MOVEQ #0,D0 ; The two keys are equal
BRA.S DTKCExit ; So we're done
DTKCIsLT MOVEQ #-1,D0 ; Search key < trial key
BRA.S DTKCExit ;
DTKCIsGT MOVEQ #1,D0 ; Search key > trial key
DTKCExit BRA DefExit ; use common return code
ENDIF
;_______________________________________________________________________________
; Routine: DefKCmp (default key comparison routine)
; Function: Compare 2 keys as unsigned binary
; Input: A0.L - search key pointer (user key)
; A1.L - trial key pointer (BTree)
; A4.L - ptr(BTCB)
; Output: D0.W - result code
; +n search key (A0) > trial key (A1)
; 0 search key (A0) = trial key (A1)
; -n search key (A0) < trial key (A1)
;_______________________________________________________________________________
DefKCmp ;; D0-D5/A2-A3 are free
MOVEQ #0,D0 ; clear D0
MOVE D0,D1 ; clear D1
MOVE.B (A0)+,D0 ; D0.W=user key length
MOVE.B (A1)+,D1 ; D1.W=Btree key length
MOVE D0,D2 ; use the smaller len as loop index
CMP D2,D1 ; D1 < D2?
BGE.S @2 ; No
MOVE D1,D2 ; D1 is smaller
@2 SUBQ #1,D2
@4 CMP.B (A1)+,(A0)+
DBNE D2,@4
BEQ.S DefKEqual ; 2 keys are the same (so far)
BSR UnsCmpRet ; not equal, set up D0
BRA DefExit ; use common return code
DefKEqual CMP D1,D0 ; if length is the same then they are really equal
BEQ DefExitOK ; cool
BLO.S A1longer ; A1 is longer
MOVEQ #1,D0 ; A0 is longer => A0>A1
BRA DefExit ; use common return code
A1longer MOVEQ #-1,D0 ; A1 is longer => A1>A0
BRA DefExit ; use common return code
;_______________________________________________________________________________
; Routine: BTKCmp (BTree Key Compare)
;
; Function: Compares two keys (a search key and a trial key).
; This is a small interpreter that will handle different key types.
; Each type is then processed by the corresponding comparison routine.
; User's key has been validated before it comes to here.
; Input: A0.L - search key pointer (user)
; A1.L - trial key pointer (BTree)
; * 4(SP).L = BTCB, BTreemaint2.a (ExtSearchNode)
; * This key comparison routine depends on that BTCB is passed on stack
; * when get called (because I need the KD from it), therefore the calling
; * convention cannot be changed !!! Leave it there on return.
; Output: D0.W - result code, uses D1
; +n search key (A0) > trial key (A1)
; 0 search key (A0) = trial key (A1)
; -n search key (A0) < trial key (A1)
;
; <03Jan91> KST Type kdDTString is no longer used by DTmgr.
;_______________________________________________________________________________
BTKCmp ;; A4 was BTCB and is saved on SP by "ExtSearchNode"
;; each compare routine is responsible for updating A0,A1,A2 and D2!
MOVEA.L 4(SP),A4 ; A4 = BTCB
MOVEM.L D2-D5/A2-A3/A5,-(SP)
;; set up for the default case (unsigned binary)
;; no default case for this release, but we leave the code here for future,
;; since BTInit will not honor a NULL KD, so it's safe to keep the code around.
;; Besides, we cannot return error from this call ! <8/31/89>
MOVE.L btcKDPtr(A4),D0 ; default case?
BEQ.S DefKCmp ; yes, go do it
MOVEA.L D0,A2 ; A2 = ptr(KD)
CMPI.B #kdReserved,1(A2) ; type = kdDTString? (2,9,1) <9/18/89>
BEQ.S DefExit ; can't return error, so just exit <03Jan91 #33>
ADDQ #1,A0 ; skip total key length byte
ADDQ #1,A1
MOVEQ #0,D2
MOVE.B (A2)+,D2 ; D2.W = KD length
DefLoop TST.W D2 ; more to come?
BEQ.S DefExitOK ; no, all done
MOVE.B (A2)+,D3 ; D3.B = selector
BNE.S @2 ; 0 if skip bytes
SUBQ.W #2,D2 ; type = kdSkip
MOVEQ #0,D0
MOVE.B (A2)+,D0 ; D0.W = # of bytes
ADDA.W D0,A0 ; skip N bytes
ADDA.W D0,A1
BRA.S DefLoop
@2 ;; not kdSkip: A2.l=ptr(KD), A0 = search key, A1 = trial key, D1.b=string attr
;; D2.w=KD length, D3.b=D5=KD type, D4.w=buffer size (if FLString)
MOVEQ #0,D5
MOVE.B D3,D5
LEA kCmpTable,A3 ; use jump table
LEA updStrPtr,A5 ; string update routine
CMPI.B #kdString,D3 ; is it string?
BEQ.S doCompare ; yes
CMPI.B #kdFLString,D3 ; is it FL string?
BNE.S common ; no, forget it
;; FL string: need different string update routine and need to get
;; buffer length from the key descriptor
LEA updFLStrPtr,A5 ; string update routine
MOVEQ #0,D4
MOVE.B (A2)+,D4 ; D4.W = string buffer len
SUBQ #1,D2 ; D2-1 for buffer length byte
BRA.S doCompare ; string
;; not string => byte, word or long are common here, string is special case
common MOVEQ #0,D3 ; clear high byte, it could be -1 from DBRA loop <11Aug89>
MOVE.B (A2)+,D3 ; # of occurrence
SUBQ #1,D3 ; for loop index
SUBQ.W #2,D2 ; KD length - 2
doCompare SUBQ #1,D5 ; make selector offset from 0
ADD D5,D5
ADDA.W (A3,D5),A3
JSR (A3) ; do the comparison
BNE.S DefExit ; not equal, stop
BRA.S DefLoop
DefExit TST D0
MOVEM.L (SP)+,D2-D5/A2-A3/A5
RTS
DefExitOK MOVEQ #0,D0 ; no error
BRA.S DefExit
;___________________________________________________________________
; Input: A0,A1= first char of Keys; D0 is free, D4.W=buffer length
; Function: Update key pointer to pass the fixed-length string (points to next field)
;___________________________________________________________________
updFLStrPtr SUBQ.W #1,D4 ; exclude length byte
ADDA.W D4,A0 ; points to next FL string
ADDA.W D4,A1
;; in case there is more than 1 occurrence (fixed length string)
;; so D4 should be restored for next reference !
ADDQ.W #1,D4
RTS
;___________________________________________________________
; Input: A0,A1= first char of Keys; D0 is free
; Function: Update key pointer to pass the string (points to next field)
;___________________________________________________________
updStrPtr MOVEQ #0,D0
MOVE.B -1(A0),D0 ; points to length byte !!
ADDA.W D0,A0
MOVE.B -1(A1),D0 ; points to length byte !!
ADDA.W D0,A1
RTS
kCmpTable DC.W unByteCmp-kCmpTable ; 1
DC.W sByteCmp -kCmpTable ; 2
DC.W StrCmp -kCmpTable ; 3
DC.W unWordCmp-kCmpTable ; 4
DC.W sWordCmp -kCmpTable ; 5
DC.W unLongCmp-kCmpTable ; 6
DC.W sLongCmp -kCmpTable ; 7
DC.W StrCmp -kCmpTable ; 8 FLString share the same code as 3
;_________________________________________________________________________________
;; Input: A0,A1=Keys, A2=KD (occurrence, keyattr), A4=BTCB, A5=key update routine
;; D2.W =KD len, D4 = fixed string buffer length if type = kdFLstring
;; D0,D1,D3,A3 are free
;; each compare routine is responsible for updating A0,A1,A2 and D2!
;_________________________________________________________________________________
StrCmp
MOVE.B (A2)+,D3 ; # of occurrence
MOVE.B (A2)+,D1 ; string attr
SUBQ.W #3,D2 ; string uses 3 bytes
strcmpLoop MOVEQ #0,D0
MOVE.B (A0)+,D0 ; search key length
SWAP D0 ; in high-order word
MOVE.B (A1)+,D0 ; low-order word
;; A0, A1 points to the first char of the string
CMPI.B #casesen+diacNsen,D1
BEQ.S @4
CMPI.B #diacNsen,D1
BEQ.S @6
CMPI.B #casesen,D1
BEQ.S @8
@2 _RelString ; anything else
BRA.S strcmpExit
@4 _RelString ,MARKS ,CASE
BRA.S strcmpExit
@6 _RelString ,MARKS ; diacSens=False, caseSens=False
BRA.S strcmpExit
@8 _RelString ,CASE ; diacSens=True, caseSens=True
strcmpExit ;; D0 already set, make sure CR unchanged when return
BNE.S @6 ; stop
SUBQ.B #1,D3 ; another string?
BEQ.S @2 ; no, all done
;; do we need to update A0 and A1 ? => yes
JSR (A5) ; update string pointers
BRA.S strcmpLoop
@2 MOVE.W D0,-(SP) ; save result
TST.W D2 ; more key to compare?
BEQ.S @4 ; br if no
JSR (A5) ; update key pointers (points to next key)
@4 MOVE.W (SP)+,D0
TST.W D0 ; result of sting comp
@6 RTS
;____________________________________________________________________
; unsigned byte, word, long compare routine
; Input: A0,A1=Keys, A2=KD (occur and keyattr), A4=BTCB, D2.W=KD len
; A2=updated KDptr, D2.W=updated KD len, D3=occurrence-1.
; D0,D1,A3 are free
; each compare routine is responsible for updating A0,A1!
;____________________________________________________________________
unByteCmp
@2 CMP.B (A1)+,(A0)+
DBNE D3,@2
;____________________________________________________________________
; Function: unsigned byte, word, long compare routine common return handler
; Input: condition code set
; Output: set D0 and return (unsigned)
;____________________________________________________________________
UnsCmpRet BHI.S SKIsHI ; search ParID > trial parID ->
BLO.S SKIsLO ; search ParID < trial parID ->
MOVEQ #0,D0 ; search ParID = trial parID
BRA.S CmpExit
SKIsHI MOVEQ #1,D0
BRA.S CmpExit
SKIsLO MOVEQ #-1,D0
CmpExit TST.W D0
RTS
;____________________________________________________
; unsigned word
;____________________________________________________
unWordCmp
@2 CMP (A1)+,(A0)+
DBNE D3,@2
;; set D0 and return
BRA.S UnsCmpRet
;_____________________________________________________
; unsigned long
;_____________________________________________________
unLongCmp
@2 CMP.L (A1)+,(A0)+
DBNE D3,@2
;; set D0 and return
BRA.S UnsCmpRet
;____________________________________________________________________
; Signed byte compare routine
; Input: A0,A1=Keys, A2=KD (occur and keyattr), A4=BTCB, D2.W=KD len
; A2=updated KDptr, D2.W=updated KD len, D3=occurrence-1.
; D0,D1,A3 are free
; each compare routine is responsible for updating A0,A1!
;____________________________________________________________________
sByteCmp
@2 CMP.B (A1)+,(A0)+
DBNE D3,@2
;; common return code, set D0 and return
sCmpRet BGT.S SKIsGT ; search ParID > trial parID ->
BLT.S SKIsLT ; search ParID < trial parID ->
MOVEQ #0,D0 ; search ParID = trial parID
BRA.S sCmpExit
SKIsGT MOVEQ #1,D0
BRA.S sCmpExit
SKIsLT MOVEQ #-1,D0
sCmpExit TST.W D0
RTS
;____________________________________________________
; signed word
;____________________________________________________
sWordCmp
@2 CMP (A1)+,(A0)+ ; compare word
DBNE D3,@2
;; set D0 and return
BRA.S sCmpRet
;____________________________________________________
; signed long
;____________________________________________________
sLongCmp
@2 CMP.L (A1)+,(A0)+ ; compare long
DBNE D3,@2
;; set D0 and return
BRA.S sCmpRet
; internal routines:
;_______________________________________________________________________
; Routine: checkKD
; Function: key descriptor syntax check
; Input: (A0.L = pointer to ioparam, D1.W = trap word)
; A1 = ptr(kd), D0.W = btKDLenErr (length error)
; Modification History:
; 04Jan90 KSCT added check for kdDTString type. This is used by DTDBMgr only,
; and the kd should = 2,9,1 (total length = 2)
; 04Jan91 KSCT Took out the kdDTString type support.
;_______________________________________________________________________
checkKD MOVEQ #0,D2
MOVE.B (A1)+,D2 ; KD length
BEQ.S typeExit ; if KD = 0, punt
CMPI.W #kdMaxLen,D2 ; is it too big?
BLS.S ckType ; br if OK
typeExit TST.W D0
RTS
;; validate each KD type
ckType MOVE.W #btKDTypeErr,D0 ; KD type err
MOVEM.L D1/D3-D4,-(SP) ; <1/4/90>
MOVE D2,D4 ; save total KD length <1/4/90>
typeLoop TST.W D2 ; all done?
BNE.S typeLoop1 ; no
tLoopDone MOVEQ #0,D0 ; yes, no error
BRA.S tloopEnd ; ready to leave
typeLoop1 MOVE.B (A1)+,D1 ; D1.B = type
CMPI.B #kdReserved,D1 ; this is only allowed to be used by DTDB
BEQ.S tloopEnd ; this type is not used <03Jan91 #33>
CMPI.B #kdUseKCProc,D1 ; is this special type? <29Mar90>
BNE.S @1 ; good, it's not <29Mar90>
;; DT's KD should be "2,9,1", useKC should be "2,10,1" <29Mar90>
@0 CMPI #2,D4 ; total KD length = 2 ? <29Mar90>
BNE.S tloopEnd ; if not then punt=> <29Mar90>
@1 SUBQ.W #2,D2 ; consume at least 2 bytes
BMI.S tloopEnd ; total length error, punt
MOVEQ #0,D3
MOVE.B (A1)+,D3 ; D3.B = occurrence (or buffer len if FL string)
BEQ.S tloopEnd ; can't = 0
CMPI.W #maxOccur,D3 ; happen too many times?
BHI.S tloopEnd ; br if error
;; # of occurrence is OK, (or FL string buffer is OK)
CMPI.B #kdString,D1 ; is this a string?
BEQ.S @2 ; yes
CMPI.B #kdFLString,D1 ; is this a FLstring?
BNE.S @6 ; no
;; here, type is a Fixed Length string, check occurrence and string attr
;; buffer length has been checked, it is not zero.
SUBQ.W #1,D2 ; consume 1 more byte for buffer len
MOVE.B (A1)+,D3 ; D3.B = occurrence
BEQ.S tloopEnd ; can't = 0
CMPI.W #maxOccur,D3 ; happen too many times?
BHI.S tloopEnd ; br if error
;; here, type is string, check string attr
@2 ;; code shared with Fixed Length string type
MOVE.B (A1)+,D3 ; D3.B = attr
SUBQ.W #1,D2 ; consume 1 more byte for attr
BMI.S tloopEnd ; total length error, punt
ANDI.B #keyAttrmsk,D3 ; attr OK? (not a valid KD type)
BEQ.S typeLoop ; valid key attr
MOVE.W #BTKeyAttrErr,D0 ; return with error
BRA.S tloopEnd
@6 ;; not string and FLstring, then it must be one of general types
CMPI.B #kdMaxnum,D1 ; supported type?
BLO.S typeLoop ; D1<max, type OK, continue
tloopEnd MOVEM.L (SP)+,D1/D3-D4 ; <1/4/90>
BRA.S typeExit
;______________________________________________________________________
; Routine: bitmapInit
; Function: Init the bitmap from A0 in the header/map node. 1 = used, 0 = free
; some optimization here, if more than 8 nodes, set the whole byte,
; if more than 16 nodes,set the whole word.
; Inout: A0 = bitmap, D2=size of the bitmap, D6=number of map nodes
; output: D6 = number of map node remains to be initialized
;______________________________________________________________________
bitmapInit
CMP.L D2,D6 ; occupy the whole bitmap?
BLO.S initPart ; no
;; it takes the whole map, convert the size to words
SUB.L D2,D6 ; D6=nodes remaining
LSR.L #4,D2 ; divide by 16
SUBQ.L #1,D2
@1 MOVE #$FFFF,(A0)+ ; set the word
DBF D2,@1
BRA.S MNinitEnd
initPart ;; init part of the map, this node does it all
CMPI #8,D6 ; more than 8 nodes?
BLO.S initByte ; no
MOVE.B #$FF,(A0)+
SUBQ #8,D6 ; take care of 8 nodes
BHI.S initPart ; more to come
initByte ;; init part of a byte
MOVEQ #7,D2 ; from bit 7
initBitLoop DBF D6,initBit ; if not 0, go set a bit
MOVEQ #0,D6 ; all done
MNinitEnd RTS
initBit BSET D2,(A0) ; mark as used
SUBQ.L #1,D2 ; next bit
BRA.S initBitLoop ; continue
;______________________________________________________________________
; Routine: checkey
; Function: make sure the user's key matches with the fields in the key descriptor.
; Input: A0=A3=user ioParam, A4=BTCB, A1=ptr(FCBs)
; Return: condition and error code set. D0=0 means OK
; Trash: A2,D1,D2
;______________________________________________________________________
checkey MOVE.L btcKeyCR(A4),D0 ; kc routine <28Mar90>
LEA BTKCmp,A2 ; my key compare routine <28Mar90>
CMP.L D0,A2 ; are they using mine? <28Mar90>
BEQ.S @2 ; yes, parse the key <28Mar90>
MOVEQ #0,D0 ; if not using mine, <28Mar90>
BEQ ckeyexit2 ; don't parse, exit <28Mar90>
@2 ; <28Mar90>
MOVE.L btcKDPtr(A4),D0
BEQ ckeyexit2 ; default key, exit
MOVEA.L D0,A2 ; A2 = KD ptr
MOVE.W #btKeyFdErr,D0 ; D0 = error code
MOVEM.L A1/D3-D4,-(SP) ; save FCBsptr
MOVEA.L ioBTKeyPtr(A0),A1 ; A1 = ptr(user key)
MOVEQ #0,D1
MOVE.B (A1)+,D1 ; D1.W = user key len
BLE.S ckeyexit ; keyLen<=0, punt on error
MOVEQ #0,D2 ; zero out D2-D4
MOVE D2,D3
MOVE D2,D4
MOVE.B (A2)+,D2 ; D2.W = (system) KD len
ckeyloop TST D1 ; key exhausted?
BLE.S ckeyexit ; <=0, punt on error
MOVE.B (A2)+,D3 ; D3 = key type
MOVE.B (A2)+,D4 ; D4 = occurrence (if not FL string)
SUBQ.W #kdBytesPerKey,D2 ; each field consumes 2 bytes
CMPI.B #kdReserved,D3 ; is it the special type? <9/18/89>
BEQ.S ckeyexit ; no longer used <03Jan91 #33>
CMPI.B #kdSignedByte,D3 ; is it byte operation?
BHI.S notskip ; no
;; skip N bytes, unsigned and signed byte are all treated the same as byte
;; this takes care of type = 0, 1 and 2
ckeycommon SUB.W D4,D1 ; skip N bytes
ADDA.W D4,A1 ; points to next field
BRA.S ckeyend
notskip CMPI.B #kdString,D3 ; is it string?
BEQ.S @stringType ; yes
CMPI.B #kdFLString,D3 ; is it FL string?
BNE.S @notstring ; no
;; here, it is a fixed length string
MOVE.B D4,D3 ; D3 = key buffer total length
MOVE.B (A2)+,D4 ; D4 = occurrence
SUBQ.W #1,D4 ; index -= 1
SUBQ.W #kdBytesFLStr,D2 ; FL string uses 2 byte more than others
ADDA #1,A2 ; skip attr byte!
@2 SUB.W D3,D1 ; skip N bytes (buffer size)
ADDA.W D3,A1 ; points to next field
DBF D4,@2 ; continue if more FLstring
BRA.S @stringEnd
@stringType ;; yes, this is a string
SUBQ.W #1,D4 ; index -= 1
SUBQ.W #kdBytesStr,D2 ; string uses one byte more than others
ADDA #1,A2 ; bump KD ptr too!
@3 MOVE.B (A1)+,D3 ; D3 = string length
SUB.W D3,D1 ; skip N bytes
SUBQ.W #1,D1 ; skip the length byte too!
ADDA.W D3,A1 ; points to next field
DBF D4,@3 ; continue if more string
@stringEnd MOVEQ #0,D4 ; clear high order byte
BRA.S ckeyend
@notstring ;; here, it must be either a word or long. D4=number of occurrence
ADD.W D4,D4 ; *2 (a word type, skip 2*N bytes)
CMPI.B #kdSignedWord,D3 ; is it Word?
BLS.S ckeycommon ; yes, signed or unsigned word
;; here, it must be long, skip 4*N bytes
ADD.W D4,D4 ; *2 (skip 2*N more bytes)
BRA.S ckeycommon ; use common code
ckeyend TST.W D2 ; more to come?
BNE.S ckeyloop ; yes
TST.W D1 ; key len should = 0 too
BNE.S ckeyexit ; error =>
ckNewType MOVEQ #0,D0 ; perfect
ckeyexit MOVEM.L (SP)+,A1/D3-D4
ckeyexit2 TST.W D0 ; set SR
RTS
;______________________________________________________________________
; Routine: ChkSize
; Function: make sure the record size fits in the node, check both key and data
; Input: A0=key, D1.L=size of data, A4=BTCB
; Return: condition code set; <= 0 means OK.
; If not OK(>0), then D0 = error code, D2 = total record size
;______________________________________________________________________
ChkSize
MOVEQ #0,D2
MOVE.W #btnoFit,D0 ; set error code = record too big
MOVE.B (A0),D2 ; get key length
BEQ.S @2 ; key length = 0?
CMP.W btcKeyLen(A4),D2 ; key too long?
BGT.S @2 ; yes
EXT.L D2
BTST #0,D2 ; is it odd
BNE.S @1 ; yes,
ADDQ.L #1,D2 ; no, even (even key needs 2 more bytes)
@1 ADDQ.L #1,D2 ; include length byte
BCLR #0,D2
ADD.L D1,D2 ; total size = key size + data size
CMPI.L #MaxRecSize,D2 ; is the record fit
BRA.S @4 ; CR and D0 set
@2 ;; key length too big or zero
MOVE #btKeyLenErr,D0 ; set error code
MOVE #0,CCR ; set condition code (>0)
@4 RTS
; _________________________________________________________
;; check if all hints are 0
;; Input: A3 = ioParam
;; Ouput: D1.L = write count; D2.L = Node #; D3.W = Index#
; _________________________________________________________
ZeroHints
MOVE.L ioBTHint1(A3),D1 ; write count
MOVE.L ioBTHint2(A3),D2 ; node #
MOVE ioBTHint3(A3),D3 ; index #
BNE.S notzero
TST.L D2
BNE.S notzero
TST.L D1
notzero RTS
;_________________________________________________________________________________
; Input: (A2,D5)=refnum, A1=VCB, D1 is free
; output: D0=error code, A0 = ptr(buffer). Should always succeed.
; Function: Get a free buffer, also clear it! The buffer is only used to initialize
; and update (xBTUpdateKD) the B*Tree file.
; This function is sync since there is no I/O !
;_________________________________________________________________________________
GetaCBlock
MOVE D5,D0
MOVE.L A1,-(sp) ; free a1
MOVEa.L FSVarsPtr,A1
MOVEA.L fsVars.btMgr(A1),A1 ; get BTvars
MOVEA.L btBufQHdr(A1),A1 ; A1 = buffer Qheader
MOVEQ #kGBNoRead,D1 ; indicate noRead
MOVEQ #0,D2 ; node=0
JSR ExtGetBlock ; <SM1>
BNE.S @2 ; no buffer?
;; buffer in A0 has marked inuse, clear it (just temp use by INIT) <9/8/89>
LEA -lenbtBH(A0),A1 ; A1 = ptr to CBH <9/8/89>
BCLR #CBHinuse,btBHFlags(A1) ; set not in-use <9/8/89>
MOVEA.L A0,A1 ; A1=A0=ptr(buffer)
;; Clear the buffer. At INIT time, nodesize is a constant
MOVEQ #(btnodesize/4 - 1),D1 ; buffer length in long - 1
@1 CLR.L (A1)+ ; clear the buffer
DBF D1,@1 ; continue
@2 MOVEa.L (sp)+,A1
TST D0
IF btDebug THEN
BNE.S @goof ; should never happen
RTS
@goof _Debugger
ELSE
RTS
ENDIF
; _________________________________________________________________________
; Input: A3=ioParam, A4=BTCB, D0=error code, D1=0 if file has not changed
; If D0=0, then D2=node hint, D3 is free
; Output: none, will not return
; Function: Common return code for B*Tree calls. For a successful operation, the hint
; is updated, otherwise Hint2 and Hint3 are cleared, Hint1 unchanged. (except
; for BTSearch, if search failed, the insertion point is returned)
; Also, if the file has changed, we bump the write count.
; _________________________________________________________________________
BTReturn
TST.W D0 ; any error?
BEQ.S BTRET1 ; no, all right
BMI.S @2 ; branch if already negative
SUBI.W #BTErrConst,D0 ; make it negative
@2 CLR.L ioActCount(A3) ; no data is written
;; if error, write count unchanged, other hints are cleared (except BTSearch)
CLR.L ioBTHint2(A3) ; no node
CLR.W ioBTHint3(A3) ; no index
BRA.S BTRET ; and return
BTRET1 ;; record inserted, get hints to application
;; A4 = BTCB
TST.B D1 ; BTree changed?
BEQ.S BTRET2 ; No, skip next
;; here, btree file has been changed, update LEOF !!
ADDQ.L #1,BTCWcount(A4) ; bump write count
MOVE.L FCBsptr,A1 ; get FCBs <20Aug90>
MOVE.W ioRefNum(A3),D1 ; and refnum <20Aug90>
MOVE.L FCBPLEN(A1,D1.W),D3 ; D3.L = PEOF <20Aug90>
CMP.L FCBEOF(A1,D1.W),D3 ; LEOF = PEOF? <20Aug90>
BEQ.S BTRET2 ; already equal <20Aug90>
MOVE.L D3,FCBEOF(A1,D1.W) ; make LEOF = PEOF <20Aug90>
BSET #FCBModBit,FCBMdRByt(A1,D1.W) ; mark FCB dirty <20Aug90>
BSR ExtBTAdjEOF ; adjust other EOFs <20Aug90>
BTRET2 MOVE.L BTCWcount(A4),ioBTHint1(A3) ; write count
MOVE.L D2,ioBTHint2(A3) ; node #, don't use btcNodeM
MOVE.W BTCIndexM(A4),ioBTHint3(A3) ; index #
BTRET BRA ExtBTCmdDone
ENDPROC ; BTFuncs
;__________________________________________________________________________________
; Routine: ExtIsBtree
; Function: Make sure the RefNum is good, the file is open and is a BTree file.
; Input: A0=user ioParam, D0.W=0 if request for write permission.
; Output: condition and error code set. D0=0 means OK, if D0=0 then A4=BTCB
; A1=FCB array,A2=VCB,D1=RefNum,D2 trashed by RfnCall.
; A0 preserved.
; Modification History:
; 27Nov90 KSCT Because we share BTCB for multiple access, we need to make sure
; the btcbRefNum in the BTCB is the current requested file.
;__________________________________________________________________________________
ExtIsBtree PROC EXPORT
TST.W D0 ; write permssn request?
BEQ.S @2 ; yes
BSR btRfNCall ; no, verify the file is open only
BRA.S @4
@2 BSR btTstMod ; check RfnCall and write Perm
; D1.W=RefNum, D2.L=file number,
; A1.L=ptr(FCB buffer start), A2.L=VCB pointer
@4 BNE.S @IsBtRet ; br if not open or write protected
IF NOT btDebugSYS THEN ; if debug, don't check ID <16Apr90>
MOVE.L fcbFlNm(A1,D1),D0 ; Pick up the file number <11/30/89>
CMP.L #fsUsrCNID,D0 ; Check: is it a system B*-Tree? <11/30/89>
BLO.S @notBt ; If so, we're in trouble <11/30/89>
ENDIF ; if debug, don't check <16Apr90>
MOVE.L FCBBTCBptr(A1,D1),D0; D0 = BTCB
BEQ.S @notBt ; not btree
MOVEa.L D0,A4 ; A4=BTCB
CMP.B #1,BTCRcount(A4) ; only 1 reference ? <27Nov90 #30>
BEQ.S @6 ; yes <27Nov90 #30>
;; If more than reference, then we need to make sure that the <27Nov90 #30>
;; RefNum points to the same file that we are accessing. <27Nov90 #30>
MOVE.W ioRefNum(A0),D0 ; accessing this file <27Nov90 #30>
CMP.W BTCRefNum(A4),D0 ; they better be the same <27Nov90 #30>
BEQ.S @6 ; cool => <27Nov90 #30>
MOVE.W D0,BTCRefNum(A4) ; correct RefNum <27Nov90 #30>
@6 MOVEQ #0,D0 ; no error
BRA.S @isBTRet
@notBt MOVE.W #NotBTree,D0
@IsBtRet RTS
;______________________________________________________________________
; Btree Manager's very own RfnCall
; Version that doesn't set ReqstVol, destroying potential value
; for the FS call in progress
;______________________________________________________________________
BtreeMgrRfNCall:
MOVE.L FCBSPtr,A1 ; get ptr to FCBs
MOVEQ #0,D1 ; clear D1 high word
MOVE.W IORefNum(A0),D1 ; get refnum
MOVEQ #RfNumErr,D0 ; Be pessimistic here...
MOVEQ #0,D2 ; Clear upper half of D2
MOVE.W D1,D2 ; Copy for check
DIVU FSFCBLen,D2 ; Divide by FCB size <03Feb87>
SWAP D2 ; Get remainder in low word
SUBQ.W #2,D2 ; Remainder had better be 2 (length word)
BNE.S @2 ; If not, that's a bad refnum
CMP.W (A1),D1 ; Refnum within range?
BCC.S @2 ; If too high, that's too bad.
MOVEQ #FNOpnErr,D0 ; Is this file actually open?
MOVEA.L FCBVPTR(A1,D1),A2 ; get VCB pointer, too <18Feb91 #36>
MOVE.L FCBFlNm(A1,D1),D2 ; get the file's filenum <18Feb91 #36>
BEQ.S @2 ; Sigh - and we were so close...
MOVEQ #0,D0 ; It's open - complete success!
@2 TST.W D0 ; Set condition codes
RTS
;______________________________________________________________________
; Routine: btRfNCall
; Function: make sure the file is open, if it returns ExtFSErr, then it's OK
; Input: A0=ioParam block (uses refnum), A1 is free
; Output: D0=0 means OK. D1.W=RefNum, D2.L=file number,
; A1.L=ptr(FCB buffer start), A2.L=VCB pointer
;______________________________________________________________________
btRfNCall:
BSR BtreeMgrRfnCall ; don't use ROM routine <06Feb91 #35>
BEQ.S @2 ; no error
CMP #ExtFSErr,D0 ; external FS error?
BEQ.S @NotAProblem ; that's not our problem
cmp.w #volOffLinErr, d0 ; volume off line? <2.9>
bne.s @2 ; if not, then there's a real error <2.9>
@NotAProblem:
MOVEQ #0,D0 ; external FS is OK for us
@2 RTS
;______________________________________________________________________
; Routine: btTstMod
; Function: make sure the file is open, if it returns ExtFSErr, then it's OK
; can't use ROM tstMod because it doesn't work for external FS
; Input: A0=ioParam block (uses refnum), A1 is free
; Output: D0=0 means OK.
; Trash: A1,A2,D1,D2 by jRfnCall
;______________________________________________________________________
btTstMod BSR.S btRfnCall ; file open?
BNE.S tmExit2 ; no
MOVEQ #WrPermErr,D0 ; check if file opened for write
BTST #FCBWrtBit,FCBMdRByt(A1,D1.W)
BEQ.S tmExit ; exit if no write permission
BSR.S CVFlgs ; check if vol locked or wr protected
tmExit TST.W D0 ; return status flags set on error
tmExit2 RTS
;_______________________________________________________________________
; Routine: CVFlgs
; Arguments: A2.L (input) -- VCB pointer
; D0.W (output) -- error code (volume locked, wr prot error)
; Function: Check the volume's flags to see if modify requests are allowed.
;_______________________________________________________________________
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)
ENDPROC
;______________________________________________________________________
; Routine: ExtCopyParam
; Function: Get BT private param in A3 then copy parameters from A0 to A3
; and set A0 = A3.
; Inout: A0 = user Param, A1/A3 are free
; output: A0=A3 = BT private Param, A0 trashed!
;______________________________________________________________________
ExtCopyParam PROC EXPORT
MOVEa.L FSVarsPtr,A1
MOVEA.L fsVars.btMgr(A1),A1
MOVEA.L btVParam(A1),A3 ; A3 = get BTParam
MOVEQ #(btParamLen/4 - 1), D1 ; param length in long - 1
MOVE.L A3,-(SP) ; save A3
;; before copy, we should zero the whole thing !!
@5 CLR.L (A3)+ ; clear the param
DBF D1,@5 ; continue
MOVEA.L (SP)+,A3 ; restore BT param
MOVE ioTrap(A0),ioTrap(A3) ; use async bit
MOVE.L ioFileName(A0),ioFileName(A3) ; copy name
MOVE ioVRefNum(A0),ioVRefNum(A3) ; copy vRefNum
MOVE.L ioDirID(A0),ioDirID(A3) ; copy DirID
MOVEA.L A3,A0 ; A0=A3 is our param now
RTS
ENDPROC
;______________________________________________________________________________
; Routine: ExtckClumpSize
; Function: Force D6 to be multiple of allocation block size so that _SetEOF
; will extend the file and make LEOF = PEOF.
; Inout: D6.L = clump size, A2.L = VCB
; output: D6.L = multiple of allocation block size and >= clump size
;______________________________________________________________________________
ExtckClumpSize PROC EXPORT ; used also by BtreeAlloc.a <18Dec90 #32>
MOVEM.L D3/D4,-(SP) ; save D3, D4 <18Dec90 #32>
MOVE.L VCBAlBlkSiz(A2),D4 ; D4.L = allocation block size <18Dec90 #32>
MOVE.L D4,D3 ; D3.L = D4.L <18Dec90 #32>
@3 CMP.L D4,D6 ; D6 = D4? <18Dec90 #32>
BEQ.S @ret ; yes, nothing to worry <18Dec90 #32>
BMI.S @less ; D6 < D4 <18Dec90 #32>
ADD.L D3,D4 ; D4 = D4+D3 <18Dec90 #32>
BRA.S @3 ; and continue <18Dec90 #32>
@less MOVE.L D4,D6 ; use this size <18Dec90 #32>
@ret MOVEM.L (SP)+,D3/D4 ; restore D3, D4 <18Dec90 #32>
RTS ; and return <18Dec90 #32>
ENDP
;__________________________________________________________________________________
; Routine: ExtBTOpen <SM1>
; Function: patch to BTOpen --> BTCB has been extended, and we need to allocate
; storage for Key descriptor.
; Input: D3.W - file refnum <28Mar90>
; A0.L - pointer to key compare routine
; A1.L - pointer to cache queue
; A4.L - BTParam <SM3>
; A5.L - ioParam <28Mar90>
; Output: D0.W - result code
; 0 = ok
; -n = FS Open error
; BTnoBTCB = no available BTCB
; Other registers preserved.
;
; Modification history:
; 26Jul90 KSCT Check header node should use the file's logical EOF,
; don't use physical EOF.
; 12Jan92 KSCT ROM (and AppleShare's) B*Tree file relies on that PEOF = LEOF.
; to make our file compatible with the old INIT, we set the LEOF=PEOF
; if they are not the same and update the # of nodes in the BTHeader.
; (This happens when you copy a B*Tree file from one disk to another.)
; 02Jun92 KSCT If the file is open read only, then don't try to modify the FCB.
; If we can write to the file, mark the cache buffer dirty too. <#40><SM3>
; 06Jul92 KSCT It's not a good idea to modify the FCB directly because it does
; not work on a FileShare volume. Has to call SetEOF(). <#41><SM3>
;__________________________________________________________________________________
ExtBTOpen PROC EXPORT ; <SM1>
IMPORT ExtGetBlock, ExtRelBlock, MarkDirty, ExtDoAOCRWF ; <SM1><SM3>
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
MOVEM.L D1-D6/A0-A4,-(A6) ; save regs <SM3>
; MOVE.W D0,D3 ; D3 = file refnum <28Mar90>
MOVE.L A0,D4 ; D4 = ptr(key compare routine)
MOVE.L A1,D5 ; D5 = cache queue ptr
MOVE.L A4,D6 ; D6 = BTParam <SM3>
;
; allocate and initialize a BTCB
MOVE.L #lenBTCB70,D0 ; allocate space for BTCB
_NewPtr ,SYS,CLEAR ;
BNE ptBOExit1 ; couldn't get it ->
MOVEA.L A0,A4 ; A4 = BTCB ptr
MOVEA.L FCBSPtr,A3 ; A3 = start of FCB array
MOVE.L A4,FCBBTCBptr(A3,D3.W) ; set BTCB ptr in FCB
MOVE.W D3,BTCRefNum(A4) ; set refnum
MOVE.L D4,BTCKeyCR(A4) ; set ptr(key compare routine)
MOVE.L D5,BTCCQptr(A4) ; set ptr to cache queue
;
; get BTH from disk
MOVE.W D3,D0 ; file refnum
MOVEA.L D5,A1 ; cache queue ptr
MOVEQ #0,D1 ; no GetBlock options (read if not read)
MOVEQ #0,D2 ; BTH is block 0
JSR ExtGetBlock ; get the block <SM1>
BNE ptBOExit1 ; couldn't get it ->
MOVEA.L A0,A2 ; A2 = cache buffer ptr (header)
;
; make sure the BTree header node is ok
BOChkHdr
LEA lenND(A2),A0 ; A0 = ptr to BTH
MOVE.W BTHNodeSize(A0),D0 ; node size
BEQ.S BOBadHdr ; node size = 0, error ->
MOVE.W D0,D1 ;
ANDI.W #$1FF,D1 ;
BNE.S BOBadHdr ; node size not 512 multiple, error ->
MOVE.L fcbEof(A3,D3.W),D2 ; logical length <26Jul90>
DIVU D0,D2 ; logical length / node size <12Jan92 #38>
SWAP D2 ; = # of nodes
CLR.W D2 ;
SWAP D2 ;
CMP.L BTHNNodes(A0),D2 ; same # as in BTH?
BNE.S BOBadHdr ; no, error ->
CMP.L BTHFree(A0),D2 ; free count < # of nodes?
BLO.S BOBadHdr ; no, error ->
SUBQ.L #1,D2 ; D2 = max node #
CMPI.W #ExtBTMaxDepth,BTHDepth(A0) ; tree depth <= max? <11Apr90><SM1>
BHI.S BOBadHdr ; no, error ->
CMP.L BTHRoot(A0),D2 ; root node # <= max?
BLO.S BOBadHdr ; no error ->
CMP.L BTHFNode(A0),D2 ; 1st leaf node # <= max?
BLO.S BOBadHdr ; no error ->
CMP.L BTHLNode(A0),D2 ; last node # <= max?
BHS.S BOCpyBTH ; yes -> all OK
BOBadHdr
;; A bad header, return this is not a B*Tree ...
;; buffer in A0 has marked inuse, clear it. <20Jun90>
LEA -lenND(A0),A0 ; A0 = ptr to buffer <20Jun90>
LEA -lenbtBH(A0),A0 ; A0 = ptr to CBHdr <20Jun90>
BCLR #CBHinuse,btBHFlags(A0) ; set not in-use <20Jun90>
MOVEQ #BTBadHdr,D0 ; result = 'bad header node'
BOBadHdr2 MOVE.W D0,-(A6) ; save result code
MOVEA.L A4,A0
_DisposPtr ; release BTCB
MOVE.W (A6)+,D0 ; restore result code
BRA ptBOExit ; ->
BOCpyBTH
;; The header (A2) looks good, so continue BTOpen (A0 = ptr to BTH) ...
;; We set the LEOF = PEOF if they are not the same... <12Jan92 #39>
MOVE.L FCBPLEN(A3,D3.W),D1 ; D1.L = PEOF <12Jan92 #39>
SUB.L FCBEOF(A3,D3.W),D1 ; LEOF <= PEOF? <12Jan92 #39>
BLS.S @eq ; br if not <12Jan92 #39>
;; If the file is open read only, then skip all the nonsense ! <02Jun92 #40><SM3>
BTST #fcbFlgWBit,fcbFlags(A3,D3.W) ; can we write to it? <02Jun92 #40><SM3>
BEQ.S @eq ; no, so don't update <02Jun92 #40><SM3>
;; PEOF > LEOF, we force them to be equal here ... <12Jan92 #39>
MOVEM.L A0/D1,-(A6) ; free A0/D1 <06Jul92 #41><SM3>
MOVEA.L D6,A0 ; get BTParam <06Jul92 #41><SM3>
MOVE.L FCBEOF(A3,D3.W),D0 ; get current LEOF <06Jul92 #41><SM3>
ADD.L D1,D0 ; update LEOF <06Jul92 #41><SM3>
MOVE.L D0,IOLEOF(A0) ; set new eof <06Jul92 #41><SM3>
MOVEQ #DoSetEOF,D1 ; indicate this is SetEOF <06Jul92 #41><SM3>
BSR ExtDoAOCRWF ; A1 is free <06Jul92 #41><SM3>
MOVEM.L (A6)+,A0/D1 ; restore A0/D1 <06Jul92 #41><SM3>
BNE.S @eq ; no disk space -> <06Jul92 #41><SM3>
;; Update the # of nodes in the BTHeader too. <12Jan92 #39>
MOVE.W BTHNodeSize(A0),D0 ; node size <12Jan92 #39>
DIVU D0,D1 ; (physical length - logical) <12Jan92 #39>
SWAP D1 ; / node size <12Jan92 #39>
CLR.W D1 ; = # of nodes to add <12Jan92 #39>
SWAP D1 ; <12Jan92 #39>
ADD.L D1,BTHNNodes(A0) ; update total nodes <12Jan92 #39>
ADD.L D1,BTHFree(A0) ; update free nodes <12Jan92 #39>
;; So far, we fixed everything except writing to disk. Mark the buffer dirty ...
;; FCB has been marked dirty by SetEOF() call ...
JSR MarkDirty ; mark A2 node dirty too <19May92 #40><SM3>
@eq
;; now copy BTH into BTCB ...
MOVE.W #lenMemBTH70-1,D0 ; loop index
LEA lenND(A2),A0 ; ptr(source)
LEA BTCDepth(A4),A1 ; ptr(dest)
@1 MOVE.B (A0)+,(A1)+ ; move it
DBRA D0,@1 ; ...in
;; The followings are for B*Tree Manager only (extention to BTCB):
;; Type 0 .. 127 and $FF uses fixed length index key,
;; Type $FE uses variable length index key and supports large data record.
;; This version of B*Tree Manager can not access $FE Btree files !! <13Mar90>
MOVE.B bthBTType+lenND(A2),D0 ; D0.B = Btree type <13Mar90>
CMPI.B #validBTType,D0 ; user B*tree? <13Mar90>
BLO.S @archaic ; no, system or AppleShare,or ..<13Mar90>
CMPI.B #userBT1Type,D0 ; user TYPE1? <13Mar90>
BEQ.S @archaic ; yes <13Mar90>
MOVE.W #btVersionErr,D0 ; can't access new type files <13Mar90>
BRA BOBadHdr2 ; exit <13Mar90>
@archaic
MOVE.B D0,btcType(A4) ; set Btree type
;; set clump size, write count and reference count for this BTree file !!
MOVE.L btcClump(A4),D0 ; do we have clump? <10/3/89>
BNE.S @2 ; yes <10/3/89>
;; AppleShare B*Tree file's clumpsize = 0, too bad! <10/3/89>
MOVEA.L FCBVPtr(A3,D3.W),A1 ; A1 = VCB <10/3/89>
MOVE.L VCBClpSiz(A1),D0 ; use volume clump size <10/3/89>
@2 MOVE.L D0,fcbClmpSize(A3,D3) ; (56) <10/3/89>
MOVE.L #WCSigLong,BTCWcount(A4); set write count (60)
MOVE.B #1, BTCRcount(A4) ; set reference count (68)
MOVEQ #0,D0
MOVE.B kdPtr(A2),D0 ; key descriptor length
BNE.S @3 ; has KD <23Feb90>
;; It is an error if there is no KD. <23Feb90>
;; Since we now support user's KCmp routine, we open and fake a key descriptor...
MOVE.W #btNoKDErr,D0 ; preset error code <28Jan91 #34>
TST.L ioBTKCProc(A5) ; does user specify KC proc? <28Jan91 #34>
BEQ.S ptBOExit ; no KD and no KC routine <28Jan91 #34>
BRA.S @9 ; continue ... <28Jan91 #34>
@3 ;; D0.L = key descriptor length
MOVEQ #1,D1 ; next byte is type <28Mar90>
MOVE.B kdPtr(A2,D1),D1 ; key descriptor type <28Mar90>
CMPI.B #kdUseKCProc,D1 ; use private proc? <28Mar90>
BNE.S @4 ; no, use KD <28Mar90>
MOVE.L ioBTKCProc(A5),D1 ; does user specify KC proc? <28Mar90>
BNE.S @4 ; Yes, use theirs <28Mar90>
MOVE #btNoKCProcErr,D0 ; return error <28Mar90>
BRA.S ptBOExit ; no key descriptor <28Mar90>
@4 ADDQ.W #1,D0 ; include length byte
_NewPtr ,SYS,CLEAR
BNE.S BOBadHdr2 ; couldn't get it ->
MOVE.L A0,btcKDPtr(A4) ; store it in BTCB (64)
LEA kdPtr(A2),A1 ; source
MOVEQ #0,D0
MOVE.B kdPtr(A2),D0 ; key descriptor length
@5 MOVE.B (A1)+,(A0)+ ; copy it
DBRA D0,@5 ; ....in
@9
CLR.W D0 ; result = 'ok'
ptBOExit ; release header block and exit
MOVE.W D0,-(A6) ; save result code
MOVEA.L D5,A1 ; cache queue ptr
MOVEQ #0,D1 ; release 'clean'
MOVEA.L A2,A0 ; cache buffer ptr
JSR ExtRelBlock ; <SM1>
BEQ.S @1 ; ok ->
MOVE.W D0,(A6) ; replace previous result code
@1 MOVE.W (A6)+,D0 ; restore result code
ptBOExit1
MOVEM.L (A6)+,D1-D6/A0-A4 ; restore regs <SM3>
MOVE.L (A6)+,-(SP) ; put return address back on stack
TST.W D0 ; set condition codes
RTS ; exit BTOpen
ENDPROC
END