📄 bdevio.a86
字号:
title 'BDEVIF - Block DEVice Input/Output support'
; File : $BDEVIO.A86$
;
; Description :
;
; Original Author : DIGITAL RESEARCH
;
; Last Edited By : $CALDERA$
;
;-----------------------------------------------------------------------;
; Copyright Work of Caldera, Inc. All Rights Reserved.
;
; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
; CIVIL LIABILITY.
;-----------------------------------------------------------------------;
;
; *** Current Edit History ***
; *** End of Current Edit History ***
;
; $Log$
; BDEVIO.A86 1.27 94/11/30 16:25:22
; added delayed retry for read/write to locked region
; added support for using multiple FAT copies on reads if one fails;
; BDEVIO.A86 1.26 94/02/22 17:11:25
; Fix where corrupt dir entry results in read beyond end-of-chain (Filelink bug)
; BDEVIO.A86 1.25 93/12/15 03:07:11
; New ddioif entry point so Int 25/26 bypasses address normalisation
; BDEVIO.A86 1.24 93/12/08 03:15:14
; Force rebuild_ldt_root if root in JOIN's subdirectory
; BDEVIO.A86 1.23 93/11/19 18:29:29
; Fix for SERVER print queue viewing problem
; BDEVIO.A86 1.22 93/09/21 12:43:37
; On fdos read/write do EOF checks before SHARE LOCK checks
; BDEVIO.A86 1.21 93/09/14 20:02:50
; Trust LFLG_PHYSICAL
; BDEVIO.A86 1.20 93/09/02 22:22:56
; Use 32 bit sectors to read fat for build bpb if appropriate (SYQUEST bug)
; BDEVIO.A86 1.19 93/08/27 18:46:49
; int 26 discards hash codes
; BDEVIO.A86 1.18 93/07/20 22:42:25
; Even fewer checks on int 25/26
; BDEVIO.A86 1.12 93/06/23 02:57:07
; Add auto-commit to fdowrw
; BDEVIO.A86 1.11 93/05/14 13:47:41
; Shorten media change code slightly
; BDEVIO.A86 1.9 93/03/16 22:30:21 IJACK
; UNDELETE support changes
; ENDLOG
eject ! include i:mserror.equ ; F_DOS erros
eject ! include i:fdos.equ
eject ! include i:driver.equ
eject ! include i:doshndl.def
eject ! include bdos.equ
eject ! include rh.equ
;*****************************************************
;*
;* bdos data area
;*
;*****************************************************
PCMODE_DATA dseg word
extrn current_ddsc:dword
extrn current_dhndl:dword
extrn current_dsk:byte ; default drive
extrn current_ldt:dword ; currently selected LDT
extrn dma_offset:word ; DTA offset
extrn dma_segment:word ; DTA segment
extrn ddsc_ptr:dword
extrn err_drv:byte
extrn error_dev:dword ; failing device for Int 24's
extrn fdos_stub:dword
extrn ioexerr:byte
extrn last_drv:byte
extrn ldt_ptr:dword
extrn lock_bios:dword
extrn phys_drv:byte
extrn rwmode:byte
extrn share_stub:dword
extrn unlock_bios:dword
extrn verify_flag:byte
extrn net_retry:word
BDOS_DATA dseg word
extrn bcb_root:dword
extrn deblock_seg:word
extrn fdos_hds_drv:byte
extrn fdos_hds_blk:word
extrn fdos_hds_root:word
extrn fdos_ret:word
public adrive
public clsize
public dosfat
public cur_dma
public cur_dma_seg
public datadd
public diradd
public dirinroot
public dirperclu
public fatadd
public hdsaddr
public lastcl
public logical_drv
public mult_sec
public nfatrecs
public nfats
public pblock
public physical_drv
public psecsiz
public req_hdr
public secperclu
eject
; The following specify the drive selected for the current operation
hdsaddr dw 0 ; current HDS address (0 means at root)
logical_drv db 0 ; logical drive number
physical_drv db 0 ; physical disk number
; The following describe the currently active drive - not this may differ from
; the currently selected drive above due to eg. flushing dirty buffers
; Local copy of DDSC_ variables - ORDER CRITICAL - must match DDSC_
local_ddsc rb 0
psecsiz dw 0 ; byte size of sector
clmsk db 0
clshf db 0
fatadd dw 0 ; sector offset of 1st FAT sector
byte_nfats db 0 ; number of FAT's
dirinroot dw 0 ; # dir entries in root
datadd dw 0 ; sector offset of data sector
lastcl dw 0 ; # last cluster (after adjustment)
if DOS5
dw 0 ; # sectors per FAT
else
db 0 ; # sectors per FAT (nb. may be inaccurate on large drives)
endif
diradd dw 0 ; sector offset of 1st root DIR sector
LOCAL_DDSC_LEN equ offset $ - offset local_ddsc
; some extra parameters calculated from local_ddsc for convenience
nfats dw 0 ; # FAT's (WORD is handier)
nfatrecs dw 0 ; # sectors per FAT (accurate version)
clsize dw 0 ; cluster size in bytes
secperclu dw 0 ; # sectors per cluster
dirperclu dw 0 ; # dir enrties in subdir
dosfat dw 0 ; FAT length indicator (FAT12 or FAT16)
; The following specify the next block read/write operation on the active drive
adrive db 0ffh ; currently active disk
pblock dw 0, 0 ; absolute block address
mult_sec dw 1 ; multi sector count passed to xios
cur_dma dw 0
cur_dma_seg dw 0
fdrwreq dw 0 ; requested count (roundup)
public fdrwflg
fdrwflg db 0 ; bdosrw flags
fdrwcnt dw 0 ; requested byte count for read/write
fdrwptr rd 0 ; disk transfer address for read/write
fdrwoff dw 0 ; offset for R/W DTA
fdrwseg dw 0 ; segment for R/W DTA
fdrwsec rd 1 ; physical block for fdosrw
fdrwsecoff dw 0 ; offset within sector
fdrwdircnt dw 0 ; # sectors in direct xfer
byteoff dw 0 ; fdosrw local variable
dw 0 ; byte offset with file
blk dw 0 ; current cluster of filepos
blkidx dw 0 ; current cluster index within file
blkoffset dw 0 ; offset within cluster
; static request header for DOS device driver I/O
Public req_hdr
req_hdr rb 0
req_len db 22
req_unit rb 1
req_cmd rb 1
req_status rw 1
req_rwmode db 0 ; action hint for device drivers
rb 7
req_media rb 1
rb 16
req1_return equ byte ptr req_media+1
req1_volid equ word ptr req_media+2
req2_buffer equ word ptr req_media+1
req2_bpb equ word ptr req_media+5
req3_buffer equ word ptr req_media+1
req3_count equ word ptr req_media+5
req3_sector equ word ptr req_media+7
req3_volid equ word ptr req_media+9
req4_buffer equ word ptr req_media+1
req4_count equ word ptr req_media+5
req4_sector equ word ptr req_media+7
req4_volid equ dword ptr req_media+9
req4_bigsector equ dword ptr req_media+13
eject
BDOS_CODE cseg
extrn alloc_chain:near
extrn bpb2ddsc:near ; converts BPB to DDSC
extrn buffers_check:near ; look for buffers
extrn delfat:near
extrn discard_all:near ; discard all buffers
extrn discard_dir:near ; discard directory buffers
extrn discard_dirty:near ; discard all dirty buffers
extrn discard_files:near ; discard open files
extrn fdos_error:near
extrn fdos_restart:near
extrn file_update:near
extrn fixfat:near
extrn getnblk:near ; get block value from FAT
extrn get_ldt:near
extrn get_ldt_raw:near
extrn hdsblk:near ; get current HDS block
extrn hshdscrd:near
extrn locate_buffer:near
extrn rebuild_ldt_root:near
extrn timestamp_dhndl:near
extrn update_dat:near
extrn update_fat:near
extrn share_delay:near
public block_device_driver
public clus2sec
public device_driver
public read_block
public select_adrive
public select_logical_drv
public select_physical_drv
public write_block
eject
eject
Public get_ddsc
get_ddsc:
;--------
; On Entry:
; AL = physical drive
; On Exit:
; CY set if bad drive, else
; ES:BX -> DDSC_
; (All other registers preserved)
;
cmp al,ss:phys_drv
jae get_ddsc30
les bx,ss:ddsc_ptr
get_ddsc10:
cmp bx,0FFFFh ; end of the line
je get_ddsc30
cmp al,es:DDSC_UNIT[bx] ; does the unit match ?
je get_ddsc20 ; no, try the next
les bx,es:DDSC_LINK[bx]
jmps get_ddsc10
get_ddsc20:
; clc
ret
get_ddsc30:
stc
ret
eject
; Read/Write from/to disk file
; entry: CURRENT_DNHDL -> file handle
; BDRWFLG = 1 => read
; 0 => write
; ES:DI = buffer (32 bit: off/seg)
; CX = requested byte count (16 bit)
; exit: FDOS_RET = number of bytes read/written
; CURRENT_DHNDL incremented by FDOS_RET
public fdosrw ; read/write to/from disk file
fdosrw:
;------
call fdrw_prepare ; set up address, where we are in file
jc fdrw_error ; stop if we have a problem
call fdrw_size ; extend file if necessary
jc fdrw_error ; bail out if we can't
cmp fdrwcnt,0 ; are we truncating?
jne fdrw_loop ; read/write if non-zero count
test fdrwflg,1 ; writing zero bytes?
jnz fdrw_error ; (reading has no meaning)
call fdw_trunc ; writing truncates the file
jmps fdrw_nobigger
fdrw_error:
ret
fdrw_loop: ; loop here for long reads/writes
call fdrw_seek ; seek to position for xfer
jc fdrw_exit ; should get error's now...
jnz fdrw_buffered ; deblocking required if not aligned
mov cx,fdrwcnt ; CX = requested transfer size
cmp cx,psecsiz ; at least one sector transferred?
jb fdrw_buffered ; if less, need deblocked transfer
mov fdrwreq,cx ; requested count for direct r/w
call direct_rw ; transfer straight to/from TPA
jmps fdrw_more
fdrw_buffered: ; perform deblocked read/write
call deblock_rw ; transfer via BDOS buffer
fdrw_more:
add fdrwoff,ax ; adjust buffer address
add fdos_ret,ax ; adjust return code
add byteoff,ax ; adjust file offset
adc byteoff+2,0
sub fdrwcnt,ax ; adjust remaining count
ja fdrw_loop ; still more to do
fdrw_exit:
les bx,current_dhndl
mov ax,fdos_ret ; get total xfered and update position
add es:DHNDL_POSLO[bx],ax
adc es:DHNDL_POSHI[bx],0
test fdrwflg,1
jnz fdrw_return ; skip if reading
mov ax,byteoff ; has the file grown ?
mov dx,byteoff+WORD
sub ax,es:DHNDL_SIZELO[bx]
sbb dx,es:DHNDL_SIZEHI[bx]
jb fdrw_nobigger ; yes, update the file size
add es:DHNDL_SIZELO[bx],ax
adc es:DHNDL_SIZEHI[bx],dx
fdrw_nobigger:
call timestamp_dhndl ; record the current time
test es:DHNDL_MODE[bx],DHM_COMMIT
jz fdrw_return ; is auto-commit in place ?
call file_update ; yes, commit the file
fdrw_return:
ret
fdw_trunc:
;---------
; On Entry:
; BLKIDX = block number within file
; BLKOFFSET = block offset
; On Exit:
; DHNDL_SIZE adjusted, any excess clusters freed
;
les bx,current_dhndl
mov cx,blkoffset ; get offset within current block
mov ax,blkidx ; get logical block number
jcxz fdw_t10 ; skip if no data in last block
inc ax ; else add in another cluster
fdw_t10: ; AX = # of clusters required in file
test ax,ax
jnz fdw_t20
xchg ax,es:DHNDL_BLK1[bx] ; forget about chain
jmps fdw_t50
fdw_t20:
xchg ax,cx ; CX = # of blocks to keep
mov ax,es:DHNDL_BLK1[bx] ; get first block in file
fdw_t30: ; scan all block we want to keep
push cx
push ax
call getnblk ; get next block
pop bx
pop cx
cmp ax,lastcl ; stop on premature end of chain
ja fdw_t60
loop fdw_t30
push ax ; yep, remember what
mov ax,dosfat
xchg ax,bx ; truncate chain at cluster AX
call fixfat ; as thats all we need
pop ax
fdw_t50:
call delfat ; release the chain
fdw_t60:
les bx,current_dhndl
mov ax,byteoff ; now truncate the file
mov es:DHNDL_SIZELO[bx],ax
mov ax,byteoff+2
mov es:DHNDL_SIZEHI[bx],ax
xor ax,ax ; cause reads/writes to scan
mov es:DHNDL_BLK[bx],ax ; block chain from start
mov es:DHNDL_IDX[bx],ax
mov fdos_ret,ax ; no logical errors
ret
fdrw_prepare:
;------------
; Normalise the xfer address and count
; Calculate current position in the file
;
; On Entry:
; ES:DI -> buffer
; CX = bytes to xfer
; On Exit:
; FDRWSEG:FDRWOFF -> normalised buffer
; FDRWCNT = bytes to xfer
; FDOS_RET = bytes xfer'd (0)
; PREREAD = TRUE
; BYTEOFF = current offset in file
; BLKIDX = cluster containing current file position
; BLKOFFSET = offset within cluster
; CY set if current position theoretically impossible
;
xor ax,ax ; AX = 0
mov fdos_ret,ax ; initialize byte return count
mov fdrwcnt,cx ; save byte count for read/write
mov ax,000Fh
and ax,di ; get offset within paragraph
mov fdrwoff,ax ; save normalized offset for read/write
add ax,cx ; do we overflow 64k ?
jnc fdrw_p10 ; yes, then forget about what would
sub fdrwcnt,ax ; overflow this segment
fdrw_p10:
mov cl,4
shr di,cl ; DI = paragraph offset
mov ax,es
add ax,di ; AX = effective segment
jnc fdrw_p20 ; if above 1 MByte base it at FFFF
inc ax ; AX = para's above FFFF
shl ax,cl ; make it bytes
add fdrwoff,ax ; add to offset
mov ax,0ffffh ; use our magic segment
fdrw_p20:
mov fdrwseg,ax ; save normalized segment for read/write
les bx,current_dhndl
mov ax,es:DHNDL_POSLO[bx]
mov byteoff,ax ; copy position to local variables
mov ax,es:DHNDL_POSHI[bx]
mov byteoff+WORD,ax
mov cx,clsize
mov ax,lastcl
mul cx ; DX:AX = maximum size of disk
sub ax,byteoff
sbb dx,byteoff+WORD ; beyond this we can't go
jc fdrw_p30
mov ax,byteoff ; DX:AX = current file size
mov dx,byteoff+WORD
div clsize
mov blkidx,ax ; save it for later
mov blkoffset,dx ; DX = offset within cluster
clc ; theoretically possible
fdrw_p30:
ret
fdrw_size:
;---------
; On reads check xfer starts within file, and clip size to reflect EOF.
; On writes try to extend to cluster chain so it is big enough to contain
; the data we wish to write.
;
; On Entry:
; BYTEOFF = current position in file
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -