mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-11-29 17:15:47 +00:00
530 lines
14 KiB
NASM
530 lines
14 KiB
NASM
|
;
|
|||
|
; Disk utilities of 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 ROM - miscellaneous routines
|
|||
|
NAME ROM
|
|||
|
|
|||
|
i_need CLUSNUM,WORD
|
|||
|
i_need NEXTADD,WORD
|
|||
|
i_need LASTPOS,WORD
|
|||
|
i_need SECCLUSPOS,BYTE
|
|||
|
i_need FATBYT,WORD
|
|||
|
i_need RECPOS,4
|
|||
|
i_need THISFCB,DWORD
|
|||
|
i_need TRANS,BYTE
|
|||
|
i_need BYTCNT1,WORD
|
|||
|
i_need CURBUF,DWORD
|
|||
|
i_need BYTSECPOS,WORD
|
|||
|
i_need DMAADD,WORD
|
|||
|
i_need SECPOS,WORD
|
|||
|
i_need VALSEC,WORD
|
|||
|
|
|||
|
procedure GET_random_record,NEAR
|
|||
|
entry GETRRPOS1
|
|||
|
MOV CX,1
|
|||
|
entry GetRRPos
|
|||
|
MOV DI,DX
|
|||
|
CMP BYTE PTR [DI],-1
|
|||
|
JNZ NORMFCB1
|
|||
|
ADD DI,7
|
|||
|
NORMFCB1:
|
|||
|
MOV AX,WORD PTR [DI.fcb_RR]
|
|||
|
MOV DX,WORD PTR [DI.fcb_RR+2]
|
|||
|
return
|
|||
|
GET_random_record ENDP
|
|||
|
|
|||
|
SUBTTL FNDCLUS -- Skip over allocation units
|
|||
|
PAGE
|
|||
|
procedure FNDCLUS,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
; Inputs:
|
|||
|
; CX = No. of clusters to skip
|
|||
|
; ES:BP = Base of drive parameters
|
|||
|
; [THISFCB] point to FCB
|
|||
|
; Outputs:
|
|||
|
; BX = Last cluster skipped to
|
|||
|
; CX = No. of clusters remaining (0 unless EOF)
|
|||
|
; DX = Position of last cluster
|
|||
|
; DI destroyed. No other registers affected.
|
|||
|
|
|||
|
PUSH ES
|
|||
|
LES DI,[THISFCB]
|
|||
|
MOV BX,ES:[DI.fcb_LSTCLUS] ; fcb_lstclus is packed with dir clus
|
|||
|
AND BX,0FFFh ; get rid of dir nibble
|
|||
|
MOV DX,ES:[DI.fcb_CLUSPOS]
|
|||
|
OR BX,BX
|
|||
|
JZ NOCLUS
|
|||
|
SUB CX,DX
|
|||
|
JNB FINDIT
|
|||
|
ADD CX,DX
|
|||
|
XOR DX,DX
|
|||
|
MOV BX,ES:[DI.fcb_FIRCLUS]
|
|||
|
FINDIT:
|
|||
|
POP ES
|
|||
|
JCXZ RET10
|
|||
|
entry SKPCLP
|
|||
|
invoke UNPACK
|
|||
|
CMP DI,0FF8H
|
|||
|
JAE RET10
|
|||
|
XCHG BX,DI
|
|||
|
INC DX
|
|||
|
LOOP SKPCLP
|
|||
|
RET10: return
|
|||
|
|
|||
|
NOCLUS:
|
|||
|
POP ES
|
|||
|
INC CX
|
|||
|
DEC DX
|
|||
|
return
|
|||
|
FNDCLUS ENDP
|
|||
|
|
|||
|
SUBTTL BUFSEC -- BUFFER A SECTOR AND SET UP A TRANSFER
|
|||
|
PAGE
|
|||
|
procedure BUFSEC,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
; Inputs:
|
|||
|
; AH = priority of buffer
|
|||
|
; AL = 0 if buffer must be read, 1 if no pre-read needed
|
|||
|
; ES:BP = Base of drive parameters
|
|||
|
; [CLUSNUM] = Physical cluster number
|
|||
|
; [SECCLUSPOS] = Sector position of transfer within cluster
|
|||
|
; [BYTCNT1] = Size of transfer
|
|||
|
; Function:
|
|||
|
; Insure specified sector is in buffer, flushing buffer before
|
|||
|
; read if necessary.
|
|||
|
; Outputs:
|
|||
|
; ES:DI = Pointer to buffer
|
|||
|
; SI = Pointer to transfer address
|
|||
|
; CX = Number of bytes
|
|||
|
; [NEXTADD] updated
|
|||
|
; [TRANS] set to indicate a transfer will occur
|
|||
|
|
|||
|
MOV DX,[CLUSNUM]
|
|||
|
MOV BL,[SECCLUSPOS]
|
|||
|
CALL FIGREC
|
|||
|
invoke GETBUFFR
|
|||
|
MOV BYTE PTR [TRANS],1 ; A transfer is taking place
|
|||
|
MOV SI,[NEXTADD]
|
|||
|
MOV DI,SI
|
|||
|
MOV CX,[BYTCNT1]
|
|||
|
ADD DI,CX
|
|||
|
MOV [NEXTADD],DI
|
|||
|
LES DI,[CURBUF]
|
|||
|
ADD DI,BUFINSIZ ; Point to buffer
|
|||
|
ADD DI,[BYTSECPOS]
|
|||
|
return
|
|||
|
BUFSEC ENDP
|
|||
|
|
|||
|
SUBTTL BUFRD, BUFWRT -- PERFORM BUFFERED READ AND WRITE
|
|||
|
PAGE
|
|||
|
procedure BUFRD,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
; Do a partial sector read via one of the system buffers
|
|||
|
; ES:BP Points to DPB
|
|||
|
|
|||
|
PUSH ES
|
|||
|
MOV AX,LBRPRI SHL 8 ; Assume last byte read
|
|||
|
CALL BUFSEC
|
|||
|
MOV BX,ES
|
|||
|
MOV ES,[DMAADD+2]
|
|||
|
MOV DS,BX
|
|||
|
ASSUME DS:NOTHING
|
|||
|
XCHG DI,SI
|
|||
|
SHR CX,1
|
|||
|
JNC EVENRD
|
|||
|
MOVSB
|
|||
|
EVENRD:
|
|||
|
REP MOVSW
|
|||
|
POP ES
|
|||
|
LDS DI,[CURBUF]
|
|||
|
LEA BX,[DI.BufInSiz]
|
|||
|
SUB SI,BX ; Position in buffer
|
|||
|
invoke PLACEBUF
|
|||
|
CMP SI,ES:[BP.dpb_sector_size]
|
|||
|
JB RBUFPLACED
|
|||
|
invoke PLACEHEAD
|
|||
|
RBUFPLACED:
|
|||
|
PUSH SS
|
|||
|
POP DS
|
|||
|
return
|
|||
|
BUFRD ENDP
|
|||
|
|
|||
|
procedure BUFWRT,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
; Do a partial sector write via one of the system buffers
|
|||
|
; ES:BP Points to DPB
|
|||
|
|
|||
|
MOV AX,[SECPOS]
|
|||
|
INC AX ; Set for next sector
|
|||
|
MOV [SECPOS],AX
|
|||
|
CMP AX,[VALSEC] ; Has sector been written before?
|
|||
|
MOV AL,1
|
|||
|
JA NOREAD ; Skip preread if SECPOS>VALSEC
|
|||
|
XOR AL,AL
|
|||
|
NOREAD:
|
|||
|
PUSH ES
|
|||
|
CALL BUFSEC
|
|||
|
MOV DS,[DMAADD+2]
|
|||
|
ASSUME DS:NOTHING
|
|||
|
SHR CX,1
|
|||
|
JNC EVENWRT
|
|||
|
MOVSB
|
|||
|
EVENWRT:
|
|||
|
REP MOVSW
|
|||
|
POP ES
|
|||
|
LDS BX,[CURBUF]
|
|||
|
MOV BYTE PTR [BX.BUFDIRTY],1
|
|||
|
LEA SI,[BX.BufInSiz]
|
|||
|
SUB DI,SI ; Position in buffer
|
|||
|
MOV SI,DI
|
|||
|
MOV DI,BX
|
|||
|
invoke PLACEBUF
|
|||
|
CMP SI,ES:[BP.dpb_sector_size]
|
|||
|
JB WBUFPLACED
|
|||
|
invoke PLACEHEAD
|
|||
|
WBUFPLACED:
|
|||
|
PUSH SS
|
|||
|
POP DS
|
|||
|
return
|
|||
|
BUFWRT ENDP
|
|||
|
|
|||
|
SUBTTL NEXTSEC -- Compute next sector to read or write
|
|||
|
PAGE
|
|||
|
procedure NEXTSEC,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
; Compute the next sector to read or write
|
|||
|
; ES:BP Points to DPB
|
|||
|
|
|||
|
TEST BYTE PTR [TRANS],-1
|
|||
|
JZ CLRET
|
|||
|
MOV AL,[SECCLUSPOS]
|
|||
|
INC AL
|
|||
|
CMP AL,ES:[BP.dpb_cluster_mask]
|
|||
|
JBE SAVPOS
|
|||
|
MOV BX,[CLUSNUM]
|
|||
|
CMP BX,0FF8H
|
|||
|
JAE NONEXT
|
|||
|
invoke UNPACK
|
|||
|
MOV [CLUSNUM],DI
|
|||
|
INC [LASTPOS]
|
|||
|
MOV AL,0
|
|||
|
SAVPOS:
|
|||
|
MOV [SECCLUSPOS],AL
|
|||
|
CLRET:
|
|||
|
CLC
|
|||
|
return
|
|||
|
NONEXT:
|
|||
|
STC
|
|||
|
return
|
|||
|
NEXTSEC ENDP
|
|||
|
|
|||
|
SUBTTL OPTIMIZE -- DO A USER DISK REQUEST WELL
|
|||
|
PAGE
|
|||
|
procedure OPTIMIZE,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
; Inputs:
|
|||
|
; BX = Physical cluster
|
|||
|
; CX = No. of records
|
|||
|
; DL = sector within cluster
|
|||
|
; ES:BP = Base of drives parameters
|
|||
|
; [NEXTADD] = transfer address
|
|||
|
; Outputs:
|
|||
|
; AX = No. of records remaining
|
|||
|
; BX = Transfer address
|
|||
|
; CX = No. or records to be transferred
|
|||
|
; DX = Physical sector address
|
|||
|
; DI = Next cluster
|
|||
|
; [CLUSNUM] = Last cluster accessed
|
|||
|
; [NEXTADD] updated
|
|||
|
; ES:BP unchanged. Note that segment of transfer not set.
|
|||
|
|
|||
|
PUSH DX
|
|||
|
PUSH BX
|
|||
|
MOV AL,ES:[BP.dpb_cluster_mask]
|
|||
|
INC AL ; Number of sectors per cluster
|
|||
|
MOV AH,AL
|
|||
|
SUB AL,DL ; AL = Number of sectors left in first cluster
|
|||
|
MOV DX,CX
|
|||
|
MOV CX,0
|
|||
|
OPTCLUS:
|
|||
|
; AL has number of sectors available in current cluster
|
|||
|
; AH has number of sectors available in next cluster
|
|||
|
; BX has current physical cluster
|
|||
|
; CX has number of sequential sectors found so far
|
|||
|
; DX has number of sectors left to transfer
|
|||
|
; ES:BP Points to DPB
|
|||
|
; ES:SI has FAT pointer
|
|||
|
invoke UNPACK
|
|||
|
ADD CL,AL
|
|||
|
ADC CH,0
|
|||
|
CMP CX,DX
|
|||
|
JAE BLKDON
|
|||
|
MOV AL,AH
|
|||
|
INC BX
|
|||
|
CMP DI,BX
|
|||
|
JZ OPTCLUS
|
|||
|
DEC BX
|
|||
|
FINCLUS:
|
|||
|
MOV [CLUSNUM],BX ; Last cluster accessed
|
|||
|
SUB DX,CX ; Number of sectors still needed
|
|||
|
PUSH DX
|
|||
|
MOV AX,CX
|
|||
|
MUL ES:[BP.dpb_sector_size] ; Number of sectors times sector size
|
|||
|
MOV SI,[NEXTADD]
|
|||
|
ADD AX,SI ; Adjust by size of transfer
|
|||
|
MOV [NEXTADD],AX
|
|||
|
POP AX ; Number of sectors still needed
|
|||
|
POP DX ; Starting cluster
|
|||
|
SUB BX,DX ; Number of new clusters accessed
|
|||
|
ADD [LASTPOS],BX
|
|||
|
POP BX ; BL = sector postion within cluster
|
|||
|
invoke FIGREC
|
|||
|
MOV BX,SI
|
|||
|
return
|
|||
|
BLKDON:
|
|||
|
SUB CX,DX ; Number of sectors in cluster we don't want
|
|||
|
SUB AH,CL ; Number of sectors in cluster we accepted
|
|||
|
DEC AH ; Adjust to mean position within cluster
|
|||
|
MOV [SECCLUSPOS],AH
|
|||
|
MOV CX,DX ; Anyway, make the total equal to the request
|
|||
|
JMP SHORT FINCLUS
|
|||
|
OPTIMIZE ENDP
|
|||
|
|
|||
|
SUBTTL FIGREC -- Figure sector in allocation unit
|
|||
|
PAGE
|
|||
|
procedure FIGREC,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
|
|||
|
; Inputs:
|
|||
|
; DX = Physical cluster number
|
|||
|
; BL = Sector postion within cluster
|
|||
|
; ES:BP = Base of drive parameters
|
|||
|
; Outputs:
|
|||
|
; DX = physical sector number
|
|||
|
; No other registers affected.
|
|||
|
|
|||
|
PUSH CX
|
|||
|
MOV CL,ES:[BP.dpb_cluster_shift]
|
|||
|
DEC DX
|
|||
|
DEC DX
|
|||
|
SHL DX,CL
|
|||
|
OR DL,BL
|
|||
|
ADD DX,ES:[BP.dpb_first_sector]
|
|||
|
POP CX
|
|||
|
return
|
|||
|
FIGREC ENDP
|
|||
|
|
|||
|
SUBTTL GETREC -- Figure record in file from fcb
|
|||
|
PAGE
|
|||
|
procedure GETREC,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
|
|||
|
; Inputs:
|
|||
|
; DS:DX point to FCB
|
|||
|
; Outputs:
|
|||
|
; CX = 1
|
|||
|
; DX:AX = Record number determined by fcb_EXTENT and fcb_NR fields
|
|||
|
; DS:DI point to FCB
|
|||
|
; No other registers affected.
|
|||
|
|
|||
|
MOV DI,DX
|
|||
|
CMP BYTE PTR [DI],-1 ; Check for extended FCB
|
|||
|
JNZ NORMFCB2
|
|||
|
ADD DI,7
|
|||
|
NORMFCB2:
|
|||
|
MOV CX,1
|
|||
|
MOV AL,[DI.fcb_NR]
|
|||
|
MOV DX,[DI.fcb_EXTENT]
|
|||
|
SHL AL,1
|
|||
|
SHR DX,1
|
|||
|
RCR AL,1
|
|||
|
MOV AH,DL
|
|||
|
MOV DL,DH
|
|||
|
MOV DH,0
|
|||
|
return
|
|||
|
GETREC ENDP
|
|||
|
|
|||
|
SUBTTL ALLOCATE -- Assign disk space
|
|||
|
PAGE
|
|||
|
procedure ALLOCATE,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
; Inputs:
|
|||
|
; BX = Last cluster of file (0 if null file)
|
|||
|
; CX = No. of clusters to allocate
|
|||
|
; DX = Position of cluster BX
|
|||
|
; ES:BP = Base of drive parameters
|
|||
|
; [THISFCB] = Points to FCB
|
|||
|
; Outputs:
|
|||
|
; IF insufficient space
|
|||
|
; THEN
|
|||
|
; Carry set
|
|||
|
; CX = max. no. of records that could be added to file
|
|||
|
; ELSE
|
|||
|
; Carry clear
|
|||
|
; BX = First cluster allocated
|
|||
|
; FAT is fully updated including dirty bit
|
|||
|
; fcb_FIRCLUS field of FCB set if file was null
|
|||
|
; SI,BP unchanged. All other registers destroyed.
|
|||
|
|
|||
|
PUSH BX ; save the fat byte
|
|||
|
XOR BX,BX
|
|||
|
invoke UNPACK
|
|||
|
MOV [FATBYT],DI
|
|||
|
POP BX
|
|||
|
|
|||
|
PUSH DX
|
|||
|
PUSH CX
|
|||
|
PUSH BX
|
|||
|
MOV AX,BX
|
|||
|
CLUSALLOC:
|
|||
|
MOV DX,BX
|
|||
|
FINDFRE:
|
|||
|
INC BX
|
|||
|
CMP BX,ES:[BP.dpb_max_cluster]
|
|||
|
JLE TRYOUT
|
|||
|
CMP AX,1
|
|||
|
JG TRYIN
|
|||
|
POP BX
|
|||
|
MOV DX,0FFFH
|
|||
|
invoke RELBLKS
|
|||
|
POP AX ; No. of clusters requested
|
|||
|
SUB AX,CX ; AX=No. of clusters allocated
|
|||
|
POP DX
|
|||
|
invoke RESTFATBYT
|
|||
|
INC DX ; Position of first cluster allocated
|
|||
|
ADD AX,DX ; AX=max no. of cluster in file
|
|||
|
MOV DL,ES:[BP.dpb_cluster_mask]
|
|||
|
MOV DH,0
|
|||
|
INC DX ; DX=records/cluster
|
|||
|
MUL DX ; AX=max no. of records in file
|
|||
|
MOV CX,AX
|
|||
|
SUB CX,WORD PTR [RECPOS] ; CX=max no. of records that could be written
|
|||
|
JA MAXREC
|
|||
|
XOR CX,CX ; If CX was negative, zero it
|
|||
|
MAXREC:
|
|||
|
STC
|
|||
|
return
|
|||
|
|
|||
|
TRYOUT:
|
|||
|
invoke UNPACK
|
|||
|
JZ HAVFRE
|
|||
|
TRYIN:
|
|||
|
DEC AX
|
|||
|
JLE FINDFRE
|
|||
|
XCHG AX,BX
|
|||
|
invoke UNPACK
|
|||
|
JZ HAVFRE
|
|||
|
XCHG AX,BX
|
|||
|
JMP SHORT FINDFRE
|
|||
|
HAVFRE:
|
|||
|
XCHG BX,DX
|
|||
|
MOV AX,DX
|
|||
|
invoke PACK
|
|||
|
MOV BX,AX
|
|||
|
LOOP CLUSALLOC
|
|||
|
MOV DX,0FFFH
|
|||
|
invoke PACK
|
|||
|
POP BX
|
|||
|
POP CX ; Don't need this stuff since we're successful
|
|||
|
POP DX
|
|||
|
invoke UNPACK
|
|||
|
invoke RESTFATBYT
|
|||
|
XCHG BX,DI
|
|||
|
OR DI,DI
|
|||
|
retnz
|
|||
|
PUSH ES
|
|||
|
LES DI,[THISFCB]
|
|||
|
AND BX,0FFFh
|
|||
|
MOV ES:[DI.fcb_FIRCLUS],BX
|
|||
|
AND ES:[DI.fcb_LSTCLUS],0F000h ; clear out old lstclus
|
|||
|
OR ES:[DI.fcb_LSTCLUS],BX ; or the new guy in...
|
|||
|
POP ES
|
|||
|
return
|
|||
|
ALLOCATE ENDP
|
|||
|
|
|||
|
procedure RESTFATBYT,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
PUSH BX
|
|||
|
PUSH DX
|
|||
|
PUSH DI
|
|||
|
XOR BX,BX
|
|||
|
MOV DX,[FATBYT]
|
|||
|
invoke PACK
|
|||
|
POP DI
|
|||
|
POP DX
|
|||
|
POP BX
|
|||
|
return
|
|||
|
RESTFATBYT ENDP
|
|||
|
|
|||
|
SUBTTL RELEASE -- DEASSIGN DISK SPACE
|
|||
|
PAGE
|
|||
|
procedure RELEASE,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
; Inputs:
|
|||
|
; BX = Cluster in file
|
|||
|
; ES:BP = Base of drive parameters
|
|||
|
; Function:
|
|||
|
; Frees cluster chain starting with [BX]
|
|||
|
; AX,BX,DX,DI all destroyed. Other registers unchanged.
|
|||
|
|
|||
|
XOR DX,DX
|
|||
|
entry RELBLKS
|
|||
|
; Enter here with DX=0FFFH to put an end-of-file mark
|
|||
|
; in the first cluster and free the rest in the chain.
|
|||
|
invoke UNPACK
|
|||
|
retz
|
|||
|
MOV AX,DI
|
|||
|
invoke PACK
|
|||
|
CMP AX,0FF8H
|
|||
|
MOV BX,AX
|
|||
|
JB RELEASE
|
|||
|
RET12: return
|
|||
|
RELEASE ENDP
|
|||
|
|
|||
|
SUBTTL GETEOF -- Find the end of a file
|
|||
|
PAGE
|
|||
|
procedure GETEOF,NEAR
|
|||
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|||
|
|
|||
|
; Inputs:
|
|||
|
; ES:BP Points to DPB
|
|||
|
; BX = Cluster in a file
|
|||
|
; DS = CS
|
|||
|
; Outputs:
|
|||
|
; BX = Last cluster in the file
|
|||
|
; DI destroyed. No other registers affected.
|
|||
|
|
|||
|
invoke UNPACK
|
|||
|
CMP DI,0FF8H
|
|||
|
JAE RET12
|
|||
|
MOV BX,DI
|
|||
|
JMP SHORT GETEOF
|
|||
|
GETEOF ENDP
|
|||
|
|
|||
|
do_ext
|
|||
|
|
|||
|
CODE ENDS
|
|||
|
END
|
|||
|
|