1302 lines
37 KiB
NASM
1302 lines
37 KiB
NASM
;
|
||
; Disk 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 DISK - Disk utility routines
|
||
NAME Disk
|
||
|
||
i_need COUTDSAV,BYTE
|
||
i_need COUTSAV,DWORD
|
||
i_need CINDSAV,BYTE
|
||
i_need CINSAV,DWORD
|
||
i_need CONSWAP,BYTE
|
||
i_need IDLEINT,BYTE
|
||
i_need THISFCB,DWORD
|
||
i_need DMAADD,DWORD
|
||
i_need DEVCALL,BYTE
|
||
i_need CALLSCNT,WORD
|
||
i_need CALLXAD,DWORD
|
||
i_need CONTPOS,WORD
|
||
i_need NEXTADD,WORD
|
||
i_need CONBUF,BYTE
|
||
i_need User_SS,WORD
|
||
i_need User_SP,WORD
|
||
i_need DSKStack,BYTE
|
||
i_need InDOS,BYTE
|
||
i_need NumIO,BYTE
|
||
i_need CurDrv,BYTE
|
||
i_need ThisDrv,BYTE
|
||
i_need ClusFac,BYTE
|
||
i_need SecClusPos,BYTE
|
||
i_need DirSec,WORD
|
||
i_need ClusNum,WORD
|
||
i_need NxtClusNum,WORD
|
||
i_need ReadOp,BYTE
|
||
i_need DskErr,BYTE
|
||
i_need RecCnt,WORD
|
||
i_need RecPos,4
|
||
i_need Trans,BYTE
|
||
i_need BytPos,4
|
||
i_need SecPos,WORD
|
||
i_need BytSecPos,WORD
|
||
i_need BytCnt1,WORD
|
||
i_need BytCnt2,WORD
|
||
i_need SecCnt,WORD
|
||
i_need ThisDPB,DWORD
|
||
i_need LastPos,WORD
|
||
i_need ValSec,WORD
|
||
i_need GrowCnt,DWORD
|
||
|
||
SUBTTL LOAD -- MAIN READ ROUTINE AND DEVICE IN ROUTINES
|
||
PAGE
|
||
; * * * * Drivers for file input from devices * * * *
|
||
|
||
procedure SWAPBACK,NEAR
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
PUSH ES
|
||
PUSH DI
|
||
PUSH SI
|
||
PUSH BX
|
||
MOV BX,1
|
||
invoke get_sf_from_jfn
|
||
ADD DI,sf_fcb
|
||
MOV BL,BYTE PTR [COUTDSAV]
|
||
LDS SI,[COUTSAV]
|
||
ASSUME DS:NOTHING
|
||
MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI
|
||
MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS
|
||
MOV ES:[DI.fcb_DEVID],BL
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
XOR BX,BX
|
||
invoke get_sf_from_jfn
|
||
ADD DI,sf_fcb
|
||
MOV BL,BYTE PTR [CINDSAV]
|
||
LDS SI,[CINSAV]
|
||
ASSUME DS:NOTHING
|
||
MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI
|
||
MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS
|
||
MOV ES:[DI.fcb_DEVID],BL
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV BYTE PTR [CONSWAP],0
|
||
MOV BYTE PTR [IDLEINT],1
|
||
SWAPRET:
|
||
POP BX
|
||
POP SI
|
||
POP DI
|
||
POP ES
|
||
return
|
||
SWAPBACK ENDP
|
||
|
||
procedure SWAPCON,NEAR
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
PUSH ES
|
||
PUSH DI
|
||
PUSH SI
|
||
PUSH BX
|
||
MOV BYTE PTR [CONSWAP],1
|
||
MOV BYTE PTR [IDLEINT],0
|
||
XOR BX,BX
|
||
invoke get_sf_from_jfn
|
||
ADD DI,sf_fcb
|
||
MOV BL,ES:[DI.fcb_DEVID]
|
||
MOV BYTE PTR [CINDSAV],BL
|
||
LDS SI,DWORD PTR ES:[DI.fcb_FIRCLUS]
|
||
ASSUME DS:NOTHING
|
||
MOV WORD PTR [CINSAV],SI
|
||
MOV WORD PTR [CINSAV+2],DS
|
||
LDS SI,[THISFCB]
|
||
MOV BL,[SI.fcb_DEVID]
|
||
LDS SI,DWORD PTR [SI.fcb_FIRCLUS]
|
||
MOV ES:[DI.fcb_DEVID],BL
|
||
MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI
|
||
MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV BX,1
|
||
invoke get_sf_from_jfn
|
||
ADD DI,sf_fcb
|
||
MOV BL,ES:[DI.fcb_DEVID]
|
||
MOV BYTE PTR [COUTDSAV],BL
|
||
LDS SI,DWORD PTR ES:[DI.fcb_FIRCLUS]
|
||
ASSUME DS:NOTHING
|
||
MOV WORD PTR [COUTSAV],SI
|
||
MOV WORD PTR [COUTSAV+2],DS
|
||
LDS SI,[THISFCB]
|
||
MOV BL,[SI.fcb_DEVID]
|
||
LDS SI,DWORD PTR [SI.fcb_FIRCLUS]
|
||
MOV ES:[DI.fcb_DEVID],BL
|
||
MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI
|
||
MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS
|
||
PUSH SS
|
||
POP DS
|
||
JMP SWAPRET
|
||
SWAPCON ENDP
|
||
|
||
procedure LOAD,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
;
|
||
; Inputs:
|
||
; DS:DI point to FCB
|
||
; DX:AX = Position in file to read
|
||
; CX = No. of records to read
|
||
; Outputs:
|
||
; DX:AX = Position of last record read
|
||
; CX = No. of bytes read
|
||
; ES:DI point to FCB
|
||
; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set
|
||
|
||
call SETUP
|
||
ASSUME DS:DOSGROUP
|
||
OR BL,BL ; Check for named device I/O
|
||
JS READDEV
|
||
call DISKREAD
|
||
return
|
||
|
||
READDEV:
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
LES DI,[DMAADD]
|
||
TEST BL,40H ; End of file?
|
||
JZ ENDRDDEVJ3
|
||
TEST BL,ISNULL ; NUL device?
|
||
JZ TESTRAW ; NO
|
||
XOR AL,AL ; Indicate EOF
|
||
ENDRDDEVJ3: JMP ENDRDDEVJ2
|
||
|
||
DVRDRAW:
|
||
ASSUME DS:DOSGROUP
|
||
PUSH ES
|
||
POP DS
|
||
ASSUME DS:NOTHING
|
||
DVRDRAWR:
|
||
MOV BX,DI ; DS:BX transfer addr
|
||
XOR DX,DX ; Start at 0
|
||
XOR AX,AX ; Media Byte, unit = 0
|
||
invoke SETREAD
|
||
LDS SI,[THISFCB]
|
||
invoke DEVIOCALL
|
||
MOV DX,DI ; DX is preserved by INT 24
|
||
MOV AH,86H ; Read error
|
||
MOV DI,[DEVCALL.REQSTAT]
|
||
TEST DI,STERR
|
||
JZ CRDROK ; No errors
|
||
invoke CHARHARD
|
||
MOV DI,DX
|
||
CMP AL,1
|
||
JZ DVRDRAWR ; Retry
|
||
CRDROK:
|
||
MOV DI,DX
|
||
ADD DI,[CALLSCNT] ; Amount transferred
|
||
JMP SHORT ENDRDDEVJ2
|
||
|
||
TESTRAW:
|
||
TEST BL,020H ; Raw mode?
|
||
JNZ DVRDRAW
|
||
TEST BL,ISCIN ; Is it console device?
|
||
JZ NOTRDCON
|
||
JMP READCON
|
||
NOTRDCON:
|
||
MOV AX,ES
|
||
MOV DS,AX
|
||
ASSUME DS:NOTHING
|
||
MOV BX,DI
|
||
XOR DX,DX
|
||
MOV AX,DX
|
||
PUSH CX
|
||
MOV CX,1
|
||
invoke SETREAD
|
||
POP CX
|
||
LDS SI,[THISFCB]
|
||
LDS SI,DWORD PTR [SI.fcb_FIRCLUS]
|
||
DVRDLP:
|
||
invoke DSKSTATCHK
|
||
invoke DEVIOCALL2
|
||
PUSH DI
|
||
MOV AH,86H
|
||
MOV DI,[DEVCALL.REQSTAT]
|
||
TEST DI,STERR
|
||
JZ CRDOK
|
||
invoke CHARHARD
|
||
POP DI
|
||
MOV [CALLSCNT],1
|
||
CMP AL,1
|
||
JZ DVRDLP ;Retry
|
||
XOR AL,AL ;Pick some random character
|
||
JMP SHORT DVRDIGN
|
||
CRDOK:
|
||
POP DI
|
||
CMP [CALLSCNT],1
|
||
JNZ ENDRDDEVJ2
|
||
PUSH DS
|
||
MOV DS,WORD PTR [CALLXAD+2]
|
||
MOV AL,BYTE PTR [DI]
|
||
POP DS
|
||
DVRDIGN:
|
||
INC WORD PTR [CALLXAD]
|
||
MOV [DEVCALL.REQSTAT],0
|
||
INC DI
|
||
CMP AL,1AH ; ^Z?
|
||
JZ ENDRDDEVJ
|
||
CMP AL,c_CR ; CR?
|
||
LOOPNZ DVRDLP
|
||
ENDRDDEVJ:
|
||
DEC DI
|
||
ENDRDDEVJ2:
|
||
JMP SHORT ENDRDDEV
|
||
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
TRANBUF:
|
||
LODSB
|
||
STOSB
|
||
CMP AL,c_CR ; Check for carriage return
|
||
JNZ NORMCH
|
||
MOV BYTE PTR [SI],c_LF
|
||
NORMCH:
|
||
CMP AL,c_LF
|
||
LOOPNZ TRANBUF
|
||
JNZ ENDRDCON
|
||
XOR SI,SI ; Cause a new buffer to be read
|
||
invoke OUT ; Transmit linefeed
|
||
OR AL,1 ; Clear zero flag--not end of file
|
||
ENDRDCON:
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
CALL SWAPBACK
|
||
MOV [CONTPOS],SI
|
||
ENDRDDEV:
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV [NEXTADD],DI
|
||
JNZ SETFCBC ; Zero set if Ctrl-Z found in input
|
||
LES DI,[THISFCB]
|
||
AND ES:BYTE PTR [DI.fcb_DEVID],0FFH-40H ; Mark as no more data available
|
||
SETFCBC:
|
||
call SETFCB
|
||
return
|
||
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
READCON:
|
||
ASSUME DS:DOSGROUP
|
||
CALL SWAPCON
|
||
MOV SI,[CONTPOS]
|
||
OR SI,SI
|
||
JNZ TRANBUF
|
||
CMP BYTE PTR [CONBUF],128
|
||
JZ GETBUF
|
||
MOV WORD PTR [CONBUF],0FF80H ; Set up 128-byte buffer with no template
|
||
GETBUF:
|
||
PUSH CX
|
||
PUSH ES
|
||
PUSH DI
|
||
MOV DX,OFFSET DOSGROUP:CONBUF
|
||
invoke $STD_CON_STRING_INPUT ; Get input buffer
|
||
POP DI
|
||
POP ES
|
||
POP CX
|
||
MOV SI,2 + OFFSET DOSGROUP:CONBUF
|
||
CMP BYTE PTR [SI],1AH ; Check for Ctrl-Z in first character
|
||
JNZ TRANBUF
|
||
MOV AL,1AH
|
||
STOSB
|
||
DEC DI
|
||
MOV AL,10
|
||
invoke OUT ; Send linefeed
|
||
XOR SI,SI
|
||
JMP SHORT ENDRDCON
|
||
|
||
LOAD ENDP
|
||
|
||
SUBTTL STORE -- MAIN WRITE ROUTINE AND DEVICE OUT ROUTINES
|
||
PAGE
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
procedure STORE,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DS:DI point to FCB
|
||
; DX:AX = Position in file of disk transfer
|
||
; CX = Record count
|
||
; Outputs:
|
||
; DX:AX = Position of last record written
|
||
; CX = No. of records written
|
||
; ES:DI point to FCB
|
||
; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set
|
||
|
||
call SETUP
|
||
ASSUME DS:DOSGROUP
|
||
OR BL,BL
|
||
JS WRTDEV
|
||
invoke DATE16
|
||
MOV ES:[DI.fcb_FDATE],AX
|
||
MOV ES:[DI.fcb_FTIME],DX
|
||
call DISKWRITE
|
||
return
|
||
|
||
WRITECON:
|
||
PUSH DS
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
CALL SWAPCON
|
||
POP DS
|
||
ASSUME DS:NOTHING
|
||
MOV SI,BX
|
||
PUSH CX
|
||
WRCONLP:
|
||
LODSB
|
||
CMP AL,1AH ; ^Z?
|
||
JZ CONEOF
|
||
invoke OUT
|
||
LOOP WRCONLP
|
||
CONEOF:
|
||
POP AX ; Count
|
||
SUB AX,CX ; Amount actually written
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
CALL SWAPBACK
|
||
JMP SHORT ENDWRDEV
|
||
|
||
DVWRTRAW:
|
||
ASSUME DS:NOTHING
|
||
XOR AX,AX ; Media Byte, unit = 0
|
||
invoke SETWRITE
|
||
LDS SI,[THISFCB]
|
||
invoke DEVIOCALL
|
||
MOV DX,DI
|
||
MOV AH,87H
|
||
MOV DI,[DEVCALL.REQSTAT]
|
||
TEST DI,STERR
|
||
JZ CWRTROK
|
||
invoke CHARHARD
|
||
MOV BX,DX ; Recall transfer addr
|
||
CMP AL,1
|
||
JZ DVWRTRAW ; Try again
|
||
CWRTROK:
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV AX,[CALLSCNT] ; Get actual number of bytes transferred
|
||
ENDWRDEV:
|
||
LES DI,[THISFCB]
|
||
XOR DX,DX
|
||
DIV ES:[DI.fcb_RECSIZ]
|
||
MOV CX,AX ; Partial record is ignored
|
||
call ADDREC
|
||
return
|
||
|
||
ASSUME DS:DOSGROUP
|
||
WRTDEV:
|
||
OR BL,40H ; Reset EOF for input
|
||
XOR AX,AX
|
||
JCXZ ENDWRDEV ; problem of creating on a device.
|
||
PUSH DS
|
||
MOV AL,BL
|
||
LDS BX,[DMAADD]
|
||
ASSUME DS:NOTHING
|
||
MOV DI,BX
|
||
XOR DX,DX ; Set starting point
|
||
TEST AL,020H ; Raw?
|
||
JNZ DVWRTRAW
|
||
TEST AL,ISCOUT ; Console output device?
|
||
JNZ WRITECON
|
||
TEST AL,ISNULL
|
||
JNZ WRTNUL
|
||
MOV AX,DX
|
||
CMP BYTE PTR [BX],1AH ; ^Z?
|
||
JZ WRTCOOKDONE ; Yes, transfer nothing
|
||
PUSH CX
|
||
MOV CX,1
|
||
invoke SETWRITE
|
||
POP CX
|
||
LDS SI,[THISFCB]
|
||
LDS SI,DWORD PTR [SI.fcb_FIRCLUS]
|
||
DVWRTLP:
|
||
invoke DSKSTATCHK
|
||
invoke DEVIOCALL2
|
||
PUSH DI
|
||
MOV AH,87H
|
||
MOV DI,[DEVCALL.REQSTAT]
|
||
TEST DI,STERR
|
||
JZ CWROK
|
||
invoke CHARHARD
|
||
POP DI
|
||
MOV [CALLSCNT],1
|
||
CMP AL,1
|
||
JZ DVWRTLP
|
||
JMP SHORT DVWRTIGN
|
||
CWROK:
|
||
POP DI
|
||
CMP [CALLSCNT],0
|
||
JZ WRTCOOKDONE
|
||
DVWRTIGN:
|
||
INC DX
|
||
INC WORD PTR [CALLXAD]
|
||
INC DI
|
||
PUSH DS
|
||
MOV DS,WORD PTR [CALLXAD+2]
|
||
CMP BYTE PTR [DI],1AH ; ^Z?
|
||
POP DS
|
||
JZ WRTCOOKDONE
|
||
MOV [DEVCALL.REQSTAT],0
|
||
LOOP DVWRTLP
|
||
WRTCOOKDONE:
|
||
MOV AX,DX
|
||
POP DS
|
||
JMP ENDWRDEV
|
||
|
||
WRTNUL:
|
||
MOV DX,CX ;Entire transfer done
|
||
JMP WRTCOOKDONE
|
||
|
||
STORE ENDP
|
||
|
||
procedure get_io_fcb,near
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
; Convert JFN number in BX to FCB in DS:SI
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
PUSH ES
|
||
PUSH DI
|
||
invoke get_sf_from_jfn
|
||
JC RET44P
|
||
MOV SI,DI
|
||
ADD SI,sf_fcb
|
||
PUSH ES
|
||
POP DS
|
||
ASSUME DS:NOTHING
|
||
RET44P:
|
||
POP DI
|
||
POP ES
|
||
return
|
||
get_io_fcb ENDP
|
||
|
||
SUBTTL GETTHISDRV -- FIND CURRENT DRIVE
|
||
PAGE
|
||
; Input: AL has drive identifier (1=A, 0=default)
|
||
; Output: AL has physical drive (0=A)
|
||
; Carry set if invalid drive (and AL is garbage anyway)
|
||
procedure GetThisDrv,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
CMP BYTE PTR [NUMIO],AL
|
||
retc
|
||
DEC AL
|
||
JNS PHYDRV
|
||
MOV AL,[CURDRV]
|
||
PHYDRV:
|
||
MOV BYTE PTR [THISDRV],AL
|
||
return
|
||
GetThisDrv ENDP
|
||
|
||
SUBTTL DIRREAD -- READ A DIRECTORY SECTOR
|
||
PAGE
|
||
procedure DirRead,NEAR
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; AX = Directory block number (relative to first block of directory)
|
||
; ES:BP = Base of drive parameters
|
||
; [DIRSEC] = First sector of first cluster of directory
|
||
; [CLUSNUM] = Next cluster
|
||
; [CLUSFAC] = Sectors/Cluster
|
||
; Function:
|
||
; Read the directory block into [CURBUF].
|
||
; Outputs:
|
||
; [NXTCLUSNUM] = Next cluster (after the one skipped to)
|
||
; [SECCLUSPOS] Set
|
||
; ES:BP unchanged [CURBUF] Points to Buffer with dir sector
|
||
; All other registers destroyed.
|
||
|
||
MOV CL,[CLUSFAC]
|
||
DIV CL ; AL # clusters to skip, AH position in cluster
|
||
MOV [SECCLUSPOS],AH
|
||
MOV CL,AL
|
||
XOR CH,CH
|
||
MOV DX,[DIRSEC]
|
||
ADD DL,AH
|
||
ADC DH,0
|
||
MOV BX,[CLUSNUM]
|
||
MOV [NXTCLUSNUM],BX
|
||
JCXZ FIRSTCLUSTER
|
||
SKPCLLP:
|
||
invoke UNPACK
|
||
XCHG BX,DI
|
||
CMP BX,0FF8H
|
||
JAE HAVESKIPPED
|
||
LOOP SKPCLLP
|
||
HAVESKIPPED:
|
||
MOV [NXTCLUSNUM],BX
|
||
MOV DX,DI
|
||
MOV BL,AH
|
||
invoke FIGREC
|
||
entry FIRSTCLUSTER
|
||
XOR AL,AL ; Indicate pre-read
|
||
MOV AH,DIRPRI
|
||
invoke GETBUFFR
|
||
ret
|
||
DirRead ENDP
|
||
|
||
SUBTTL FATSECRD -- READ A FAT SECTOR
|
||
PAGE
|
||
procedure FATSecRd,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; Same as DREAD
|
||
; DS:BX = Transfer address
|
||
; CX = Number of sectors
|
||
; DX = Absolute record number
|
||
; ES:BP = Base of drive parameters
|
||
; Function:
|
||
; Calls BIOS to perform FAT read.
|
||
; Outputs:
|
||
; Same as DREAD
|
||
|
||
MOV DI,CX
|
||
MOV CL,ES:[BP.dpb_FAT_count]
|
||
MOV AL,ES:[BP.dpb_FAT_size]
|
||
XOR AH,AH
|
||
MOV CH,AH
|
||
PUSH DX
|
||
NXTFAT:
|
||
PUSH CX
|
||
PUSH AX
|
||
MOV CX,DI
|
||
CALL DSKREAD
|
||
POP AX
|
||
POP CX
|
||
JZ RET41P
|
||
ADD DX,AX
|
||
LOOP NXTFAT
|
||
POP DX
|
||
MOV CX,DI
|
||
|
||
; NOTE FALL THROUGH
|
||
|
||
SUBTTL DREAD -- DO A DISK READ
|
||
PAGE
|
||
entry DREAD
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DS:BX = Transfer address
|
||
; CX = Number of sectors
|
||
; DX = Absolute record number
|
||
; ES:BP = Base of drive parameters
|
||
; Function:
|
||
; Calls BIOS to perform disk read. If BIOS reports
|
||
; errors, will call HARDERR for further action.
|
||
; DS,ES:BP preserved. All other registers destroyed.
|
||
|
||
CALL DSKREAD
|
||
retz
|
||
MOV BYTE PTR [READOP],0
|
||
invoke HARDERR
|
||
CMP AL,1 ; Check for retry
|
||
JZ DREAD
|
||
return ; Ignore otherwise
|
||
RET41P: POP DX
|
||
return
|
||
FATSecRd ENDP
|
||
|
||
SUBTTL DSKREAD -- PHYSICAL DISK READ
|
||
PAGE
|
||
procedure DskRead,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DS:BX = Transfer addr
|
||
; CX = Number of sectors
|
||
; DX = Absolute record number
|
||
; ES:BP = Base of drive parameters
|
||
; Function:
|
||
; Call BIOS to perform disk read
|
||
; Outputs:
|
||
; DI = CX on entry
|
||
; CX = Number of sectors unsuccessfully transfered
|
||
; AX = Status word as returned by BIOS (error code in AL if error)
|
||
; Zero set if OK (from BIOS)
|
||
; Zero clear if error
|
||
; SI Destroyed, others preserved
|
||
|
||
PUSH CX
|
||
MOV AH,ES:[BP.dpb_media]
|
||
MOV AL,ES:[BP.dpb_UNIT]
|
||
PUSH BX
|
||
PUSH ES
|
||
invoke SETREAD
|
||
JMP DODSKOP
|
||
|
||
SUBTTL DWRITE -- SEE ABOUT WRITING
|
||
PAGE
|
||
entry DWRITE
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DS:BX = Transfer address
|
||
; CX = Number of sectors
|
||
; DX = Absolute record number
|
||
; ES:BP = Base of drive parameters
|
||
; Function:
|
||
; Calls BIOS to perform disk write. If BIOS reports
|
||
; errors, will call HARDERR for further action.
|
||
; BP preserved. All other registers destroyed.
|
||
|
||
CALL DSKWRITE
|
||
retz
|
||
MOV BYTE PTR [READOP],1
|
||
invoke HARDERR
|
||
CMP AL,1 ; Check for retry
|
||
JZ DWRITE
|
||
return
|
||
|
||
SUBTTL DSKWRITE -- PHYSICAL DISK WRITE
|
||
PAGE
|
||
entry DSKWRITE
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DS:BX = Transfer addr
|
||
; CX = Number of sectors
|
||
; DX = Absolute record number
|
||
; ES:BP = Base of drive parameters
|
||
; Function:
|
||
; Call BIOS to perform disk read
|
||
; Outputs:
|
||
; DI = CX on entry
|
||
; CX = Number of sectors unsuccessfully transfered
|
||
; AX = Status word as returned by BIOS (error code in AL if error)
|
||
; Zero set if OK (from BIOS)
|
||
; Zero clear if error
|
||
; SI Destroyed, others preserved
|
||
|
||
PUSH CX
|
||
MOV AH,ES:[BP.dpb_media]
|
||
MOV AL,ES:[BP.dpb_UNIT]
|
||
PUSH BX
|
||
PUSH ES
|
||
invoke SETWRITE
|
||
DODSKOP:
|
||
MOV CX,DS ; Save DS
|
||
POP DS ; DS:BP points to DPB
|
||
PUSH DS
|
||
LDS SI,DS:[BP.dpb_driver_addr]
|
||
invoke DEVIOCALL2
|
||
MOV DS,CX ; Restore DS
|
||
POP ES ; Restore ES
|
||
POP BX
|
||
MOV CX,[CALLSCNT] ; Number of sectors transferred
|
||
POP DI
|
||
SUB CX,DI
|
||
NEG CX ; Number of sectors not transferred
|
||
MOV AX,[DEVCALL.REQSTAT]
|
||
TEST AX,STERR
|
||
return
|
||
DskRead ENDP
|
||
|
||
SUBTTL SETUP -- SETUP A DISK READ OR WRITE FROM USER
|
||
PAGE
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
procedure SETUP,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DS:DI point to FCB
|
||
; DX:AX = Record position in file of disk transfer
|
||
; CX = Record count
|
||
; Outputs:
|
||
; DS = DOSGROUP
|
||
; BL = fcb_DEVID from FCB
|
||
; CX = No. of bytes to transfer (0 = 64K)
|
||
; [THISDPB] = Base of drive parameters
|
||
; [RECCNT] = Record count
|
||
; [RECPOS] = Record position in file
|
||
; ES:DI Points to FCB
|
||
; [THISFCB] = ES:DI
|
||
; [NEXTADD] = Displacement of disk transfer within segment
|
||
; [SECPOS] = Position of first sector
|
||
; [BYTPOS] = Byte position in file
|
||
; [BYTSECPOS] = Byte position in first sector
|
||
; [CLUSNUM] = First cluster
|
||
; [SECCLUSPOS] = Sector within first cluster
|
||
; [DSKERR] = 0 (no errors yet)
|
||
; [TRANS] = 0 (No transfers yet)
|
||
; [THISDRV] = Physical drive unit number
|
||
|
||
PUSH AX
|
||
MOV AL,[DI]
|
||
DEC AL
|
||
MOV BYTE PTR [THISDRV],AL
|
||
MOV AL,[DI.fcb_DEVID]
|
||
MOV SI,[DI.fcb_RECSIZ]
|
||
OR SI,SI
|
||
JNZ HAVRECSIZ
|
||
MOV SI,128
|
||
MOV [DI.fcb_RECSIZ],SI
|
||
HAVRECSIZ:
|
||
MOV WORD PTR [THISFCB+2],DS
|
||
PUSH SS
|
||
POP DS ; Set DS to DOSGROUP
|
||
ASSUME DS:DOSGROUP
|
||
MOV WORD PTR [THISFCB],DI
|
||
OR AL,AL ; Is it a device?
|
||
JNS NOTDEVICE
|
||
XOR AL,AL ; Fake in drive 0 so we can get BP
|
||
NOTDEVICE:
|
||
invoke GETBP
|
||
POP AX
|
||
JNC CheckRecLen
|
||
XOR CX,CX
|
||
MOV BYTE PTR [DSKERR],4
|
||
POP BX
|
||
return
|
||
|
||
CheckRecLen:
|
||
CMP SI,64 ; Check if highest byte of RECPOS is significant
|
||
JB SMALREC
|
||
XOR DH,DH ; Ignore MSB if record >= 64 bytes
|
||
SMALREC:
|
||
MOV [RECCNT],CX
|
||
MOV WORD PTR [RECPOS],AX
|
||
MOV WORD PTR [RECPOS+2],DX
|
||
MOV BX,WORD PTR [DMAADD]
|
||
MOV [NEXTADD],BX
|
||
MOV BYTE PTR [DSKERR],0
|
||
MOV BYTE PTR [TRANS],0
|
||
MOV BX,DX
|
||
MUL SI
|
||
MOV WORD PTR [BYTPOS],AX
|
||
PUSH DX
|
||
MOV AX,BX
|
||
MUL SI
|
||
POP BX
|
||
ADD AX,BX
|
||
ADC DX,0 ; Ripple carry
|
||
JNZ EOFERR
|
||
MOV WORD PTR [BYTPOS+2],AX
|
||
MOV DX,AX
|
||
MOV AX,WORD PTR [BYTPOS]
|
||
MOV BX,ES:[BP.dpb_sector_size]
|
||
CMP DX,BX ; See if divide will overflow
|
||
JNC EOFERR
|
||
DIV BX
|
||
MOV [SECPOS],AX
|
||
MOV [BYTSECPOS],DX
|
||
MOV DX,AX
|
||
AND AL,ES:[BP.dpb_cluster_mask]
|
||
MOV [SECCLUSPOS],AL
|
||
MOV AX,CX ; Record count
|
||
MOV CL,ES:[BP.dpb_cluster_shift]
|
||
SHR DX,CL
|
||
MOV [CLUSNUM],DX
|
||
MUL SI ; Multiply by bytes per record
|
||
MOV CX,AX
|
||
ADD AX,WORD PTR [DMAADD] ; See if it will fit in one segment
|
||
ADC DX,0
|
||
JZ OK ; Must be less than 64K
|
||
MOV AX,WORD PTR [DMAADD]
|
||
NEG AX ; Amount of room left in segment
|
||
JNZ PARTSEG
|
||
DEC AX
|
||
PARTSEG:
|
||
XOR DX,DX
|
||
DIV SI ; How many records will fit?
|
||
MOV [RECCNT],AX
|
||
MUL SI ; Translate that back into bytes
|
||
MOV BYTE PTR [DSKERR],2 ; Flag that trimming took place
|
||
MOV CX,AX
|
||
JCXZ NOROOM
|
||
OK:
|
||
LES DI,[THISFCB]
|
||
MOV BL,ES:[DI.fcb_DEVID]
|
||
return
|
||
|
||
EOFERR:
|
||
MOV BYTE PTR [DSKERR],1
|
||
XOR CX,CX
|
||
NOROOM:
|
||
LES DI,[THISFCB]
|
||
POP BX ; Kill return address
|
||
return
|
||
SETUP ENDP
|
||
|
||
SUBTTL BREAKDOWN -- CUT A USER READ OR WRITE INTO PIECES
|
||
PAGE
|
||
procedure BREAKDOWN,near
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; CX = Length of disk transfer in bytes
|
||
; ES:BP = Base of drive parameters
|
||
; [BYTSECPOS] = Byte position witin first sector
|
||
; Outputs:
|
||
; [BYTCNT1] = Bytes to transfer in first sector
|
||
; [SECCNT] = No. of whole sectors to transfer
|
||
; [BYTCNT2] = Bytes to transfer in last sector
|
||
; AX, BX, DX destroyed. No other registers affected.
|
||
|
||
MOV AX,[BYTSECPOS]
|
||
MOV BX,CX
|
||
OR AX,AX
|
||
JZ SAVFIR ; Partial first sector?
|
||
SUB AX,ES:[BP.dpb_sector_size]
|
||
NEG AX ; Max number of bytes left in first sector
|
||
SUB BX,AX ; Subtract from total length
|
||
JAE SAVFIR
|
||
ADD AX,BX ; Don't use all of the rest of the sector
|
||
XOR BX,BX ; And no bytes are left
|
||
SAVFIR:
|
||
MOV [BYTCNT1],AX
|
||
MOV AX,BX
|
||
XOR DX,DX
|
||
DIV ES:[BP.dpb_sector_size] ; How many whole sectors?
|
||
MOV [SECCNT],AX
|
||
MOV [BYTCNT2],DX ; Bytes remaining for last sector
|
||
OR DX,[BYTCNT1]
|
||
retnz ; NOT (BYTCNT1 = BYTCNT2 = 0)
|
||
CMP AX,1
|
||
retnz
|
||
MOV AX,ES:[BP.dpb_sector_size] ; Buffer EXACT one sector I/O
|
||
MOV [BYTCNT2],AX
|
||
MOV [SECCNT],DX ; DX = 0
|
||
return
|
||
BreakDown ENDP
|
||
|
||
SUBTTL DISKREAD -- PERFORM USER DISK READ
|
||
PAGE
|
||
procedure DISKREAD,NEAR
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; Outputs of SETUP
|
||
; Function:
|
||
; Perform disk read
|
||
; Outputs:
|
||
; DX:AX = Position of last record read
|
||
; CX = No. of records read
|
||
; ES:DI point to FCB
|
||
; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set
|
||
|
||
MOV AX,ES:WORD PTR [DI.fcb_FILSIZ]
|
||
MOV BX,ES:WORD PTR [DI.fcb_FILSIZ+2]
|
||
SUB AX,WORD PTR [BYTPOS]
|
||
SBB BX,WORD PTR [BYTPOS+2]
|
||
JB RDERR
|
||
JNZ ENUF
|
||
OR AX,AX
|
||
JZ RDERR
|
||
CMP AX,CX
|
||
JAE ENUF
|
||
MOV CX,AX
|
||
ENUF:
|
||
LES BP,[THISDPB]
|
||
CALL BREAKDOWN
|
||
MOV CX,[CLUSNUM]
|
||
invoke FNDCLUS
|
||
OR CX,CX
|
||
JZ SHORT SKIPERR
|
||
RDERR:
|
||
JMP WRTERR
|
||
RDLASTJ:JMP RDLAST
|
||
SETFCBJ2: JMP SETFCB
|
||
|
||
SKIPERR:
|
||
|
||
MOV [LASTPOS],DX
|
||
MOV [CLUSNUM],BX
|
||
CMP [BYTCNT1],0
|
||
JZ RDMID
|
||
invoke BUFRD
|
||
RDMID:
|
||
CMP [SECCNT],0
|
||
JZ RDLASTJ
|
||
invoke NEXTSEC
|
||
JC SETFCBJ2
|
||
MOV BYTE PTR [TRANS],1 ; A transfer is taking place
|
||
ONSEC:
|
||
MOV DL,[SECCLUSPOS]
|
||
MOV CX,[SECCNT]
|
||
MOV BX,[CLUSNUM]
|
||
RDLP:
|
||
invoke OPTIMIZE
|
||
PUSH DI
|
||
PUSH AX
|
||
PUSH BX
|
||
MOV DS,WORD PTR [DMAADD+2]
|
||
ASSUME DS:NOTHING
|
||
PUSH DX
|
||
PUSH CX
|
||
CALL DREAD
|
||
POP BX
|
||
POP DX
|
||
ADD BX,DX ; Upper bound of read
|
||
MOV AL,ES:[BP.dpb_drive]
|
||
invoke SETVISIT
|
||
NXTBUF: ; Must see if one of these sectors is buffered
|
||
MOV [DI.VISIT],1 ; Mark as visited
|
||
CMP AL,[DI.BUFDRV]
|
||
JNZ DONXTBUF ; Not for this drive
|
||
CMP [DI.BUFSECNO],DX
|
||
JC DONXTBUF ; Below first sector
|
||
CMP [DI.BUFSECNO],BX
|
||
JNC DONXTBUF ; Above last sector
|
||
CMP BYTE PTR [DI.BUFDIRTY],0
|
||
JZ CLBUFF ; Buffer is clean, so OK
|
||
; A sector has been read in when a dirty copy of it is in a buffer
|
||
; The buffered sector must now be read into the right place
|
||
POP AX ; Recall transfer address
|
||
PUSH AX
|
||
PUSH DI ; Save search environment
|
||
PUSH DX
|
||
SUB DX,[DI.BUFSECNO] ; How far into transfer?
|
||
NEG DX
|
||
MOV SI,DI
|
||
MOV DI,AX
|
||
MOV AX,DX
|
||
MOV CX,ES:[BP.dpb_sector_size]
|
||
MUL CX
|
||
ADD DI,AX ; Put the buffer here
|
||
ADD SI,BUFINSIZ
|
||
SHR CX,1
|
||
PUSH ES
|
||
MOV ES,WORD PTR [DMAADD+2]
|
||
REP MOVSW
|
||
JNC EVENMOV
|
||
MOVSB
|
||
EVENMOV:
|
||
POP ES
|
||
POP DX
|
||
POP DI
|
||
MOV AL,ES:[BP.dpb_drive]
|
||
CLBUFF:
|
||
invoke SCANPLACE
|
||
DONXTBUF:
|
||
invoke SKIPVISIT
|
||
JNZ NXTBUF
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
POP CX
|
||
POP CX
|
||
POP BX
|
||
JCXZ RDLAST
|
||
CMP BX,0FF8H
|
||
JAE SETFCB
|
||
MOV DL,0
|
||
INC [LASTPOS] ; We'll be using next cluster
|
||
JMP RDLP
|
||
|
||
RDLAST:
|
||
MOV AX,[BYTCNT2]
|
||
OR AX,AX
|
||
JZ SETFCB
|
||
MOV [BYTCNT1],AX
|
||
invoke NEXTSEC
|
||
JC SETFCB
|
||
MOV [BYTSECPOS],0
|
||
invoke BUFRD
|
||
|
||
entry SETFCB
|
||
LES SI,[THISFCB]
|
||
MOV AX,[NEXTADD]
|
||
MOV DI,AX
|
||
SUB AX,WORD PTR [DMAADD] ; Number of bytes transfered
|
||
XOR DX,DX
|
||
MOV CX,ES:[SI.fcb_RECSIZ]
|
||
DIV CX ; Number of records
|
||
CMP AX,[RECCNT] ; Check if all records transferred
|
||
JZ FULLREC
|
||
MOV BYTE PTR [DSKERR],1
|
||
OR DX,DX
|
||
JZ FULLREC ; If remainder 0, then full record transfered
|
||
MOV BYTE PTR [DSKERR],3 ; Flag partial last record
|
||
SUB CX,DX ; Bytes left in last record
|
||
PUSH ES
|
||
MOV ES,WORD PTR [DMAADD+2]
|
||
XCHG AX,BX ; Save the record count temporarily
|
||
XOR AX,AX ; Fill with zeros
|
||
SHR CX,1
|
||
JNC EVENFIL
|
||
STOSB
|
||
EVENFIL:
|
||
REP STOSW
|
||
XCHG AX,BX ; Restore record count to AX
|
||
POP ES
|
||
INC AX ; Add last (partial) record to total
|
||
FULLREC:
|
||
MOV CX,AX
|
||
MOV DI,SI ; ES:DI point to FCB
|
||
SETCLUS:
|
||
TEST ES:[DI].fcb_DEVID,-1
|
||
JS ADDREC ; don't set clisters if device
|
||
MOV AX,[CLUSNUM]
|
||
AND ES:[DI.fcb_LSTCLUS],0F000h ; fcb_lstclus is packed with dir clus
|
||
OR ES:[DI.fcb_LSTCLUS],AX ; drop in the correct part of fcb_lstclus
|
||
MOV AX,[LASTPOS]
|
||
MOV ES:[DI.fcb_CLUSPOS],AX
|
||
entry AddRec
|
||
MOV AX,WORD PTR [RECPOS]
|
||
MOV DX,WORD PTR [RECPOS+2]
|
||
JCXZ RET28 ; If no records read, don't change position
|
||
DEC CX
|
||
ADD AX,CX ; Update current record position
|
||
ADC DX,0
|
||
INC CX
|
||
RET28: return
|
||
DISKREAD ENDP
|
||
|
||
SUBTTL DISKWRITE -- PERFORM USER DISK WRITE
|
||
PAGE
|
||
procedure DISKWRITE,NEAR
|
||
ASSUME DS:DOSGROUP,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; Outputs of SETUP
|
||
; Function:
|
||
; Perform disk write
|
||
; Outputs:
|
||
; DX:AX = Position of last record written
|
||
; CX = No. of records written
|
||
; ES:DI point to FCB
|
||
; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set
|
||
|
||
AND BL,3FH ; Mark file as dirty
|
||
MOV ES:[DI.fcb_DEVID],BL
|
||
LES BP,[THISDPB]
|
||
CALL BREAKDOWN
|
||
MOV AX,WORD PTR [BYTPOS]
|
||
MOV DX,WORD PTR [BYTPOS+2]
|
||
JCXZ WRTEOFJ
|
||
ADD AX,CX
|
||
ADC DX,0 ; AX:DX=last byte accessed
|
||
DIV ES:[BP.dpb_sector_size] ; AX=last sector accessed
|
||
MOV BX,AX ; Save last full sector
|
||
OR DX,DX
|
||
JNZ CALCLUS
|
||
DEC AX ; AX must be zero base indexed
|
||
CALCLUS:
|
||
MOV CL,ES:[BP.dpb_cluster_shift]
|
||
SHR AX,CL ; Last cluster to be accessed
|
||
PUSH AX
|
||
PUSH DX ; Save the size of the "tail"
|
||
PUSH ES
|
||
LES DI,[THISFCB]
|
||
MOV AX,ES:WORD PTR [DI.fcb_FILSIZ]
|
||
MOV DX,ES:WORD PTR [DI.fcb_FILSIZ+2]
|
||
POP ES
|
||
DIV ES:[BP.dpb_sector_size]
|
||
MOV CX,AX ; Save last full sector of current file
|
||
OR DX,DX
|
||
JZ NORNDUP
|
||
INC AX ; Round up if any remainder
|
||
NORNDUP:
|
||
MOV [VALSEC],AX ; Number of sectors that have been written
|
||
XOR AX,AX
|
||
MOV WORD PTR [GROWCNT],AX
|
||
MOV WORD PTR [GROWCNT+2],AX
|
||
POP AX
|
||
SUB BX,CX ; Number of full sectors
|
||
JB NOGROW
|
||
JZ TESTTAIL
|
||
MOV CX,DX
|
||
XCHG AX,BX
|
||
MUL ES:[BP.dpb_sector_size] ; Bytes of full sector growth
|
||
SUB AX,CX ; Take off current "tail"
|
||
SBB DX,0 ; 32-bit extension
|
||
ADD AX,BX ; Add on new "tail"
|
||
ADC DX,0 ; ripple tim's head off
|
||
JMP SHORT SETGRW
|
||
|
||
HAVSTART:
|
||
MOV CX,AX
|
||
invoke SKPCLP
|
||
JCXZ DOWRTJ
|
||
invoke ALLOCATE
|
||
JNC DOWRTJ
|
||
WRTERR:
|
||
XOR CX,CX
|
||
MOV BYTE PTR [DSKERR],1
|
||
MOV AX,WORD PTR [RECPOS]
|
||
MOV DX,WORD PTR [RECPOS+2]
|
||
LES DI,[THISFCB]
|
||
return
|
||
|
||
DOWRTJ: JMP DOWRT
|
||
|
||
WRTEOFJ:
|
||
JMP WRTEOF
|
||
|
||
TESTTAIL:
|
||
SUB AX,DX
|
||
JBE NOGROW
|
||
XOR DX,DX
|
||
SETGRW:
|
||
MOV WORD PTR [GROWCNT],AX
|
||
MOV WORD PTR [GROWCNT+2],DX
|
||
NOGROW:
|
||
POP AX
|
||
MOV CX,[CLUSNUM] ; First cluster accessed
|
||
invoke FNDCLUS
|
||
MOV [CLUSNUM],BX
|
||
MOV [LASTPOS],DX
|
||
SUB AX,DX ; Last cluster minus current cluster
|
||
JZ DOWRT ; If we have last clus, we must have first
|
||
JCXZ HAVSTART ; See if no more data
|
||
PUSH CX ; No. of clusters short of first
|
||
MOV CX,AX
|
||
invoke ALLOCATE
|
||
POP AX
|
||
JC WRTERR
|
||
MOV CX,AX
|
||
MOV DX,[LASTPOS]
|
||
INC DX
|
||
DEC CX
|
||
JZ NOSKIP
|
||
invoke SKPCLP
|
||
NOSKIP:
|
||
MOV [CLUSNUM],BX
|
||
MOV [LASTPOS],DX
|
||
DOWRT:
|
||
CMP [BYTCNT1],0
|
||
JZ WRTMID
|
||
MOV BX,[CLUSNUM]
|
||
invoke BUFWRT
|
||
WRTMID:
|
||
MOV AX,[SECCNT]
|
||
OR AX,AX
|
||
JZ WRTLAST
|
||
ADD [SECPOS],AX
|
||
invoke NEXTSEC
|
||
MOV BYTE PTR [TRANS],1 ; A transfer is taking place
|
||
MOV DL,[SECCLUSPOS]
|
||
MOV BX,[CLUSNUM]
|
||
MOV CX,[SECCNT]
|
||
WRTLP:
|
||
invoke OPTIMIZE
|
||
PUSH DI
|
||
PUSH AX
|
||
PUSH DX
|
||
PUSH BX
|
||
MOV AL,ES:[BP.dpb_drive]
|
||
MOV BX,CX
|
||
ADD BX,DX ; Upper bound of write
|
||
invoke SETVISIT
|
||
ASSUME DS:NOTHING
|
||
NEXTBUFF: ; Search for buffers
|
||
MOV [DI.VISIT],1 ; Mark as visited
|
||
CMP AL,[DI.BUFDRV]
|
||
JNZ DONEXTBUFF ; Not for this drive
|
||
CMP [DI.BUFSECNO],DX
|
||
JC DONEXTBUFF ; Buffer is not in range of write
|
||
CMP [DI.BUFSECNO],BX
|
||
JNC DONEXTBUFF ; Buffer is not in range of write
|
||
MOV WORD PTR [DI.BUFDRV],00FFH ; Free the buffer, it is being over written
|
||
invoke SCANPLACE
|
||
DONEXTBUFF:
|
||
invoke SKIPVISIT
|
||
JNZ NEXTBUFF
|
||
POP BX
|
||
POP DX
|
||
MOV DS,WORD PTR [DMAADD+2]
|
||
CALL DWRITE
|
||
POP CX
|
||
POP BX
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
JCXZ WRTLAST
|
||
MOV DL,0
|
||
INC [LASTPOS] ; We'll be using next cluster
|
||
JMP SHORT WRTLP
|
||
|
||
WRTERRJ: JMP WRTERR
|
||
|
||
WRTLAST:
|
||
MOV AX,[BYTCNT2]
|
||
OR AX,AX
|
||
JZ FINWRT
|
||
MOV [BYTCNT1],AX
|
||
invoke NEXTSEC
|
||
MOV [BYTSECPOS],0
|
||
invoke BUFWRT
|
||
FINWRT:
|
||
LES DI,[THISFCB]
|
||
MOV AX,WORD PTR [GROWCNT]
|
||
MOV CX,WORD PTR [GROWCNT+2]
|
||
OR AX,AX
|
||
JNZ UPDATE_size
|
||
OR CX,CX
|
||
JZ SAMSIZ
|
||
Update_size:
|
||
ADD WORD PTR ES:[DI.fcb_FILSIZ],AX
|
||
ADC WORD PTR ES:[DI.fcb_FILSIZ+2],CX
|
||
SAMSIZ:
|
||
MOV CX,[RECCNT]
|
||
JMP SETCLUS
|
||
|
||
WRTEOF:
|
||
MOV CX,AX
|
||
OR CX,DX
|
||
JZ KILLFIL
|
||
SUB AX,1
|
||
SBB DX,0
|
||
DIV ES:[BP.dpb_sector_size]
|
||
MOV CL,ES:[BP.dpb_cluster_shift]
|
||
SHR AX,CL
|
||
MOV CX,AX
|
||
invoke FNDCLUS
|
||
JCXZ RELFILE
|
||
invoke ALLOCATE
|
||
JC WRTERRJ
|
||
UPDATE:
|
||
LES DI,[THISFCB]
|
||
MOV AX,WORD PTR [BYTPOS]
|
||
MOV ES:WORD PTR [DI.fcb_FILSIZ],AX
|
||
MOV AX,WORD PTR [BYTPOS+2]
|
||
MOV ES:WORD PTR [DI.fcb_FILSIZ+2],AX
|
||
XOR CX,CX
|
||
JMP ADDREC
|
||
|
||
RELFILE:
|
||
MOV DX,0FFFH
|
||
invoke RELBLKS
|
||
JMP SHORT UPDATE
|
||
|
||
KILLFIL:
|
||
XOR BX,BX
|
||
PUSH ES
|
||
LES DI,[THISFCB]
|
||
MOV ES:[DI.fcb_CLUSPOS],BX
|
||
XCHG BX,ES:[DI.fcb_FIRCLUS]
|
||
AND ES:[DI.fcb_LSTCLUS],0F000H
|
||
POP ES
|
||
OR BX,BX
|
||
JZ UPDATE
|
||
invoke RELEASE
|
||
JMP SHORT UPDATE
|
||
DISKWRITE ENDP
|
||
do_ext
|
||
|
||
CODE ENDS
|
||
END
|
||
|