2020-03-22 08:44:21 +00:00
|
|
|
|
;
|
|
|
|
|
; Hacks to match MacOS (most recent first):
|
|
|
|
|
;
|
|
|
|
|
; <Sys7.1> 8/3/92 Reverted <SM3> 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: ExternalMakeFSSpec.a
|
|
|
|
|
;
|
|
|
|
|
; Contains: Code to perform emulation of the MakeFSSpec call
|
|
|
|
|
; for external file systems that don't support it
|
|
|
|
|
; themselves.
|
|
|
|
|
;
|
|
|
|
|
; This file can be assembled into code that relies on an a6 stack
|
|
|
|
|
; and QMgr.a-style queueing or into a simple subroutine for glue
|
|
|
|
|
; libraries. -d MakeGlue=0 should be used in system builds and
|
|
|
|
|
; -d MakeGlue=1 for glue library builds.
|
|
|
|
|
;
|
|
|
|
|
; Written by: Dave Feldman
|
|
|
|
|
;
|
|
|
|
|
; Copyright: © 1990-1991, 1993 by Apple Computer, Inc., all rights reserved.
|
|
|
|
|
;
|
|
|
|
|
; Change History (most recent first):
|
|
|
|
|
;
|
|
|
|
|
; <SM3> 6/9/93 pdw Changed register saving from interruptRegs to pascalRegs in
|
|
|
|
|
; myCompletionRoutine because it can be called from pascal (as it
|
|
|
|
|
; is when FileShare is running). Fixes a FileShare crash that
|
|
|
|
|
; appears when doing async I/O.
|
|
|
|
|
; <4> 9/13/91 JSM Cleanup header.
|
|
|
|
|
; <3> 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.
|
|
|
|
|
; <2> 9/22/90 dnf Put real code in here
|
|
|
|
|
; <1> 8/7/90 dnf first checked in
|
|
|
|
|
;
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
LOAD 'StandardEqu.d'
|
|
|
|
|
include 'FileMgrPrivate.a'
|
|
|
|
|
|
|
|
|
|
; Get inspired and move these somewhere
|
|
|
|
|
fsSpecNameLength equ 63
|
|
|
|
|
pathSeparator equ ':' ; a colon character
|
|
|
|
|
|
|
|
|
|
; Values for d3.b during parsing
|
|
|
|
|
moreSegments equ 0 ; also implies a colon-terminated segment
|
|
|
|
|
finalSegmentColon equ 1 ; no more segments; path ended with a colon
|
|
|
|
|
finalSegmentNoColon equ -1 ; no more segments; path didn't end with a colon
|
|
|
|
|
|
|
|
|
|
; For patch or ROM builds we need to include an i/o bottleneck to handle async calls.
|
|
|
|
|
; The bottleneck code assumes QMgr.a-style queueing.
|
|
|
|
|
|
|
|
|
|
if not(MakeGlue) then
|
|
|
|
|
|
|
|
|
|
include 'QMgrEqu.a'
|
|
|
|
|
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
;
|
|
|
|
|
; Routine: myBottleNeckIO
|
|
|
|
|
;
|
|
|
|
|
; Input: a0 points to param block
|
|
|
|
|
; 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
|
|
|
|
|
|
|
|
|
|
myBottleNeckIO proc
|
|
|
|
|
import GetQMRecPtr
|
|
|
|
|
entry myCompletionRoutine
|
|
|
|
|
export myContCompatThread ; should be entry, but patch linker is dumb
|
|
|
|
|
export myContAppThread ; should be entry, but patch linker is dumb
|
|
|
|
|
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 myCompletionRoutine, a1 ; get our ioCompletion routine address
|
|
|
|
|
move.l a1, ioCompletion(a0) ; and install it into the param block
|
|
|
|
|
|
|
|
|
|
move.w #fsCompatQType, d2 ; our queue type/refnum
|
|
|
|
|
bsr GetQMRecPtr ; a1 = ptr(QMRec)
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
; 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.
|
|
|
|
|
|
|
|
|
|
myCompletionRoutine:
|
|
|
|
|
move.w #fsCompatQType, d2 ; our queue type/refnum
|
|
|
|
|
bsr GetQMRecPtr ; a1 = ptr(QMRec)
|
|
|
|
|
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 <LW2>pdw <Sys7.1>
|
|
|
|
|
pea restoreInterruptRegs ; and get in the chain to restore them later <LW2>pdw <Sys7.1>
|
2019-07-27 14:37:48 +00:00
|
|
|
|
|
|
|
|
|
myContCompatThread:
|
|
|
|
|
move.w #fsCompatQType, d2 ; our queue type/refnum
|
|
|
|
|
bsr GetQMRecPtr ; a1 = ptr(QMRec)
|
|
|
|
|
movea.l QMRec.curStack(a1), a6 ; restore alt stack pointer
|
|
|
|
|
adda.w #Lsize, a6 ; clear off the locals
|
|
|
|
|
movem.l (a6)+, BottleNeckRegs ; restore compatibility layer thread registers
|
|
|
|
|
move.l (a6)+, -(sp) ; push compatibility layer thread return address
|
|
|
|
|
move.w ioResult(a0),d0 ; set the ol' status register <3>
|
|
|
|
|
anRTSInstruction:
|
|
|
|
|
rts ; and return to caller
|
|
|
|
|
|
|
|
|
|
myContAppThread:
|
|
|
|
|
; •• we're ignoring the possibility of immediate errors
|
|
|
|
|
bset.b #0, hasContinued(a6) ; mark that we've returned
|
|
|
|
|
bne.s myContCompatThread ; 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: ; <LW2>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
|
|
|
|
|
endproc
|
|
|
|
|
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
;
|
|
|
|
|
; Routine: DoAnA060Trap
|
|
|
|
|
;
|
|
|
|
|
; Input: a0 - paramblock
|
|
|
|
|
; d0 - HFSDispatch selector
|
|
|
|
|
;
|
|
|
|
|
; Output: a0 - paramblock
|
|
|
|
|
; d0 - result code
|
|
|
|
|
;
|
|
|
|
|
; Function: Fire off an a060 call
|
|
|
|
|
;
|
|
|
|
|
; Note: After myBottleNeckIO, Z = 1 -> async, Z = 0 -> sync.
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
DoAnA060Trap: proc
|
|
|
|
|
move.l (sp)+, -(a6) ; save thread ret addr on a6
|
|
|
|
|
bsr myBottleNeckIO ; do common set up
|
|
|
|
|
bne.s @1 ; zero flag set if async
|
|
|
|
|
_HFSDispatch ; sync trap
|
|
|
|
|
jmp myContCompatThread; keep going with this call
|
|
|
|
|
@1: _HFSDispatch async ; async trap
|
|
|
|
|
jmp myContAppThread ; keep going, but give async time to app
|
|
|
|
|
endproc
|
|
|
|
|
|
|
|
|
|
; 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
|
|
|
|
|
doSomeTrap &theTrap
|
|
|
|
|
move.l (sp)+, -(a6) ; save desktop thread ret addr on a6
|
|
|
|
|
bsr myBottleNeckIO ; do common set up
|
|
|
|
|
bne.s @1 ; zero flag set if async
|
|
|
|
|
_&theTrap ; sync trap
|
|
|
|
|
jmp myContCompatThread; keep going with this desktop call
|
|
|
|
|
@1: _&theTrap async ; async trap
|
|
|
|
|
jmp myContAppThread ; keep going, but give async time to app
|
|
|
|
|
endm
|
|
|
|
|
|
|
|
|
|
doGetCatInfo: proc
|
|
|
|
|
move.w #selectGetCatInfo, d0
|
|
|
|
|
jmp DoAnA060Trap
|
|
|
|
|
endproc
|
|
|
|
|
|
|
|
|
|
doGetWDInfo: proc
|
|
|
|
|
move.w #selectGetWDInfo, d0
|
|
|
|
|
jmp DoAnA060Trap
|
|
|
|
|
endproc
|
|
|
|
|
|
|
|
|
|
doGetVolInfo: proc
|
|
|
|
|
doSomeTrap GetVolInfo
|
|
|
|
|
endproc
|
|
|
|
|
|
|
|
|
|
doHGetVol: proc
|
|
|
|
|
doSomeTrap HGetVol
|
|
|
|
|
endproc
|
|
|
|
|
|
|
|
|
|
macro
|
|
|
|
|
go_GetCatInfo
|
|
|
|
|
bsr doGetCatInfo
|
|
|
|
|
endm
|
|
|
|
|
|
|
|
|
|
macro
|
|
|
|
|
go_GetWDInfo
|
|
|
|
|
bsr doGetWDInfo
|
|
|
|
|
endm
|
|
|
|
|
|
|
|
|
|
macro
|
|
|
|
|
go_GetVolInfo
|
|
|
|
|
bsr doGetVolInfo
|
|
|
|
|
endm
|
|
|
|
|
|
|
|
|
|
macro
|
|
|
|
|
go_HGetVol
|
|
|
|
|
bsr doHGetVol
|
|
|
|
|
endm
|
|
|
|
|
|
|
|
|
|
; For glue we can go straight to traps
|
|
|
|
|
else
|
|
|
|
|
|
|
|
|
|
macro
|
|
|
|
|
go_GetCatInfo
|
|
|
|
|
_GetCatInfo
|
|
|
|
|
endm
|
|
|
|
|
|
|
|
|
|
macro
|
|
|
|
|
go_GetWDInfo
|
|
|
|
|
_GetWDInfo
|
|
|
|
|
endm
|
|
|
|
|
|
|
|
|
|
macro
|
|
|
|
|
go_GetVolInfo
|
|
|
|
|
_GetVolInfo
|
|
|
|
|
endm
|
|
|
|
|
|
|
|
|
|
macro
|
|
|
|
|
go_HGetVol
|
|
|
|
|
_HGetVol
|
|
|
|
|
endm
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
;
|
|
|
|
|
; Routine: ResetPathnameParser
|
|
|
|
|
;
|
|
|
|
|
; Input: a4 - caller's param block (uses ioNamePtr)
|
|
|
|
|
;
|
|
|
|
|
; Output: d1.l - number of characters in string (could be zero)
|
|
|
|
|
; a1 - pointer to first character in string (or nil)
|
|
|
|
|
;
|
|
|
|
|
; Function: Set registers used by parser to cause it to start at the beginning
|
|
|
|
|
; of the string when it is next called.
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
ResetPathnameParser: proc
|
|
|
|
|
|
|
|
|
|
moveq.l #0, d1 ; clear high bytes
|
|
|
|
|
move.l ioNamePtr(a4), d0 ; grab pathname pointer and set ccr's
|
|
|
|
|
movea.l d0, a1 ; move to a1 even if it's nil
|
|
|
|
|
beq.s @Exit
|
|
|
|
|
move.b (a1)+, d1 ; get the length and point at 1st char
|
|
|
|
|
@Exit:
|
|
|
|
|
rts
|
|
|
|
|
endproc
|
|
|
|
|
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
;
|
|
|
|
|
; Routine: ParseNextSegment
|
|
|
|
|
;
|
|
|
|
|
; Input: a1 - current location along pathname string
|
|
|
|
|
; a2 - pointer to FSSpec under construction
|
|
|
|
|
;
|
|
|
|
|
; d1.w - characters remaining in string in front of a1
|
|
|
|
|
;
|
|
|
|
|
; Output: a1 - update to new position along pathname string
|
|
|
|
|
; a2 - pointer to FSSpec under construction
|
|
|
|
|
;
|
|
|
|
|
; d0.w - error code (negative)
|
|
|
|
|
; d1.w - characters remaining in string in front of a1
|
|
|
|
|
;
|
|
|
|
|
; d3.l - stuff
|
|
|
|
|
; 0 moreSegments implies a colon-terminated segment
|
|
|
|
|
; 1 finalSegmentColon no more segments; path ended with a colon
|
|
|
|
|
; -1 finalSegmentNoColon no more segments; path didn't end with a colon
|
|
|
|
|
;
|
|
|
|
|
; Z
|
|
|
|
|
; set - saw an empty segment
|
|
|
|
|
; clear - saw a non-empty segment or an error occurred
|
|
|
|
|
;
|
|
|
|
|
; N
|
|
|
|
|
; set - error code in d0
|
|
|
|
|
; clear - success
|
|
|
|
|
;
|
|
|
|
|
; Function:
|
|
|
|
|
; Parse through the characters at (a1) and copy the
|
|
|
|
|
; next leaf (i.e. file/directory) name into FSSpec.name.
|
|
|
|
|
;
|
|
|
|
|
; Use the Z flag to indicate the presense of a '::' in the path
|
|
|
|
|
;
|
|
|
|
|
; Input:
|
|
|
|
|
; if d1 > 0 then
|
|
|
|
|
; a1 must point to the first character in the new segment
|
|
|
|
|
;
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
; ParseNextSegmentRegs reg a0
|
|
|
|
|
ParseNextSegment: proc
|
|
|
|
|
|
|
|
|
|
move.l a0, -(sp) ; save one register
|
|
|
|
|
move.w d2, -(sp) ; only low word
|
|
|
|
|
|
|
|
|
|
moveq.l #0, d0 ; no chars in this segment yet
|
|
|
|
|
lea.l FSSpec.name+1(a2), a0 ; address of 1st char in leaf name buffer
|
|
|
|
|
|
|
|
|
|
subq.b #1, d1 ; subtract one for dbra
|
|
|
|
|
cmp.b #pathSeparator, (a1) ; is this a colon?
|
|
|
|
|
beq.s @DoubleColon ; that means there's been 2 in a row
|
|
|
|
|
|
|
|
|
|
@Loop:
|
|
|
|
|
move.b (a1)+, d2 ; get the next character
|
|
|
|
|
cmp.b #pathSeparator, d2 ; is this a colon?
|
|
|
|
|
beq.s @SingleColon ; if so, we've got a whole segment
|
|
|
|
|
|
|
|
|
|
addq.b #1, d0 ; count the character
|
|
|
|
|
cmp.b #fsSpecNameLength, d0 ; are we overflowing FSSpec.name?
|
|
|
|
|
bhs.s @Overflow ; we overflowed, run for our lives...
|
|
|
|
|
|
|
|
|
|
move.b d2, (a0)+ ; copy the char into leaf buffer
|
|
|
|
|
|
|
|
|
|
dbra d1, @Loop ; while more characters keep going
|
|
|
|
|
|
|
|
|
|
moveq.l #finalSegmentNoColon, d3 ; we fell off the end, implying no colon there
|
|
|
|
|
bra.s @Success
|
|
|
|
|
|
|
|
|
|
@DoubleColon:
|
|
|
|
|
addq.l #1, a1 ; skip past the colon
|
|
|
|
|
@SingleColon:
|
|
|
|
|
moveq.l #moreSegments, d3 ; pretend we have more
|
|
|
|
|
tst.w d1 ; was the colon also the last character?
|
|
|
|
|
bne.s @Success ; if not, keep going
|
|
|
|
|
moveq.l #finalSegmentColon, d3 ; indicate our fate (done, with a colon)
|
|
|
|
|
|
|
|
|
|
@Success:
|
|
|
|
|
move.b d0, FSSpec.name(a2) ; turn FSSpec.name into a PString
|
|
|
|
|
@Exit:
|
|
|
|
|
move.w (sp)+, d2 ; restore low word
|
|
|
|
|
movea.l (sp)+, a0 ; restore one register
|
|
|
|
|
tst.w d0 ; Z if empty string, N if error
|
|
|
|
|
rts
|
|
|
|
|
|
|
|
|
|
@Overflow:
|
|
|
|
|
moveq.l #bdNamErr, d0 ; bummer - too many characters in file name
|
|
|
|
|
bra.s @Exit
|
|
|
|
|
endproc
|
|
|
|
|
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
;
|
|
|
|
|
; Routine: DetermineVolume
|
|
|
|
|
;
|
|
|
|
|
; Input:
|
|
|
|
|
; a1 - beginning of pathname (or nil)
|
|
|
|
|
; a2 - pointer to FSSpec under construction
|
|
|
|
|
; a4 - caller's param block (uses ioVRefNum and ioDirID)
|
|
|
|
|
;
|
|
|
|
|
; d1 - # of characters in string (could be zero)
|
|
|
|
|
; Output:
|
|
|
|
|
; FSSpec.vRefNum contains volume reference number
|
|
|
|
|
;
|
|
|
|
|
; d1.w - number of characters left in pathname
|
|
|
|
|
; d4.l - dirID of selected directory
|
|
|
|
|
; a1 - place to start parsing pathname from
|
|
|
|
|
; a2 - pointer to FSSpec under construction
|
|
|
|
|
; a4 - caller's param block (uses ioVRefNum and ioDirID)
|
|
|
|
|
;
|
|
|
|
|
; Function: Parse up ioVRefnum, ioNamePtr and ioDir to find the volume/directory
|
|
|
|
|
; pair. Set the FSSpec to describe the vol/dir pair, and return the
|
|
|
|
|
; dirID of the directory in question in d4.
|
|
|
|
|
;
|
|
|
|
|
; Handle all of the no-path-to-parse cases here:
|
|
|
|
|
; no vRef, dirID or path
|
|
|
|
|
; just a vRef
|
|
|
|
|
; just a wdRef
|
|
|
|
|
; just a vRef+dirID
|
|
|
|
|
; a colon for a pathname
|
|
|
|
|
;
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
DetermineVolume: proc
|
|
|
|
|
@DetermineVolumeRegs: reg d2/a0/a3
|
|
|
|
|
movem.l @DetermineVolumeRegs, -(a6)
|
|
|
|
|
suba.w #ioHVQElSize, a6 ; allocate a volume param block on a6
|
|
|
|
|
move.l a6, a0 ; leave pb in a0
|
|
|
|
|
|
|
|
|
|
; Check to see if there is a non-nil, non-zero length pathname
|
|
|
|
|
moveq.l #finalSegmentColon, d3 ; assume we have nothing to parse
|
|
|
|
|
tst.b d1 ; do we have a nil ptr or zero length name?
|
|
|
|
|
beq.s @UseVRefAndDirID ; if so, go use vRef+dirID
|
|
|
|
|
|
|
|
|
|
bsr ParseNextSegment ; parse next segment into FSSpec.name
|
|
|
|
|
bmi.s @Exit ; can't party if the parser don't want to
|
|
|
|
|
beq.s @UseVRefAndDirID ; initial colon implies vRef+dirID
|
|
|
|
|
|
|
|
|
|
tst.l d3 ; check parser results
|
|
|
|
|
bpl.s @VolumeNamePresent ; if it ended with a colon, it's a vol name
|
|
|
|
|
|
|
|
|
|
; We've got a special case - the pathname is a solo cname. Reset the path parser
|
|
|
|
|
; so that we'll see it again.
|
|
|
|
|
bsr ResetPathnameParser
|
|
|
|
|
moveq.l #moreSegments, d3 ; make sure they look at this again
|
|
|
|
|
bra.s @UseVRefAndDirID ; and go use the vRef and dirID fields
|
|
|
|
|
|
|
|
|
|
@VolumeNamePresent:
|
|
|
|
|
clr.w ioVRefNum(a0) ; use pathname, please
|
|
|
|
|
move.w #-1, ioFDirIndex(a0) ; use pathname, please
|
|
|
|
|
|
|
|
|
|
lea.l FSSpec.name(a2), a3 ; get the address of the just-parsed segment
|
|
|
|
|
move.l a3, ioNamePtr(a0) ; use caller's pathname
|
|
|
|
|
|
|
|
|
|
; slam a colon on because HFS sucks rocks
|
|
|
|
|
|
|
|
|
|
addq.b #1,d0 ; add a colon on to the end
|
|
|
|
|
cmp.b #fsSpecNameLength,d0 ; ooops! no space
|
|
|
|
|
bhs.s @BadNameError
|
|
|
|
|
move.b d0, (a3) ; jam the longer length
|
|
|
|
|
move.b #pathSeparator, (a3, d0.w) ; put in the lovely separator for the pleasure of Dirks
|
|
|
|
|
|
|
|
|
|
go_GetVolInfo
|
|
|
|
|
bne.s @Exit ; run away
|
|
|
|
|
move.w ioVRefNum(a0), FSSpec.vRefNum(a2) ; this is the volume
|
|
|
|
|
move.l #fsRtDirID, d4 ; use the root if we need to keep going
|
|
|
|
|
bra.s @Exit ; and we're done
|
|
|
|
|
|
|
|
|
|
; We don't have a volume name ('cause the path starts with a colon, the path is a
|
|
|
|
|
; solo file/directory name, or there's no path), so use the ioVRefNum and ioDirID
|
|
|
|
|
; fields to establish the volume and directory to start parsing from.
|
|
|
|
|
@UseVRefAndDirID:
|
|
|
|
|
clr.l ioNamePtr(a0) ; we don't need the name here
|
|
|
|
|
move.w ioVRefNum(a4), ioVRefNum(a0) ; use caller's vRef/WDRef
|
|
|
|
|
beq.s @HandleDefaultCase ; GetWDInfo has no clue about default directories
|
|
|
|
|
|
|
|
|
|
clr.w ioWDIndex(a0) ; no indexing, please
|
|
|
|
|
clr.l ioWDProcID(a0) ; any proc ID will do
|
|
|
|
|
clr.w ioWDVRefNum(a0) ; any volume will do
|
|
|
|
|
go_GetWDInfo
|
|
|
|
|
bne.s @Exit ; punt on errors
|
|
|
|
|
bra.s @GotVolAndDir
|
|
|
|
|
|
|
|
|
|
@HandleDefaultCase:
|
|
|
|
|
go_HGetVol
|
|
|
|
|
bne.s @Exit
|
|
|
|
|
|
|
|
|
|
@GotVolAndDir:
|
|
|
|
|
move.w ioWDVRefNum(a0), FSSpec.vRefNum(a2) ; use the volume from GetWDInfo
|
|
|
|
|
move.l ioDirID(a4), d4 ; are we overriding with the user's dirID?
|
|
|
|
|
bne.s @Exit ; if so, stop thinking now
|
|
|
|
|
move.l ioWDDirID(a0), d4 ; use dirID from vRef/wdRef or pathname
|
|
|
|
|
@Exit:
|
|
|
|
|
adda.w #ioHVQElSize, a6 ; deallocate volume param block on a6
|
|
|
|
|
movem.l (a6)+, @DetermineVolumeRegs
|
|
|
|
|
tst.w d0
|
|
|
|
|
rts
|
|
|
|
|
|
|
|
|
|
@BadNameError:
|
|
|
|
|
moveq.l #bdNamErr, d0 ; bummer - too many characters in file name
|
|
|
|
|
bra.s @Exit
|
|
|
|
|
endproc
|
|
|
|
|
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
;
|
|
|
|
|
; Routine: CorrectCapitals
|
|
|
|
|
;
|
|
|
|
|
; Input: a2 - pointer to FSSpec with leaf name
|
|
|
|
|
;
|
|
|
|
|
; Output: a2 - FSSpec has correct (same-as-catalog) spelling of leaf name
|
|
|
|
|
; d0 - result code
|
|
|
|
|
;
|
|
|
|
|
; Function: Replace the leaf name in FSSpec.name(a2) with the spelling as it
|
|
|
|
|
; is stored in the catalog.
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
CorrectCapitalsRegs reg a0/a1
|
|
|
|
|
CorrectCapitals proc
|
|
|
|
|
move.l (sp)+, -(a6) ; ret addr to local stack
|
|
|
|
|
movem.l CorrectCapitalsRegs, -(a6)
|
|
|
|
|
suba.w #ioHVQElSize, a6 ; allocate a pb
|
|
|
|
|
movea.l a6, a0
|
|
|
|
|
suba.w #256, a6 ; max name length is 256 bytes
|
|
|
|
|
movea.l a6, a1 ; a1 = ptr(name buffer)
|
|
|
|
|
|
|
|
|
|
move.l a1, ioFileName(a0) ; provide space for name output
|
|
|
|
|
move.w FSSpec.vRefNum(a2), ioVRefNum(a0) ; use the right volume
|
|
|
|
|
move.l FSSpec.parID(a2), d0 ; get parent directory
|
|
|
|
|
cmp.l #fsRtParID, d0 ; are we looking for the root's name?
|
|
|
|
|
beq.s @RootName
|
|
|
|
|
|
|
|
|
|
move.w #1, ioFDirIndex(a0) ; start indexing at 1
|
|
|
|
|
move.l d0, ioDirID(a0) ; use the right directory
|
|
|
|
|
|
|
|
|
|
@IndexLoop:
|
|
|
|
|
go_GetCatInfo
|
|
|
|
|
bne.s @Exit ; punt on errors
|
|
|
|
|
|
|
|
|
|
move.l a0,-(sp) ; stash regs
|
|
|
|
|
move.l a1,-(sp)
|
|
|
|
|
lea FSSpec.name(a2), a0 ; point to source name
|
|
|
|
|
moveq.l #0, d0 ; clear everything
|
|
|
|
|
move.b (a0)+, d0 ; length of caller's string
|
|
|
|
|
swap d0 ; up high where _RelString likes it
|
|
|
|
|
move.b (a1)+, d0 ; length of catalog's string
|
|
|
|
|
_FSRelString ; compare 'em
|
|
|
|
|
movea.l (sp)+, a1 ; restore regs
|
|
|
|
|
movea.l (sp)+, a0
|
|
|
|
|
beq.s @Hit ; cruise when they match
|
|
|
|
|
add.w #1, ioFDirIndex(a0) ; check out the next one
|
|
|
|
|
move.l FSSpec.parID(a2), ioDirID(a0) ; use the right directory
|
|
|
|
|
bra.s @IndexLoop
|
|
|
|
|
|
|
|
|
|
; GetCatInfo seems to not want to return info about the root directory when asked for
|
|
|
|
|
; the first item (indexed) in fsRtParID. Thus, we hack.
|
|
|
|
|
@RootName:
|
|
|
|
|
clr.w ioVolIndex(a0) ; no indexing for us
|
|
|
|
|
go_GetVolInfo
|
|
|
|
|
bne.s @Exit
|
|
|
|
|
|
|
|
|
|
@Hit:
|
|
|
|
|
moveq.l #0, d0 ; clear everything
|
|
|
|
|
lea.l FSSpec.name(a2),a0 ; a0 target FSSpec
|
|
|
|
|
move.b (a1), d0 ; get length of catalog-spelled name
|
|
|
|
|
cmp.b #63, d0 ; a massive MFS name?
|
|
|
|
|
bls.s @1 ; if length <= 63, we've enough room
|
|
|
|
|
moveq.l #63, d0 ; sorry; you only get the 1st 63 chars
|
|
|
|
|
@1:
|
|
|
|
|
move.b d0, (a1) ; set clipped string length back into source
|
|
|
|
|
@loop:
|
|
|
|
|
move.b (a1)+, (a0)+ ; set chars into FSSpec.name
|
|
|
|
|
dbra d0, @loop
|
|
|
|
|
|
|
|
|
|
moveq.l #noErr, d0 ; yay!
|
|
|
|
|
@Exit:
|
|
|
|
|
adda.w #ioHVQElSize+256,a6 ; deallocate the pb and name buffer
|
|
|
|
|
movem.l (a6)+, CorrectCapitalsRegs
|
|
|
|
|
move.l (a6)+, -(sp) ; ret addr back
|
|
|
|
|
tst.w d0
|
|
|
|
|
rts
|
|
|
|
|
endproc
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
;
|
|
|
|
|
; Routine: ExternalMakeFSSpec
|
|
|
|
|
;
|
|
|
|
|
; Input: a0 - caller's param block (uses ioVRefNum, ioNamePtr, ioDirID and ioMisc)
|
|
|
|
|
;
|
|
|
|
|
; Output: FSSpec (pointed to by ioMisc) is properly set
|
|
|
|
|
; d0 - result code
|
|
|
|
|
;
|
|
|
|
|
; Function: Parse up ioVRefnum, ioNamePtr and ioDir to make an FSSpec
|
|
|
|
|
;
|
|
|
|
|
; register usage:
|
|
|
|
|
; a0 - our working parameter block
|
|
|
|
|
; a1 - current place along the caller's pathname
|
|
|
|
|
; a2 - FSSpec record
|
|
|
|
|
; a4 - caller's param block
|
|
|
|
|
; d1 - characters left in pathname in front of a1
|
|
|
|
|
;
|
|
|
|
|
; Assumes that suitably big a6 (≈800 bytes) is set up (presumably the compatibility layer)
|
|
|
|
|
; This routine follows all of the conventions to be called in the compatibility layer
|
|
|
|
|
; but would also run fine as glue if someone aims a6 at a stack.
|
|
|
|
|
;________________________________________________________________________________
|
|
|
|
|
ExternalMakeFSSpecRegs reg a2-a4/d3-d4
|
|
|
|
|
ExternalMakeFSSpec: proc export
|
|
|
|
|
|
|
|
|
|
move.l (sp)+, -(a6) ; we do i/o
|
|
|
|
|
movem.l ExternalMakeFSSpecRegs, -(a6)
|
|
|
|
|
movea.l a0, a4 ; save caller's pb pointer in a safe reg
|
|
|
|
|
sub.w #ioHVQElSize, a6 ; allocate a (big) param block on a6
|
|
|
|
|
movea.l a6, a0 ; keep a pointer to it around in a0
|
|
|
|
|
|
|
|
|
|
move.l ioFSSpecPtr(a4), a2 ; a2 = ptr(Caller's FSSpec record)
|
|
|
|
|
lea.l FSSpec.name(a2), a3 ; use FSSpec.name for path segment name storage
|
|
|
|
|
move.l a3, ioNamePtr(a0) ; have
|
|
|
|
|
bsr ResetPathnameParser ; get ready to parse pathname
|
|
|
|
|
|
|
|
|
|
bsr DetermineVolume ; go get the volume and directory established
|
|
|
|
|
bne @ErrorExit
|
|
|
|
|
|
|
|
|
|
move.w FSSpec.vRefNum(a2), ioVRefNum(a0) ; we know the volume now
|
|
|
|
|
|
|
|
|
|
@DirIDButNoCatInfo:
|
|
|
|
|
move.l d4, ioDirID(a0) ; remember this so we can recognize our parents
|
|
|
|
|
tst.l d3 ; check result of last parse
|
|
|
|
|
bne.s @GetCatInfoByDirID ; no more segments? Get the name and par of this dir
|
|
|
|
|
|
|
|
|
|
@ParseSegments:
|
|
|
|
|
bsr ParseNextSegment ; using a1/d1 return next segment
|
|
|
|
|
bmi @ErrorExit ; splitsville if the parser won't dance
|
|
|
|
|
beq.s @DoubleColon ; handle double colon case
|
|
|
|
|
|
|
|
|
|
clr.w ioFDirIndex(a0) ; use dirID and name, please
|
|
|
|
|
go_GetCatInfo ; look and see if we can find anything
|
|
|
|
|
|
|
|
|
|
; There are two reasons that the following code rejects files when a colon is present:
|
|
|
|
|
; 1) a file in the middle of a path is an error, and its ioDirID is not a dirID
|
|
|
|
|
; 2) a file at the end of a colon-terminated path is an error, too (Bill B. sez)
|
|
|
|
|
|
|
|
|
|
bne.s @WeLikeItFine ; an error happened, so we can’t be picky
|
|
|
|
|
btst.b #ioDirFlg, ioFlAttrib(a0) ; was the thing we found a directory?
|
|
|
|
|
bne.s @WeLikeItFine ; yes, and we’re always happy to find directories
|
|
|
|
|
tst.l d3 ; did we have a colon?
|
|
|
|
|
bmi.s @WeLikeItFine ; no, and that is correct for a file
|
|
|
|
|
moveq.l #dirNFErr, d0 ; silly rabbi, colons are for directories
|
|
|
|
|
bra.s @ErrorExit
|
|
|
|
|
@WeLikeItFine:
|
|
|
|
|
|
|
|
|
|
tst.l d3 ; are we out of segments?
|
|
|
|
|
bne.s @DoneParsing ; if so, got to get out
|
|
|
|
|
|
|
|
|
|
tst.w d0 ; did we have trouble getting through the directory
|
|
|
|
|
bne.s @ErrorExit ; errors are our cue to cruise
|
|
|
|
|
|
|
|
|
|
move.l ioDirID(a0), d4 ; now, look within this directory
|
|
|
|
|
bra.s @ParseSegments
|
|
|
|
|
|
|
|
|
|
@DoubleColon:
|
|
|
|
|
cmp.l #fsRtDirID, d4 ; are we trying to go higher than the root?
|
|
|
|
|
beq.s @DirNFExit ; yes, we can’t (even though GetCatInfo would)
|
|
|
|
|
move.w #-1, ioFDirIndex(a0) ; we need this guy's parent
|
|
|
|
|
go_GetCatInfo
|
|
|
|
|
bne.s @ErrorExit ; barf on badness
|
|
|
|
|
move.l ioFlParID(a0), d4 ; get parent because we are done
|
|
|
|
|
bra.s @DirIDButNoCatInfo
|
|
|
|
|
|
|
|
|
|
@GetCatInfoByDirID:
|
|
|
|
|
move.w #-1, ioFDirIndex(a0) ; we need this guy's parent
|
|
|
|
|
go_GetCatInfo
|
|
|
|
|
bne.s @ErrorExit ; barf on badness
|
|
|
|
|
move.l ioFlParID(a0), d4 ; get parent because we are done
|
|
|
|
|
|
|
|
|
|
@DoneParsing:
|
|
|
|
|
move.l d4, FSSpec.parID(a2) ; use the parent from the last GetCatInfo
|
|
|
|
|
tst.w d0 ; did we get an error here?
|
|
|
|
|
beq.s @FoundSomething ; if not, we found something real
|
|
|
|
|
cmp.w #fnfErr, d0 ; did we get fnfErr, a perfectly acceptable error?
|
|
|
|
|
bne.s @ErrorExit ; no, it was another error, report it
|
|
|
|
|
|
|
|
|
|
; GetCatInfo returns an fnfErr instead of a dirNFErr when given a bad directory ID. Since an fnfErr
|
|
|
|
|
; from MakeFSSpec is an invitation to call _Create, we filter out bad directories here.
|
|
|
|
|
move.w #-1, ioFDirIndex(a0) ; info about directory
|
|
|
|
|
clr.l ioNamePtr(a0) ; we don't want the name back
|
|
|
|
|
move.l FSSpec.parID(a2), ioDirID(a0) ; use the directory we're about to return
|
|
|
|
|
go_GetCatInfo
|
|
|
|
|
bne.s @ErrorExit ; an error implies a bad directory
|
|
|
|
|
moveq.l #fnfErr, d0 ; good directory, so restore the fnfErr
|
|
|
|
|
cmp.l #fsRtParID, d4 ; were we searching in the root’s parent?
|
|
|
|
|
bne.s @Exit ; no, we can return safely (can't create in fsRtParID)
|
|
|
|
|
|
|
|
|
|
@ErrorExit:
|
|
|
|
|
cmp.w #fnfErr, d0 ; if an fnfErr made it here, it is really a dirNFErr
|
|
|
|
|
bne.s @notFNF
|
|
|
|
|
@DirNFExit:
|
|
|
|
|
moveq.l #dirNFErr, d0 ; return a dirNFErr instead
|
|
|
|
|
@notFNF:
|
|
|
|
|
clr.w (a2)+ ; clear the FSSpec.vRefNum
|
|
|
|
|
clr.l (a2)+ ; clear the FSSpec.parID
|
|
|
|
|
clr.b (a2)+ ; clear the FSSpec.name length byte
|
|
|
|
|
bra.s @Exit
|
|
|
|
|
|
|
|
|
|
@FoundSomething:
|
|
|
|
|
bsr CorrectCapitals ; Get correct spelling of leaf name
|
|
|
|
|
@Exit:
|
|
|
|
|
adda.w #ioHVQElSize, a6 ; deallocate param block
|
|
|
|
|
movem.l (a6)+, ExternalMakeFSSpecRegs
|
|
|
|
|
move.l (a6)+, -(sp)
|
|
|
|
|
tst.w d0
|
|
|
|
|
rts
|
|
|
|
|
endproc
|
|
|
|
|
end
|