MS-DOS/v2.0/source/FAT.ASM

362 lines
9.9 KiB
NASM
Raw Permalink Normal View History

1983-08-13 01:53:34 +01:00
;
; FAT operations 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 FAT - FAT maintenance routines
NAME FAT
i_need CURBUF,DWORD
i_need CLUSSPLIT,BYTE
i_need CLUSSAVE,WORD
i_need CLUSSEC,WORD
i_need THISDRV,BYTE
i_need DEVCALL,BYTE
i_need CALLMED,BYTE
i_need CALLRBYT,BYTE
i_need BUFFHEAD,DWORD
i_need CALLXAD,DWORD
i_need CALLBPB,DWORD
SUBTTL UNPACK -- UNPACK FAT ENTRIES
PAGE
ASSUME SS:DOSGROUP
procedure UNPACK,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Cluster number
; ES:BP = Base of drive parameters
; Outputs:
; DI = Contents of FAT for given cluster
; Zero set means DI=0 (free cluster)
; SI Destroyed, No other registers affected. Fatal error if cluster too big.
CMP BX,ES:[BP.dpb_max_cluster]
JA HURTFAT
CALL MAPCLUSTER
ASSUME DS:NOTHING
MOV DI,[DI]
JNC HAVCLUS
PUSH CX
MOV CL,4
SHR DI,CL
POP CX
STC
HAVCLUS:
AND DI,0FFFH
PUSH SS
POP DS
return
HURTFAT:
PUSH AX
MOV AH,80H ; Signal Bad FAT to INT int_fatal_abort handler
MOV DI,0FFFH ; In case INT int_fatal_abort returns (it shouldn't)
invoke FATAL
POP AX ; Try to ignore bad FAT
return
UNPACK ENDP
SUBTTL PACK -- PACK FAT ENTRIES
PAGE
procedure PACK,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Cluster number
; DX = Data
; ES:BP = Pointer to drive DPB
; Outputs:
; The data is stored in the FAT at the given cluster.
; SI,DX,DI all destroyed
; No other registers affected
CALL MAPCLUSTER
ASSUME DS:NOTHING
MOV SI,[DI]
JNC ALIGNED
PUSH CX
MOV CL,4
SHL DX,CL
POP CX
AND SI,0FH
JMP SHORT PACKIN
ALIGNED:
AND SI,0F000H
PACKIN:
OR SI,DX
MOV [DI],SI
LDS SI,[CURBUF]
MOV [SI.BUFDIRTY],1
CMP BYTE PTR [CLUSSPLIT],0
PUSH SS
POP DS
ASSUME DS:DOSGROUP
retz
PUSH AX
PUSH BX
PUSH CX
MOV AX,[CLUSSAVE]
MOV DS,WORD PTR [CURBUF+2]
ASSUME DS:NOTHING
ADD SI,BUFINSIZ
MOV [SI],AH
PUSH SS
POP DS
ASSUME DS:DOSGROUP
PUSH AX
MOV DX,[CLUSSEC]
MOV SI,1
XOR AL,AL
invoke GETBUFFRB
LDS DI,[CURBUF]
ASSUME DS:NOTHING
MOV [DI.BUFDIRTY],1
ADD DI,BUFINSIZ
DEC DI
ADD DI,ES:[BP.dpb_sector_size]
POP AX
MOV [DI],AL
PUSH SS
POP DS
POP CX
POP BX
POP AX
return
PACK ENDP
SUBTTL MAPCLUSTER - BUFFER A FAT SECTOR
PAGE
procedure MAPCLUSTER,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; ES:BP Points to DPB
; BX Is cluster number
; Function:
; Get a pointer to the cluster
; Outputs:
; DS:DI Points to contents of FAT for given cluster
; DS:SI Points to start of buffer
; Carry set if cluster data is in high 12 bits of word
; No other registers effected
MOV BYTE PTR [CLUSSPLIT],0
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AX,BX
SHR AX,1
ADD AX,BX
XOR DX,DX
MOV CX,ES:[BP.dpb_sector_size]
DIV CX ; AX is FAT sector # DX is sector index
ADD AX,ES:[BP.dpb_first_FAT]
DEC CX
PUSH AX
PUSH DX
PUSH CX
MOV DX,AX
XOR AL,AL
MOV SI,1
invoke GETBUFFRB
LDS SI,[CURBUF]
ASSUME DS:NOTHING
LEA DI,[SI.BufInSiz]
POP CX
POP AX
POP DX
ADD DI,AX
CMP AX,CX
JNZ MAPRET
MOV AL,[DI]
PUSH SS
POP DS
ASSUME DS:DOSGROUP
INC BYTE PTR [CLUSSPLIT]
MOV BYTE PTR [CLUSSAVE],AL
MOV [CLUSSEC],DX
INC DX
XOR AL,AL
MOV SI,1
invoke GETBUFFRB
LDS SI,[CURBUF]
ASSUME DS:NOTHING
LEA DI,[SI.BufInSiz]
MOV AL,[DI]
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV BYTE PTR [CLUSSAVE+1],AL
MOV DI,OFFSET DOSGROUP:CLUSSAVE
MAPRET:
POP DX
POP CX
POP BX
MOV AX,BX
SHR AX,1
POP AX
return
MAPCLUSTER ENDP
SUBTTL FATREAD -- CHECK DRIVE GET FAT
PAGE
ASSUME DS:DOSGROUP,ES:NOTHING
procedure FAT_operation,NEAR
FATERR:
AND DI,STECODE ; Put error code in DI
MOV AH,2 ; While trying to read FAT
MOV AL,BYTE PTR [THISDRV] ; Tell which drive
invoke FATAL1
entry FATREAD
ASSUME DS:DOSGROUP,ES:NOTHING
; Function:
; If disk may have been changed, FAT is read in and buffers are
; flagged invalid. If not, no action is taken.
; Outputs:
; ES:BP = Base of drive parameters
; All other registers destroyed
MOV AL,BYTE PTR [THISDRV]
invoke GETBP
MOV AL,DMEDHL
MOV AH,ES:[BP.dpb_UNIT]
MOV WORD PTR [DEVCALL],AX
MOV BYTE PTR [DEVCALL.REQFUNC],DEVMDCH
MOV [DEVCALL.REQSTAT],0
MOV AL,ES:[BP.dpb_media]
MOV BYTE PTR [CALLMED],AL
PUSH ES
PUSH DS
MOV BX,OFFSET DOSGROUP:DEVCALL
LDS SI,ES:[BP.dpb_driver_addr] ; DS:SI Points to device header
ASSUME DS:NOTHING
POP ES ; ES:BX Points to call header
invoke DEVIOCALL2
PUSH SS
POP DS
ASSUME DS:DOSGROUP
POP ES ; Restore ES:BP
MOV DI,[DEVCALL.REQSTAT]
TEST DI,STERR
JNZ FATERR
XOR AH,AH
XCHG AH,ES:[BP.dpb_first_access] ; Reset dpb_first_access
MOV AL,BYTE PTR [THISDRV] ; Use physical unit number
OR AH,BYTE PTR [CALLRBYT]
JS NEWDSK ; new disk or first access?
JZ CHKBUFFDIRT
return ; If Media not changed
CHKBUFFDIRT:
INC AH ; Here if ?Media..Check buffers
LDS DI,[BUFFHEAD]
ASSUME DS:NOTHING
NBUFFER: ; Look for dirty buffers
CMP AX,WORD PTR [DI.BUFDRV]
retz ; There is a dirty buffer, assume Media OK
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ NBUFFER
; If no dirty buffers, assume Media changed
NEWDSK:
invoke SETVISIT
NXBUFFER:
MOV [DI.VISIT],1
CMP AL,[DI.BUFDRV] ; For this drive?
JNZ SKPBUFF
MOV WORD PTR [DI.BUFDRV],00FFH ; Free up buffer
invoke SCANPLACE
SKPBUFF:
invoke SKIPVISIT
JNZ NXBUFFER
LDS DI,ES:[BP.dpb_driver_addr]
TEST [DI.SDEVATT],ISFATBYDEV
JNZ GETFREEBUF
context DS
MOV BX,2
CALL UNPACK ; Read the first FAT sector into CURBUF
LDS DI,[CURBUF]
JMP SHORT GOTGETBUF
GETFREEBUF:
ASSUME DS:NOTHING
PUSH ES ; Get a free buffer for BIOS to use
PUSH BP
LDS DI,[BUFFHEAD]
invoke BUFWRITE
POP BP
POP ES
GOTGETBUF:
ADD DI,BUFINSIZ
MOV WORD PTR [CALLXAD+2],DS
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV WORD PTR [CALLXAD],DI
MOV AL,DBPBHL
MOV AH,BYTE PTR ES:[BP.dpb_UNIT]
MOV WORD PTR [DEVCALL],AX
MOV BYTE PTR [DEVCALL.REQFUNC],DEVBPB
MOV [DEVCALL.REQSTAT],0
MOV AL,BYTE PTR ES:[BP.dpb_media]
MOV [CALLMED],AL
PUSH ES
PUSH DS
PUSH WORD PTR ES:[BP.dpb_driver_addr+2]
PUSH WORD PTR ES:[BP.dpb_driver_addr]
MOV BX,OFFSET DOSGROUP:DEVCALL
POP SI
POP DS ; DS:SI Points to device header
ASSUME DS:NOTHING
POP ES ; ES:BX Points to call header
invoke DEVIOCALL2
POP ES ; Restore ES:BP
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV DI,[DEVCALL.REQSTAT]
TEST DI,STERR
JNZ FATERRJ
MOV AL,BYTE PTR ES:[BP.dpb_media]
LDS SI,[CALLBPB]
ASSUME DS:NOTHING
CMP AL,BYTE PTR [SI.BPMEDIA]
JZ DPBOK
invoke $SETDPB
LDS DI,[CALLXAD] ; Get back buffer pointer
MOV AL,BYTE PTR ES:[BP.dpb_FAT_count]
MOV AH,BYTE PTR ES:[BP.dpb_FAT_size]
MOV WORD PTR [DI.BUFWRTCNT-BUFINSIZ],AX ;Correct buffer info
DPBOK:
context ds
MOV AX,-1
TEST ES:[BP.dpb_current_dir],AX
retz ; If root, leave as root
MOV ES:[BP.dpb_current_dir],AX ; Path may be bad, mark invalid
return
FATERRJ: JMP FATERR
FAT_operation ENDP
do_ext
CODE ENDS
END