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

3249 lines
123 KiB
Plaintext
Raw Normal View History

2020-03-22 08:44:21 +00:00
;
; Hacks to match MacOS (most recent first):
;
; <Sys7.1> 8/3/92 Reverted <SM1> by putting back the "ROM" prefixes and removing the
; copied-in routines. Reverted the branch changes in <SM2> and <SM3>.
; Reverted <SM4> by changing pascalRegs back to interruptRegs (i.e. not
; saving a2/a3/d3).
; 9/2/94 SuperMario ROM source dump (header preserved below)
;
2019-07-27 14:37:48 +00:00
;
; File: DTDBMgr.a
;
; Contains: Desktop Database manager routines
;
; Written by: Patrick W. Dirks, July 6 1986.
; Rewritten by: David Feldman, April 7, 1989.
;
; Copyright: © 1986-1993 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM4> 6/9/93 pdw Changed register saving from interruptRegs to pascalRegs in
; completionRoutine because it is supposed to be using this
; convention.
; <SM3> 10/27/92 CSS Changed some word bsrs to bigjsrs.
; <SM2> 10/27/92 CSS Changed short branch to word branch.
; <SM1> 4/1/92 kc Copied the routines DesktopCloseDownProc, CheckDesktopSupport and DTDBMgrInit
; from FileMgrPatches.a. Removed the "ROM" prefix from the RomBind routines.
; • Pre-SuperMario comments follow •
; <32> 9/13/91 JSM Cleanup header.
; <31> 5/23/91 dba MPW 3.2 assembler no longer supports local labels for records
; <30> 3/28/91 dnf ewa, #SetFileAttribsIsntAsyncSafe: The SetFileAttribs subroutine
; doesn't save its return address on the a6 stack, causing crashes
; when doing async I/O.
; <29> 3/20/91 dnf sad, #DTGetInfoConsumesGranite: Fix DTGetInfo so that the
; AddFileSizes routine that it calls actually works. It is good to
; know that someone is now actually using this call.
; <28> 3/19/91 dnf dba, #dnf: Dont clobber Z bit when restoring return addresses
; from the a6 stack.
; <27> 3/17/91 dnf ppd, #dnf-0013: Use the result code from ioResult(a0) instead of
; from d0 to be extra-clean on async calls.
; <26> 3/17/91 dnf dba, dty, #84670, #82944: Change more routines to make them work
; in an asynchronous world. The desktop manager now does all of
; its I/O synchronously (except for _FindFolder, a gaping time
; bomb)
; <25> 2/12/91 dnf gbm, #81716: Move the call to DTCloseDown from the Process
; Manager's notification hook to a patch to _Unmount (in
; FileMgrPatches.a) so that it will come after we know that
; nobody on the hook has rejected the unmount. Also put in tweak
; for brc #81858 (replace #fnfErr with #afpItemNotFound)
; <24> 1/22/91 dnf (ppd, tgh) Force DTOpenInform, DTGetPath and DTCloseDown to be
; synchronous. Dont use MakePBLookAsync anymore.
; <23> 1/17/91 dnf (pwd) Make sure that FindDTFiles has the volume info before it
; tries to decide if the volume is locked or not.
; <22> 12/21/90 dnf (dfh) Move substitution of volume name + shadow for the standard
; name until after we're sure we're not going to create files with
; the standard name. Restore the pb ptr after enqueue the
; DTDBQElt.
; <21> 12/18/90 dnf (dba) Save a hint for each desktop database b-tree file in the
; DTDBQElt, and pass it to all BTree Manager calls. Looks for and
; creates shadow desktop folders in the preferences folder. Also
; rewrote FindDTFiles to be simpler and smaller. Did _Allocate of
; clump size in RealOpenDT and in ResetDT to minimize
; fragmentation. Used HGetFileInfo/HSetFileInfo instead of
; Get/SetCatInfo to be more specific about files vs. directories.
; FlushVol instead of FlushFile.
; <20> 12/16/90 dnf (dba) Fix OpenDTInform bug by getting RealDTOpen to return a
; valid result. Get rid of code that was never executed that made
; a lame attempt to update the key descriptor.
; <19> 12/5/90 dnf (with dba) Have RemoveAPPL look at AppSpec.parID instead of
; ioDirID from the DTParamBlock. Have AddAPPL do this too.
; <18> 12/5/90 dnf (with dba) Fixed three places where we didnt move the return
; address to the a6 stack before calling potentially async
; routines. Expand the size of a volume name storage to 32 bytes,
; since it is really the root directory name, and is not
; necessarily 28 bytes or smaller. Started work on Preferences
; folder support, but it is still IFd out for this check-in.
; <17> 9/25/90 dnf (dnf/pwd) Set up FSVars.dtOwnCall to point to each parameter
; block used by the desktop manager so that FileShare can allow
; these calls to pass unmolested.
; <16> 9/22/90 dnf (dnf/pwd) Remove include of QMgr.a; it's now a separate file.
; Dispatch desktop calls to external file systems by transferring
; them to the file system queue and returning an #extFSErr.
; <15> 8/6/90 dnf Make DTAddIcon canonify files before putting them into the
; database. Have DTGetInfo return the volume containing the files
; in ioVRefNum. Revert to using local key compare routine instead
; of a (special) key descriptor.
; <14> 7/30/90 dnf Change all bsr and jsr instructions that point at Rom bind
; symbols into jsrRom macros.
; <13> 6/2/90 gbm Fix Daves eensy weensy little mistake of CHECKING IN x xxxx xx
; xxxxx xxxxxxxxx!!!! (Appropriate slime deleted anyway. <dnf 15>)
; <12> 6/2/90 dnf Make DTDeleteAPPL move the next-newest app to the front of the
; list
; <11> 5/15/90 dnf Make sure that StandardLocals always returns an even-sized
; locals block
; <10> 4/24/90 dnf Fix signed compare bug in GetComment
; <9> 4/22/90 dnf Fix reopening of shadow databases
; <8> 4/20/90 dnf Add creator type check to RemoveAPPL
; <7> 4/13/90 dnf Fix AddAPPL swap case.
; <6> 4/10/90 dnf Clip GetComment ioActCounts. Look in server folder for
; databases. Change routine names to match public call titles
; Rework APPL algorithms to improve speed.
; <5> 2/9/90 DNF Set up a4 on entry to DTSetUp in DTClose; Set ioReqCount with a
; long in RmvAPPL
; <4> 2/8/90 dnf Change FindDTVol to save regs on a7
; <3> 2/4/90 DNF Add shadow support, implement xOpenDT
; <2> 1/9/90 DNF Add xOpenDT call
; <2.0> 12/8/89 dnf Added dangling DTDBQElt check on OpenDT
; <1.9> 11/17/89 dnf Volume notification for both Offline and Unmount. OpenDT checks
; GetVolParms
; <1.8> 11/10/89 dnf Save all async-trashable regs at I/O bottleneck
; <1.7> 11/8/89 dnf Clear filler byte on IconKeys, set length correctly, add Unmount
; notification
; <1.6> 10/17/89 dnf Fix data rec allocation on APPL calls
; <1.5> 10/11/89 dnf Async bottleneck for I/O, FindDTVol, file refs for DTRefNum,
; <1.4> 9/18/89 dnf Fix bug in GetAPPL, map btRecNotFnd to afpItemNotFnd, new
; dispatcher
; <1.3> 9/1/89 dnf Get proper pointer in a1 for DTClose's call to _Dequeue, test
; the result
; <1.2> 8/7/89 dnf Change IconRec to IconDRec to avoid collisions with QD equates
; <1.1> 7/6/89 dnf Complete alpha code, start of testing
; <1.0> 5/30/89 dnf Integrate CatSearch, FileID's and Desktop Database Mgr into one
; ptch
; 4/7/89 DNF Rewritten to use newly exported Btree manager calls, new DT data
; structures, new DT dispatching, and new external file system
; handling. This rewrite uses almost all of the existing logic for
; the service routines.
; 5/23/88 PWD Changed AddAPPL to use DTContd flag logic for complete cycle
; (FindRecord as well as subsequent GetRecords); the entire
; AddAPPL now unfolds into a true loop instead of burrowing its
; way down the stack with successive serial number retries.
; 5/3/88 PWD Added code to set up DTORefNum and DTVRefNum at open time; fixed
; MapCSpec to use new DTORefNum to do _GetCatInfo, fixing a bug
; where comment calls on CD ROM volumes would try the mapping with
; the wrong VRefNum.
; 4/25/88 PWD Changed all interrupt-lockout code to use $0600 instead of $0300
; or HiIntMask.
; 3/1/88 PWD Changed to free reserved space at first DTOpen call made.
; 10/23/87 PWD Fixed AddIcon to rewrite B*-Tree entry with new TagInfo if an
; icon is overwritten with a new icon image.
; 10/8/87 PWD Changed to use common routine (FindDT) to check whether DB
; exists in DTOpen and GtMetaInfo. For CD-ROM volumes, only
; indicate DB support if the Desktop DB file already exists.
; 9/16/87 PWD Changed to set Type & Creator on Desktop datafile.
; 8/13/87 PWD Changed to use shadow-Desktop in System Folder of BootDrive if
; volume is locked and no Desktop DB exists.
; 7/27/87 CRZ Changed some branches to short branches and vice versa.
; 6/26/87 PWD Changed version number from 1 to 2 to indicate DTClose bug
; fixed, FSQueueHook support in.
; 6/17/87 PWD Fixed bug in DTClose where it RTS-ed instead of branching to
; DTDone when DTSetup returned VolOfflinErr. Changed to use AFP
; error message names. Added code to invoke FSQueueHook on all
; calls.
; 1/6/87 PWD Changed DTFlags to DTFFlags to avoid conflict with Deferred Task
; Manager equate
; 1/2/87 PWD Changed to retry call if Server Folder ID is set in Finder info
; but no such folder is found.
; 12/8/86 PWD Changed to skip completion routines called synchronously to save
; stack space.
; 12/1/86 PWD Changed to clump out data file by explicit _Allocate calls
; before an icon is written out instead of modifying FCBClpSize.
; 11/20/86 PWD Changed to clear hint before re-inserting entry after BTDelete
; in InsEntry. Changed key comparison to ignore length of trial
; key (padded out in index nodes). Changed all routines to pass
; full-length keys (Getxxx would get fouled up by passing
; partial-length keys to new key comparison routine.
; 11/17/86 PWD Fixed GetMetaInfo call to return right bit for DT support
; Changed to check refNum in detail only for local operation
; 11/13/86 PWD Fixed dispatch logic to properly preserve A1 after DTDone
; 11/12/86 PWD Fixed async return code. Always RTS after async I/O initiation
; Incorporated various small modifications per Rich's suggestions
; Changed to use GetTrapAddress/SetTrapAddress on install and
; remove.
; 11/2/86 PWD Changed to support only drives 3 and up to prevent the
; proliferation of Desktop databases on diskettes. Changed DTOpen
; to set invisible and system (name lock) bits on both files.
; Changed AddAPPL to stop re-writing B*-Tree records if a
; duplicate entry is requested with the same tag. Added DTReset
; and DTStatus calls. Changed GetIcon and GtIcnInfo to return icon
; position in ioPosOffset. Changed GetIcon to take a hint when
; given. Changed serial number assignment algorithm in AddAPPL to
; return last entries added first.
; 10/28/86 PWD Fixed GetIcon to handle _Read errors correctly.
; 10/23/86 PWD Converted for use under MPW.
; 10/15/86 PWD Changed GetIcon to stop using ioIconDefault field. Changed to
; return new meta-info indicating new DT support present.
; 10/13/86 PWD Added code to set up ReqstVol on ExtFSErr returns.
; 10/12/86 PWD Fixed similar bugs in AddAPPL and RmvAPPL which caused name
; comparisons between the B*-Tree record and PB Record to fail.
; Fixed bug in RfnChk (failed to set condition codes on exit).
; Added code to force clump size for Desktop Datafile.
; 10/10/86 PWD Fixed to check for offline volumes before starting any
; operation. Fixed bug which clobbered lo-mem due to bogus
; ioOwnBuf on _HOpen. Added code to do a BTFlush.
; 10/6/86 PWD Fixed to locate target VCB correctly under all circumstances
; Changed DTGetAPPL to special case index=0; treat like index=1
; Fixed calls to MapCSpec to handle errors correctly.
; 10/4/86 PWD Fixed to properly set up ioTrap field on all calls.
; 10/2/86 PWD Fixed bug in DTOpen: don't use user's PB for _HOpen call.
; Changed to repond to GetVolMetaInfo calls to indicate new
; desktop support.
; 9/24/86 PWD Changed to use new key structure
; 8/21/86 PWD Changed to remove patch installation code and local storage
; 8/5/86 PWD Added code to convert internal B*-Tree error codes to AFP
; errors, and filter out other positive error returns
; 7/17/86 PWD Separated out from DTMgr to allow DTSvcs to be included in patch
; code (where it's in blank seg) and FSCP, where it sits with the
; B*-Tree manager in the BTMgr segment.
;
print push
print off
LOAD 'StandardEqu.d'
INCLUDE 'BTreeEqu.a'
INCLUDE 'DTDBMgrEqu.a'
INCLUDE 'DTDBMgrPriv.a'
include 'LinkedPatchMacros.a'
include 'QMgrEqu.a'
include 'FileMgrPrivate.a'
include 'MFPrivate.a'
include 'HardwarePrivateEqu.a'
include 'Folders.a'
include 'InternalOnlyEqu.a' ; <SM3> CSS
print pop
BLANKS ON
STRING ASIS
entry DequeueDTDBQElt
entry deepShitError
import GetQMRecPtr
macro
MakeLocals
endm
; All of the routines in the desktop manager that have a parameter block as one of their
; locals have one of size DTBigPBSize, and it is always the first local on a6.
; All of the service routines of the DTMgr use a very similar local variable layout
; The only difference among the routines is the size of the Data block they need.
; This macro takes a label name (for the locals record) and a size for the data block
; in that record.
macro
StandardLocals &name, &datalen
&name record 0, increment
bigPB ds.b DTBigPBSize ; big enough for any call made from the DT routines
Key ds.b DTMaxKeySize ; enough space to form any DT key
align 2 ; max key length could be odd
Data ds.b &datalen ; enough space for a data record of requested length
align 2 ; data size could be odd
LSize equ *-bigPB
endr
endm
; The key descriptor we use for our BTrees simply tells the btree manager that we'll
; always be using our own key descriptor routine.
DTKeyDescriptor: proc
dc.b 2 ; length of descriptor
dc.b kdUseKCProc ; we'll always be using a compare proc
dc.b 1 ; just one of them
align 2 ; line things up
endproc
; so desktop symbols start from here
proc
_DTDebugRts 'DTDBQueueManager', 0
endproc
2020-03-22 08:44:21 +00:00
; ex<SM1><Sys7.1> Removed DesktopCloseDownProc, DTDBMgrInit and CheckDesktopSupport
2019-07-27 14:37:48 +00:00
;________________________________________________________________________________
;
; Routine: BottleNeckIO
;
; Input: a0 points to dt's ioParam or BTioParam
; Output: d0 contains result code
; a1 trash
;
; Function: Make traps which do I/O and do the right thing with completion
; routines.
;________________________________________________________________________________
;
BottleNeckRegs reg d1-d7/a1-a5 ; async could trash any regs
BottleNeckLocals record 0, increment
hasContinued ds.b 1 ; flag byte to watch stack depth
align 2
Lsize equ *-BottleNeckLocals
endr
BottleNeckIO proc export
movem.l BottleNeckRegs, -(a6) ; save our regs on hfs stack
with BottleNeckLocals
subq.w #Lsize, a6
bclr.b #0, hasContinued(a6) ; initialize completion routine flag
lea.l completionRoutine, a1 ; get our ioCompletion routine address
move.l a1, ioCompletion(a0) ; and install it into the param block
movea.l FSVarsPtr, a1 ; <17>
move.l a0, FSVars.dtOwnCall(a1); leave a bread crumb for FileShare <17>
moveq.l #desktopQType, d2 ; our queue type/refnum
2020-03-22 08:44:21 +00:00
bsr GetQMRecPtr ; ex<SM3><Sys7.1>
2019-07-27 14:37:48 +00:00
move.l a6, QMRec.curStack(a1) ; save current alt stack pointer
; •• do high water mark checking here
btst.b #asyncCall, QMRec.qmFlags(a1) ; is this call async?
rts ; return to specific trap handling routine
_DTDebugTail 'TheBottleNeck', 0
; Some drivers have the nasty habit of calling their completion routines before returning
; from the trap that called them. This might lead to unbounded stack buildup from
; successive calls. To solve this we have a bit (in hasContinued) which is set both
; in the completion routine and after the trap.
; Case 1: The completion routine is called before we return from the trap. In this case
; we just cruise back to the driver, since we'll get control again when the driver
; rts's from our trap. When that happens we can just continue our call.
; Case 2: We get returned to before the completion routine is run (truly asynchronous).
; We rts to the app (giving back the async time) and we know we'll get control again
; at the completion routine. When we continue from here we need to save the
; appropriate interrupt registers.
; This little scheme is, of course, a critical section, but we're single threaded right now,
; so it doesn't matter.
completionRoutine:
moveq.l #desktopQType, d2 ; our queue type/refnum
2020-03-22 08:44:21 +00:00
bsr GetQMRecPtr ; ex<SM3><Sys7.1>
2019-07-27 14:37:48 +00:00
move.l a6, -(sp) ; save a6 for a sec
movea.l QMRec.curStack(a1), a6 ; get our a6 back
bset.b #0, hasContinued(a6) ; mark that we've been back
movea.l (sp)+, a6 ; restore a6
beq.s anRTSInstruction ; if we haven't returned from the trap, rts to driver
2020-03-22 08:44:21 +00:00
movem.l interruptRegs, -(sp) ; save all regs that pascal callers need saved <SM4>pdw<Sys7.1>
pea restoreInterruptRegs ; and get in the chain to restore them later <Sys7.1>
2019-07-27 14:37:48 +00:00
contDeskThread:
moveq.l #desktopQType, d2 ; our queue type/refnum
2020-03-22 08:44:21 +00:00
bsr GetQMRecPtr ; ex<SM3><Sys7.1>
2019-07-27 14:37:48 +00:00
movea.l QMRec.curStack(a1), a6 ; restore alt stack pointer
adda.w #Lsize, a6 ; clear off the locals
movem.l (a6)+, BottleNeckRegs ; restore desktop thread registers
move.l (a6)+, -(sp) ; push desktop thread return address
move.w ioResult(a0),d0 ; get the real error code and set ccr's <27>
anRTSInstruction:
rts ; and return to caller
contAppThread:
bset.b #0, hasContinued(a6) ; mark that we've returned
bne.s contDeskThread ; if we already ran the completion routine, then
; continue without saving registers
rts ; return async time to application
2020-03-22 08:44:21 +00:00
restoreInterruptRegs: ; <SM4>pdw<Sys7.1>
movem.l (sp)+, interruptRegs ; restore the regs that we saved last time through <Sys7.1>
2019-07-27 14:37:48 +00:00
rts ; back to the app thread
_DTDebugTail 'Completion',0
; Macro for generating code that executes a synchronous or asynchronous trap
; based on the value of the zero flag. Zero set = async, zero clear = sync.
macro
&sym: doSomeTrap &theTrap
entry &sym
&sym:
move.l (sp)+, -(a6) ; save desktop thread ret addr on a6
bsr.s BottleNeckIO ; do common set up
bne.s @async ; branch if Z = 0 (async call)
_&theTrap ; sync trap
bra contDeskThread ; keep going with this desktop call
@async: _&theTrap async ; async trap
bra contAppThread ; keep going, but give async time to app
_DTDebugRts 'do&theTrap',0
endm
; Macro for generating code that executes a synchronous or asynchronous hfsdispatch
; based on the value of the zero flag. Zero set = async, zero clear = sync.
macro
&sym: doSomeA060Trap &theTrap, &theDispatch
entry &sym
&sym:
move.l (sp)+, -(a6) ; save desktop thread ret addr on a6
bsr.s BottleNeckIO ; do common set up
bne.s @async ; branch if Z = 0 (async call)
moveq.l #&theDispatch, d0 ; tell'em which HFS dispatch to do
_HFSDispatch ; sync trap
bra contDeskThread ; keep going with this desktop call
@async: moveq.l #&theDispatch, d0 ; tell'em which HFS dispatch to do
_HFSDispatch async ; async trap
bra contAppThread ; keep going, but give async time to app
_DTDebugRts 'do&theTrap',0
endm
; Macro for generating code that executes a synchronous or asynchronous hfsdispatch
; based on the value of the zero flag. Zero set = async, zero clear = sync.
macro
&sym: doSomeA08ETrap &theTrap, &theDispatch
entry &sym
&sym:
move.l (sp)+, -(a6) ; save desktop thread ret addr on a6
bsr.s BottleNeckIO ; do common set up
bne.s @async ; branch if Z = 0 (async call)
moveq.l #&theDispatch, d0 ; tell'em which HFS dispatch to do
dc.w $A08E ; sync trap
bra contDeskThread ; keep going with this desktop call
@async: moveq.l #&theDispatch, d0 ; tell'em which HFS dispatch to do
dc.w $A48E ; async trap
bra contAppThread ; keep going, but give async time to app
_DTDebugRts 'do&theTrap',0
endm
doHOpen: doSomeTrap HOpen
doHDelete: doSomeTrap HDelete
doClose: doSomeTrap Close
doRead doSomeTrap Read
doWrite: doSomeTrap Write
doGetCatInfo: doSomeA060Trap GetCatInfo, selectGetCatInfo
doHGetVInfo: doSomeTrap HGetVInfo
doHGetFileInfo: doSomeTrap HGetFileInfo
doHSetFileInfo: doSomeTrap HSetFileInfo
doHCreate: doSomeTrap HCreate
doAllocate: doSomeTrap Allocate
doSetEOF: doSomeTrap SetEOF
doGetEOF: doSomeTrap GetEOF
doGetFCBInfo: doSomeA060Trap GetFCBInfo, selectGetFCBInfo
doFlushVol: doSomeTrap FlushVol
doMakeFSSpec: doSomeA060Trap MakeFSSpec, selectMakeFSSpec
doGetVolParms: doSomeA060Trap GetVolParms, selectGetVolParms
doBTSearch: doSomeA08ETrap BTSearch, 6
doBTGetRec: doSomeA08ETrap BTGetRec, 7
doBTSetRec: doSomeA08ETrap BTSetRec, 4
doBTReplRec: doSomeA08ETrap BTReplRec, 5
doBTDelRec: doSomeA08ETrap BTDelRec, 8
doBTFlush: doSomeA08ETrap BTFlush, 10
endproc
;
; A little wrapper for Begin/EndSystemMode to save regs including CCR
;
myBeginSystemMode: proc
myBeginSystemModeRegs reg d0-d2/a0/a1
move.w sr,-(sp)
movem.l myBeginSystemModeRegs, -(sp) ; pascal call trashes these
suba.w #2, sp ; space for output
_BeginSystemMode
adda.w #2, sp ; ignore the error
movem.l (sp)+, myBeginSystemModeRegs
rtr
_DTDebugTail 'myBeginSystemMode',0
endproc
myEndSystemMode: proc
myEndSystemModeRegs reg a0/a1/d0-d2
move.w sr,-(sp)
movem.l myEndSystemModeRegs, -(sp) ; pascal call trashes these
suba.w #2, sp ; space for output
_EndSystemMode
adda.w #2, sp ; ignore the error
movem.l (sp)+, myEndSystemModeRegs
rtr
_DTDebugTail 'myEndSystemMode',0
endproc
;________________________________________________________________________________
;
; Routine: DeskMgrQueue
;
; input: user's DTparam in a0
; output: a1 - trashed
;
; Function: We're always called here while on the file system queue (upon which we
; checked for calls to external file systems). We first extricate ourselves
; from the file system queue and then enqueue ourselves on the desktop manager
; queue, setting up our own alternate (a6) stack and leaving all set to
; process the call.
;
; Note that we jump to QMEnqueue so that we leave only one level of
; return address on top of the stack.
;________________________________________________________________________________
;
entry DTDone
DeskMgrQueue: proc
import UnMungeTrapWord, MakePBLookAsync, GetOffFSQueue
import QMEnqueue
jsr GetOffFSQueue ; Get a0 (now FSQHead) off FSQueue
moveq.l #desktopQType, d2 ; the dtqueue refnum
; bsr MakePBLookAsync ; adjust for the fact that we could be async now
jsr UnMungeTrapWord ; leave true trap word and dispatch in d1/d0
jmp QMEnqueue ; get queued up, dispatched to. CmdDone addr on a6 stack
_DTDebugRts 'DeskMgrQueue',0
endp
DTDone: proc
import UnMungeTrapWord, FSQUEUE , CMDDONE
move.l (a6)+, a1 ; get completion address from a6 stack
; error mapping - the original implementation of the desktop manager returned afp error
; codes, so we need to continue to do so.
@MapErrors:
cmp.w #btRecNotFnd, d0 ; did we get a btRecNotFnd error? <dnf 1.4>
bne.s @notBtRecNotFnd ; no - go check the next error
move.w #afpItemNotFound, d0 ; yes - then replace it with the right afp error<dnf 1.4>
bra.s @justLeave
@notBtRecNotFnd:
cmp.w #btEofErr, d0 ; did we get run into the end of the btree file?
bne.s @notBtEofErr ; no - go check the next error
move.w #afpItemNotFound, d0 ; yes - tell'em about it in afp style
bra.s @justLeave
@notBtEofErr:
cmp.w #fnfErr, d0 ; #fnfErr is an HFS error code <25>
bne.s @notFnfErr ; no - go check the next thing <25>
move.w #afpItemNotFound, d0 ; be true to our afp roots <25>
@notFnfErr:
@justLeave:
jmp (a1)
_DTDebugRts 'DTDone', 4
endp
;________________________________________________________________________________
;
; Routine: DTVolExtFSCheck
;
; Function: Check whether this desktop call should be routed to an external
; file system. We're always called here already on the file system
; queue. That gives us the right to peek around lomem looking for
; our volume. If the call turns out to be for an external file system
; we strip one return address (the one back to the DTMgr routine which
; called us), set ReqstVol and return an #extFSErr to CMDDONE , which
; dutifully dispatches it down the toExtFS chain.
;
; If the call turns out to be local, we rts to the DTMgr routine which
; called us. The DTMgr routine will then call DTMgrQueue, which knows
; the the param block it is attempting to enqueue on the desktop manager
; queue needs to be removed from the file system queue first.
;
; Inputs: a0 - caller's desktop manager param block
;
;________________________________________________________________________________
DTVolExtFSCheck: proc
2020-03-22 08:44:21 +00:00
jsrROM ROMDTRMV3 ; Excuse me, Mr. FS, please find us a volume ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bne.s @LocalErr ; early trouble is a sign to leave
tst.w vcbFSID(a2) ; is this a local volume?
beq.s @LocalVolume
move.l a2, ReqstVol ; inform external file systems of our volume choice
move.b ioTrap+1(a0), d0 ; grab our dispatch selector
cmp.b #selectDTGetPath, d0 ; was it DTGetPath?
beq.s @GrabAnFCB ; externals expect an FCB on a DTOpen
cmp.b #selectDTOpenInform, d0 ; was it DTOpenInform?
bne.s @ExternalExit ; if not, just let'em have the call
@GrabAnFCB:
2020-03-22 08:44:21 +00:00
jsrROM ROMGT1STFCB ; get (A1,D1) pointing to first FCB ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
@1 tst.l FCBFlNm(a1,d1) ; FCB unused?
beq.s @GotFCB ; br if so
2020-03-22 08:44:21 +00:00
jsrROM ROMGTNXTFCB ; get next one until we run out ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bcs.s @1
moveq.l #TMFOErr,d0 ; too many files open
clr.w IORefNum(a0) ; make refnum invalid
bra.s @LocalErr ; don't bother to pass this one along
@GotFCB:
add.l a1,d1 ; Point to the FCB
@ExternalExit:
moveq.l #extFSErr, d0 ; tell'em we can't handle it
@LocalErr:
tst.l (sp)+ ; discard the return address to DTMgr caller
2020-03-22 08:44:21 +00:00
jmpROM ROMCMDDONE ; leave through the file system ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
@LocalVolume:
move.l FSVarsPtr, a3 ; a3 = ptr(file system global area)
move.l FSVars.DTDBMgr(a3), a3 ; a3 = ptr(DTDB manager's global area)
move.w vcbVRefNum(a2), DTGlobals.targetVRef(a3) ; save our volume for later
rts ; this call is for us
endproc
;________________________________________________________________________________
;
; Routine: DTRfnExtFSCheck
;
; Function: Check whether this desktop call should be routed to an external
; file system. We're always called here already on the file system
; queue. That gives us the right to peek around lomem looking for
; our volume. If the call turns out to be for an external file system
; we strip one return address (the one back to the DTMgr routine which
; called us), set ReqstVol and return an #extFSErr to CMDDONE , which
; dutifully dispatches it down the toExtFS chain.
;
; If the call turns out to be local, we rts to the DTMgr routine which
; called us. The DTMgr routine will then call DTMgrQueue, which knows
; the the param block it is attempting to enqueue on the desktop manager
; queue needs to be removed from the file system queue first.
;
; Inputs: a0 - caller's desktop manager param block
;
;________________________________________________________________________________
DTRfnExtFSCheck: proc
import RefNumCheck
move.w ioRefNum(a0), d0 ; get the refnum in question
move.w d0, d1 ; save a copy for later
jsr RefNumCheck ; see if we like this refnum
bne.s @LocalErr ; early trouble is a sign to leave
movea.l FCBSPtr, a1 ; point to the FCBs
movea.l fcbVPtr(a1, d1.w), a2 ; get the VCB in question
tst.w vcbFSID(a2) ; is this a local volume?
beq.s @LocalVolume
move.l a2, ReqstVol ; inform external file systems of our volume choice
moveq.l #extFSErr, d0 ; tell'em we can't handle it
@LocalErr:
tst.l (sp)+ ; discard the return address to DTMgr caller
2020-03-22 08:44:21 +00:00
jmpROM ROMCMDDONE ; leave through the file system ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
@LocalVolume:
rts ; this call is for us
endproc
;________________________________________________________________________________
; <21>
; Routine: SaveHintInDTDBQElt param block -> dtqelt
;
; Function: Gets the btree hint out of the current param block and
; stores it in the globabls for the database that the
; current call is running on.
;
; Inputs: a0 - btioParam block
; a3 - pointer to current DTDBQElt
;
; Outputs: a0 - pointer to BTParam
; a3 - pointer to current DTDBQElt
; also preserves CCR
;
;________________________________________________________________________________
SaveHintInDTDBQElt proc
Registers reg a1/a2
movem.l Registers,-(sp)
lea.l DTDBQElt.lastHint(a3), a1 ; a1 = ptr(recent bt hint in DTDBQElt)
lea.l ioBTHint(a0), a2 ; a2 = ptr(bt hint in param block)
move.l (a2)+,(a1)+ ; a hint is 16 bytes
move.l (a2)+,(a1)+
move.l (a2)+,(a1)+
move.l (a2)+,(a1)+
movem.l (sp)+,Registers
rts
endproc
;________________________________________________________________________________
; <21>
; Routine: GetHintFromDTDBQElt dtqelt -> param block
;
; Function: Gets the btree hint out of the the globabls for the database
; that the current call is running on and stores it into the
; btioParam on a0.
;
; Inputs: a0 - btioParam block
; a3 - pointer to current DTDBQElt
;
; Outputs: a0 - pointer to BTParam
; a3 - pointer to current DTDBQElt
;
;________________________________________________________________________________
GetHintFromDTDBQElt proc
Registers reg a1/a2
movem.l Registers,-(sp)
lea.l DTDBQElt.lastHint(a3),a1 ; a1 = ptr(recent bt hint in DTDBQElt)
lea.l ioBTHint(a0),a2 ; a2 = ptr(bt hint in param block)
move.l (a1)+,(a2)+ ; a hint is 16 bytes
move.l (a1)+,(a2)+
move.l (a1)+,(a2)+
move.l (a1)+,(a2)+
movem.l (sp)+,Registers
rts
endproc
;________________________________________________________________________________
;
; Routine: SetUpBTPB
;
; Function: Gets a param block on a0, and then fills in BTRefNum, key and data pointers
; based on the standard locals layout.
;
; Inputs: a3 - pointer to current DTDBQElt
; a6 - pointer to executing routine's locals
;
; Outputs: a0 - pointer to BTParam
; a2 - pointer to space to build the BTree key
; a3 - pointer to current DTDBQElt
;
;________________________________________________________________________________
SetUpBTPB: proc
StandardLocals BTDummy, 2 ; just to get key and data offsets
with BTDummy ; Key and Data refer to locals
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
bsr GetHintFromDTDBQElt ; get the hint <21>
move.w DTDBQElt.DBRefNum(a3), ioRefNum(a0) ; use the btree refnum
lea.l Data(a6), a2 ; standard location of BTree record data buffer
move.l a2, ioBuffer(a0) ; tell the param block about it
lea.l Key(a6), a2 ; a2 = ptr(place to build key)
move.l a2, ioBTKeyPtr(a0) ; tell the param block about it
rts
endwith
_DTDebugTail 'SetUpBTPB',0
endproc
;________________________________________________________________________________
; <21>
; Routine: DoneBTPB
;
; Function: Gets the btree hint out of the current param block and
; stores it in the globabls for the database that the
; current call is running on.
;
; Inputs: a3 - pointer to current DTDBQElt
; a6 - pointer to executing routine's locals
; also preserves CCR
;________________________________________________________________________________
DoneBTPB proc
StandardLocals BTDummy, 2 ; just to get key and data offsets
with BTDummy ; Key and Data refer to locals
move.w sr,-(sp) ; save CCR
move.l a0,-(sp)
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
bsr SaveHintInDTDBQElt
move.l (sp)+,a0
rtr ; restore CCR
endwith
_DTDebugTail 'DoneBTPB',0
endproc
;________________________________________________________________________________
;
; Routine: SetUpDFPB
;
; Function: Gets a param block on a0, and then fills in DFRefNum
;
; Inputs: a3 - pointer to current DTDBQElt
; a6 - pointer to current StandardLocals
;
; Outputs: a0 - pointer to param block
;
;________________________________________________________________________________
SetUpDFPB: proc
StandardLocals DFDummy, 0 ; just to get offsets
with DFDummy
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.w DTDBQElt.DFRefNum(a3), ioRefNum(a0) ; use icon data file refNum
rts
_DTDebugTail 'SetUpDFPB',0
endwith
endproc
;________________________________________________________________________________
;
; Routine: FindDTVol
;
; Function: See if a desktop database is open for a given VRefNum
;
; Inputs: d0 = user's VRefNum
;
; Output: d0 = noErr or rfNumErr
; a3 = Pointer to DTDBQElt block for selected database
;
; All other registers preserved.
; Note that the DesktopCloseDownProc in FileMgrPatches.a calls this routine.
;________________________________________________________________________________
;
FindDTVol: proc export ; <25> added the export
move.l d1, -(sp) ; save d1 around call
move.l FSVarsPtr, a3 ; a3 = ptr(file system global area)
move.l FSVars.DTDBMgr(a3), a3 ; a3 = ptr(DTDB manager's global area)
move.l DTGlobals.qHead(a3), a3 ; a3 = ptr(1st open database)
bra.s @nextPtr ; check for nil (no open databases)
@WalkQueue:
cmp.w DTDBQElt.XVRefNum(a3), d0 ; is this the right volume?
beq.s @foundIt ; yes? Then stop looking
move.l DTDBQElt.qLink(a3), a3 ; move on to the next one
@nextPtr:
move.l a3, d1 ; set condition codes to check for nil
bne.s @WalkQueue ; something there? keep looking.
; If we get here, then we saw a nil pointer, which means none of the open databases
; matched the user's volume. Return a rfNumErr
move.w #rfNumErr, d0 ; set result code
bra.s @leave
@foundIt: move.w #0, d0 ; no errors
@leave: move.l (sp)+, d1 ; restore d1
tst.w d0 ; set the result code
rts
_DTDebugTail 'FindDTVol',0
endproc
;________________________________________________________________________________
;
; Routine: DTSetup
;
; Function: Setup common to all desktop manager operations which take a DTRefNum.
;
; Inputs: a4 = DT Parameter block
; a6 = alt stack
; Output: d0 = error code (from FindDTVars).
; a3 = Pointer to DTQElt block (if DTRef checked out)
; a6 = alt stack
;
; All other registers preserved.
;________________________________________________________________________________
;
DTSetup: proc
move.l d1, -(a6) ; save d1 around call
move.w ioDTRefNum(a4), d0 ; extract DTRefNum from user's param block
move.l FSVarsPtr, a3 ; a3 = ptr(file system global area)
move.l FSVars.DTDBMgr(a3), a3 ; a3 = ptr(DTDB manager's global area)
move.l DTGlobals.qHead(a3), a3 ; a3 = ptr(1st open database)
bra.s @nextPtr ; check for nil (no open databases)
@WalkQueue:
cmp.w DTDBQElt.DTRefNum(a3), d0 ; is this the right database?
beq.s @foundIt ; yes? Then stop looking
move.l DTDBQElt.qLink(a3), a3 ; move on to the next one
@nextPtr:
move.l a3, d1 ; set condition codes to check for nil
bne.s @WalkQueue ; something there? keep looking.
; If we get here, then we saw a nil pointer, which means none of the open databases
; matched the user's DTRefNum. Return a rfNumErr
move.w #rfNumErr, d0 ; set result code
bra.s @leave
@foundIt: move.w #0, d0 ; no errors
@leave: move.l (a6)+, d1 ; restore d1
tst.w d0 ; set the result code
rts
_DTDebugTail 'DTSetUp',0
endproc
;________________________________________________________________________________
;
; Routine: CheckCSpec
;
; Function: Get info on a CNodeID in the catalog. Translate the user's
; DTRefNum into the right volume for the check.
;
; Inputs: a3 = DTDBQElt block for current database
; a4 = User's DTParam block
;
; Outputs: d0 = result code from _GetCatInfo on CNode
; d1 = CNodeID of the CNode we just checked
;
;________________________________________________________________________________
CheckCSpec: proc
CCSLocals record 0, increment
bigPB ds.b DTBigPBSize ; big enough to make any HFS or Btree call
LSize equ *-bigPB
endr
@CCSRegs reg a0/a1
with CCSLocals
move.l (sp)+, -(a6) ; save desktop return addr around i/o
movem.l @CCSRegs, -(a6) ; save regs
suba.w #LSize, a6 ; allocate locals on a6
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.l ioFileName(a4), ioFileName(a0) ; use user's name ptr
move.w DTDBQElt.XVRefNum(a3), ioVRefNum(a0) ; use correct volume ref
clr.w ioFDirIndex(a0) ; no indexing
move.l ioDirID(a4), ioDirID(a0) ; use user's DirID
go_GetCatInfo ; Look up this CNode's CNID
move.l ioDirID(a0), d1 ; ioDirID now contains CNodeID, so return it
add.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @CCSRegs
move.l (a6)+, -(sp) ; restore desktop return address
tst.w d0
rts
endwith
_DTDebugTail 'CheckCSpec',0
endproc
;________________________________________________________________________________
; <21>
; Routine: MyFindFolder/MyMakeFolder
;
; A little wrapper for FindFolder that is register-based.
; Currently, we implement two extra specialties the are handy for us
; 'root' returns the root directory
; 'serv' returns the server directory (we won't create this, though)
;
; Inputs:
; d1.w vRefNum or wdRefNum we're interested in
; d2.l folder specialty
;
; Outputs:
; d0.w error code (ccr set)
; d1.w vRefNum
; d2.l directory ID
;________________________________________________________________________________
MyMakeFolder: proc
entry myFindFolder
moveq.l #kCreateFolder,d0
bra.s MakeFindCommon
MyFindFolder:
moveq.l #kDontCreateFolder,d0
MakeFindLocals record 0, increment
vRef ds.w 1 ; stores the vRefNum of the volume under consideration
dirID ds.l 1 ; stores the directory ID of the directory we're looking in
bigPB ds.b ioHVQElSize ; enough for an HGetVolInfo
LSize equ *
endr
MakeFindRegs reg a0/a1
FolderMgrSupportsRootAndServ equ 0
with MakeFindLocals
MakeFindCommon:
move.l (sp)+,-(a6) ; we do I/O <26>
movem.l MakeFindRegs, -(a6) ; so we save on the A6 stack <26>
sub.w #LSize,a6
if not(FolderMgrSupportsRootAndServ) then
cmp.l #'root',d2 ; looking for the root directory?
beq.s @mine
cmp.l #'serv',d2 ; looking for the server folder?
bne.s StandardFind
@mine:
cmp.w #kOnSystemDisk, d1 ; folder manager's special system disk indicator?
bne.s @useTheVolume
move.w BootDrive, d1 ; try the boot drive (a.k.a where the active system is)
@useTheVolume:
lea.l bigPB(a6),a0 ; a0 = ptr(param block)
clr.l ioFileName(a0) ; we don't want the volume name
move.w d1,ioVRefNum(a0) ; VRef of volume to look at
clr.w ioVolIndex(a0) ; no indexing; use VRef only
go_HGetVInfo
bne.s @error ; punt on errors
move.w ioVRefNum(a0),d1 ; HGetVInfo extracts vRefs from wdRefs
cmp.l #'root',d2 ; looking for the root directory?
beq.s @root
move.l ioVFndrInfo+28(a0),d2 ; d2 = DirID of server folder
bne.s @test ; got one, success
moveq.l #fnfErr,d0 ; just like the folder manager
@error:
@test:
bra.s Done
@root:
moveq.l #fsRtDirID,d2
bra.s Done ; get out of here, and test the result code <28>
StandardFind:
endif
subq.l #2,sp ; allocate a word for error code
move.w d1,-(sp) ; look for the folder on this volume
move.l d2,-(sp) ; look for this folder
move.w d0,-(sp) ; tell whether to create
pea.l vRef(a6) ; stuff the volume in here
pea.l dirID(a6) ; and the directory here
; Note: This is call will do synchronous I/O, which is strictly illegal in
; the Desktop Manager, since Desktop Manager calls can trigger requests on
; the front the File System queue (which could themselves be Desktop Manager
; calls) and a executing a syncwait for the triggered call could hang the
; system. The only solace we can take is that this call is executed only
; when a volume is mounted, so it won't hang the system very often.
_FindFolder
move.w vRef(a6),d1 ; grab the volume
move.l dirID(a6),d2 ; grab the directory
move.w (sp)+,d0 ; grab the error
Done:
add.w #LSize,a6
movem.l (a6)+,MakeFindRegs ; get the stuff back <26>
move.l (a6)+,-(sp) ; we did I/O <26>
tst.w d0 ; make sure we set the ccr <28>
rts
endwith
endproc
;________________________________________________________________________________
; <21>
; Routine: FindDTFiles
;
; Find the desktop database files, if they exist. If they don't exist, return the
; appropriate location and name for them.
;
; The desktop database files are always a pair of files with names that differ
; only in the last character. For normal desktop files, the names are 'Desktop DB'
; and 'Desktop DF'. DB is a btree file, DF is a data file with icons in it. For
; shadow desktops (databases maintained on a different volume to support a volume that
; isn't writeable) the files are named '<volume name> DDB' and '<volume name> DDF'
;
; The idea: On unlocked volumes, we'll look for a database file in the root (the normal spot),
; then server folder (in case the volume is a server that had a file created
; there by the old desktop manager), and the system folder (in case the volume is a
; regular hard drive and the user was running the old Desktop Manager INIT).
; If we don't find one, we'll return the root as the place to create one.
;
; On locked volumes, we'll do the first part of above, then take a look
; in the currently active preferences folder and system folder for a shadow database.
; If we strike out both above and in the active system folder, we'll return the active
; preferences folder as the place to create the shadow database.
;
; Inputs: a1.l - pointer to 32 character buffer
; d0.w - vRefNum of volume to open DT on
;
; Outputs: a0.l - preserved
; a1.l - ptr(Name for btree file). Datafile name is always formed from btree file name
; by changing the last character from a 'B' to an 'F'
; d0.w - result code (error invalidates d1/d2/d3)
; d1.w - VRefNum of volume containing actual database files
; d2.l - ParID of directory containing actual database files
; d3.b - Set true if the files exist, false if they don't
; If the files don't exist, they should be created in d1/d2 w/name (a1)
;________________________________________________________________________________
FindDTFiles: proc
FindDTLocals record 0, increment
bigPB ds.b DTBigPBSize ; big enough for all HFS calls
LSize equ *
endr
FindDTRegs reg d4/a0/a2/a3
with FindDTLocals
move.l (sp)+,-(a6) ; we do I/O <26>
movem.l FindDTRegs,-(a6) ; save regs <26>
sub.w #LSize,a6 ; allocate locals
move.w d0,d3 ; save caller's requested volume
; Use the standard dt btree file name.
lea.l StandardName, a0 ; a0 = ptr(the standard btree file name)
moveq.l #0, d0 ; clear high bytes
move.b (a0), d0 ; get length of string
addq.b #1, d0 ; add one for the length byte
_BlockMove ; copy standard name into caller's (a1) buffer
move.l #'root',d2 ; try the root first
bsr CheckDTExists
beq Found
move.l #'serv',d2 ; try the server folder next
bsr CheckDTExists
beq Found
move.l #kSystemFolderType,d2 ; try the server folder next
bsr CheckDTExists
beq Found
lea.l bigPB(a6),a0 ; a0 = ptr(param block)
clr.l ioFileName(a0) ; we don't want the volume name
move.w d3,ioVRefNum(a0) ; vRef of volume to look at
clr.w ioVolIndex(a0) ; no indexing; use VRef only
go_HGetVInfo
2020-03-22 08:44:21 +00:00
bne.s Error ; punt on errors <SM2> CSS <Sys7.1>
2019-07-27 14:37:48 +00:00
move.w bigPB+ioVAtrb(a6), d0 ; get the volume attributes
btst.l #15, d0 ; software locked?
bne.s VolLocked
btst.l #7, d0 ; hardware locked?
bne.s VolLocked ; if not, then we need to make new files
move.l #'root',d2 ; make it in the root
bra.s Create
VolLocked:
; Replace the standard name with the name of the volume we're shadowing
lea.l bigPB(a6),a0 ; a0 = ptr(param block)
move.l a1,ioFileName(a0) ; tell the param block where to store the vol. name
move.w d3,ioVRefNum(a0) ; vRef of volume to look at
clr.w ioVolIndex(a0) ; no indexing; use VRef only
go_HGetVInfo
bne.s Error ; punt on errors
; Transform volume name into shadow btree file name by adding StandardShadow to it.
moveq.l #0,d0 ; clear high bytes
moveq.l #0,d2
movea.l a1, a2 ; save base address of name string
lea.l StandardShadow,a0 ; a0 = ptr(shadow pstring)
move.b (a0)+,d0 ; d0 = number of characters to copy
move.b (a1),d2 ; d2 = length of volume name
add.b d0,(a1)+ ; update length to include shadow characters
add.w d2,a1 ; point to end of volume name
_BlockMove
movea.l a2, a1 ; restore a1 to point as base of string
move.w #kOnSystemDisk,d3 ; now we're looking on the system disk for shadow databases
move.l #kPreferencesFolderType,d2 ; try the preferences folder first
bsr.s CheckDTExists
beq.s Found
move.l #'serv',d2 ; try the server folder next
bsr CheckDTExists
beq.s Found
move.l #kSystemFolderType,d2 ; try the system folder last
bsr.s CheckDTExists
beq.s Found
move.l #kPreferencesFolderType,d2 ; make it in the preferences folder
Create:
move.w d3,d1 ; get volume to create on
bsr MyMakeFolder
bne.s Error
moveq.l #0,d3 ; indicate files don't exist
bra.s Done
Found:
moveq.l #1,d3 ; indicate that files exist
Error:
Done:
add.w #LSize,a6
movem.l (a6)+,FindDTRegs ; restore <26>
move.l (a6)+,-(sp) ; we did I/O <26>
tst.w d0 ; be nice and set up flags <28>
rts
; This routine assumes the a6 stack from FindDTFiles
;
; input: d3.w the volume to check
; d2.l the special folder to check
; a1.l ptr(name to look for)
;
; output: d1.w volume found on
; d2.l directory found in
; d0.w error code
CheckDTExists:
move.l (sp)+,-(a6) ; we do I/O <26>
move.w d3,d1
bsr myFindFolder ; convert d2 from specialty to dirID
bne.s @error
lea.l bigPB+4(a6), a0 ; a0 = ptr(param block) (add 4 for ret. addr. on a6) <28>
move.l a1,ioFileName(a0) ; we want info on this file
move.w d1,ioVRefNum(a0) ; look on our current volume
clr.w ioFDirIndex(a0) ; no indexing; look by dirID and CName only
move.l d2,ioDirID(a0) ; in the proper directory
go_HGetFileInfo
@error:
move.l (a6)+,-(sp) ; we did I/O <26>
tst.w d0 ; make sure we set the ccr's <28>
rts
_DTDebugTail 'FindDTFiles',18 ; the names = 18 bytes
endwith
string pascal
StandardName:
dc.b 'Desktop DB' ; of the standard name for the desktop database btree file
align
StandardShadow:
dc.b ' DDB' ; suffix for shadow i.e. 'Hard Disk' becomes 'Hard Disk DDB'
align
string asis
endproc
;________________________________________________________________________________
; <1.7><1.9><25>
; Routine: DesktopNotifyProc
;
; Inputs notifyFrame stack frame
;
; Outputs: result from CloseDT call (normally noErr)
; We don't do anything if FindDTVol shows that desktop database is closed
;
; Function: Flush the desktop database on Offline calls
; Flush the desktop database on Unmount calls
;
;________________________________________________________________________________
DesktopNotifyProc: proc
@DesktopNotifyProcRegs reg a1/a3/d0
link a6, #0 ; set up a stack frame
movem.l @DesktopNotifyProcRegs, -(sp)
with notifyFrame
move.l vnbPtr(a6), a1 ; a1 = ptr(volume notice block)
move.w VNBNotice(a1), d0 ; d0 = notice value
cmp.w #VNAboutToGoOffline, d0 ; is this an offline notification?
beq.s @DoOfflineAction ; go do our stuff
cmp.w #VNAboutToUnmount, d0 ; is this an unmount notification?
bne.s @SuccessExit ; no? then leave
; This is an offline or unmount notification. Try to flush the desktop database for the
; indicated volume.
@DoOfflineAction:
move.w VNBVolume(a1), d0 ; get the volume for which we're being notified
bsr FindDTVol ; try to find a DTDBQElt for this volume
bne.s @SuccessExit ; no database? Smile and leave
sub.w #ioDTQElSize, sp ; allocate a DT param block
movea.l sp, a0 ; a0 = ptr(our DT param block)
move.w DTDBQElt.DTRefNum(a3), ioRefNum(a0) ; stash the DTRefNum for this volume
_DTFlush
move.w d0, theErr(a6) ; return the error from CloseDT
add.w #ioDTQElSize, sp ; deallocate the DT param block
bra.s @Exit ; and leave
@SuccessExit:
move.w #noErr, theErr(a6) ; indicate no problems
@Exit:
movem.l (sp)+, @DesktopNotifyProcRegs
unlk a6 ; undo the stack frame
move.l (sp)+, a0 ; get the return address
add.w #4, sp ; blow away the input parameter
jmp (a0) ; return to caller
_DTDebugRts 'DesktopNotifyProc', 0
endproc
;________________________________________________________________________________
;
; Routine: RealOpenDT
;
; Inputs: a0 - pointer to caller's DT param block
; uses only ioVRefNum
;
; Outputs: d0 - result code
; d1.b - file exists flag
; true = files existed before this open call; they were just opened
; false = files did not exist before call; they were just created
;
; Function: Open an access path to the Desktop database. If the database is already
; open for the specified volume, return its refNum.
;
; This call is synchronous only. Yes, those move.l (sp)+, -(a6) lines
; could be removed someday.
;________________________________________________________________________________
RealOpenDTLocals record 0, increment
bigPB ds.b DTBigPBSize ; big enough to make any HFS or Btree call
userVRef ds.w 1 ; User's requested vRefNum
dbName ds.b 32 ; Space for name of database files
volParmBuf equ dbName ; 32 bytes is fine for a _GetVolParms buffer <20>
existsFlag ds.b 1 ; true if the files already existed
align
LSize equ *-bigPB
endr
entry SetFileAttribs
entry DTKeyCmp
RealOpenDT: proc export
@OpenDTRegs reg a0-a4/d2
with RealOpenDTLocals
move.l (sp)+, -(a6) ; we do i/o
movem.l @OpenDTRegs, -(a6)
suba.w #LSize, a6
movea.l a0, a4 ; move user's DTParam to a safe register
;
; Grab the volume that this call is aimed at (determined when checking for external file systems)
;
move.l FSVarsPtr, a3 ; a3 = ptr(file system global area)
move.l FSVars.DTDBMgr(a3), a3 ; a3 = ptr(DTDB manager's global area)
move.w DTGlobals.targetVRef(a3),userVRef(a6) ; pick up caller's requested volume (true vRef)
;
; First, check to make sure that this volume's DT isn't already open
;
move.w userVRef(a6), d0 ; is this volume's database already open?
bsr FindDTVol ; go look for DT files (DTDBQElt ptr in a3 if success)
bne.s @NotAlreadyOpen ; if not, we'll have to open it
;
; Everything's cool - this really is an already opened database.
;
move.w DTDBQElt.DTRefNum(a3), ioDTRefNum(a4) ; put the DTRefNum into user's PB
st.b existsFlag(a6) ; say we got it open, and it was already there <20>
bra @SuccessExit ; get out <20>
;
; The database is not currently open on the given volume. Go open it.
;
@NotAlreadyOpen:
; <1.9>
; Make sure that this volume supports a desktop database
;
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.w userVRef(a6), ioVRefNum(a0) ; fill in the volume ref
clr.l ioNamePtr(a0) ; no volume name
lea.l volParmBuf(a6), a1 ; big enough for dumb _GetVolParms implementors <20>
move.l a1, ioBuffer(a0) ; and fill it in
move.l #vMAttrib+4, ioReqCount(a0) ; and say much we want <20>
go_GetVolParms
bne @NoSupportExit ; punt on errors <20>
move.l vMAttrib(a1), d0 ; get the volume bits
btst.l #bHasDesktopMgr, d0 ; desktop database support?
beq @NoSupportExit ; no? Then don't open
;
; See if the files exist already
;
lea.l dbName(a6), a1 ; a1 = ptr(space for btree file name)
move.w userVRef(a6), d0 ; d0 = volume to look for files for
bsr FindDTFiles ; go look for DT files (d1 = vol, d2 = dir, d3 = flg)
bne @OpenDTExit ; punt on serious errors
move.b d3, existsFlag(a6) ; do the files need to be created? (i.e. d3 = false)
bne @OpenFiles ; If they don't, go open them now
;
; The files didn't exist, but d1 has the vRef to create them on, d2 has the directory to
; create them in and a1 points to the name to create for the Btree file.
;
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
moveq.l #0, d0 ; clear high bytes
move.b (a1), d0 ; get length of btree file name
move.b #'F', (a1, d0.w) ; change name to datafile name
move.l a1, ioFileName(a0) ; use datafile name
move.w d1, ioVRefNum(a0) ; use volume from FindDTFiles
move.l d2, ioDirID(a0) ; use directory from FindDTFiles
go_HCreate ; create the data file
bne @OpenDTExit ; punt on errors
move.l #DTDataFileType, d3 ; set the data file type
bsr SetFileAttribs ; and the appropriate attrib bits
bne @DeleteDataExit
moveq.l #0, d0 ; clear high bytes
move.b (a1), d0 ; get length of data file name
move.b #'B', (a1, d0.w) ; change name to btree name
go_HCreate ; create the file that will become the btree file
bne @DeleteDataExit ; errors? Delete data file and leave
move.w #DTMaxKeySize, ioBTMaxKLen(a0) ; set maximum key size
clr.l ioBTClumpSize(a0) ; use volume clump size
pea.l DTKeyDescriptor ; push pointer to our key descriptor
move.l (sp)+, ioBTKDPtr(a0) ; and tell the btree about it
go_BTInit ; initialize btree file
bne @DeleteBothExit
move.l #DTBTFileType, d3 ; set the btree file type
bsr SetFileAttribs ; and the appropriate attrib bits
bne @DeleteBothExit
;
; Try to open the files: allocate space in the system heap for a DTDBQElt and do the opens
;
@OpenFiles:
move.l #DTDBQElt.Size,d0 ; Size of DT variable block
_NewPtr sys, clear ; Try to allocate the space in the system heap
bne @OpenDTExit ; give up if there's no memory
movea.l a0, a3 ; a3 = ptr(DTDBQElt)
@OpenBTFile:
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.l a1, ioFileName(a0) ; use btree name from FindDTFiles
move.w d1, ioVRefNum(a0) ; use vRef from FindDTFiles
move.b #fsRdWrPerm, ioPermssn(a0) ; grab write permission
move.l d2, ioDirID(a0) ; use DirID from FindDTFiles
pea.l DTKeyCmp ; use our own key comparison procedure
move.l (sp)+,ioBTKCProc(a0)
go_BTOpen
bne @DeallocateExit ; if not, that's trouble <20>
move.w ioRefNum(a0), DTDBQElt.DBRefNum(a3) ; save away the btree file refnum
moveq.l #0, d0 ; clear high bytes
move.b (a1), d0 ; get length of database name
move.b #'F', (a1, d0.w) ; change last character to an F
move.b #fsRdWrPerm, ioPermssn(a0) ; grab write permission
clr.l ioOwnBuf(a0) ; use volume buffer
go_HOpen
bne @CloseBTExit ; punt on errors
move.w ioRefNum(a0), DTDBQElt.DFRefNum(a3) ; save away the data file refnum
;
; So far, so good. Both files are open, and we've got a QElt ready.
; Fill in the rest of the info, enqueue it, get unmount notification, and we're done
;
move.w DTDBQElt.DBRefNum(a3), DTDBQElt.DTRefNum(a3) ; DTRefNum = ioRefNum of the btree file
move.w DTDBQElt.DBRefNum(a3), ioDTRefNum(a4) ; return DTRefNum to caller
clr.b DTDBQElt.Flags(a3) ; clear out our flags
clr.b DTDBQElt.Reserved(a3) ; clear out the reserved byte
move.w userVRef(a6), DTDBQElt.XVRefNum(a3) ; save user's target volume
move.w d1, DTDBQElt.VRefNum(a3) ; save the real volume where files are
move.l d2, DTDBQElt.ParID(a3) ; and the real directory
move.l #DTDataClump, DTDBQElt.DFClumpSize(a3) ; and an arbitrary clump
clr.l DTDBQElt.lastHint(a3) ; no btree hint yet
move.l FSVarsPtr, a1 ; a1 = ptr(file system global area)
move.l FSVars.DTDBMgr(a1), a1 ; a1 = ptr(DTDB manager's global area)
lea.l DTGlobals.qFlags(a1), a1 ; a1 = ptr(DTQueue header)
movea.l a3, a0 ; move DTDBQElt ptr into a0
_Enqueue
tst.w d0 ; enqueue is a toolbox trap
beq.s @SkyStillUp
jmp deepShitError ; if the sky falls, duck
@SkyStillUp:
;
; <21> If the files just got created, try to allocate a contiguous clump just for performance.
;
tst.b existsFlag(a6) ; are we brand new?
bne.s @alreadyExisted ; no, dont allocate a clump
lea.l bigPB(a6), a0 ; a0 = ptr(param block) <22>
move.l DTDBQElt.DFClumpSize(a3), ioReqCount(a0) ; d1 = the data file's clump size
go_Allocate ; request the additional space
@alreadyExisted:
;
; <1.7> Install MultiFinder unmount notification
;
move.l FSVarsPtr, a1 ; a1 = ptr(file system global area)
move.l FSVars.DTDBMgr(a1), a1 ; a1 = ptr(DTDB manager's global area)
bset.b #notifyBit, DTGlobals.infoFlags(a1) ; do we already have notification installed?
bne.s @skipNotify ; yes? ->
lea.l -2(sp), sp ; leave space for OSErr output
pea.l DesktopNotifyProc ; the routine called at notification time
move.l #'KWAK', -(sp) ; we don't have a refCon
bsr myBeginSystemMode ; be the system
_RequestVolumeNotification ; sign up for notify
bsr myEndSystemMode ; be the app
move.w (sp)+, d0 ; did we succeed?
beq.s @ItWorked
jmp deepShitError ; if not, the sky is falling
@ItWorked:
@skipNotify:
@SuccessExit: ; all successful exits are through here <20>
moveq.l #noErr, d0 ; we succeeded
tst.b existsFlag(a6) ; return a result
beq.s @OpenDTExit
moveq #1,d1 ; files existed, so we return a 1
bra.s @OpenDTExitResultInD1
; We failed while initializing the btree file, so delete both files before cruising
@DeleteBothExit:
move.w d0, ioResult(a4) ; save the error that got us here
go_HDelete ; delete the btree file
move.w ioResult(a4), d0 ; replace err w/real err that got us here
; We failed while creating the btree file, so delete the datafile before cruising
@DeleteDataExit:
move.w d0, ioResult(a4) ; save the error that got us here
moveq.l #0, d0 ; clear high bytes
move.b (a1), d0 ; get length of btree file name
move.b #'F', (a1, d0.w) ; change name to data file name
move.l a1, ioFileName(a0) ; use data file name
go_HDelete ; delete the data file
move.w ioResult(a4), d0 ; replace err w/real err that got us here
bra.s @OpenDTExit
; We failed on opening the datafile, so close the btree file before punting
@CloseBTExit:
move.w d0, ioResult(a4) ; save the error that got us here
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.w DTDBQElt.DBRefNum(a3), ioRefNum(a0)
go_BTClose
move.w ioResult(a4), d0 ; and make sure that it gets back to the user
; We allocated a DTDBQElt before failing, so deallocate it before punting
@DeallocateExit:
movea.l a3, a0 ; get DTDBQElt ptr
move.w d0, -(sp) ; save failure-provoking result code
_DisposPtr ; and free up DTDBQElt
move.w (sp)+, d0 ; restore failure-provoking result code
bra.s @OpenDTExit ; and leave
@NoSupportExit:
move.w #wrgVolTypErr, d0 ; indicate the boo-boo
@OpenDTExit:
moveq.l #0, d1 ; clear high bytes
@OpenDTExitResultInD1: ; <20>
adda.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @OpenDTRegs
move.l (a6)+, -(sp)
rts
endwith
_DTDebugTail 'OpenDT',0
endproc
; ==========
; Routine: SetFileAttribs (requires locals frame of RealOpenDT)
;
; Inputs: a0 - pointer to PB w/vRef, ioNamePtr, and ioDirID set
; a4 - pointer to OpenDT parameter block
; a6 - pointer to RealOpenDT locals (uses userVRef) (does compensation for saved addr)
; d2 - dirID of file
; d3 - file type (DTFL or BTFL)
;
; Outputs: registers preserved
; d0 - noErr or result code from call which failed
;
; Set the finder info (type in d3, creator DMGR)
; Set the attribute bits:
; regular desktops: invisible
; shadow desktops: visible
; ==========
SetFileAttribs: proc
with RealOpenDTLocals
move.l (sp)+,-(a6) ; we do I/O <30>
clr.w ioFDirIndex(a0) ; no indexing; look by dirID and CName only
go_HGetFileInfo ; fill the param block with cat info <21>
bne @errorExit
move.l d3, ioFlUsrWds+fdType(a0) ; set the file type
move.l #DTFileCreator, ioFlUsrWds+fdCreator(a0) ; set the file creator
cmp.w userVRef+4(a6), d1 ; compare target volume to actual volume <30>
bne.s @shadow ; if they're different, we're shadowing
move.w #fInvisible, d0 ; bit pattern for invisible flag
bra.s @setAttributes
@shadow:
moveq.l #0,d0 ; no special attributes
@setAttributes
or.w d0, ioFlUsrWds+fdFlags(a0) ; logical or into current attributes
move.l d2, ioDirID(a0) ; set correct directory (GetCatInfo blasts it)
clr.w ioFDirIndex(a0) ; no indexing; look by dirID and CName only
go_HSetFileInfo ; set our new info <21>
@errorExit:
move.l (a6)+,-(sp) ; we did I/O <30>
tst.w d0 ; restore those cute cc's <30>
rts
endproc
;________________________________________________________________________________
;
; Routine: DTOpenInform
;
; Inputs: a0 - pointer to caller's DT param block
; uses only ioVRefNum
;
; Outputs: d0 - result code
;
; Function: Same as DTGetPath, except returns a flag in ioTagInfo indicating
; whether or not the files already existed.
; True = already existed
; False = were just created
;________________________________________________________________________________
DTOpenInform: proc export
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUESYNC ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTVolExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue
bsr RealOpenDT ; d1 true/false for dtExisted
and.l #1, d1 ; return low bit only <20>
move.l d1, ioTagInfo(a0)
bra DTDone
_DTDebugRTS 'DTOpenInform', 0
endproc
;________________________________________________________________________________
;
; Routine: DTGetPath
;
; Inputs: a0 - pointer to caller's DT param block
; uses only ioVRefNum
;
; Outputs: d0 - result code
;
; Function: Open an access path to the Desktop database. If the database is already
; open for the specified volume, return its refNum.
;________________________________________________________________________________
DTGetPath: proc export
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUESYNC ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTVolExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue
bsr RealOpenDT
bra DTDone
_DTDebugRTS 'DTGetPath', 0
endproc
;________________________________________________________________________________
;
; Routine: DequeueDTDBQElt
;
; Inputs: a0 - pointer to DTDBQElt to remove
; Outputs none
;
; Function: Dequeue and deallocate a DTDBQElt. No check of a0 is
; done. The block it points to must be both allocated
; and in the queue.
; Called by: CloseDT and VerifyOpenFiles
;________________________________________________________________________________
DequeueDTDBQElt: proc
move.l a1, -(sp)
move.l FSVarsPtr, a1 ; a1 = ptr(file system global area)
move.l FSVars.DTDBMgr(a1), a1 ; a1 = ptr(DTDB manager's global area)
lea.l DTGlobals.qFlags(a1), a1 ; a1 = ptr(DTQueue header) <dnf 1.3>
_Dequeue
tst.w d0 ; 'cause _Dequeue doesn't test <dnf 1.3>
beq.s @Ok
jmp deepShitError ; we're really up the creek if this fails
@Ok:
_DisposPtr ; free it up the element
movea.l (sp)+, a1
rts
_DTDebugTail 'DequeueDTDBQElt', 0
endproc
;________________________________________________________________________________
;
; Routine: DTCloseDown
;
; Inputs: a0 - pointer to caller's DT param block
; uses only ioDTRefNum
;
; Outputs: d0 - result code
;
; Function: Close the desktop database for a volume
;________________________________________________________________________________
DTCloseDown: proc export
DTCloseDownLocals record 0, increment
bigPB ds.b DTBigPBSize ; big enough to make any HFS or Btree call
LSize equ *-bigPB
endr
@DTCloseDownRegs reg a0-a4/d1-d2
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUESYNC ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue
with DTCloseDownLocals
movem.l @DTCloseDownRegs, -(a6)
suba.w #LSize, a6
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne.s @DTCloseDownExit
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.w DTDBQElt.DBRefNum(a3), ioRefNum(a0)
go_BTClose
move.w DTDBQElt.DFRefNum(a3), ioRefNum(a0)
go_Close ; same goes for here
movea.l a3, a0 ; move DTDBQElt to a0
bsr DequeueDTDBQElt ; dequeue and dispose of it
@DTCloseDownExit:
adda.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @DTCloseDownRegs
bra DTDone
endwith
_DTDebugRts 'DTCloseDown',0
endproc
;________________________________________________________________________________
;
; Routine: DTAddIcon
;
; Input: a0 - user's DT param block
; Output: d0 - result code
;
; Function: Add an icon bitmap to the Desktop database under its FileType/Creator
;________________________________________________________________________________
;
DTAddIcon: proc export
StandardLocals AddIconLocals, IconDRec ; normal locals w/icon sized data rec
@AddIconRegs reg a0-a4/d1-d2 ; set of regs to save around AddIcon
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; Wait our turn.
with AddIconLocals ; Key and Data refer to locals
movem.l @AddIconRegs, -(a6)
suba.w #LSize, a6 ; allocate locals on the a6 stack
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne @AddIconExit ; and punt on errors
move.l ioReqCount(a0), d0 ; d0 = user's icon data size
cmp.l #DTMaxIconSize, d0 ; icon too big?
ble.s @SizeOK ; then keep going
moveq #paramErr, d0 ; otherwise, complain
bra @AddIconExit ; and cruise
;
; First, search the btree to see if there's an icon with the same key already in the database
;
@SizeOK:
bsr SetUpBTPB ; standard BT param in a0 w/btree refNum
move.l #IconDRec.IRLen, ioReqCount(a0) ; indicate size of icon data record
move.b #IconKey.IKLen-1, (a2)+ ; Set length of key (minus length byte)
move.b #IconKeyType,(a2)+ ; ... and key type
move.l ioFlCreator(a4),(a2)+ ; Set up CreatorType
move.l ioFlType(a4),(a2)+ ; ... and FileType
move.b ioIconType(a4),(a2)+ ; Pass in the requested icon Type
clr.b (a2)+ ; clear the filler byte <1.7>
go_BTSearch
bsr DoneBTPB ; finished with BTPB <21>
beq.s @ChkSize ; If no errors, check icon size
cmp.w #btRecNotFnd, d0 ; Entry not found?
beq.s @AddNew ; No problem - go create a brand new one
bra @AddIconExit ; Other errors are more serious
;
; An entry for an icon of the same FlCreator/FlType/IconType already exists,
; make sure its the same size as the requested new one.
;
@ChkSize:
lea.l Data(a6), a2 ; a2 = ptr(B*-Tree Icon data record)
move.w IconDRec.IconSize(a2), d0 ; Pick up current icon size
cmp.w ioReqCount+2(a4), d0 ; Same size as replacement?
beq.s @CanWrite ; Yes - go overwrite it
move.w #afpIconTypeError,d0
bra @AddIconExit ; otherwise, fail miserably
@CanWrite:
move.l IconDRec.IconPos(a2), d0 ; Pick up old position
bra.s @AIWriteIcon ; And go overwrite the old icon bits
;
; We'll have to allocate space in the DF file for a new entry. Just add to the end.
;
@AddNew:
bsr SetUpDFPB ; Get an ioParam on a0 w/data file refnum
go_GetEOF ; Find LEOF of the datafile
bne.s @AddIconExit ; Problems? See your registered pharmacist.
move.l ioLEOF(a0), d0 ; Pick up position to write icon at
;
; Arrive here from CanWrite or AddNew with d0 = position to write icon bits in Desktop DF:
; Write the icon into the data file, and if that succeeds, add the icon record to the Btree.
;
@AIWriteIcon:
lea.l Data(a6), a2 ; a2 = ptr(B*-Tree Icon data record)
move.l ioTagInfo(a4),IconDRec.TagInfo(a2) ; Copy tag information into data record
move.l d0,IconDRec.IconPos(a2) ; save file position in icon btree rec
move.w ioReqCount+2(a4),IconDRec.IconSize(a2) ; Copy size of icon
; a quick check to see if we need to extend the data file
move.w DTDBQElt.DFRefNum(a3), d1 ; use the datafile's refNum
move.l FCBSPtr,a1 ; a1 = ptr(FCB array)
lea.l 0(a1,d1.w),a1 ; a1 = ptr(datafile's FCB)
move.l d0,d2 ; move icon's file position to d2 for some calculating
add.l ioReqCount(a4),d2 ; d2 = file position + bitmap size
cmp.l fcbPLen(a1),d2 ; Check against the current PEOF
bls.s @AIGoWrite ; If icon end < PEOF, start writing
; To minimize fragmentation, we extend the icon datafile by a bunch each time
bsr SetUpDFPB ; Get an ioParam on a0 w/data file refnum
move.l DTDBQElt.DFClumpSize(a3), ioReqCount(a0) ; d1 = the data file's clump size
go_Allocate ; Request the additional space
; The file's big enough, so write the icon data to the datafile
@AIGoWrite:
bsr SetUpDFPB ; Get an ioParam on a0 w/data file refnum
move.l ioBuffer(a4), ioBuffer(a0) ; data comes from user's pointer
clr.l ioReqCount(a0) ; size is just a word
move.w ioReqCount+2(a4), ioReqCount+2(a0) ; get size from user pb
move.w #fsFromStart, ioPosMode(a0) ; position is relative to byte 0
move.l IconDRec.IconPos(a2), ioPosOffset(a0) ; use the icon pos we've computed
go_Write ; Fire off the write
bne.s @AddIconExit ; punt on errors
; set the icon record in the Btree file
bsr SetUpBTPB ; standard BT param in a0 w/btree refNum
move.l #IconDRec.IRLen, ioReqCount(a0) ; tell the btree about the length
go_BTSetRec ; the key is still cool from the search
bsr DoneBTPB ; finish up with the BTPB <21>
@AddIconExit:
adda.w #LSize, a6 ; get rid of our locals
movem.l (a6)+, @AddIconRegs ; and restore our registers
bra DTDone ; We're all set.
endwith
_DTDebugRts 'DTAddIcon',0
endproc
;________________________________________________________________________________
;
; Routine: DTGetIcon
;
; Input: a0 - user's DT param block
; Output: d0 - result code
;
; Function: Retrieve an icon from the Desktop database by Creator/Type
;________________________________________________________________________________
;
DTGetIcon: proc export
StandardLocals GetIconLocals, IconDRec
@GetIconRegs reg a0-a4/d1-d2 ; set of regs to save around AddIcon
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; Wait our turn.
with GetIconLocals ; Key and Data refer to locals
movem.l @GetIconRegs, -(a6)
suba.l #LSize, a6 ; allocate locals
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne.s @GetIconExit ; punt on errors
; go look for the requested icon's entry in the btree
bsr SetUpBTPB ; a0 = ptr(BTioParam)
move.l #IconDRec.IRLen, ioReqCount(a0) ; indicate size of icon data record
move.b #IconKey.IKLen-1, (a2)+ ; Stuff key length (minus length byte)
move.b #IconKeyType, (a2)+ ; and the type
move.l ioFlCreator(a4), (a2)+ ; creator from user's DTPB
move.l ioFlType(a4), (a2)+ ; type from user's DTPB
move.b ioIconType(a4), (a2)+ ; icon type from user's DTPB
clr.b (a2)+ ; clear the filler byte <1.7>
go_BTSearch
bsr DoneBTPB ; finish up with the BTPB <21>
bne.s @GetIconExit ; punt on errors
move.l IconDRec.TagInfo+Data(a6), ioTagInfo(a4) ; return tag information
;
; Read the icon from the data file
;
bsr SetUpDFPB ; Get an ioParam on a0 w/data file refnum
move.l ioBuffer(a4), ioBuffer(a0) ; data goes to the user's buffer
moveq.l #0, d0 ; clear high word
move.w IconDRec.IconSize+Data(a6), d0 ; d0 = size of icon data
cmp.w ioReqCount+2(a4), d0 ; is the user's size big enough?
bls.s @sizeOk ; yes, read the whole icon
move.w ioReqCount+2(a4), d0 ; otherwise clip to provided space
@sizeOk:
move.l d0, ioReqCount(a0) ; the correct length
move.w #fsFromStart, ioPosMode(a0) ; position from start of file
move.l IconDRec.IconPos+Data(a6), ioPosOffset(a0) ; get position from icon's btree rec
go_Read ; go get the icon data
bne.s @GetIconExit ; punt on errors
move.l ioActCount(a0),ioActCount(a4) ; Return actual byte count
@GetIconExit
adda.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @GetIconRegs
bra DTDone ; We're all set.
endwith
_DTDebugRts 'DTGetIcon',0
endproc
;________________________________________________________________________________
;
; Routine: DTGetIconInfo
;
; Input: a0 - user's DT param block
; Output: d0 - result code
;
; Function: Retrieve an icon from the Desktop database by Creator/Index
;________________________________________________________________________________
;
DTGetIconInfo: proc export
StandardLocals GetIconInfoLocals, IconDRec
@GetIconInfoRegs reg a0-a4/d1-d2 ; set of regs to save around this call
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; Wait our turn
with GetIconInfoLocals ; Key and Data refer to locals
movem.l @GetIconInfoRegs, -(a6)
suba.w #LSize, a6
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne @GetIconInfoExit2 ; Punt on any error
; Do a search. We know we won't find anything, but the hint will put us just
; to the "left" of all of the icons with this icon creator
bsr SetUpBTPB ; a0 = ptr(BTioParam), a2 = ptr(key)
move.l #IconDRec.IRLen, ioReqCount(a0) ; we know how big the record is
move.b #05, (a2)+ ; special short key (•• magic constant)
move.b #IconKeyType, (a2)+ ; standard icon type
move.l ioFlCreator(a4), (a2)+ ; user's requested creator
go_BTSearch
cmp.w #btRecNotFnd, d0 ; was the error a search miss?
bne.s @GetIconInfoExit ; otherwise, something's wrong
; With the ioBTHint set up, go get the indexed record
move.w ioIndex(a4), d0 ; get the caller's index
bne.s @IndexOK ; did the user use a silly index, like zero?
move.w #btRecNotFnd, d0 ; well, that one doesn't exist
bra.s @GetIconInfoExit ; so leave
@IndexOK:
subq.w #1, d0 ; indicies start at 1, so adjust offset
move.w d0, ioBTPosMode(a0) ; record offset from current position
move.w #IconKey.IKLen, ioKReqCount(a0) ; we know how big the key is (including length byte here)
go_BTGetRec
bne.s @GetIconInfoExit ; Bad day at the office? then leave.
move.b IconKey.Type+Key(a6), d0 ; get the key id
cmp.b #IconKeyType, d0 ; is it still an icon key?
beq.s @CheckCreator ; if so, go see if the creator is still the same
move.w #afpItemNotFound, d0 ; otherwise, the index was too high
bra.s @GetIconInfoExit ; so return an error
@CheckCreator:
move.l IconKey.CrType+Key(a6), d0 ; pick up the icon's creator type
cmp.l ioFlCreator(a4), d0 ; check against user's requested type
beq.s @FoundGoodOne ; same = good
move.w #afpItemNotFound, d0 ; otherwise, index was too high
bra.s @GetIconInfoExit ; so return an error
@FoundGoodOne:
move.l IconDRec.TagInfo+Data(a6), ioTagInfo(a4) ; return this icon's tag
clr.l ioActCount(a4) ; clear whole long
move.w IconDRec.IconSize+Data(a6), ioActCount+2(a4); and return word-sized icon size
move.b IconKey.IconType+Key(a6), ioIconType(a4) ; return this icon's iconType
move.l IconKey.FlType+Key(a6), ioFlType(a4) ; return this icon's fileType
moveq.l #0, d0 ; All is well.
@GetIconInfoExit:
bsr DoneBTPB ; finish up with the BTPB <21>
@GetIconInfoExit2:
adda.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @GetIconInfoRegs
bra DTDone ; We're all set.
endwith
_DTDebugRts 'DTGetIconInfo',0
endproc
;________________________________________________________________________________
; The Application List
;
; Applications are stored in the app list by their creator and a synthetic 16-bit
; sequence number. The seqnums exist to provide unique keys and ordering to each
; application with a given creator.
;
; The two app list routines which need to manipulate the list (add and delete)
; use a common iterator function that calls them once for each application in
; the list. The iterator runs from higher seqnums to lower seqnums. (right to
; left).
;
; Apps are kept in the list so that the leftmost entry is always the youngest
; (as recorded by the creation date of the application file).
;________________________________________________________________________________
;________________________________________________________________________________
; Routine: SetUpAPPLIterator
;
; Input: a2 - standard locals (param block, key, data)
; a3 - dtdbqelt pointer
; d1 - creator type
;
; Output: a0 - BT param block with valid hint, key and data sizes
; d0 - result code from BTSearch (btRecNotFound error is suppressed)
;
; Function: Initialize a btree param block to point one to the right of
; the "first" (i.e. rightmost) APPL entry of the given creator.
; A btRecNotFound error is expected since we're using a short key,
; so return noErr if we see it. All other errors are passed through.
;
;________________________________________________________________________________
;
SetUpAPPLIterator: proc
move.l (sp)+, -(a6) ; <18>
with APPLLocals ; Key and Data are application-sized
move.l a1, -(a6)
lea.l bigPB(a2), a0 ; a0 = ptr(btree param block)
bsr GetHintFromDTDBQElt ; fetch the hints
move.w DTDBQElt.DBRefNum(a3), ioRefNum(a0) ; use the btree file's refnum
lea.l Data(a2), a1 ; a1 = ptr(APPL record data block)
move.l a1, ioBuffer(a0)
lea.l Key(a2), a1 ; a1 = ptr(APPL key block)
move.l a1, ioBTKeyPtr(a0)
move.b #5, (a1)+ ; use short key so we'll be at the far left
move.b #APPLKeyType, (a1)+ ; this is an APPL key
move.l d1, (a1) ; with the requested creator
add.l #1, (a1)+ ; tweak the key up to the next higher creator
move.l #APPLRec.ARLen, ioReqCount(a0) ; set for later indexed BTGetRec calls
move.w #APPLKey.AKLen, ioKReqCount(a0) ; set for later indexed BTGetRec calls
go_BTSearch ; go miss the target
move.l d1, APPLKey.SeqNum+Key(a2) ; restore correct creator type
cmp.w #btRecNotFnd, d0 ; did we miss (as expected?)
beq.s @NoErrExit ; yes? Leave with a smile
bra.s @Exit ; otherwise pass the error through
@NoErrExit:
moveq.l #0, d0
@Exit:
tst.w d0
move.l (a6)+, a1
move.l (a6)+, -(sp) ; <18>
rts
endwith
_DTDebugTail 'SetUpAPPLIterator',0
endproc
;________________________________________________________________________________
; Routine: APPLIterator
;
; Input: a0 - BT param block with valid hint, key, and data pointers
; a1 - callback procedure
; a2 - standard locals (param block, key, data)
; d1 - creator type
;
; Output: a0 - BT param block with valid hint, key, and data pointers
; a1 - callback procedure
; a2 - standard locals (param block, key, data)
; d0 - noErr if normal termination; terminating error code otherwise
; d1 - creator type
;
; Function: This iterator is used by the APPL calls (Add, Remove, and Get).
; It iterates through all APPL records with a creator type that
; matches the one in the user's param block. For each record,
; a callback procedure is called. Iteration continues until either
; no more APPL records with the right creator are available or
; the callback procedure returns a zero in d0.
;
; Registers a3-a5 and d2-d7 are passed directly to the callback
; procedure; it is responsible for restoring all registers except d0.
;
; Index through the records backwards (ffff through 0) to maintain
; compatibility with AppleShare's desktop manager.
;________________________________________________________________________________
;
APPLIterator: proc
move.l (sp)+, -(a6) ; <18>
with APPLLocals
move.w #-1, ioBTPosMode(a0) ; get records in descending key order
@Iterate:
go_BTGetRec ; get the next record
beq.s @Examine ; if noErr, check for reasonableness
cmp.w #btBofErr, d0 ; are we out of records?
bra.s @Exit ; else, a real error has ocurred
@Examine:
move.b APPLKey.Type+Key(a2), d0 ; get this record's key type
cmp.b #APPLKeyType, d0 ; is this an APPL key?
bne.s @NoErrExit ; if not, we're out of reasonable records
move.l APPLKey.CrType+Key(a2), d0 ; get this record's creator
cmp.l d0, d1 ; is this the right creator?
bne.s @NoErrExit ; if not, we're out of reasonable records
jsr (a1) ; give the caller a shot at it
tst.w d0 ; are they all through?
beq.s @NoErrExit
bra.s @Iterate
@NoErrExit:
moveq.l #0, d0
@Exit:
move.l (a6)+, -(sp) ; <18>
rts
endwith
_DTDebugTail 'APPLIterator',0
endproc
;________________________________________________________________________________
; Routine: APPLCompareNames
;
; Input: a2 - standard APPL locals
;
; Output: d0 - trashed
; ccr state from _CmpString of names
;
; Function:
; This routine compares the name from the current APPL rec (sitting in the
; APPL locals) to the name in the AppSpec (sitting in the APPL locals).
;
; You must have set up the AppSpec in APPLLocals before using this routine.
;________________________________________________________________________________
APPLCompareNames: proc
with APPLLocals
@stash reg a0/a1
movem.l @stash, -(sp) ; save away for a sec
moveq.l #0, d0 ; clear high bytes
lea.l AppSpec+FSSpec.name(a2), a0 ; a0 = ptr(leaf name of app)
move.b (a0)+, d0 ; d0 = length, a0 = ptr(1st char)
swap d0 ; length of 1st string into high word
lea.l APPLRec.CName+Data(a2), a1 ; a1 = ptr(CName of current entry)
move.b (a1)+, d0 ; d0 = length, a1 = ptr(1st char)
_FSCmpString ; are the names the same?
movem.l (sp)+, @stash
rts
endwith
_DTDebugTail 'APPLCompareNames', 0
endproc
;________________________________________________________________________________
; Routine: AddAPPLCallback
;
; Input: a0 - BT param block with valid hint, key, and data pointers
; a1 - callback procedure
; a2 - standard APPL locals
; a3 - DTDBQElt pointer
; a4 - user DT param block
; d1 - creator type
;
; Output: a0 - BT param block
; a1 - callback procedure
; a2 - standard locals (param block, key, data)
; a3 - DTDBQElt pointer
; a4 - user DT param block
; d0 - zero to signal end of iteration; nonzero otherwise
; d1 - creator type
;
; Function:
; This routine will get called once per APPL entry with a creator matching the
; one of the application being added to the list.
; It does these things:
; Look for a sequence number at which to add the new application.
; Keep track of the creation date and sequence number of the last record it saw
; Look for a duplicate entry, which means we don't need to insert anything.
;
; If no free sequence number is found when scanning the list, index(a2) will
; be one to the left of the last existing record - by definition a free
; seqnum.
;________________________________________________________________________________
;
AddAPPLCallback: proc
with APPLLocals
bset.b #applSawARecord, flags(a2) ; we've seen at least one record
move.l APPLRec.TagInfo+Data(a2), theDate(a2) ; record leftmost record's create date
move.w APPLKey.SeqNum+Key(a2), theSeqNum(a2) ; record leftmost record's sequence number
move.l APPLRec.parID+Data(a2), d0 ; pick up the ParID
cmp.l AppSpec.parID(a2), d0 ; entry in the same folder? <19>
bne.s @NotADuplicate
bsr APPLCompareNames ; are the names the same?
bne.s @NotADuplicate ; no ->
; The current application record has the same creator, parID and name as the app
; being added.
move.l APPLRec.TagInfo+Data(a2), d0 ; get this application's creation date
cmp.l crDate(a2), d0 ; check it against our prospective entry
bne.s @DifferentCreateDate ; handle same app/different date case
bset.b #applFoundADup, flags(a2) ; indicate our find
moveq.l #0, d0 ; signal the end of this search
bra.s @Exit
; We've got most of a duplicate entry - everything except the create date matches.
; This really shouldn't happen, but if it does, simply return the seqnum of the
; current record as the place we should insert the new application.
@DifferentCreateDate:
move.w APPLKey.SeqNum+Key(a2), index(a2) ; use this seqnum
bra.s @FoundASeqNum
@NotADuplicate:
btst.b #applFoundASeqNum, APPLLocals.flags(a2) ; do we need to find a seqnum?
bne.s @KeepIterating
move.w APPLKey.SeqNum+Key(a2), d0 ; get the current record's seqnum
cmp.w index(a2), d0 ; collision?
bne.s @FoundASeqNum ; if not, we've found a good seqnum
sub.w #1, index(a2) ; subtract to get next prospective seqnum
bra.s @KeepIterating
@FoundASeqNum:
bset.b #applFoundASeqNum, flags(a2) ; indicate our find
@KeepIterating:
moveq.l #1, d0 ; indicate that we should keep iterating
@Exit:
rts
endwith
_DTDebugTail 'AddAPPLCallback',0
endproc
;________________________________________________________________________________
; Routine: DTAddAPPL
;
; Input: a0 - user's DT param block
; Output: d0 - result code
;
; Register Use: a0 - bt param block
; a1 -
; a2 - locals
; a3 - DTDBQElt
; a4 - user's param block
;
; Function: Add an entry for an application into the application list
;
; Add the given application to the app list. If this application is younger than
; all existing applications, make sure its sequence number is lowest. If it's not
; the youngest, add the application at the highest available seqnum.
; If the application has the same name, directory and tag as an entry in the list,
; no action is necessary. If the application has the same name and directory but a
; different tag, delete the existing entry and insert the application as if there
; had been no duplicate.
;________________________________________________________________________________
DTAddAPPL: proc export
@AddAPPLRegs reg a0-a4/d1-d2 ; set of regs to save around this call
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; Wait our turn
with APPLLocals ; Key and Data are APPL-sized
movem.l @AddAPPLRegs, -(a6)
suba.w #LSize, a6 ; allocate locals
movea.l a6, a2 ; setup a2 as locals ptr
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne @Exit2 ; Punt on any errors
lea.l bigPB(a2), a0 ; a0 = ptr(param block)
move.l ioFileName(a4), ioFileName(a0) ; use user's application name
move.w DTDBQElt.XVRefNum(a3), ioVRefNum(a0); use correct volume ref
clr.w ioFDirIndex(a0) ; no indexing
move.l ioDirID(a4), ioDirID(a0) ; use user's DirID
go_HGetFileInfo ; Go get this app's creation date <21>
bne @Exit2 ; run away on errors
move.l ioFlCrDat(a0), APPLLocals.crDate(a2) ; save the creation date
move.l ioDirID(a4), ioDirID(a0) ; reset dirID field (modified by GetCatInfo)
lea.l AppSpec(a2), a1 ; address of our FSSpec record
move.l a1, ioFSSpecPtr(a0) ; tell the param block about it
go_MakeFSSpec
bne @Exit2 ; run away on errors
move.w #$ffff, index(a2) ; initial seqnum is ffff to maintain compatibility
clr.b flags(a2) ; clear all iterator signal flags
move.l ioFlCreator(a4), d1 ; d1 = creator type for new APPL list entry
bsr SetUpAPPLIterator ; get ready to iterate through existing entries
lea.l AddAPPLCallback, a1 ; a1 = ptr(AddAPPL's iterator callback)
bsr APPLIterator ; go look at each existing record
move.w index(a2), d1 ; set up free seqnum
btst.b #applSawARecord, flags(a2) ; did we see at least one good record?
beq.s @Insert ; if not, insert the new sole record
@SawAnExistingRecord:
btst.b #applFoundADup, APPLLocals.flags(a2) ; did we find a duplicate?
bne.s @NoErrExit ; if so, take the easy way out
; We have a valid seqnum. There's at least one other record with this creator,
; so make sure that the leftmost record has the newest creation date.
; There are four possibilities here, based on two facts:
; The free seqnum is left or right of the leftmost existing record
; The leftmost existing record is newer or older (by creation date) than the app being added
;
; free seqnum right of existing leftmost free seqnum left of existing leftmost
; caller's app newer: swap insert at free seqnum
; caller's app older: insert at free seqnum swap
;
; A swap puts the existing leftmost record into the free seqnum and the caller's
; app into the newly available seqnum where the leftmost app used to be. Note that
; this operation either ensures that the leftmost record stays that way (by moving it
; to a new, even lower seqnum) or that the new record becomes the leftmost (when the
; free seqnum was off to the right).
;
; This ensures that the leftmost record is always the one with the youngest app.
@HaveASeqNum:
move.l theDate(a2), d0 ; d0 = creation date of leftmost existing record
cmp.l crDate(a2), d0 ; compare that to the app's creation date
bhi.s @ExistingRecIsNewer
move.w theSeqNum(a2), d0 ; d0 = seqnum of the leftmost existing record
cmp.w index(a2), d0 ; compare that to this app's assigned seqnum
blo.s @DoASwap ; left seq < free seq, left rec older than caller's
bra.s @Insert ; left seq > free seq, left rec older than caller's
@ExistingRecIsNewer:
move.w theSeqNum(a2), d0 ; d0 = seqnum of leftmost existing record
cmp.w index(a2), d0 ; compare that to this app's assigned seqnum
blo.s @Insert ; left seq < free seq, left rec newer than caller's
; Move the existing leftmost record to the newly selected seqnum and the
; caller's app at the (freed up) seqnum of the existing leftmost
; record. We know that the iterator left us one to the left of the leftmost
; record.
@DoASwap:
move.l ioFlCreator(a4), APPLKey.CrType+Key(a2) ; iterator always bumps into previous creator type
move.w theSeqNum(a2), APPLKey.SeqNum+Key(a2) ; we want the leftmost record
go_BTSearch ; get the leftmost record
move.w index(a2), APPLKey.SeqNum+Key(a2) ; use the selected free seqnum
go_BTSetRec ; move the leftmost record into the list at the free spot
move.w theSeqNum(a2), d1 ; and add the new record at the leftmost position
; Add the caller's application at the sequence number in d1
@Insert:
lea.l APPLKey.Len+Key(a2), a1 ; a1 = ptr(APPL key)
move.b #APPLKey.AKLen-1, (a1)+ ; make a full length APPL key (-1 for length byte)
move.b #APPLKeyType, (a1)+ ; make it an APPL key
move.l ioFlCreator(a4), (a1)+ ; use the caller's creator
move.w d1, (a1)+ ; use the seqnum in d1
lea.l APPLRec.TagInfo+Data(a2), a1 ; a1 = ptr(APPL record)
move.l crDate(a2), (a1)+ ; use this app's creation date
move.l AppSpec+FSSpec.parId(a2), (a1)+ ; and parent ID
lea.l AppSpec+FSSpec.name(a2), a0 ; a0 = ptr(CName of app)
moveq.l #0, d0 ; clear high bytes
move.b (a0), d0 ; name length into d0 (+1 for itself, -1 for dbra)
@loop:
move.b (a0)+, (a1)+
dbra d0, @loop
lea.l bigPB(a2), a0 ; get our param block pointer back
go_BTSetRec ; all fields are still valid
bra.s @Exit ; return the error straight back
@NoErrExit:
moveq.l #0, d0
@Exit:
bsr SaveHintInDTDBQElt ; save off the hint
@Exit2:
add.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @AddAPPLRegs
bra DTDone ; We're all set.
endwith
_DTDebugRts 'DTAddAPPL',0
endproc
;________________________________________________________________________________
; Routine: RemoveAPPLCallback
;
; Input: a0 - BT param block with valid hint, key, and data pointers
; a1 - callback procedure
; a2 - standard APPL locals
; a3 - DTDBQElt pointer
; d1 - creator type
;
; Output: a0 - BT param block
; a1 - callback procedure
; a2 - standard locals (param block, key, data)
; a3 - DTDBQElt pointer
; d0 - zero to signal end of iteration; nonzero otherwise
; d1 - creator type
;
; Function:
; This routine will get called once per APPL entry with a creator matching the
; one of the application being removed to the list.
; It does these things:
; Look for an entry whose name and dirID match the caller's pb
; If there's a match, find out if it is the leftmost entry
; Keep track of the youngest non-matching app seen, in case
; the matching app was leftmost and the youngest one needs to
; be found and made leftmost.
;
;________________________________________________________________________________
;
RemoveAPPLCallback: proc
with APPLLocals
add.w #1, count(a2) ; tally this record
btst.b #applFoundAMatch, flags(a2) ; have we already seen a match?
beq.s @NoMatchYet ; if not, keep on looking
bset.b #applNotLeftmost, flags(a2) ; we've seen a match, and now another
; record, which means that the match
; wasn't the leftmost (youngest) entry,
; so no rebalancing will be necessary.
moveq.l #0, d0 ; Tell the iterator to chill out
bra.s @Exit ; And we're done iterating
@NoMatchYet:
move.l APPLRec.parID+Data(a2), d0 ; pick up the ParID
cmp.l AppSpec.parID(a2), d0 ; entry in the same folder? <19>
bne.s @NotAMatch
bsr APPLCompareNames ; are the names the same?
bne.s @NotAMatch ; no ->
; The current application record has the same creator, parID and name as the app
; being added.
bset.b #applFoundAMatch, flags(a2) ; remember that we've found it
move.w APPLKey.SeqNum+Key(a2), index(a2) ; remember its SeqNum
bra.s @KeepIterating ; and go look for a more-leftmost entry
; The current entry is a miss. Check to see if it is the "newest" to date in the
; scan
@NotAMatch:
move.l theDate(a2), d0 ; date of the current "youngest"
cmp.l APPLRec.TagInfo+Data(a2), d0 ; is this record younger?
bhi.s @KeepIterating ; if not, just keep going
move.w APPLKey.SeqNum+Key(a2), theSeqNum(a2) ; remember this SeqNum
move.l APPLRec.TagInfo+Data(a2), theDate(a2) ; remember this date
@KeepIterating:
moveq.l #1, d0 ; tell the iterator to keep at it
@Exit:
rts
endwith
_DTDebugTail 'RemoveAPPLCallback',0
endproc
;________________________________________________________________________________
; Routine: DTRemoveAPPL
;
; Input: a0 - user's DT param block
; Output: d0 - result code
;
; Register Use: a0 - bt param block
; a1 -
; a2 - locals
; a3 - DTDBQElt
; a4 - user's param block
;
; Function: Delete an entry for an application in the application list
;
; Remove the given application to the app list. If this application is younger than
; all existing applications, make sure that after it is deleted the next-youngest
; app is promoted to the front of the list.
;________________________________________________________________________________
DTRemoveAPPL: proc export
@RemoveAPPLRegs reg a0-a4/d1-d2
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; wait our turn
with APPLLocals
movem.l @RemoveAPPLRegs, -(a6)
suba.w #LSize, a6 ; allocate locals
movea.l a6, a2 ; set up a2 as locals ptr
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne @Exit2 ; Punt on any errors
lea.l bigPB(a2), a0 ; a0 = ptr(param block)
move.l ioFileName(a4), ioFileName(a0) ; use user's application name
move.w DTDBQElt.XVRefNum(a3), ioVRefNum(a0); use correct volume ref
move.l ioDirID(a4), ioDirID(a0) ; use user's DirID
lea.l AppSpec(a2), a1 ; address of our FSSpec record
move.l a1, ioFSSpecPtr(a0) ; tell the param block about it
go_MakeFSSpec
beq.s @1 ; no err? How pleasant.
cmp.w #fnfErr, d0 ; app doesn't have to be here
bne.s @Exit2 ; other errors spell trouble
@1:
clr.b flags(a2) ; clear all iterator signal flags
clr.l theDate(a2) ; oldest possible create date
clr.w theSeqNum(a2) ; indicate no younger APPL in the list
clr.w count(a2) ; we've seen no records
move.l ioFlCreator(a4), d1 ; d1 = creator type for APPL entry to delete
bsr SetUpAPPLIterator ; get ready to look through existing entries
lea.l RemoveAPPLCallback, a1 ; a1 = ptr(RemoveAPPL's iterator callback)
bsr APPLIterator ; go look at existing records
btst.b #applFoundAMatch, flags(a2) ; did we see a hit?
beq.s @NoMatchFound
move.l ioFlCreator(a4), APPLKey.CrType+Key(a2) ; put our creator back into key
; We saw a hit. There are several things to consider, in this order
; 1) If there are only one or two records, we never need to re-balance
; 2) If the hit wasn't leftmost, we don't need to re-balance
; 3) If the hit was the leftmost record, we need to re-balance.
cmp.w #2, count(a2) ; did we see more than 2 records?
bls.s @DeleteMatch ; if not, just go delete the hit
btst.b #applNotLeftmost, flags(a2) ; was the hit leftmost?
bne.s @DeleteMatch ; if not, just go delete it
; We need to rebalance. Since we know the seqnums of the youngest record
; and the seqnum of the leftmost record, we'll just get the youngest and
; set it into the leftmost position.
move.w theSeqNum(a2), APPLKey.SeqNum+Key(a2) ;
go_BTSearch ; get the youngest
bne.s @Exit ; errors are trouble
move.w index(a2), APPLKey.SeqNum+Key(a2) ; leftmost SeqNum
go_BTReplRec ; replace match with youngest
bne.s @Exit ; errors are trouble
move.w theSeqNum(a2), index(a2) ; aim our upcoming delete at
; the old position of the youngest
@DeleteMatch:
move.w index(a2), APPLKey.SeqNum+Key(a2)
go_BTDelRec ; delete the match (or the old
; position of the youngest)
bra.s @Exit ; pass errors straight back
@NoMatchFound:
move.l #btRecNotFnd, d0 ; tell'em about it and give up
@Exit:
bsr SaveHintInDTDBQElt ; save off the hint <21>
@Exit2:
adda.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @RemoveAPPLRegs ; restore registers
bra DTDone ; We're all set.
endwith
_DTDebugRts 'DTRemoveAPPL',0
endp
;________________________________________________________________________________
;
; Routine: DTGetAPPL
;
; Input: a0 points to user's DTParam
; Output: d0 contains result code
;
; Function: Retrieve an APPL entry from the Desktop database by Creator/index
;________________________________________________________________________________
DTGetAPPL: proc export
StandardLocals GetAPPLLocals, APPLRec
@GetAPPLRegs reg a0-a4/d1-d2 ; set of regs to save around GetAPPL
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; Wait our turn
with GetAPPLLocals ; Key and Data refer to locals
movem.l @GetAPPLRegs, -(a6)
suba.w #LSize, a6 ; allocate locals on a6
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne @GetAPPLExit2 ; and run if we see trouble
bsr SetUpBTPB ; a0 = ptr(BTioParam), a2 = ptr(key)
move.l #APPLRec.ARLen, ioReqCount(a0) ; indicate size of an APPL data record
move.b #APPLKey.AKLen-1, (a2)+ ; set APPL key length (minus length byte)
move.b #APPLKeyType, (a2)+ ; and APPL type
move.l ioFlCreator(a4), (a2)+ ; look for user's creator
clr.l (a2)+ ; and a value "left" of all seqnums
go_BTSearch
cmp.w #btRecNotFnd, d0 ; was the error a simple not found?
bne.s @GetAPPLExit ; no, must be something more serious
move.w ioIndex(a4), d0 ; get the user's requested index
tst.w d0 ; is index 0?
bne.s @notSpecial ; if not, don't adjust
moveq.l #1, d0 ; caller wants "best" app, which happens to be 1st one
@notSpecial:
subq.w #1, d0 ; the user's index starts at 1
move.w d0, ioBTPosMode(a0) ; tell the btree the record offset
move.w #APPLKey.AKLen, ioKReqCount(a0) ; tell the btree how much space for key return
go_BTGetRec
bne.s @GetAPPLExit ; Punt on errors
move.b APPLKey.Type+Key(a6), d0 ; pick up the key ID
cmp.b #APPLKeyType, d0 ; is this record an APPL entry?
beq.s @FoundAPPL ; yes - check the creators ; <dnf 1.4>
move.w #btRecNotFnd, d0 ; no - search failed
bra.s @GetAPPLExit ; So punt
@FoundAPPL: ; ; <dnf 1.4>
move.l APPLKey.CrType+Key(a6), d0 ; pick up this APPL entries' creator ; <dnf 1.4>
cmp.l ioFlCreator(a4), d0 ; is it still the same as the caller's? ; <dnf 1.4>
beq.s @FoundOne ; yes - return information ; <dnf 1.4>
move.w #btRecNotFnd, d0 ; no - search failed ; <dnf 1.4>
bra.s @GetAPPLExit ; So punt ; <dnf 1.4>
@FoundOne:
move.l APPLRec.TagInfo+Data(a6), ioTagInfo(a4) ; return tag information
move.l APPLRec.parID+Data(a6), ioFlParID(a4) ; return ParID
tst.l ioFileName(a4) ; did the user want the file name?
beq.s @NoCopy ; no - don't copy it over
lea.l APPLRec.CName+Data(a6), a0 ; a0 = ptr(the Cname string)
movea.l ioFileName(a4), a1 ; a1 = ptr(user's Cname string)
moveq.l #0, d0 ; clear high bytes
move.b (a0), d0 ; get length
addq.b #1, d0 ; add one for the length byte
_BlockMove ; copy the string over
@NoCopy:
moveq.l #0,d0 ; All is well.
@GetAPPLExit:
bsr DoneBTPB ; finish up with the BTPB <21>
@GetAPPLExit2:
adda.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @GetAPPLRegs
bra DTDone ; We're all set.
endwith
_DTDebugRts 'DTGetAPPL',0
endp
;________________________________________________________________________________
;
; Routine: DTSetComment
;
; Input: a0 points to user's DTParam
; Output: d0 contains result code
;
; Function: Add a comment for a file or folder to the Desktop database
;________________________________________________________________________________
DTSetComment: proc export
StandardLocals SetCommentLocals, CommentRec
@SetCommentRegs reg a0-a4/d1-d2 ; set of regs to save around SetComment
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; Wait our turn
with SetCommentLocals ; Key and Data refer to locals
movem.l @SetCommentRegs, -(a6)
suba.w #LSize, a6 ; allocate locals on a6
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne.s @AddCmtExit ; exit, stage left, if, like, errors are happenin
bsr CheckCSpec ; Make sure the file or directory exists
bne.s @AddCmtExit ; Punt on errors
;
; Build a Comment data record. Notice that since we build the data record at Data(a6),
; SetUpBTPB will automatically point the BTParam at it.
;
moveq.l #0, d0 ; clear high bytes (for _BlockMove)
move.l ioReqCount(a4), d0 ; get comment text length
cmp.l #MaxCommentLen, d0 ; is the comment too large?
bls.s @NoClip ; if not, no need to clip it
move.l #MaxCommentLen, d0 ; clip length to max
@NoClip:
move.b d0, CommentRec.CmtSize+Data(a6) ; set the comment length
move.l ioBuffer(a4), a0 ; get ready to copy the user's data
lea.l CommentRec.CmtData+Data(a6), a1 ; into the Comment record
_BlockMove ; copy that comment...
bsr SetUpBTPB ; a0 = ptr(BTioParam), a2 = ptr(key)
moveq.l #0, d0 ; clear high bytes
move.b CommentRec.CmtSize+Data(a6), d0 ; d0 = size of comment data
addq.b #1, d0 ; add one for length byte
move.l d0, ioReqCount(a0) ; tell BTParam how big this comment record is
move.b #CommentKey.CKLen-1, (a2)+ ; set key length (minus length byte)
move.b #CommentKeyType, (a2)+ ; set key type
move.l d1, (a2)+ ; d1 still has CNodeID from CheckCSpec
go_BTSetRec
bsr DoneBTPB ; finish up with the BTPB <21>
@AddCmtExit:
adda.w #LSize, a6 ; dispose of locals
movem.l (a6)+, @SetCommentRegs ; restore regs
bra DTDone ; We're all set.
endwith
_DTDebugRts 'DTSetComment',0
endproc
;________________________________________________________________________________
;
; Routine: DTGetComment
;
; Input: a0 points to user's DTParam
; Output: d0 contains result code
;
; Function: Retrieve a comment for a file or folder from the Desktop database
;________________________________________________________________________________
DTGetComment: proc export
StandardLocals GetCommentLocals, CommentRec
@GetCommentRegs reg a0-a4/d1-d2 ; set of regs to save around GetComment
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; Wait our turn
with GetCommentLocals ; Key and Data refer to locals
movem.l @GetCommentRegs, -(a6)
suba.w #LSize, a6 ; allocate locals on a6
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne.s @GetCommentExit ; Errors? Run and hide.
clr.l ioActCount(a4) ; in case we don't make it
bsr CheckCSpec ; Look up the CNode's CNID
bne.s @GetCommentExit ; punt on errors
@GCGotCNID:
bsr SetUpBTPB ; a0 = ptr(BTioParam), a2 = ptr(key)
move.l #CommentRec.CRLen, ioReqCount(a0) ; indicate size of a comment record
move.b #CommentKey.CKLen-1, (a2)+ ; set the key length (minus length byte)
move.b #CommentKeyType, (a2)+ ; and the type
move.l d1, (a2)+ ; d1 = CNodeID of requested file (from CheckCSpec)
go_BTSearch ; go get that comment
bsr DoneBTPB ; finish up with the BTPB <21>
bne.s @GetCommentExit ; Yipes! an error!
moveq.l #0, d0 ; clear high bytes
move.b CommentRec.CmtSize+Data(a6), d0 ; d0 = length of comment data
cmp.b #MaxCommentLen, d0 ; for some strange reason, is comment too big?
bls.s @sizeOK
move.b #MaxCommentLen, d0 ; clip it.
@sizeOK:
move.l d0, ioActCount(a4) ; tell the user how much data there was
lea.l CommentRec.CmtData+Data(a6), a0 ; copy starts from the Data
move.l ioBuffer(a4), a1 ; a1 = address of user's buffer
_BlockMove ; put the Comment Data in the user's buffer
moveq.l #0,d0 ; All went well
@GetCommentExit:
adda.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @GetCommentRegs
bra DTDone ; We're all set.
endwith
_DTDebugRts 'DTGetComment',0
endproc
;________________________________________________________________________________
;
; Routine: DTRemoveComment
;
; Input: a0 points to user's DTParam
; Output: d0 contains result code
;
; Function: Remove a comment for a file or folder from the Desktop database
;________________________________________________________________________________
;
DTRemoveComment: proc export
StandardLocals RemoveCommentLocals, 0 ; we only need a pb and a key here. Zero Data
@RemoveCommentRegs reg a0-a4/d1-d2 ; set of regs to save around RmvCmt
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; Wait our turn
with RemoveCommentLocals ; Key and Data refer to locals
movem.l @RemoveCommentRegs, -(a6) ; save regs
suba.l #LSize, a6 ; allocate and clear locals on a6
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne.s @RmvCmtExit ; Zorro defects
bsr CheckCSpec ; does the file exist? (d1 = CNodeID)
bne.s @RmvCmtExit ; punt on errors
bsr SetUpBTPB ; a0 = ptr(BTparam), a2 = ptr(key)
move.b #CommentKey.CKLen-1, (a2)+ ; set key length (minus length byte)
move.b #CommentKeyType, (a2)+ ; it's a comment key
move.l d1, (a2)+ ; d1 = CNodeID of file to delete comment for
go_BTDelRec
bsr DoneBTPB ; finish up with the BTPB <21>
@RmvCmtExit:
adda.w #LSize, a6 ; deallocate locals
movem.l (a6)+, @RemoveCommentRegs
bra DTDone ; We're all set.
endwith
_DTDebugRts 'RmvComment',0
endp
;________________________________________________________________________________
;
; Routine: DTFlush
;
; Input: a0 points to user's DTParam
; Output: d0 contains result code
;
; Function: Flush buffers associated with a database
;________________________________________________________________________________
DTFlush: proc export
DTFlushLocals record 0, increment
bigPB ds.b DTBigPBSize ; big enough for all HFS calls
LSize equ *-bigPB
endr
@DTFlushRegs reg a0/a3-a4
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; wait our turn
with DTFlushLocals
movem.l @DTFlushRegs, -(a6) ; save regs
suba.w #LSize, a6 ; allocate locals on file system stack
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne.s @DTFlushExit ; punt on errors
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.w DTDBQElt.DBRefNum(a3), ioRefNum(a0) ; use the btree file refnum
go_BTFlush
bne.s @DTFlushExit ; punt on errors
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.w DTDBQElt.VRefNum(a3), ioVRefNum(a0) ; use the data file refnum
clr.l ioVNPtr(a0) ; no name needed <21>
go_FlushVol ; flush a volume at a time <21>
@DTFlushExit:
adda.w #LSize, a6
movem.l (a6)+, @DTFlushRegs
bra DTDone
endwith
_DTDebugRts 'DTFlush',0
endproc
;________________________________________________________________________________
;
; Routine: DTReset
;
; Input: a0 points to user's DTParam
; Output: d0 contains result code
;
; Function: Reinitialize the btree files (leaving them both open)
; SetEOF on both to zero
; Call BTInit on the BTree file
;________________________________________________________________________________
DTReset: proc export
DTResetLocals record 0, increment
bigPB ds.b DTBigPBSize ; big enough for all HFS calls
DBName ds.b 32 ; holds btree file name
DBParID ds.l 1 ; ParID of btree file
LSize equ *-bigPB
endr
@DTResetRegs reg a0-a4/d1-d2
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; wait our turn
with DTResetLocals
movem.l @DTResetRegs, -(a6) ; save regs
suba.w #LSize, a6 ; allocate locals on file system stack
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne @DTResetExit ; and punt on errors
;
; Get the name and parent ID of the btree file
;
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
lea.l DBName(a6), a1 ; a1 = ptr(space for btree file name)
move.l a1, ioFileName(a0) ; tell the param block about it
clr.w ioVRefNum(a0) ; look at all FCB's
move.w DTDBQElt.DBRefNum(a3), ioRefNum(a0) ; look for the btree file
clr.l ioFCBIndx(a0) ; and look only by ioRefNum
go_GetFCBInfo
bne @DTResetExit
move.l ioFCBParID(a0), DBParID(a6) ; stash btree's parID
;
; Free up all of the space in both files
;
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.w DTDBQElt.DBRefNum(a3), ioRefNum(a0) ; zap the btree file
clr.l ioLEOF(a0) ; deallocate all space
go_SetEOF
bne @DTResetExit ; errors are serious trouble here
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.w DTDBQElt.DFRefNum(a3), ioRefNum(a0) ; zap the data file
clr.l ioLEOF(a0) ; deallocate all space
go_SetEOF
bne @DTResetExit ; errors are serious trouble here
;
; <21> To minimize fragmentation, we extend the icon datafile by a bunch each time
;
move.l DTDBQElt.DFClumpSize(a3), ioReqCount(a0) ; d1 = the data file's clump size
go_Allocate ; Request the additional space
;
; Close the btree file so we can BTInit it
;
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
move.w DTDBQElt.DBRefNum(a3), ioRefNum(a0)
go_BTClose
bne.s @DTResetExit
;
; Now call BTInit on the btree file
;
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
lea.l DBName(a6), a1 ; a1 = ptr(DB file name)
move.l a1, ioFileName(a0) ; use btree file name
move.w DTDBQElt.VRefNum(a3), ioVRefNum(a0) ; use the volume the file was on
move.w #DTMaxKeySize, ioBTMaxKLen(a0) ; set maximum key size
clr.l ioBTClumpSize(a0) ; use volume clump size
move.l DBParID(a6), ioDirID(a0) ; use DirID from when it was open
pea.l DTKeyDescriptor ; push pointer to our key descriptor
move.l (sp)+, ioBTKDPtr(a0) ; and tell the btree about it
go_BTInit ; initialize btree file
bne.s @DTResetExit
;
; And then open it back up
;
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
lea.l DBName(a6), a1 ; a1 = ptr(DB file name)
move.l a1, ioFileName(a0) ; use the name it had when it was open
move.w DTDBQElt.VRefNum(a3), ioVRefNum(a0) ; use vRef from when it was open
move.b #fsRdWrPerm, ioPermssn(a0) ; use exclusive read/write perm
move.l DBParID(a6), ioDirID(a0) ; use DirID from when it was open
pea.l DTKeyCmp ; use our own key comparison procedure
move.l (sp)+,ioBTKCProc(a0)
go_BTOpen
bne @DTResetExit ; punt if there's trouble
move.w ioRefNum(a0), DTDBQElt.DBRefNum(a3) ; save away the btree file refnum
moveq.l #noErr, d0 ; we made it.
@DTResetExit:
adda.w #LSize, a6
movem.l (a6)+, @DTResetRegs
bra DTDone
endwith
_DTDebugRts 'DTReset',0
endproc
;________________________________________________________________________________
; Routine: DTDelete
;
; Input: a0 points to param block with ioVRefNum
; Output: d0 contains result code
;
; Function: Delete all files that make up the desktop database
; Note that DTReset only works if the desktop database can be
; opened, while DTDelete takes a volume refnum
;________________________________________________________________________________
DTDelete: proc export
DTDeleteLocals record 0, increment
bigPB ds.b DTBigPBSize ; big enough for all HFS calls
DBName ds.b 32 ; holds btree file name
DBParID ds.l 1 ; ParID of btree file
LSize equ *-bigPB
endr
@DTDeleteRegs reg a0-a4/d1-d2
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTVolExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; wait our turn
with DTDeleteLocals
movem.l @DTDeleteRegs, -(a6) ; save regs
suba.w #LSize, a6 ; allocate locals on file system stack
movea.l a0, a4 ; move user's DTParam to a safe register
move.l FSVarsPtr, a3 ; a3 = ptr(file system global area)
move.l FSVars.DTDBMgr(a3), a3 ; a3 = ptr(DTDB manager's global area)
move.w DTGlobals.targetVRef(a3), d0 ; get caller's target volume
move.w d0, d2 ; save a copy
bsr FindDTVol ; is this volume's database already open?
beq.s @DatabaseOpenExit ; if so, we can't delete the files
lea.l DBName(a6), a1 ; a1 = ptr(space for database file name)
move.w d2, d0 ; d0 = vRef
bsr FindDTFiles ; go look for the database files
; note that we don't bother to look for errors here
; delete the btree file
lea.l bigPB(a6), a0
move.l a1, ioNamePtr(a0) ; aim at the btree file
move.w d1, ioVRefNum(a0) ; on the right volume
move.l d2, ioDirID(a0) ; in the right directory
go_HDelete ; ignore errors
moveq.l #0, d0 ; clear high bytes
move.b (a1), d0 ; get length of btree file name
move.b #'F', (a1, d0.w) ; change name to datafile name
go_HDelete ; ignore errors
moveq.l #noErr, d0 ; we always "succeed"
bra.s @DTDeleteExit
@DatabaseOpenExit:
moveq.l #fBsyErr, d0 ; can't delete if the database is open
@DTDeleteExit:
adda.w #LSize, a6
movem.l (a6)+, @DTDeleteRegs
bra DTDone
endwith
_DTDebugRts 'DTDelete',0
endproc
;________________________________________________________________________________
; Routine: DTGetInfo
;
; Input: a0 points to user's DTParam
; Output: d0 contains result code
;
; Function: Returns informative and entertaining facts about today's desktop
;
; ioFlLgLen gets the sum of the logical lengths of the desktop files
; ioFlPyLen gets the sum of the physical lengths of the desktop files
; ioDTFlCnt gets the number of desktop files
; ioDirID gets the parent directory of the desktop files
;
; Even though neither file normally has a resource fork, we compute them
; in in case someone has added one.
;________________________________________________________________________________
DTGetInfo: proc export
GetDTILocals record 0, increment
bigPB ds.b DTBigPBSize ; big enough for all HFS calls
CName ds.b 32 ; space for a name
LSize equ *-bigPB
endr
@DTGetInfoRegs reg a0-a4/d1-d2
2020-03-22 08:44:21 +00:00
jsrROM ROMFSQUEUE ; just to check for external file systems ex<SM1><Sys7.1> Put back "ROM"
2019-07-27 14:37:48 +00:00
bsr DTRfnExtFSCheck ; find the right volume and hope it's ours
bsr DeskMgrQueue ; wait our turn
with GetDTILocals
movem.l @DTGetInfoRegs, -(a6) ; save regs
suba.w #LSize, a6 ; allocate locals on file system stack
movea.l a0, a4 ; move user's DTParam to a safe register
bsr DTSetup ; Do common setup. a3 = ptr(DTDBQElt)
bne.s @DTGetInfoExit ; and punt on errors
lea.l bigPB(a6), a0 ; a0 = ptr(param block)
lea.l CName(a6), a1 ; space for a name
move.l a1, ioNamePtr(a0) ; tell 'em where to put the name
clr.l ioDTLgLen(a4) ; clear out so we can add <29>
clr.l ioDTPyLen(a4) ; <29>
move.w DTDBQElt.DBRefNum(a3), ioRefNum(a0) ; use the btree file
bsr.s @AddFileSizes
bne.s @DTGetInfoExit
move.w DTDBQElt.DFRefNum(a3), ioRefNum(a0) ; use the data file
bsr.s @AddFileSizes
bne.s @DTGetInfoExit
move.w #2, ioDTFlCnt(a4) ; indicate # of desktop files
move.w DTDBQElt.VRefNum(a3), ioVRefNum(a4) ; indicate volume with files
moveq.l #0, d0 ; we succeeded <29>
@DTGetInfoExit:
adda.w #LSize, a6
movem.l (a6)+, @DTGetInfoRegs
bra DTDone
; assumes
; a0 - param block with refnum and name pointer set up
; a4 - user dt param block
;
@AddFileSizes:
move.l (sp)+, -(a6) ; <18>
clr.l ioFCBIndx(a0) ; return info by refnum only
go_GetFCBInfo
bne.s @scram
move.l ioFCBParID(a0), ioDirID(a0) ; move for GetCatInfo call
clr.w ioFDirIndex(a0) ; by name & vref
go_HGetFileInfo ; <21>
bne.s @scram
move.l ioDTLgLen(a4), d0 ; get the current value <29>
add.l ioFlLgLen(a0), d0 ; add in data fork logical length
add.l ioFlRLgLen(a0), d0 ; add in the resource fork logical length
move.l d0, ioDTLgLen(a4) ; stash it away <29>
move.l ioDTPyLen(a4), d0 ; get the current value <29>
add.l ioFlPyLen(a0), d0 ; add in data fork physical length
add.l ioFlRPyLen(a0), d0 ; add in the resource fork physical length
move.l d0, ioDTPyLen(a4) ; stash it away <29>
moveq.l #0,d0 ; we succeeded <29>
@scram:
move.l (a6)+, -(sp) ; <18>
tst.w d0 ; <29>
rts ; rah
endwith
_DTDebugTail 'DTGetInfo',0
endproc
;________________________________________________________________________________
;
; 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.
;________________________________________________________________________________
;
DTKeyCmp: proc
MOVEM.L A0-A1/D1,-(SP) ; Save away scratch registers
;
; 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 MOVEM.L (SP)+,A0-A1/D1 ; Restore scratch registers [leaves CC alone]
RTS ; And call it a day, leaving CC set from D0
;________________________________________________________________________________
;
; Routine: deepShitError
;
; Input:
; Output:
;
; Function: Called when an error that shouldn't happen has, and the system
; is in an inconsistent state.
;
; Called when our request for unmount notification fails.
; Called in an _enqueue fails in OpenDT
; Called if a _dequeue fails in CloseDT
;________________________________________________________________________________
deepShitError proc
move.w #HFSDSErr, d0
_SysError ; bye-bye
endproc
end