2370 lines
94 KiB
Plaintext
2370 lines
94 KiB
Plaintext
;
|
||
; 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)
|
||
;
|
||
|
||
;
|
||
; 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>
|
||
|
||
GtNxtMatch jsrROM ROMGTNXTFCB ; go to next FCB <03Feb87><SM1><Sys7.1> De-inlined and put back "ROM"
|
||
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>
|
||
@NxtMatch jsrROM ROMGTNXTFCB ; go to next FCB <SM1><Sys7.1> De-inlined and put back "ROM"
|
||
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
|
||
BRA.S GetExit ; invalid marker <SM2> CSS <Sys7.1>
|
||
@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
|
||
jsrROM ROMGT1STFCB ; A1=FCB ptrm, D1=FCB index <SM1><Sys7.1> De-inlined and put back "ROM"
|
||
|
||
; First close all the open files belong to this process:
|
||
; A1=FCBptr, A2=Ext. FCBptr, D1.W=RefNum, D2=id2, D3.W=loop index, D4.W=ext FCBlen,
|
||
; D5.W=original FCBlen, D6=id1
|
||
@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
|