mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-12-01 18:15:47 +00:00
1084 lines
29 KiB
NASM
1084 lines
29 KiB
NASM
;
|
||
; Directory routines for MSDOS
|
||
;
|
||
|
||
INCLUDE DOSSEG.ASM
|
||
|
||
CODE SEGMENT BYTE PUBLIC 'CODE'
|
||
ASSUME SS:DOSGROUP,CS:DOSGROUP
|
||
|
||
.xlist
|
||
.xcref
|
||
INCLUDE DOSSYM.ASM
|
||
INCLUDE DEVSYM.ASM
|
||
.cref
|
||
.list
|
||
|
||
TITLE DIR - Directory and path cracking
|
||
NAME Dir
|
||
|
||
i_need NoSetDir,BYTE
|
||
i_need EntFree,WORD
|
||
i_need DirStart,WORD
|
||
i_need LastEnt,WORD
|
||
i_need ClusNum,WORD
|
||
i_need CurBuf,DWORD
|
||
i_need ThisFCB,DWORD
|
||
i_need Attrib,BYTE
|
||
i_need DelAll,BYTE
|
||
i_need VolID,BYTE
|
||
i_need Name1,BYTE
|
||
i_need ThisDPB,DWORD
|
||
i_need EntLast,WORD
|
||
i_need Creating,BYTE
|
||
i_need SecClusPos,BYTE
|
||
i_need ClusFac,BYTE
|
||
i_need NxtClusNum,WORD
|
||
i_need DirSec,WORD
|
||
i_need DriveSpec,BYTE
|
||
i_need Device_availability,BYTE
|
||
i_need RootStart,BYTE
|
||
i_need DevString,BYTE
|
||
i_need DevStrLen,BYTE
|
||
|
||
SUBTTL BUILDDIR,NEWDIR -- ALLOCATE DIRECTORIES
|
||
PAGE
|
||
procedure BUILDDIR,NEAR
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; ES:BP Points to DPB
|
||
; [THISFCB] Set if using NEWDIR entry point
|
||
; [LASTENT] current last valid entry number in directory if no free
|
||
; entries
|
||
; Function:
|
||
; Grow directory if no free entries and not root
|
||
; Outputs:
|
||
; CARRY SET IF FAILURE
|
||
; ELSE
|
||
; AX entry number of new entry
|
||
; If a new dir [DIRSTART],[CLUSFAC],[CLUSNUM],[DIRSEC] set
|
||
; AX = first entry of new dir
|
||
; GETENT should be called to set [LASTENT]
|
||
|
||
MOV AX,[ENTFREE]
|
||
CMP AX,-1
|
||
JNZ GOTRET
|
||
CMP [DIRSTART],0
|
||
JNZ NEWDIR
|
||
STC
|
||
return ; Can't grow root
|
||
|
||
entry NEWDIR
|
||
MOV BX,[DIRSTART]
|
||
OR BX,BX
|
||
JZ NULLDIR
|
||
invoke GETEOF
|
||
NULLDIR:
|
||
MOV CX,1
|
||
invoke ALLOCATE
|
||
retc
|
||
MOV DX,[DIRSTART]
|
||
OR DX,DX
|
||
JNZ ADDINGDIR
|
||
call SETDIRSRCH
|
||
MOV [LASTENT],-1
|
||
JMP SHORT GOTDIRREC
|
||
ADDINGDIR:
|
||
CMP [CLUSNUM],0FF8H
|
||
JB NOTFIRSTGROW
|
||
MOV [CLUSNUM],BX
|
||
NOTFIRSTGROW:
|
||
MOV DX,BX
|
||
XOR BL,BL
|
||
invoke FIGREC
|
||
GOTDIRREC:
|
||
MOV CL,ES:[BP.dpb_cluster_mask]
|
||
INC CL
|
||
XOR CH,CH
|
||
ZERODIR:
|
||
PUSH CX
|
||
MOV AL,0FFH
|
||
invoke GETBUFFR
|
||
MOV CX,ES:[BP.dpb_sector_size]
|
||
PUSH ES
|
||
LES DI,[CURBUF]
|
||
PUSH DI
|
||
ADD DI,BUFINSIZ
|
||
XOR AX,AX
|
||
SHR CX,1
|
||
REP STOSW
|
||
JNC EVENZ
|
||
STOSB
|
||
EVENZ:
|
||
POP DI
|
||
INC AL
|
||
MOV ES:[DI.BUFDIRTY],AL
|
||
POP ES
|
||
POP CX
|
||
INC DX
|
||
LOOP ZERODIR
|
||
MOV AX,[LASTENT]
|
||
INC AX
|
||
GOTRET:
|
||
CLC
|
||
return
|
||
|
||
BUILDDIR ENDP
|
||
|
||
;
|
||
; set up a . and .. directory entry for a directory
|
||
;
|
||
procedure SETDOTENT,NEAR
|
||
ASSUME DS:DOSGROUP
|
||
MOV CX,4
|
||
MOV AX,2020H
|
||
REP STOSW
|
||
STOSB
|
||
MOV SI,WORD PTR [THISFCB]
|
||
MOV AL,attr_directory
|
||
STOSB
|
||
ADD DI,10
|
||
MOV AX,[SI.fcb_FTIME]
|
||
STOSW
|
||
MOV AX,[SI.fcb_FDATE]
|
||
STOSW
|
||
MOV AX,DX
|
||
STOSW
|
||
XOR AX,AX
|
||
STOSW
|
||
STOSW
|
||
return
|
||
SETDOTENT ENDP
|
||
|
||
SUBTTL GETFILE, GETNAME, FINDNAME -- LOOK FOR A FILE
|
||
PAGE
|
||
procedure SEARCH,near
|
||
|
||
entry GETFILE
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
; Same as GETNAME except ES:DI points to FCB on successful return
|
||
invoke MOVNAME
|
||
retc
|
||
PUSH DX
|
||
PUSH DS
|
||
CALL FINDNAME
|
||
POP ES
|
||
POP DI
|
||
return
|
||
|
||
entry GETNAME
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DS,DX point to FCB
|
||
; Function:
|
||
; Find file name in disk directory. First byte is
|
||
; drive number (0=current disk). "?" matches any
|
||
; character.
|
||
; Outputs:
|
||
; Carry set if file not found
|
||
; ELSE
|
||
; Zero set if attributes match (always except when creating)
|
||
; AH = Device ID (bit 7 set if not disk)
|
||
; [THISDPB] = Base of drive parameters
|
||
; DS = DOSGROUP
|
||
; ES = DOSGROUP
|
||
; [CURBUF+2]:BX = Pointer into directory buffer
|
||
; [CURBUF+2]:SI = Pointer to First Cluster field in directory entry
|
||
; [CURBUF] has directory record with match
|
||
; [NAME1] has file name
|
||
; All other registers destroyed.
|
||
|
||
invoke MOVNAME
|
||
ASSUME ES:DOSGROUP
|
||
retc ; Bad file name?
|
||
|
||
entry FINDNAME
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
invoke DEVNAME
|
||
JC FindEntry
|
||
invoke BUILDFCB
|
||
return
|
||
ASSUME ES:NOTHING
|
||
|
||
; NOTE THE FALL THROUGH
|
||
|
||
SUBTTL FINDENTRY -- LOOK FOR AN ENTRY
|
||
PAGE
|
||
entry FindEntry
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; [THISDPB] set
|
||
; [SECCLUSPOS] = 0
|
||
; [DIRSEC] = Starting directory sector number
|
||
; [CLUSNUM] = Next cluster of directory
|
||
; [CLUSFAC] = Sectors/Cluster
|
||
; [NAME1] = Name to look for
|
||
; Function:
|
||
; Find file name in disk directory.
|
||
; "?" matches any character.
|
||
; Outputs:
|
||
; Carry set if name not found
|
||
; ELSE
|
||
; Zero set if attributes match (always except when creating)
|
||
; AH = Device ID (bit 7 set if not disk)
|
||
; [THISDPB] = Base of drive parameters
|
||
; DS = DOSGROUP
|
||
; ES = DOSGROUP
|
||
; [CURBUF+2]:BX = Pointer into directory buffer
|
||
; [CURBUF+2]:SI = Pointer to First Cluster field in directory entry
|
||
; [CURBUF] has directory record with match
|
||
; [NAME1] has file name
|
||
; [LASTENT] is entry number of the entry
|
||
; All other registers destroyed.
|
||
|
||
CALL STARTSRCH
|
||
CMP BYTE PTR [ATTRIB],attr_volume_id
|
||
; Looking for vol ID only ?
|
||
JNZ NOTVOLSRCH ; No
|
||
CALL SETROOTSRCH ; Yes force search of root
|
||
NOTVOLSRCH:
|
||
CALL GETENTRY
|
||
entry Srch
|
||
PUSH DS
|
||
MOV DS,WORD PTR [CURBUF+2]
|
||
ASSUME DS:NOTHING
|
||
MOV AH,BYTE PTR [BX]
|
||
OR AH,AH ; End of directory?
|
||
JZ FREE
|
||
CMP AH,BYTE PTR [DELALL] ; Free entry?
|
||
JZ FREE
|
||
TEST BYTE PTR [BX+11],attr_volume_id
|
||
; Volume ID file?
|
||
JZ CHKFNAM ; NO
|
||
INC BYTE PTR [VOLID]
|
||
CHKFNAM:
|
||
MOV SI,BX
|
||
PUSH SS
|
||
POP ES
|
||
ASSUME ES:DOSGROUP
|
||
MOV DI,OFFSET DOSGROUP:NAME1
|
||
MOV CX,11
|
||
WILDCRD:
|
||
REPE CMPSB
|
||
JZ FOUND
|
||
CMP BYTE PTR ES:[DI-1],"?"
|
||
JZ WILDCRD
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
entry NEXTENT
|
||
LES BP,[THISDPB]
|
||
ASSUME ES:NOTHING
|
||
CALL NEXTENTRY
|
||
JNC SRCH
|
||
JMP SHORT SETESRET
|
||
|
||
FREE:
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV CX,[LASTENT]
|
||
CMP CX,[ENTFREE]
|
||
JAE TSTALL
|
||
MOV [ENTFREE],CX
|
||
TSTALL:
|
||
CMP AH,BYTE PTR [DELALL] ; At end of directory?
|
||
JZ NEXTENT ; No - continue search
|
||
MOV [ENTLAST],CX
|
||
STC
|
||
JMP SHORT SETESRET
|
||
|
||
FOUND:
|
||
;
|
||
; We have a file with a matching name. We must now consider
|
||
; the attributes:
|
||
; ATTRIB Action
|
||
; ------ ------
|
||
; Volume_ID Is Volume_ID in test?
|
||
; Otherwise If no create then Is ATTRIB+extra superset of test?
|
||
; If create then Is ATTRIB equal to test?
|
||
;
|
||
MOV CH,[SI] ; Attributes of file
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV AH,BYTE PTR [ATTRIB] ; Attributes of search
|
||
TEST CH,attr_volume_id ; Volume ID file?
|
||
JZ check_one_volume_id ; Nope check other attributes
|
||
TEST AH,attr_volume_id ; Can we find Volume ID?
|
||
JZ NEXTENT ; Nope, (not even $FCB_CREATE)
|
||
XOR AH,AH ; Set zero flag for $FCB_CREATE
|
||
JMP SHORT RETF ; Found Volume ID
|
||
check_one_volume_id:
|
||
CMP AH,attr_volume_id ; Looking only for Volume ID?
|
||
JZ NEXTENT ; Yes, continue search
|
||
ADD SI,15
|
||
CALL MatchAttributes
|
||
JZ RETF
|
||
TEST BYTE PTR [CREATING],-1 ; Pass back mismatch if creating
|
||
JZ NEXTENT ; Otherwise continue searching
|
||
RETF:
|
||
LES BP,[THISDPB]
|
||
MOV AH,ES:[BP.dpb_drive]
|
||
SETESRET:
|
||
PUSH SS
|
||
POP ES
|
||
return
|
||
|
||
SUBTTL GETENTRY, NEXTENTRY, GETENT -- STEP THROUGH DIRECTORY
|
||
PAGE
|
||
entry GETENTRY
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; [LASTENT] has directory entry
|
||
; ES:BP points to drive parameters
|
||
; Function:
|
||
; Locates directory entry in preparation for search
|
||
; GETENT provides entry for passing desired entry in AX
|
||
; A valid search environment MUST exist
|
||
; ENDENT,ENTLAST,ENTFREE
|
||
; Outputs:
|
||
; [CURBUF+2]:BX = Pointer to next directory entry in CURBUF
|
||
; [CURBUF+2]:DX = Pointer to first byte after end of CURBUF
|
||
; [LASTENT] = New directory entry number
|
||
|
||
MOV AX,[LASTENT]
|
||
entry GETENT
|
||
MOV [LASTENT],AX
|
||
MOV CL,4
|
||
SHL AX,CL
|
||
XOR DX,DX
|
||
SHL AX,1
|
||
RCL DX,1 ; Account for overflow in last shift
|
||
MOV BX,ES:[BP.dpb_sector_size]
|
||
AND BL,255-31 ; Must be multiple of 32
|
||
DIV BX
|
||
MOV BX,DX ; Position within sector
|
||
PUSH BX
|
||
invoke DIRREAD
|
||
POP BX
|
||
SETENTRY:
|
||
MOV DX,WORD PTR [CURBUF]
|
||
ADD DX,BUFINSIZ
|
||
ADD BX,DX
|
||
ADD DX,ES:[BP.dpb_sector_size] ; Always clears carry
|
||
return
|
||
|
||
entry NEXTENTRY
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; Same as outputs of GETENTRY, above
|
||
; Function:
|
||
; Update BX, and [LASTENT] for next directory entry.
|
||
; Carry set if no more.
|
||
|
||
MOV AX,[LASTENT]
|
||
CMP AX,[ENTLAST]
|
||
JZ NONE
|
||
INC AX
|
||
ADD BX,32
|
||
CMP BX,DX
|
||
JB HAVIT
|
||
MOV BL,BYTE PTR [SECCLUSPOS]
|
||
INC BL
|
||
CMP BL,BYTE PTR [CLUSFAC]
|
||
JB SAMECLUS
|
||
MOV BX,[NXTCLUSNUM]
|
||
CMP BX,0FF8H
|
||
JAE NONE
|
||
CMP BX,2
|
||
JB NONE
|
||
JMP GETENT
|
||
|
||
NONE:
|
||
STC
|
||
return
|
||
|
||
HAVIT:
|
||
MOV [LASTENT],AX
|
||
CLC
|
||
return
|
||
|
||
SAMECLUS:
|
||
MOV BYTE PTR [SECCLUSPOS],BL
|
||
MOV [LASTENT],AX
|
||
PUSH DS
|
||
LDS DI,[CURBUF]
|
||
ASSUME DS:NOTHING
|
||
MOV DX,[DI.BUFSECNO]
|
||
INC DX
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
invoke FIRSTCLUSTER
|
||
XOR BX,BX
|
||
JMP SETENTRY
|
||
Search ENDP
|
||
|
||
SUBTTL GETCURRDIR -- GET CURRENT DIRECTORY
|
||
PAGE
|
||
procedure Dir_search,NEAR
|
||
entry GETCURRDIR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; ES:BP Points to DPB
|
||
; FATREAD should be called before this routine
|
||
; Function:
|
||
; Find current directory for drive
|
||
; If path is bad set current directory to the root
|
||
; Outputs:
|
||
; DS = DOSGROUP
|
||
; [SECCLUSPOS] = 0
|
||
; [DIRSTART] = Cluster # of first cluster of directory ( 0 if root)
|
||
; [DIRSEC] Set to phys sec # of first sector first cluster of directory
|
||
; [CLUSNUM] Set to next cluster
|
||
; [CLUSFAC] Sectors/cluster
|
||
; Destroys all registers
|
||
|
||
MOV BX,ES:[BP.dpb_current_dir]
|
||
OR BX,BX
|
||
JZ SETROOTSRCH
|
||
CMP BX,0FF8H
|
||
JB SETDIRSRCH
|
||
PUSH ES
|
||
POP DS
|
||
LEA SI,[BP.dpb_dir_text]
|
||
CALL ROOTPATH
|
||
ASSUME DS:DOSGROUP
|
||
JNC SETCURR
|
||
MOV ES:[BP.dpb_current_dir],0
|
||
|
||
SETROOTSRCH:
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
XOR AX,AX
|
||
MOV [DIRSTART],AX
|
||
MOV BYTE PTR [SECCLUSPOS],AL
|
||
DEC AX
|
||
MOV [CLUSNUM],AX
|
||
MOV AX,ES:[BP.dpb_first_sector]
|
||
MOV DX,ES:[BP.dpb_dir_sector]
|
||
SUB AX,DX
|
||
MOV BYTE PTR [CLUSFAC],AL
|
||
MOV [DIRSEC],DX
|
||
return
|
||
|
||
SETCURR:
|
||
ASSUME DS:DOSGROUP
|
||
MOV AX,[DIRSTART]
|
||
MOV ES:[BP.dpb_current_dir],AX
|
||
return
|
||
|
||
entry SETDIRSRCH
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; BX cluster number of start of directory
|
||
; ES:BP Points to DPB
|
||
; Function:
|
||
; Set up a directory search
|
||
; Outputs:
|
||
; DS = DOSGROUP
|
||
; [DIRSTART] = BX
|
||
; [CLUSFAC],[CLUSNUM],[SECCLUSPOS],[DIRSEC] set
|
||
; destroys AX,DX
|
||
|
||
OR BX,BX
|
||
JZ SETROOTSRCH
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV [DIRSTART],BX
|
||
MOV AL,ES:[BP.dpb_cluster_mask]
|
||
INC AL
|
||
MOV BYTE PTR [CLUSFAC],AL
|
||
invoke UNPACK
|
||
MOV [CLUSNUM],DI
|
||
MOV DX,BX
|
||
XOR BL,BL
|
||
MOV BYTE PTR [SECCLUSPOS],BL
|
||
invoke FIGREC
|
||
MOV [DIRSEC],DX
|
||
return
|
||
Dir_search ENDP
|
||
|
||
SUBTTL MAKENODE -- CREATE A NEW NODE
|
||
PAGE
|
||
procedure MakeNode,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; AL - attribute to create
|
||
; DS:SI Points to asciz path
|
||
; [THISFCB] Points to an empty FCB
|
||
; Function:
|
||
; Make a new node
|
||
; Outputs:
|
||
; DS=DOSGROUP
|
||
; ES:BP Points to DPB
|
||
; AX = 0 Success
|
||
; AX = 1 A node by this name exists and is a directory
|
||
; AX = 2 A new node could not be created error
|
||
; AX = 3 A node by this name exists and is a file error
|
||
; AX = 4 Bad Path error
|
||
; AX = 5 Attribute mismatch error
|
||
; CARRY SET IF ERROR
|
||
; ELSE
|
||
; [DIRSTART],[DIRSEC],[CLUSFAC],[CLUSNUM] set to directory
|
||
; containing new node.
|
||
; [CURBUF+2]:BX Points to entry
|
||
; [CURBUF+2]:SI Points to entry.fcb_firclus
|
||
; [ThisFCB] is filled in
|
||
; If this is a new entry zero is set and
|
||
; Attribute byte in entry is directory
|
||
; else a file existed by this name and:
|
||
; [NAME1] has name
|
||
; entry is not changed in any way
|
||
; Destroys all registers
|
||
|
||
PUSH AX
|
||
CALL GetPath
|
||
MOV DL,CL ; Save CL info
|
||
POP CX
|
||
MOV BYTE PTR [ATTRIB],CL
|
||
MOV CX,AX
|
||
JNC make_exists ; File existed
|
||
JNZ make_err_4 ; Path bad
|
||
OR DL,DL ; Check "CL" return from GETPATH
|
||
JNZ make_type ; Name simply not found
|
||
make_err_4:
|
||
MOV AL,4 ; case 1 bad path
|
||
make_err_ret:
|
||
STC
|
||
return
|
||
|
||
make_type:
|
||
XOR AL,AL ; nothing exists... assume 0
|
||
STC
|
||
JMP SHORT make_save
|
||
make_exists:
|
||
JZ make_exists_dir
|
||
MOV AL,3 ; file exists type 3
|
||
TEST BYTE PTR [ATTRIB],(attr_volume_id+attr_directory)
|
||
JNZ make_err_ret_5 ; but we wanted a volid or dir
|
||
OR CH,CH
|
||
JS make_dev ; No furthur checks if device
|
||
PUSH CX
|
||
MOV DS,WORD PTR [CURBUF+2]
|
||
MOV CH,[BX+dir_attr] ; Get file attributes
|
||
TEST CH,attr_read_only
|
||
JNZ make_err_ret_5P ; Cannot create on read only files
|
||
CALL MatchAttributes
|
||
make_err_ret_5P:
|
||
POP CX
|
||
JZ make_dev ; Attributes ok
|
||
make_err_ret_5:
|
||
MOV AL,5 ; Attribute mismatch
|
||
JMP SHORT make_err_ret
|
||
|
||
make_dev:
|
||
XOR AL,AL ; Make sure zero set(atts match), carry clear(exists)
|
||
MOV AL,3 ; Restore correct value
|
||
JMP SHORT make_save
|
||
make_exists_dir:
|
||
MOV AL,1 ; directory exists
|
||
TEST BYTE PTR [ATTRIB],attr_directory
|
||
JZ make_err_ret ; we didn't want a directory
|
||
CLC
|
||
return ; just return
|
||
make_save:
|
||
PUSH AX
|
||
;
|
||
; set up for call to NewEntry - it is in the middle of FCB_CREATE
|
||
; so we must also pre-push two registers. They will be popped off
|
||
; by FCB_CREATE
|
||
;
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
PUSHF ;Save state of flags
|
||
CMP BYTE PTR [NAME1],'.' ;Detect attempt to make '.' or '..'
|
||
JNZ NOTLDOT ; Needed because no '.' or '..' in root
|
||
POPF
|
||
MOV AL,1 ;Force type 2 error
|
||
JMP SHORT SET2ERR
|
||
|
||
NOTLDOT:
|
||
POPF
|
||
PUSH ES
|
||
LES DI,[ThisFCB]
|
||
PUSH DS
|
||
PUSH DI
|
||
PUSH ES
|
||
MOV AX,CX
|
||
invoke NewEntry
|
||
POP DS
|
||
POP ES
|
||
SET2ERR:
|
||
OR AL,AL
|
||
POP AX
|
||
JZ make_set_fcb
|
||
MOV AL,2 ; create failed case 2
|
||
STC
|
||
return
|
||
make_set_fcb:
|
||
ASSUME DS:DOSGROUP
|
||
PUSH ES
|
||
LES DI,[THISFCB]
|
||
INC DI
|
||
PUSH DS
|
||
PUSH SI
|
||
MOV DS,WORD PTR [CURBUF+2]
|
||
ASSUME DS:NOTHING
|
||
MOV SI,BX
|
||
MOV CX,11
|
||
REP MOVSB
|
||
POP SI
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
POP ES
|
||
CMP AL,1
|
||
JA make_errors
|
||
OR AL,AL
|
||
CLC
|
||
return
|
||
make_errors:
|
||
STC
|
||
return
|
||
|
||
MakeNode ENDP
|
||
|
||
SUBTTL GETPATH -- PARSE AN asciz PATH
|
||
PAGE
|
||
|
||
procedure GETPATH,near
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DS:SI Points to asciz path
|
||
; Function:
|
||
; Crack the path
|
||
; Outputs:
|
||
; [DRIVESPEC] is non zero if a drive was specified
|
||
; [ROOTSTART] is non zero if a / started the path
|
||
; [ATTRIB] set to attr_directory+attr_hidden+attr_system
|
||
; Same as FINDPATH except if path specifies a device in which case
|
||
; bit 7 of AH will be set and SI and BX will point DOSGROUP relative
|
||
; Destroys all registers
|
||
|
||
XOR AX,AX
|
||
MOV WORD PTR [DRIVESPEC],AX
|
||
MOV BYTE PTR [ATTRIB],attr_directory+attr_system+attr_hidden
|
||
LODSB
|
||
invoke PATHCHRCMP
|
||
JZ DEFAULTROOT
|
||
MOV AH,AL
|
||
LODSB
|
||
CMP AL,':'
|
||
JZ DRVSPEC
|
||
DEC SI
|
||
DEC SI
|
||
PUSH DS
|
||
PUSH SI
|
||
PUSH SS
|
||
POP ES
|
||
CMP BYTE PTR [device_availability],0
|
||
JZ NOWDEV
|
||
CALL GOTPRESTRING2
|
||
JNC BUILDFCBJ ; If no carry then we have a device
|
||
NOWDEV:
|
||
CALL DEFPATH
|
||
GOFIND:
|
||
MOV AL,[NoSetDir]
|
||
PUSH AX
|
||
MOV [NoSetDir],0
|
||
CALL GETCURRDIR
|
||
POP AX
|
||
MOV [NoSetDir],AL
|
||
POP SI
|
||
POP DS
|
||
JMP FINDPATH
|
||
|
||
DEFPATH:
|
||
XOR AL,AL
|
||
DRVPATH:
|
||
invoke GETTHISDRV
|
||
retc ; Bad drive
|
||
PUSH SS
|
||
POP DS
|
||
invoke FATREAD
|
||
CLC
|
||
return
|
||
|
||
DEFAULTROOT:
|
||
PUSH DS
|
||
PUSH SI
|
||
CALL DEFPATH
|
||
POP SI
|
||
POP DS
|
||
ROOTSRCH:
|
||
INC BYTE PTR [ROOTSTART]
|
||
CMP BYTE PTR [SI],0
|
||
JZ PATHISNULL
|
||
PUSH DS
|
||
PUSH SI
|
||
PUSH ES ; Save pointer to DPB
|
||
CALL CHKDEV
|
||
POP ES
|
||
JNC BUILDFCBJ
|
||
POP SI
|
||
POP DS
|
||
JMP ROOTPATH
|
||
|
||
BUILDFCBJ:
|
||
POP AX
|
||
POP AX
|
||
context es
|
||
invoke BUILDFCB ; Clears carry sets zero
|
||
INC AL ; reset zero
|
||
return
|
||
|
||
DRVSPEC:
|
||
INC [DRIVESPEC]
|
||
MOV AL,AH
|
||
OR AL,20H ; Convert to lower case
|
||
SUB AL,60H ; Make A=1
|
||
PUSH DS
|
||
PUSH SI
|
||
PUSH AX
|
||
context es
|
||
CALL GotPreString2
|
||
ASSUME ES:NOTHING
|
||
POP AX
|
||
JNC BuildFCBJ
|
||
CALL DRVPATH
|
||
POP SI
|
||
POP DS
|
||
retc ; Bad drive
|
||
LODSB
|
||
invoke PATHCHRCMP
|
||
JZ ROOTSRCH
|
||
DEC SI
|
||
PUSH DS
|
||
PUSH SI
|
||
JMP GOFIND
|
||
|
||
PATHISNULL:
|
||
CALL SETROOTSRCH
|
||
ASSUME DS:DOSGROUP
|
||
XOR AL,AL ; Set zero (directory) clear carry
|
||
return
|
||
|
||
CHKDEV:
|
||
ASSUME DS:NOTHING
|
||
PUSH SS
|
||
POP ES
|
||
MOV DI,OFFSET DOSGROUP:DEVSTRING
|
||
XOR CX,CX
|
||
MOV CL,DEVSTRLEN
|
||
CHKPRESTRING:
|
||
REPE CMPSB
|
||
JZ GOTPRESTRING
|
||
DEC SI
|
||
invoke GETLET ; Try convert to upper case
|
||
CMP AL,ES:[DI-1]
|
||
JZ CHKPRESTRING
|
||
NOPRESTRING:
|
||
STC
|
||
return
|
||
|
||
GOTPRESTRING:
|
||
LODSB
|
||
invoke PATHCHRCMP
|
||
JNZ NOPRESTRING
|
||
GOTPRESTRING2:
|
||
MOV DI,OFFSET DOSGROUP:NAME1
|
||
MOV CX,9
|
||
TESTLOOP:
|
||
invoke GETLET
|
||
CMP AL,'.'
|
||
JZ TESTDEVICE
|
||
invoke PATHCHRCMP
|
||
JZ NOTDEV
|
||
OR AL,AL
|
||
JZ TESTDEVICE
|
||
STOSB
|
||
LOOP TESTLOOP
|
||
NOTDEV:
|
||
STC
|
||
return
|
||
|
||
TESTDEVICE:
|
||
ADD CX,2
|
||
MOV AL,' '
|
||
REP STOSB
|
||
PUSH SS
|
||
POP DS
|
||
invoke DEVNAME
|
||
return
|
||
GETPATH ENDP
|
||
|
||
SUBTTL ROOTPATH, FINDPATH -- PARSE A PATH
|
||
PAGE
|
||
procedure ROOTPATH,near
|
||
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; ES:BP Points to DPB
|
||
; FATREAD should be called before this routine
|
||
; DS:SI Points to asciz string of path which is assumed to start at
|
||
; the root (no leading '/').
|
||
; Function:
|
||
; Search from root for path
|
||
; Outputs:
|
||
; Same as FINDPATH
|
||
; Destroys all registers
|
||
|
||
PUSH DS
|
||
CALL SETROOTSRCH
|
||
POP DS
|
||
|
||
; NOTE FALL THROUGH
|
||
|
||
entry FINDPATH
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; ES:BP Points to DPB
|
||
; DS:SI Points to asciz string of path (no leading '/').
|
||
; [SECCLUSPOS] = 0
|
||
; [DIRSEC] = Phys sec # of first sector of directory
|
||
; [CLUSNUM] = Cluster # of next cluster
|
||
; [CLUSFAC] = Sectors per cluster
|
||
; Validate_path should be called before this routine is used,
|
||
; unless it is KNOWN the path is good.
|
||
; Function:
|
||
; Parse path name
|
||
; Outputs:
|
||
; ES:BP Points to DPB
|
||
; Carry set if bad path
|
||
; DS:SI Points to path element causing failure
|
||
; Zero set
|
||
; [DIRSTART],[DIRSEC],[CLUSNUM], and [CLUSFAC] are set up to
|
||
; start a search on the last directory
|
||
; CL is zero if there is a bad name in the path
|
||
; CL is non-zero if the name was simply not found
|
||
; [ENTFREE] may have free spot in directory
|
||
; [NAME1] is the name.
|
||
; CL = 81H if '*'s or '?' in name 1, 80H otherwise
|
||
; Zero reset
|
||
; File in middle of path or bad name in path
|
||
; or path too long or malformed path
|
||
; ELSE
|
||
; DS = DOSGROUP
|
||
; AH = device ID
|
||
; [CURBUF] contains directory record with match
|
||
; [CURBUF+2]:BX Points into [CURBUF] to start of entry
|
||
; [CURBUF+2]:SI Points to fcb_FIRCLUS field for entry
|
||
; [NAME1] Has entry name
|
||
; If last element is a directory zero is set and:
|
||
; [DIRSTART],[SECCLUSPOS],[DIRSEC],[CLUSNUM], and [CLUSFAC]
|
||
; are set up to start a search on it.
|
||
; If last element is a file zero is reset
|
||
; Destroys all registers
|
||
|
||
PUSH ES
|
||
PUSH SI
|
||
invoke NAMETRANS
|
||
MOV CL,AL
|
||
OR CL,80H
|
||
POP DI
|
||
POP ES
|
||
CMP SI,DI
|
||
JNZ check_device
|
||
JMP BADPATH
|
||
check_device:
|
||
PUSH DS
|
||
PUSH SI
|
||
MOV AL,BYTE PTR [SI]
|
||
|
||
;
|
||
; can we see all devices
|
||
;
|
||
context DS
|
||
CMP BYTE PTR [device_availability],0
|
||
JZ FindFile
|
||
|
||
;
|
||
; check name1 to see if we have a device...
|
||
;
|
||
PUSH ES
|
||
context ES
|
||
invoke DevName ; blast BX
|
||
POP ES
|
||
ASSUME ES:NOTHING
|
||
JC FindFile
|
||
OR AL,AL
|
||
JNZ FileInPath
|
||
POP SI
|
||
POP SI
|
||
context ES
|
||
invoke BuildFCB
|
||
INC AL
|
||
return
|
||
|
||
FindFile:
|
||
ASSUME ES:NOTHING
|
||
PUSH DI ; Start of this element
|
||
PUSH ES
|
||
PUSH CX
|
||
CALL FINDENTRY
|
||
POP CX
|
||
POP ES
|
||
POP DI
|
||
JC BADPATHPOP
|
||
LDS DI,[CURBUF]
|
||
ASSUME DS:NOTHING
|
||
TEST BYTE PTR [BX+dir_attr],attr_directory
|
||
JZ FileInPath
|
||
|
||
;
|
||
; if we are not setting the directory, then
|
||
; check for end of string
|
||
;
|
||
CMP BYTE PTR [NoSetDir],0
|
||
JZ SetDir
|
||
MOV DX,DI
|
||
MOV AX,DS
|
||
POP DI
|
||
POP DS
|
||
CMP BYTE PTR [DI],0
|
||
JZ SetRet
|
||
PUSH DS
|
||
PUSH DI
|
||
MOV DI,DX
|
||
MOV DS,AX
|
||
|
||
SetDir:
|
||
MOV DX,[SI]
|
||
SUB BX,DI
|
||
SUB SI,DI
|
||
PUSH BX
|
||
PUSH AX
|
||
PUSH SI
|
||
PUSH CX
|
||
PUSH [DI.BUFSECNO]
|
||
MOV BX,DX
|
||
CALL SETDIRSRCH
|
||
ASSUME DS:DOSGROUP
|
||
POP DX
|
||
XOR AL,AL
|
||
invoke GETBUFFR
|
||
POP CX
|
||
POP SI
|
||
POP AX
|
||
POP BX
|
||
MOV DI,WORD PTR [CURBUF]
|
||
ADD SI,DI
|
||
ADD BX,DI
|
||
POP DI
|
||
POP DS
|
||
ASSUME DS:NOTHING
|
||
MOV AL,[DI]
|
||
OR AL,AL
|
||
JZ SETRET
|
||
INC DI
|
||
MOV SI,DI
|
||
invoke PATHCHRCMP
|
||
JNZ find_bad_name
|
||
JMP FINDPATH
|
||
|
||
find_bad_name:
|
||
DEC SI
|
||
BADPATH:
|
||
XOR CL,CL ; Set zero
|
||
STC
|
||
return
|
||
|
||
FILEINPATH:
|
||
POP DI
|
||
POP DS
|
||
MOV AL,[DI]
|
||
OR AL,AL
|
||
JZ INCRET
|
||
MOV SI,DI ; Path too long
|
||
STC
|
||
return
|
||
|
||
INCRET:
|
||
INC AL ; Reset zero
|
||
SETRET:
|
||
PUSH SS
|
||
POP DS
|
||
return
|
||
|
||
BADPATHPOP:
|
||
POP SI
|
||
POP DS
|
||
MOV AL,[SI]
|
||
MOV SI,DI ; Start of bad element
|
||
OR AL,AL ; zero if bad element is last, non-zero if path too long
|
||
STC
|
||
return
|
||
ROOTPATH ENDP
|
||
|
||
SUBTTL STARTSRCH -- INITIATE DIRECTORY SEARCH
|
||
PAGE
|
||
procedure StartSrch,NEAR
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; [THISDPB] Set
|
||
; Function:
|
||
; Set up a search for GETENTRY and NEXTENTRY
|
||
; Outputs:
|
||
; ES:BP = Drive parameters
|
||
; Sets up LASTENT, ENDENT, ENTFREE=ENTLAST=-1, VOLID=0
|
||
; Destroys all registers (via FATREAD)
|
||
|
||
LES BP,[THISDPB]
|
||
XOR AX,AX
|
||
MOV [LASTENT],AX
|
||
MOV BYTE PTR [VOLID],AL ; No volume ID found
|
||
DEC AX
|
||
MOV [ENTFREE],AX
|
||
MOV [ENTLAST],AX
|
||
return
|
||
StartSrch ENDP
|
||
|
||
BREAK <MatchAttributes - the final check for attribute matching>
|
||
|
||
;
|
||
; Input: [Attrib] = attribute to search for
|
||
; CH = found attribute
|
||
; Output: JZ <match>
|
||
; JNZ <nomatch>
|
||
;
|
||
procedure MatchAttributes,near
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
PUSH AX
|
||
MOV AL,[Attrib] ; AL <- SearchSet
|
||
NOT AL ; AL <- SearchSet'
|
||
AND AL,CH ; AL <- SearchSet' and FoundSet
|
||
AND AL,attr_all ; AL <- SearchSet' and FoundSet and Important
|
||
;
|
||
; the result is non-zero if an attribute is not in the search set
|
||
; and in the found set and in the important set. This means that we do not
|
||
; have a match. Do a JNZ <nomatch> or JZ <match>
|
||
;
|
||
POP AX
|
||
return
|
||
MatchAttributes ENDP
|
||
|
||
do_ext
|
||
|
||
CODE ENDS
|
||
END
|
||
|