BDEVIO.A86
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:42k
源码类别:

操作系统开发

开发平台:

Asm

  1. title 'BDEVIF - Block DEVice Input/Output support'
  2. ;    File              : $BDEVIO.A86$
  3. ;
  4. ;    Description       :
  5. ;
  6. ;    Original Author   : DIGITAL RESEARCH
  7. ;
  8. ;    Last Edited By    : $CALDERA$
  9. ;
  10. ;-----------------------------------------------------------------------;
  11. ;    Copyright Work of Caldera, Inc. All Rights Reserved.
  12. ;      
  13. ;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
  14. ;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
  15. ;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
  16. ;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
  17. ;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
  18. ;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
  19. ;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
  20. ;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
  21. ;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
  22. ;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
  23. ;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
  24. ;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
  25. ;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
  26. ;    CIVIL LIABILITY.
  27. ;-----------------------------------------------------------------------;
  28. ;
  29. ;    *** Current Edit History ***
  30. ;    *** End of Current Edit History ***
  31. ;
  32. ;    $Log$
  33. ;    BDEVIO.A86 1.27 94/11/30 16:25:22
  34. ;    added delayed retry for read/write to locked region
  35. ;    added support for using multiple FAT copies on reads if one fails;    
  36. ;    BDEVIO.A86 1.26 94/02/22 17:11:25
  37. ;    Fix where corrupt dir entry results in read beyond end-of-chain (Filelink bug)
  38. ;    BDEVIO.A86 1.25 93/12/15 03:07:11
  39. ;    New ddioif entry point so Int 25/26 bypasses address normalisation
  40. ;    BDEVIO.A86 1.24 93/12/08 03:15:14
  41. ;    Force rebuild_ldt_root if root in JOIN's subdirectory
  42. ;    BDEVIO.A86 1.23 93/11/19 18:29:29
  43. ;    Fix for SERVER print queue viewing problem
  44. ;    BDEVIO.A86 1.22 93/09/21 12:43:37
  45. ;    On fdos read/write do EOF checks before SHARE LOCK checks
  46. ;    BDEVIO.A86 1.21 93/09/14 20:02:50
  47. ;    Trust LFLG_PHYSICAL
  48. ;    BDEVIO.A86 1.20 93/09/02 22:22:56
  49. ;    Use 32 bit sectors to read fat for build bpb if appropriate (SYQUEST bug)
  50. ;    BDEVIO.A86 1.19 93/08/27 18:46:49
  51. ;    int 26 discards hash codes
  52. ;    BDEVIO.A86 1.18 93/07/20 22:42:25
  53. ;    Even fewer checks on int 25/26 
  54. ;    BDEVIO.A86 1.12 93/06/23 02:57:07
  55. ;    Add auto-commit to fdowrw
  56. ;    BDEVIO.A86 1.11 93/05/14 13:47:41
  57. ;    Shorten media change code slightly
  58. ;    BDEVIO.A86 1.9 93/03/16 22:30:21 IJACK
  59. ;    UNDELETE support changes
  60. ;    ENDLOG
  61. eject ! include i:mserror.equ ; F_DOS erros
  62. eject ! include i:fdos.equ
  63. eject ! include i:driver.equ
  64. eject ! include i:doshndl.def
  65. eject ! include bdos.equ
  66. eject ! include rh.equ
  67. ;*****************************************************
  68. ;*
  69. ;* bdos data area
  70. ;*
  71. ;*****************************************************
  72. PCMODE_DATA dseg word
  73. extrn current_ddsc:dword
  74. extrn current_dhndl:dword
  75. extrn current_dsk:byte ; default drive
  76. extrn current_ldt:dword ; currently selected LDT
  77. extrn dma_offset:word ; DTA offset
  78. extrn dma_segment:word ; DTA segment
  79. extrn ddsc_ptr:dword
  80. extrn err_drv:byte
  81. extrn error_dev:dword ; failing device for Int 24's
  82. extrn fdos_stub:dword
  83. extrn ioexerr:byte
  84. extrn last_drv:byte
  85. extrn ldt_ptr:dword
  86. extrn lock_bios:dword
  87. extrn phys_drv:byte
  88. extrn rwmode:byte
  89. extrn share_stub:dword
  90. extrn unlock_bios:dword
  91. extrn verify_flag:byte
  92. extrn net_retry:word
  93. BDOS_DATA dseg word
  94. extrn bcb_root:dword
  95. extrn deblock_seg:word
  96. extrn fdos_hds_drv:byte
  97. extrn fdos_hds_blk:word
  98. extrn fdos_hds_root:word
  99. extrn fdos_ret:word
  100. public adrive
  101. public clsize
  102. public dosfat
  103. public cur_dma
  104. public cur_dma_seg
  105. public datadd
  106. public diradd
  107. public dirinroot
  108. public dirperclu
  109. public fatadd
  110. public hdsaddr
  111. public lastcl
  112. public logical_drv
  113. public mult_sec
  114. public nfatrecs
  115. public nfats
  116. public pblock
  117. public physical_drv
  118. public psecsiz
  119. public req_hdr
  120. public secperclu
  121. eject
  122. ; The following specify the drive selected for the current operation
  123. hdsaddr dw 0 ; current HDS address (0 means at root)
  124. logical_drv db 0 ; logical drive number
  125. physical_drv db 0 ; physical disk number
  126. ; The following describe the currently active drive - not this may differ from
  127. ; the currently selected drive above due to eg. flushing dirty buffers
  128. ; Local copy of DDSC_ variables - ORDER CRITICAL - must match DDSC_
  129. local_ddsc rb 0
  130. psecsiz dw 0 ; byte size of sector
  131. clmsk db 0
  132. clshf db 0
  133. fatadd dw 0 ; sector offset of 1st FAT sector
  134. byte_nfats db 0 ; number of FAT's
  135. dirinroot dw 0 ; # dir entries in root
  136. datadd dw 0 ; sector offset of data sector
  137. lastcl dw 0 ; # last cluster (after adjustment)
  138. if DOS5
  139. dw 0 ; # sectors per FAT
  140. else
  141. db 0 ; # sectors per FAT (nb. may be inaccurate on large drives)
  142. endif
  143. diradd dw 0 ; sector offset of 1st root DIR sector
  144. LOCAL_DDSC_LEN equ offset $ - offset local_ddsc
  145. ; some extra parameters calculated from local_ddsc for convenience
  146. nfats dw 0 ; # FAT's (WORD is handier)
  147. nfatrecs dw 0 ; # sectors per FAT (accurate version)
  148. clsize dw 0 ; cluster size in bytes
  149. secperclu dw 0 ; # sectors per cluster
  150. dirperclu dw 0 ; # dir enrties in subdir
  151. dosfat dw 0 ; FAT length indicator (FAT12 or FAT16)
  152. ; The following specify the next block read/write operation on the active drive
  153. adrive db 0ffh ; currently active disk
  154. pblock dw 0, 0 ; absolute block address
  155. mult_sec dw 1 ; multi sector count passed to xios
  156. cur_dma dw 0
  157. cur_dma_seg dw 0
  158. fdrwreq dw 0 ; requested count (roundup)
  159. public fdrwflg
  160. fdrwflg db 0 ; bdosrw flags
  161. fdrwcnt dw 0 ; requested byte count for read/write
  162. fdrwptr rd 0 ; disk transfer address for read/write
  163. fdrwoff dw 0 ; offset for R/W DTA
  164. fdrwseg dw 0 ; segment for R/W DTA
  165. fdrwsec rd 1 ; physical block for fdosrw
  166. fdrwsecoff dw 0 ; offset within sector
  167. fdrwdircnt dw 0 ; # sectors in direct xfer
  168. byteoff dw 0 ; fdosrw local variable
  169. dw 0 ; byte offset with file
  170. blk dw 0 ; current cluster of filepos
  171. blkidx dw 0 ; current cluster index within file
  172. blkoffset dw 0 ; offset within cluster
  173. ; static request header for DOS device driver I/O
  174. Public req_hdr
  175. req_hdr rb 0
  176. req_len db 22
  177. req_unit rb 1
  178. req_cmd rb 1
  179. req_status rw 1
  180. req_rwmode db 0 ; action hint for device drivers
  181. rb 7
  182. req_media rb 1
  183. rb 16
  184. req1_return equ byte ptr req_media+1
  185. req1_volid equ word ptr req_media+2
  186. req2_buffer equ word ptr req_media+1
  187. req2_bpb equ word ptr req_media+5
  188. req3_buffer equ word ptr req_media+1
  189. req3_count equ word ptr req_media+5
  190. req3_sector equ word ptr req_media+7
  191. req3_volid equ word ptr req_media+9
  192. req4_buffer equ word ptr req_media+1
  193. req4_count equ word ptr req_media+5
  194. req4_sector equ word ptr req_media+7
  195. req4_volid equ dword ptr req_media+9
  196. req4_bigsector equ dword ptr req_media+13
  197. eject
  198. BDOS_CODE cseg
  199. extrn alloc_chain:near
  200. extrn bpb2ddsc:near ; converts BPB to DDSC
  201. extrn buffers_check:near ; look for buffers
  202. extrn delfat:near
  203. extrn discard_all:near ; discard all buffers
  204. extrn discard_dir:near ; discard directory buffers
  205. extrn discard_dirty:near ; discard all dirty buffers
  206. extrn discard_files:near ; discard open files
  207. extrn fdos_error:near
  208. extrn fdos_restart:near
  209. extrn file_update:near
  210. extrn fixfat:near
  211. extrn getnblk:near ; get block value from FAT
  212. extrn get_ldt:near
  213. extrn get_ldt_raw:near
  214. extrn hdsblk:near ; get current HDS block
  215. extrn hshdscrd:near
  216. extrn locate_buffer:near
  217. extrn rebuild_ldt_root:near
  218. extrn timestamp_dhndl:near
  219. extrn update_dat:near
  220. extrn update_fat:near
  221. extrn share_delay:near
  222. public block_device_driver
  223. public clus2sec
  224. public device_driver
  225. public read_block
  226. public select_adrive
  227. public select_logical_drv
  228. public select_physical_drv
  229. public  write_block
  230. eject
  231. eject
  232. Public get_ddsc
  233. get_ddsc:
  234. ;--------
  235. ; On Entry:
  236. ; AL = physical drive
  237. ; On Exit:
  238. ; CY set if bad drive, else
  239. ; ES:BX -> DDSC_
  240. ; (All other registers preserved)
  241. ;
  242. cmp al,ss:phys_drv
  243.  jae get_ddsc30
  244. les bx,ss:ddsc_ptr
  245. get_ddsc10:
  246. cmp bx,0FFFFh ; end of the line
  247.  je get_ddsc30
  248. cmp al,es:DDSC_UNIT[bx] ; does the unit match ?
  249.  je get_ddsc20 ; no, try the next
  250. les bx,es:DDSC_LINK[bx]
  251. jmps get_ddsc10
  252. get_ddsc20:
  253. ; clc
  254. ret
  255. get_ddsc30:
  256. stc
  257. ret
  258. eject
  259. ; Read/Write from/to disk file
  260. ; entry: CURRENT_DNHDL -> file handle
  261. ; BDRWFLG = 1 => read
  262. ;   0 => write
  263. ; ES:DI = buffer (32 bit: off/seg)
  264. ; CX = requested byte count (16 bit)
  265. ; exit: FDOS_RET = number of bytes read/written
  266. ; CURRENT_DHNDL incremented by FDOS_RET
  267. public fdosrw ; read/write to/from disk file
  268. fdosrw:
  269. ;------
  270. call fdrw_prepare ; set up address, where we are in file
  271.  jc fdrw_error ;  stop if we have a problem
  272. call fdrw_size ; extend file if necessary
  273.  jc fdrw_error ;  bail out if we can't
  274. cmp fdrwcnt,0 ; are we truncating?
  275.  jne fdrw_loop ; read/write if non-zero count
  276. test fdrwflg,1 ; writing zero bytes?
  277.  jnz fdrw_error ; (reading has no meaning)
  278. call fdw_trunc ; writing truncates the file
  279. jmps fdrw_nobigger
  280. fdrw_error:
  281. ret
  282. fdrw_loop: ; loop here for long reads/writes
  283. call fdrw_seek ; seek to position for xfer
  284.  jc fdrw_exit ;  should get error's now...
  285.  jnz fdrw_buffered ; deblocking required if not aligned
  286. mov cx,fdrwcnt ; CX = requested transfer size
  287. cmp cx,psecsiz ; at least one sector transferred?
  288.  jb fdrw_buffered ; if less, need deblocked transfer
  289. mov fdrwreq,cx ; requested count for direct r/w
  290. call direct_rw ; transfer straight to/from TPA
  291. jmps fdrw_more
  292. fdrw_buffered: ; perform deblocked read/write
  293. call deblock_rw ; transfer via BDOS buffer
  294. fdrw_more:
  295. add fdrwoff,ax ; adjust buffer address
  296. add fdos_ret,ax ; adjust return code
  297. add byteoff,ax ; adjust file offset
  298. adc byteoff+2,0
  299. sub fdrwcnt,ax ; adjust remaining count
  300.  ja fdrw_loop ; still more to do
  301. fdrw_exit:
  302. les bx,current_dhndl
  303. mov ax,fdos_ret ; get total xfered and update position
  304. add es:DHNDL_POSLO[bx],ax
  305. adc es:DHNDL_POSHI[bx],0
  306. test fdrwflg,1
  307.  jnz fdrw_return ; skip if reading
  308. mov ax,byteoff ; has the file grown ?
  309. mov dx,byteoff+WORD
  310. sub ax,es:DHNDL_SIZELO[bx]
  311. sbb dx,es:DHNDL_SIZEHI[bx]
  312.  jb fdrw_nobigger ; yes, update the file size
  313. add es:DHNDL_SIZELO[bx],ax
  314. adc es:DHNDL_SIZEHI[bx],dx
  315. fdrw_nobigger:
  316. call timestamp_dhndl ; record the current time
  317. test es:DHNDL_MODE[bx],DHM_COMMIT
  318.  jz fdrw_return ; is auto-commit in place ?
  319. call file_update ; yes, commit the file
  320. fdrw_return:
  321. ret
  322. fdw_trunc:
  323. ;---------
  324. ; On Entry:
  325. ; BLKIDX = block number within file
  326. ; BLKOFFSET = block offset
  327. ; On Exit:
  328. ; DHNDL_SIZE adjusted, any excess clusters freed
  329. ;
  330. les bx,current_dhndl
  331. mov cx,blkoffset ; get offset within current block
  332. mov ax,blkidx ; get logical block number
  333.  jcxz fdw_t10 ; skip if no data in last block
  334. inc ax ; else add in another cluster
  335. fdw_t10: ; AX = # of clusters required in file
  336. test ax,ax
  337.  jnz fdw_t20
  338. xchg ax,es:DHNDL_BLK1[bx] ; forget about chain
  339. jmps fdw_t50
  340. fdw_t20:
  341. xchg ax,cx ; CX = # of blocks to keep
  342. mov ax,es:DHNDL_BLK1[bx] ; get first block in file
  343. fdw_t30: ; scan all block we want to keep
  344. push cx
  345. push ax
  346. call getnblk ; get next block
  347. pop bx
  348. pop cx
  349. cmp ax,lastcl ; stop on premature end of chain
  350.  ja fdw_t60
  351. loop fdw_t30
  352. push ax ; yep, remember what
  353. mov ax,dosfat
  354. xchg ax,bx ; truncate chain at cluster AX
  355. call fixfat ;  as thats all we need
  356. pop ax
  357. fdw_t50:
  358. call delfat ; release the chain
  359. fdw_t60:
  360. les bx,current_dhndl
  361. mov ax,byteoff ; now truncate the file
  362. mov es:DHNDL_SIZELO[bx],ax
  363. mov ax,byteoff+2
  364. mov es:DHNDL_SIZEHI[bx],ax
  365. xor ax,ax ; cause reads/writes to scan
  366. mov es:DHNDL_BLK[bx],ax ;   block chain from start
  367. mov es:DHNDL_IDX[bx],ax
  368. mov fdos_ret,ax ; no logical errors
  369. ret
  370. fdrw_prepare:
  371. ;------------
  372. ; Normalise the xfer address and count
  373. ; Calculate current position in the file
  374. ;
  375. ; On Entry:
  376. ; ES:DI -> buffer
  377. ; CX = bytes to xfer
  378. ; On Exit:
  379. ; FDRWSEG:FDRWOFF -> normalised buffer
  380. ; FDRWCNT = bytes to xfer
  381. ; FDOS_RET = bytes xfer'd (0)
  382. ; PREREAD = TRUE
  383. ; BYTEOFF = current offset in file
  384. ; BLKIDX = cluster containing current file position
  385. ; BLKOFFSET = offset within cluster
  386. ; CY set if current position theoretically impossible
  387. ;
  388. xor ax,ax ; AX = 0
  389. mov fdos_ret,ax ; initialize byte return count
  390. mov fdrwcnt,cx ; save byte count for read/write
  391. mov ax,000Fh
  392. and ax,di ; get offset within paragraph
  393. mov fdrwoff,ax ; save normalized offset for read/write
  394. add ax,cx ; do we overflow 64k ?
  395.  jnc fdrw_p10 ; yes, then forget about what would
  396. sub fdrwcnt,ax ;  overflow this segment
  397. fdrw_p10:
  398. mov cl,4
  399. shr di,cl ; DI = paragraph offset
  400. mov ax,es
  401. add ax,di ; AX = effective segment
  402.  jnc fdrw_p20 ; if above 1 MByte base it at FFFF
  403. inc ax ; AX = para's above FFFF
  404. shl ax,cl ; make it bytes
  405. add fdrwoff,ax ;  add to offset
  406. mov ax,0ffffh ; use our magic segment
  407. fdrw_p20:
  408. mov fdrwseg,ax ; save normalized segment for read/write
  409. les bx,current_dhndl
  410. mov ax,es:DHNDL_POSLO[bx]
  411. mov byteoff,ax ; copy position to local variables
  412. mov ax,es:DHNDL_POSHI[bx]
  413. mov byteoff+WORD,ax
  414. mov cx,clsize
  415. mov ax,lastcl
  416. mul cx ; DX:AX = maximum size of disk
  417. sub ax,byteoff
  418. sbb dx,byteoff+WORD ; beyond this we can't go
  419.  jc fdrw_p30
  420. mov ax,byteoff ; DX:AX = current file size
  421. mov dx,byteoff+WORD
  422. div clsize
  423. mov blkidx,ax ; save it for later
  424. mov blkoffset,dx ; DX = offset within cluster
  425. clc ; theoretically possible
  426. fdrw_p30:
  427. ret
  428. fdrw_size:
  429. ;---------
  430. ; On reads check xfer starts within file, and clip size to reflect EOF.
  431. ; On writes try to extend to cluster chain so it is big enough to contain
  432. ; the data we wish to write.
  433. ;
  434. ; On Entry:
  435. ; BYTEOFF = current position in file
  436. ; FDRWCNT = extra bytes requested
  437. ; On Exit:
  438. ; FDRWCNT adjusted if read past EOF
  439. ; CY set if problem extending file
  440. ;
  441. les bx,current_dhndl
  442. mov ax,es:DHNDL_SIZELO[bx] ; are we past the end of file
  443. mov dx,es:DHNDL_SIZEHI[bx] ;  if so we may wish to extend on write
  444. sub ax,byteoff ; AX,DX = current offset
  445. sbb dx,byteoff+WORD ; are we already beyond EOF ?
  446.  jb fdrw_s40
  447. sub ax,fdrwcnt ; will we be going beyond EOF ?
  448. sbb dx,0
  449.  jnb fdrw_s10 ; no, whole xfer is OK
  450. test fdrwflg,1 ; check if we're reading
  451.  jz fdrw_s50 ;  if we are just adjust the
  452. add fdrwcnt,ax ;  amount we can xfer
  453. fdrw_s10:
  454. ; We call share concerning the XFER to check if any of the proposed
  455. ; file region is locked.
  456. ; les bx,current_dhndl ; check for locked regions
  457. mov cx,net_retry
  458. fdrw_s15:
  459. push cx
  460. mov cx,fdrwcnt ;  in the file
  461. callf share_stub+S_FDOSRW
  462. pop cx
  463.  jnc fdrw_s20 ; CY set on error
  464. dec cx
  465.  jz fdrw_s30
  466. call share_delay
  467. jmps fdrw_s15
  468. fdrw_s20:
  469. ret
  470. fdrw_s30:
  471. jmp fdos_error ; CY clear, AX = error code
  472. fdrw_s40:
  473. ; We are going beyond EOF - if it is a read we fail it, if a write
  474. ;  try to extend the file
  475. test fdrwflg,1 ; check if we're reading
  476. stc ;  assume failure
  477.  jnz fdrw_s20 ; reads fail now, writes extend file
  478. fdrw_s50:
  479. call fdrw_s10 ; make sure SHARE doesn't object
  480. ; jmp fdwrite_extend ; if not try to extend the file
  481. fdwrite_extend:
  482. ;--------------
  483. ; Try to extend to file to the required size before we write to it
  484. ; On Entry:
  485. ; ES:BX -> DHNDL_
  486. ; BYTEOFF = current position in file
  487. ; FDRWCNT = extra requested
  488. ; On Exit:
  489. ; CY clear if cluster chain now big enough for desired file size
  490. ;
  491. mov ax,byteoff ; AX,DX = current offset
  492. mov dx,byteoff+2
  493. add ax,fdrwcnt ; AX,DX = offset after r/w if success
  494. adc dx,0 ; add offset from lower 16 bits
  495. div clsize ; AX whole blocks required
  496. test dx,dx ; any remainder ?
  497.  jz fdw_e05 ; yes, we have a partial block
  498. inc ax ; round up blocks required
  499. fdw_e05:
  500. xchg ax,cx ; CX blocks are required
  501. mov ax,es:DHNDL_BLK1[bx] ; assume we need to follow from start
  502. test ax,ax
  503.  jz fdw_e30 ; if no starting block do the lot
  504. dec cx ;  else count # extra blocks required
  505. mov dx,es:DHNDL_BLK[bx] ; do we have a current block ?
  506. test dx,dx ; if not we have to start
  507.  jz fdw_e10 ;  with the first block
  508. mov ax,dx ; new starting block as this must
  509. sub cx,es:DHNDL_IDX[bx] ;  be less than extended size
  510. fdw_e10:
  511.  jcxz fdw_e20 ; bail out of we have enough
  512. fdw_e15:
  513. push ax ; save current block
  514. push cx ; save # required
  515. call getnblk ; AX = next block in chain
  516. pop cx ; restore # required
  517. pop bx ; recover previous block
  518. cmp ax,lastcl ; end of chain yet ?
  519.  ja fdw_e40
  520. loop fdw_e15 ; try another one
  521. fdw_e20:
  522. clc ; chain is already long enough
  523. ret
  524. fdw_e30:
  525. ; We have no initial block, so allocate them all
  526. ; xor ax,ax ; no preconceptions over where we
  527. call alloc_chain ;  allocate chain of CX clusters
  528.  jc fdw_e35
  529. les bx,current_dhndl
  530. mov es:DHNDL_BLK1[bx],ax ; remember initial block
  531. clc
  532. fdw_e35:
  533. ret
  534. fdw_e40:
  535. ; We have a partial chain, ending at cluster BX
  536. push bx ; save current end of chain
  537. xchg ax,bx ; start allocating from cluster AX a
  538. call alloc_chain ;  a chain of CX clusters
  539. pop bx
  540.  jc fdw_e45
  541. xchg ax,bx ; AX = previous cluster, link cluster
  542. call fixfat ;  BX to end of the chain
  543. clc
  544. fdw_e45:
  545. ret
  546. fdrw_seek:
  547. ;---------
  548. ; On Entry:
  549. ; BYTEOFF = offset within file
  550. ; On Exit:
  551. ; BLK = cluster containing current filepos
  552. ; BLKOFFSET = offset within cluster
  553. ; BLKIDX = cluster index within file
  554. ; PBLOCK = sector containing current filepos
  555. ; POFFSET = offset within sector (reflected in ZF)
  556. ;
  557. mov ax,byteoff ; where are we now ?
  558. mov dx,byteoff+WORD
  559. div clsize
  560. mov blkidx,ax ; save cluster
  561. mov blkoffset,dx ;  and offset within it
  562. les bx,current_dhndl
  563. cmp ax,es:DHNDL_IDX[bx] ; do we know this block ?
  564.  jb fdrw_seek10 ; we can't go backwards, use 1st block
  565. mov cx,es:DHNDL_BLK[bx] ; get last index block
  566.  jcxz fdrw_seek10 ; use 1st block if it isn't valid
  567. sub ax,es:DHNDL_IDX[bx] ; skip this many
  568. jmps fdrw_seek20
  569. fdrw_seek10:
  570. mov cx,es:DHNDL_BLK1[bx] ; start with 1st block
  571. fdrw_seek20:
  572. xchg ax,cx ; AX = starting cluster
  573.  jcxz fdrw_seek40 ; CX = clusters to skip
  574. fdrw_seek30:
  575. push cx
  576. call getnblk ; get next block
  577. pop cx
  578. cmp ax,lastcl ; stop on premature end of chain
  579.  ja fdrw_seek_error ; (file size must be wrong..)
  580. loop fdrw_seek30
  581. fdrw_seek40:
  582. les bx,current_dhndl
  583. mov dx,blkidx
  584. mov es:DHNDL_IDX[bx],dx ; remember this position for next time
  585. mov es:DHNDL_BLK[bx],ax
  586. mov blk,ax ; save the block for coniguous checks
  587. mov bx,blkoffset
  588. call clus2sec ; convert to sector/offset
  589. mov word ptr fdrwsec,ax ; remember this block
  590. mov word ptr fdrwsec+WORD,dx
  591. mov fdrwsecoff,bx ;  and offset within it
  592. test bx,bx ; set ZF
  593. ; clc ; no problems
  594. ret
  595. fdrw_seek_error:
  596. stc ; we hit unexpected end of chain
  597. ret ; (shouldn't happen)
  598. ; Read/write partial sector via deblocking code
  599. ; On Entry:
  600. ; FDRWSEC = sector address on disk
  601. ; FDRWSECOFF = offset within sector
  602. ; FDRWCNT = byte count for read/write
  603. ; On Exit:
  604. ; AX = # of bytes transferred
  605. deblock_rw:
  606. ;----------
  607. mov cx,0FF00h+BF_ISDAT ; CH = preread, buffer is data
  608. mov dx,word ptr fdrwsec ; set sector to xfer from
  609. mov ah,byte ptr fdrwsec+WORD
  610. call locate_buffer ; ES:SI -> buffer
  611. mov bx,fdrwsecoff ; BX = offset within sector
  612. mov ax,psecsiz
  613. mov dx,ax ; DX = physical sector size
  614. sub ax,bx ; AX = bytes left in sector
  615. cmp ax,fdrwcnt ; more than we want to transfer?
  616.  jb deblkrw10 ; yes, only do up to end of sector
  617. mov ax,fdrwcnt ; else do up to end of request
  618. deblkrw10:
  619. mov cx,ax ; AX, CX = byte count
  620. ; (AX for return, CX for MOVSW)
  621. push ds
  622. test fdrwflg,1 ; check if reading or writing
  623.  jz dblkrw30 ; skip if writing
  624. push es
  625. les di,fdrwptr ; destination is user memory
  626. pop ds ; source segment is data buffer
  627. lea si,BCB_DATA[si+bx] ; DS:SI -> data
  628. jmps dblkrw40 ; copy the data
  629. dblkrw30: ; we're writing
  630. or es:BCB_FLAGS[si],BF_DIRTY; mark buffer as dirty
  631. lea di,BCB_DATA[si+bx] ; ES:DI -> data
  632. lds si,fdrwptr ; source is user memory
  633. dblkrw40:
  634. shr cx,1 ; make it a word count
  635. rep movsw ; move the words
  636.  jnc dblkrw50 ; skip if even # of bytes
  637. movsb ; else move last byte
  638. dblkrw50:
  639. pop ds ; restore registers
  640. ret
  641. ; entry: BYTEOFF = 32-bit offset into file
  642. ; BLKOFFSET = byte offset within cluster
  643. ; PRVBLK = block in which transfer starts
  644. ; FDRWREQ = requested transfer length
  645. ;---------
  646. direct_rw:
  647. ;---------
  648. sub dx,dx ; assume no extra blocks required
  649. mov ax,fdrwreq ; total byte count
  650. mov cx,clsize ; get number of bytes
  651. sub cx,blkoffset ; CX = bytes remaining in this block
  652. sub ax,cx ; if wholly containined within block
  653.  jbe direct_rw10 ; then leave it alone
  654. div clsize ; else get # of extra clusters
  655. xchg ax,dx ; DX = clusters, AX = remainder
  656. or ax,ax ; round up if any remainder
  657.  jz direct_rw10 ; skip if even number
  658. inc dx ; else one more cluster
  659. direct_rw10: ; DX = # of contiguous clusters req'd
  660. call check_cont ; check how many contiguous blocks
  661. mov ax,clsize ; space = cnt * dpbptr->clsize;
  662. mul cx ; AX:DX = # of bytes transferrable
  663. sub ax,blkoffset ; BX = skipped bytes in 1st cluster
  664. sbb dx,0
  665. ; AX:DX = max # of bytes transferrable
  666. ;    from current position
  667. test dx,dx
  668.  jnz direct_rw20 ; if > 64 K, use up request
  669. cmp ax,fdrwreq ; if less than we requested
  670.  jb direct_rw30 ; then lets do it
  671. direct_rw20:
  672. xor dx,dx
  673. mov ax,fdrwreq ; else use requested count
  674. direct_rw30:
  675. div psecsiz ; AX = # complete sectors
  676. mov fdrwdircnt,ax ; save direct sector count
  677. mov mult_sec,ax ; set multi sector count
  678. mul psecsiz ; AX = bytes to xfer
  679. push ax ; save for later
  680. mov ax,fdrwoff ; FDRWPTR = disk transfer address
  681. mov cur_dma,ax
  682. mov ax,fdrwseg
  683. mov cur_dma_seg,ax
  684. mov ax,word ptr fdrwsec ; set sector to xfer from
  685. mov word ptr pblock,ax
  686. mov ax,word ptr fdrwsec+WORD
  687. mov word ptr pblock+WORD,ax
  688. mov rwmode,0000$0110b ;data read/write
  689. mov cl,fdrwflg
  690. and cl,1 ; CL = read/write flag
  691.  jz direct_rw40
  692. xor cx,cx ; indicate no retries
  693. call read_block ; read in the data
  694. jmps direct_rw50
  695. direct_rw40:
  696. call write_block ; write out the data
  697. direct_rw50:
  698. call SynchroniseBuffers ; synchronize BCBs with direct transfer
  699. pop ax ; recover bytes xfered
  700. push ds ! pop es ; restore ES = SYSDAT
  701. ret
  702. check_cont: ; check for adjacent blocks or space
  703. ;----------
  704. ; entry: DX = # of extra contiguous blocks req'd
  705. ; exit: CX = # of contiguous blocks available
  706. ; We first check all adjacent allocated clusters.
  707. ; If we'd like more and we find the end of file
  708. ; and we are writing and the adjacent blocks aren't
  709. ; allocated, then we count them as well and link
  710. ; them into the file.
  711. mov ax,blk ; current block number
  712. xor cx,cx ; contiguous blocks found = 0
  713. test dx,dx ; any extra required ?
  714.  jz check_cont20
  715. check_cont10: ; get link of current block
  716. push ax ; save current block
  717. push cx ; save extra blocks so far
  718. push dx ; save extra blocks we'd like
  719. call getnblk ; get the link
  720. pop dx
  721. pop cx
  722. pop bx
  723. inc bx ; BX = current block + 1
  724. cmp ax,bx ; check if next block is contiguous
  725.  jne check_cont20 ;  and try for another
  726. inc cx ; extra contiguous cluster
  727. dec dx ; one less block to check
  728.  jnz check_cont10 ; try again if we still want more
  729. check_cont20: ; we can do CX extra clusters
  730. inc cx ; include 1st cluster too..
  731. ret
  732. ;------------------
  733. SynchroniseBuffers: ; synchronize BCBs after multi sector transfer
  734. ;------------------
  735. ; On Entry:
  736. ; FDRWSEG:FDRWOFF = transfer address for IO_READ/IO_WRITE
  737. ; FDRWDIRCNT = physical sector count for direct transfer
  738. ; FDRWSEC = sector address for transfer
  739. ; FDWRFLG = even for write, odd for read
  740. ; On Exit:
  741. ; direct transfer buffer or BCB updated if BCB overlap
  742. ;
  743. ; If any data buffer is found, that falls into the region affected
  744. ; by the direct sector transfer, the following action is performed:
  745. ; If the operation was a read and the sector buffer is clean,
  746. ; no action is required. If it was dirty, the buffer contents is
  747. ; copied to the corresponding location in the DTA buffer.
  748. ; If the operation was a write, the sector buffer is discarded.
  749. ;
  750. ;
  751. mov dx,word ptr fdrwsec
  752. mov ah,byte ptr fdrwsec+WORD
  753. mov al,adrive ; get our drive number
  754. lds bx,bcb_root ; DS:BX -> 1st buffer
  755. SynchroniseBuffers10:
  756. test ds:BCB_FLAGS[bx],BF_ISDAT; is this a data buffer?
  757.  jz SynchroniseBuffers30 ; skip if directory or FAT
  758. cmp al,ds:BCB_DRV[bx] ; does the drive match?
  759.  jne SynchroniseBuffers30 ; skip if different
  760. mov si,ds:BCB_REC[bx] ; compute bcb->rec - prec
  761. sub si,dx ; result in SI,CL (lsb..msb)
  762. mov cl,ds:BCB_REC2[bx]
  763. sbb cl,ah ; get bits 16-23 of result
  764.  jne SynchroniseBuffers30 ; skip if bcb->rec < prec
  765. cmp si,ss:fdrwdircnt ; else check against transfer length
  766.  jae SynchroniseBuffers30 ; skip if beyond transfer length
  767. test ss:fdrwflg,1 ; test direction:  read or write
  768.  jz SynchroniseBuffers20 ; skip if disk write
  769. test ds:BCB_FLAGS[bx],BF_DIRTY; if buffer dirty, did read old data
  770.  jz SynchroniseBuffers30 ; else data read was valid
  771. push ax ! push dx ; save record address
  772. mov ax,ss:psecsiz ; # of bytes in sector buffer
  773. mov cx,ax
  774. shr cx,1 ; CX = words per sector
  775. mul si ; AX = byte offset from start buffer
  776. add ax,ss:fdrwoff ; AX = offset
  777. xchg ax,di ; DI = offset
  778. mov es,ss:fdrwseg ; ES:DI -> data to be replaced
  779. lea si,BCB_DATA[bx]
  780. rep movsw ; move CX words (one physical sector)
  781. pop dx ! pop ax ; restore record address
  782. jmps SynchroniseBuffers30
  783. SynchroniseBuffers20: ; multi sector write
  784. mov ds:BCB_DRV[bx],0FFh ; discard this sector
  785. SynchroniseBuffers30:
  786. if DOS5
  787. mov bx,ds:BCB_NEXT[bx]
  788. cmp bx,ss:word ptr bcb_root
  789. else
  790. lds bx,ds:BCB_NEXT[bx] ; get next buffer address
  791. cmp bx,0ffffh
  792. endif
  793.  jne SynchroniseBuffers10 ; if so stop
  794. push ss ! pop ds ; restore DS
  795. ret
  796. eject
  797. Public blockif, ddioif
  798. ;======= ================================
  799. blockif: ; disk read/write bios interface
  800. ;======= ================================
  801. ; entry: AL = BIOS Request function number
  802. ; ADRIVE = block device to xfer to/from
  803. ; RWMODE = read/write mode
  804. ; CUR_DMA_SEG:CUR_DMA -> xfer address
  805. ; PBLOCK = starting block of xfer
  806. ; MULT_CNT = # blocks to xfer
  807. ; exit: AX = BX = output
  808. mov req_cmd,al
  809. mov al,rwmode ; copy rwmode to where the device
  810. mov req_rwmode,al ;  driver can get the hint
  811. mov ax,cur_dma ; get DMA offset
  812. push ax ; (save it)
  813. and ax,000Fh ; get offset within paragraph
  814. mov req4_buffer,ax ; set transfer offset
  815. pop ax ; (restore offset)
  816. mov cl,4
  817. shr ax,cl ; convert to paragraphs
  818. add ax,cur_dma_seg ; add in the segment
  819. mov req4_buffer+2,ax ; set transfer segment
  820. mov ax,mult_sec ; get requested sector count
  821. mov req4_count,ax ; set requested sector count
  822. ;------
  823. ddioif:
  824. ;------
  825. push es
  826. mov al,adrive ; get selected drive
  827. call get_ddsc ; ES:BX -> DDSC
  828. mov ax,word ptr pblock
  829. mov dx,word ptr pblock+WORD ; DX:AX = starting block
  830. push es
  831. les si,es:DDSC_DEVHEAD[bx] ; ES:SI -> device driver
  832. if DOS5
  833. ; DOS 4 support
  834. mov word ptr req4_bigsector,ax
  835. mov word ptr req4_bigsector+2,dx
  836. mov req_len,RH4_LEN ; set length of request header
  837. test es:DH_ATTRIB[si],DA_BIGDRV ; large sector number support?
  838.  jz blockif10 ; no, normal request header
  839. mov ax,-1 ; indicate we use 32-bit sector number
  840. blockif10:
  841. mov req4_sector,ax ; set requested sector address
  842. else
  843. mov word ptr req4_bigsector,ax
  844. mov word ptr req4_bigsector+2,dx
  845. mov req4_sector,ax ; set requested sector address
  846. mov req4_sector+2,dx ; (support large DOS drives)
  847. mov req_len,RH4_LEN ; assume 22 bytes in request header
  848. test es:DH_ATTRIB[si],DA_BIGDRV ; large sector number support?
  849.  jz blockif10 ; no, normal request header
  850. mov req_len,RH4_LEN+2 ; else indicate long request
  851. blockif10:
  852. endif
  853. pop es
  854. call block_device_driver ; make call to device driver
  855.  js blockif20
  856. xor ax,ax ; no error
  857. blockif20:
  858. mov mult_sec,1 ; reset sector count
  859. mov bx,ax ; AX, BX = return code
  860. pop es
  861. ret
  862. block_device_driver:
  863. ;------------------
  864. ; entry: ES:BX -> DDSC, req_hdr partly filled in
  865. ; exit: AX = status after function
  866. ; SF = 1 if error occurred
  867. ; note: BX preserved
  868. mov al,es:DDSC_MEDIA[bx]
  869. mov req_media,al ; set current media byte
  870. mov al,es:DDSC_RUNIT[bx] ; get relative unit #
  871. mov req_unit,al ; set the unit
  872. push ds
  873. push es
  874. push bx
  875. push ds
  876. lds si,es:DDSC_DEVHEAD[bx]
  877. pop es
  878. mov bx,offset req_hdr ; ES:BX -> request packet
  879. call device_driver ; do operation
  880. pop bx
  881. pop es
  882. pop ds
  883. ret
  884. ; On Entry:
  885. ; DS:SI Device Header
  886. ; ES:BX Current Request Header
  887. ;
  888. ; On Exit:
  889. ; AX Request Header Status
  890. ;
  891. device_driver:
  892. ;------------
  893. xor ax,ax
  894. mov es:RH_STATUS[bx],ax ; Initialise return status
  895. push es
  896. push bx
  897. push bp
  898. callf ss:lock_bios ; lock access to BIOS
  899. push cs
  900. call device_driver10 ; fake a callf
  901. callf ss:unlock_bios ; unlock access to BIOS
  902. pop bp
  903. pop bx
  904. pop es
  905. sti
  906. cld ; Restore Flags
  907. mov ax,es:RH_STATUS[bx] ; Return the Status to the caller
  908. test ax,ax ; set SF=1 if error
  909. ret
  910. device_driver10:
  911. push ds
  912. push ds:DH_INTERRUPT[si] ; interrupt routine address on stack
  913. push ds
  914. push ds:DH_STRATEGY[si] ; strategy routine address on stack
  915. retf ; retf to strategy, interrupt, us
  916. eject
  917. ; Select drive and check for door open ints
  918. ; Build fdos_hds to refer to the drive
  919. ; Exit: DL = drive to be selected (0-15)
  920. select_logical_drv:
  921. ;------------------
  922. ; On Entry:
  923. ; AL = logical drive to select (with change media checks)
  924. ; On Exit:
  925. ; ES:BX -> LDT_
  926. ;
  927. cmp al,last_drv ; is it a legal drive ?
  928.  jae select_drv_bad ;  no, reject it now
  929. mov logical_drv,al ; save logical drive
  930. call get_ldt ; ES:BX -> LDT_ for drive
  931.  jc select_physical_drv ; no LDT_ during init, must be physical
  932. mov word ptr current_ldt,bx
  933. mov word ptr current_ldt+WORD,es
  934. mov al,es:byte ptr LDT_FLAGS+1[bx] ; is the drive valid ?
  935. test al,(LFLG_NETWRKD+LFLG_JOINED)/100h
  936.  jnz select_drv_bad ; reject networked/joined drives
  937. test al,LFLG_PHYSICAL/100h
  938.  jz select_drv_bad ; reject non-physical drives
  939. mov al,es:LDT_NAME[bx] ; get the drive from the ascii name
  940. and al,1fh ;  as the drive may require rebuilding
  941. dec ax ; make it zero based
  942. push es ! push bx
  943. call select_physical_drv ; select the physical root
  944. pop bx ! pop es
  945. cmp es:LDT_ROOTLEN[bx],2 ; if logical and physical roots
  946.  jbe select_logical_drv30 ;  are the same we are OK now
  947. if JOIN
  948. mov al,es:LDT_DRV[bx] ; should we be on a different
  949. cmp al,fdos_hds_drv ;  physical drive ?
  950.  jne select_logical_drv10 ; if so then we'd better rebuild
  951. endif
  952. cmp es:LDT_BLK[bx],0FFFFh ; did we have a media change ?
  953.  jne select_logical_drv20 ; then we'd better rebuild
  954. select_logical_drv10:
  955. call rebuild_ldt_root ;  the LDT_ root block
  956. select_logical_drv20:
  957. mov ax,es:LDT_ROOT[bx] ; get virtual root from LDT
  958. mov fdos_hds_root,ax ; move there
  959. mov fdos_hds_blk,ax
  960. if JOIN
  961. mov al,es:LDT_DRV[bx] ; same with drive
  962. mov fdos_hds_drv,al
  963. endif
  964. select_logical_drv30:
  965. ret
  966. select_physical_drv:
  967. ;-------------------
  968. ; On Entry:
  969. ; AL = physical drive to select (with change media checks)
  970. ; On Exit:
  971. ; None
  972. ;
  973. xor dx,dx
  974. mov fdos_hds_blk,dx ; put it in the root by default
  975. mov fdos_hds_root,dx
  976. mov fdos_hds_drv,al ; set physical drive in working HDS
  977. cmp al,phys_drv ; should we have a DDSC_ for this drive
  978.  jae select_drv_bad ;  no, we can't select it then
  979. mov physical_drv,al ; save physical drive number
  980. call select_adrive ; no, better select it
  981.  jc select_drv_critical_error
  982. ret
  983. select_drv_bad:
  984. ;--------------
  985. ; An attempt has been made to select a bad drive,
  986. ; return a logical error "invalid drive"
  987. mov ax,ED_DRIVE ; ED_DRIVE "invalid drive"
  988. jmp fdos_error
  989. select_drv_critical_error:
  990. ;-------------------------
  991. ; The drive is logically correct, so all error at this point must
  992. ; be physical ones - so we want a critical error
  993. jmp generate_critical_error
  994. eject
  995. select_adrive:
  996. ;-------------
  997. ; This entry is called to physically select a drive (eg. when flushing buffers)
  998. ; It does not alter the current physical_drv setting, which must be re-selected
  999. ; afterwards by the caller.
  1000. ;
  1001. ; On Entry:
  1002. ; AL = disk to select (range validated)
  1003. ; On Exit:
  1004. ; CY set if a problem selecting the drive
  1005. mov adrive,al
  1006. mov err_drv,al ; save error drive
  1007. call get_ddsc ; ES:BX -> DDSC_ for drive
  1008. mov al,1 ; AL = "Unknown Unit"
  1009.  jc select_drv_err ;  error if no DDSC_
  1010. mov ax,es:word ptr DDSC_DEVHEAD[bx]
  1011. mov word ptr error_dev+0,ax
  1012. mov ax,es:word ptr DDSC_DEVHEAD+2[bx]
  1013. mov word ptr error_dev+2,ax
  1014. push es ; remember driver address for error's
  1015. push bx ; preserve DDSC_
  1016. call check_media ; see if media has changed
  1017. pop bx ; restore DDSC_
  1018. pop es
  1019.  jc select_drv_err
  1020. ; select the disk drive and fill the drive specific variables
  1021. ; entry: ES:BX -> DDSC_ of disk to select
  1022. ; AX <> 0 if drive requires BPB rebuilt
  1023. ; exit: CY flag set on error
  1024. test ax,ax ; device driver, new select?
  1025.  jz select_ddsc ; use current DDSC if old select
  1026. call build_ddsc_from_bpb ; else get BPB and build new DDSC
  1027.  jc select_drv_err ; carry flag reset
  1028. call select_ddsc ; use to DDSC for select
  1029. if DELWATCH
  1030. mov ah,DELW_NEWDISK ; we have a new disk so I guess
  1031. mov al,physical_drv ;  I'd better tell delwatch
  1032. les bx,current_ddsc ;  about the new disk so it
  1033. callf fdos_stub ;  knows to update itself
  1034. endif
  1035. clc ;select disk function ok
  1036. ret
  1037. select_drv_err:
  1038. ; On Entry:
  1039. ; AL = extended error code
  1040. ; CY set
  1041. ;
  1042. mov ioexerr,al ; save error code
  1043. ret
  1044. select_ddsc:
  1045. ;-----------
  1046. ; On Entry:
  1047. ; ES:BX -> DDSC_ of drive to be selected
  1048. mov word ptr current_ddsc,bx
  1049. mov word ptr current_ddsc+WORD,es
  1050. push ds ! push es
  1051. pop ds ! pop es ; swap ES and DS
  1052. lea si,DDSC_SECSIZE[bx] ; DS:SI -> DDSC_ original
  1053. mov di,offset local_ddsc ; ES:DI -> DDSC_ copy
  1054. mov cx,LOCAL_DDSC_LEN
  1055. rep movsb ; make a local copy of interesting bits
  1056. push es ! pop ds ; DS=ES=local data segment
  1057. mov ax,psecsiz ; now initialise some other vaiiables
  1058. mov cl,clshf
  1059. shl ax,cl ; AX = bytes per cluster
  1060. mov clsize,ax
  1061. xor ax,ax
  1062. mov al,clmsk
  1063. inc ax ; AX = sectors per cluster
  1064. mov secperclu,ax
  1065. mov al,byte_nfats ; AX = number of FATs
  1066. mov nfats,ax ;  (it's handier as a word
  1067. mov ax,diradd ; number of FAT records can be
  1068.     sub ax,fatadd       ;  bigger than 255 
  1069.     xor dx,dx           
  1070.     div nfats           
  1071.     mov nfatrecs,ax     
  1072. mov cx,FCBLEN
  1073. mov ax,clsize ; convert from cluster size
  1074. xor dx,dx ;  to number of dir entries
  1075. div cx ;  per cluster - handy for
  1076. mov dirperclu,ax ;  subdirectories
  1077. mov ax,FAT12
  1078. cmp lastcl,MAX12 ; is it a 12 bit FAT ?
  1079.  jbe select_ddsc10
  1080. mov ax,FAT16 ; no, it's 16 bit
  1081. select_ddsc10:
  1082. mov dosfat,ax ; remember which for later
  1083. clc ; drive all selected
  1084. ret
  1085. eject
  1086. build_ddsc_from_bpb: ; call device driver to build BPB, convert to DDSC_
  1087. ;-------------------
  1088. ; On Entry:
  1089. ; ES:BX -> DDSC_ to rebuild
  1090. ; On Exit:
  1091. ; ES:BX preserved
  1092. ; CY set on error
  1093. ; AL = error code
  1094. push es
  1095. push bx ; save DDSC_ address
  1096. xor di,di
  1097. mov ax,deblock_seg
  1098. mov es,ax ; ES:DI -> deblock seg
  1099. test ax,ax ; if we are deblocking spare buffer
  1100.  jnz build_bpb10 ;  might be in high memory
  1101. dec ax ; AX = FFFF
  1102. mov dx,ax ; compute impossible record #
  1103. mov cx,BF_ISDIR ; locate directory sector w/o preread
  1104. call locate_buffer ; this will find the cheapest buffer
  1105. mov es:BCB_DRV[si],0FFh ; don't really want this...
  1106. lea di,BCB_DATA[si] ; ES:DI -> disk buffer
  1107. build_bpb10:
  1108. mov req4_buffer,di ; xfer to ES:DI
  1109. mov req4_buffer+2,es
  1110. pop bx ; restore DDSC_ address
  1111. pop es
  1112. push ds
  1113. lds si,es:DDSC_DEVHEAD[bx] ; DS:SI -> device header
  1114. mov ax,ds:DH_ATTRIB[si] ; non-FAT ID driver ("non-IBM") bit
  1115. pop ds ;   in device header attributes
  1116. test ax,DA_NONIBM
  1117.  jnz bldbpb30 ; skip if media byte in FAT not used
  1118. mov req_rwmode,0 ; read of system area
  1119. mov req_len,RH4_LEN ; set length field
  1120. mov req_cmd,CMD_INPUT ; read first FAT sector off disk
  1121. if DOS5
  1122. test ax,DA_BIGDRV ; large sector numbers ?
  1123. endif
  1124. mov ax,1
  1125. mov req4_count,ax ; read 1st FAT sector
  1126. cwd ; DS:AX = sector 1
  1127. mov word ptr req4_bigsector,ax
  1128. mov word ptr req4_bigsector+2,dx
  1129. if DOS5
  1130.  jz bldbpb20
  1131. dec ax ! dec ax ; AX = 0FFFFh
  1132. bldbpb20:
  1133. endif
  1134. mov req4_sector,ax ; set requested sector address
  1135. mov req4_sector+2,dx ; (support large DOS drives)
  1136. call block_device_driver ; try to read FAT sector, AX = status
  1137.  js bldbpb_err ; skip if errors (AX negative)
  1138. bldbpb30:
  1139. mov req_len,RH2_LEN ; length of req
  1140. mov req_cmd,CMD_BUILD_BPB ; "build bpb"
  1141. call block_device_driver ; call the device driver
  1142.  js bldbpb_err ; skip if errors (AX negative)
  1143. push ds
  1144. push es
  1145. push bx
  1146. mov di,bx ; ES:DI -> DDSC_ to initialise
  1147. lds si,dword ptr req2_bpb ; DS:SI -> BPB to convert
  1148. call bpb2ddsc ; rebuild the DDSC_
  1149. pop bx
  1150. pop es
  1151. pop ds
  1152. clc ; success - we have a new DDSC_
  1153. ret
  1154. bldbpb_err:
  1155. stc ; we had a problem
  1156. ret
  1157. eject
  1158. ;-----------
  1159. check_media: ; check media if DPH media flag set
  1160. ;-----------
  1161. ; On Entry:
  1162. ; ES:BX -> DDSC_ of physical drive to check
  1163. ; On Exit:
  1164. ; CY set on error, AX = error code
  1165. ; else
  1166. ; AX <> 0 if disk requires BPB rebuild
  1167. ; If definite/possible change then LDT's marked as invalid
  1168. ; If possible then buffers/hashing discarded provided they are clean
  1169. ; If definite then all buffers/hashing for drive discarded even if dirty
  1170. ;
  1171. mov req_len,RH1_LEN ; set length field
  1172. mov req_cmd,CMD_MEDIA_CHECK ; media check routine
  1173. call block_device_driver ; call the device driver
  1174.  jns chkmed10
  1175. stc ; we have a problem, generate
  1176. ret ;  an error
  1177. chkmed10:
  1178. mov al,req_media+1 ; else get returned value
  1179. xor ah,ah ;  watch out for 1st access too..
  1180. xchg ah,es:DDSC_FIRST[bx] ; treat never accessed as changed
  1181. cmp al,1 ; 1 = no change
  1182.  jne chkmed20
  1183. dec ax ; AL=0, build bpb only if DDSC_FIRST
  1184. ; clc ; it all went OK
  1185. ret
  1186. chkmed20:
  1187. mov dl,adrive ; media may have/has changed
  1188. call mark_ldt_unsure ;  so force LDT's to unsure
  1189. ; AL = 00 if maybe changed, FF for definitely changed
  1190. test al,al
  1191.  jz chkmed_maybe ; media may have changed
  1192. chkmed_changed: ; disk has changed for sure
  1193. call discard_files ; discard open files
  1194. jmps chkmed30 ; discard buffers, build bpb required
  1195. chkmed_maybe: ; disk has possibly changed
  1196. call discard_dir ; we can always discard dir as they
  1197. mov ah,BF_DIRTY ;  won't be dirty
  1198. mov al,adrive
  1199. call buffers_check ; any dirty buffers on adrive?
  1200.  jnz chkmed40 ; yes, can't discard FAT
  1201. chkmed30:
  1202. call discard_all ; discard buffers for drive
  1203. chkmed40:
  1204. or ax,0FFFFh ; better rebuild bpb
  1205. ; clc
  1206. ret
  1207. Public mark_ldt_unsure
  1208. mark_ldt_unsure:
  1209. ;---------------
  1210. ; On Entry:
  1211. ; DL = physical drive
  1212. ; On Exit:
  1213. ; All corresponding LDT's marked as unsure
  1214. ; All reg preserved
  1215. ;
  1216. push es
  1217. push ax
  1218. push bx
  1219. xor ax,ax ; start with drive A:
  1220. mlu10:
  1221. call get_ldt_raw ; ES:BX -> LDT_
  1222.  jc mlu30 ; CY = no more LDT's
  1223. test es:LDT_FLAGS[bx],LFLG_NETWRKD+LFLG_JOINED
  1224.  jnz mlu20 ; if networked leave it alone
  1225. cmp dl,es:LDT_DRV[bx] ; does the physical drive match ?
  1226.  jne mlu20
  1227. mov es:LDT_BLK[bx],0FFFFh ; indicate we shouldn't trust BLK
  1228. mlu20:
  1229. inc ax ; onto next LDT
  1230. jmps mlu10
  1231. mlu30:
  1232. pop bx
  1233. pop ax
  1234. pop es
  1235. ret
  1236. ;-----------
  1237. write_block:
  1238. ;-----------
  1239. ; entry: RWMODE = write type
  1240. ; bit 0:
  1241. ;   1 - write, not read
  1242. ; bits 2-1 (affected disk area)
  1243. ; 0 0 - system area
  1244. ; 0 1 - FAT area
  1245. ; 1 0 - root or sub directory
  1246. ; 1 1 - data area
  1247. or rwmode,1 ; mark it as a write
  1248. xor cx,cx ; indicate no second attempt
  1249. mov al,CMD_OUTPUT ; assume normal write
  1250. cmp verify_flag,0 ; is verify on ?
  1251.  je rdwr_block
  1252. mov al,CMD_OUTPUT_VERIFY ; assume use write w/ verify
  1253. jmps rdwr_block
  1254. ;----------
  1255. read_block:
  1256. ;----------
  1257. ; entry: RWMODE = read type
  1258. ; bit 0:
  1259. ;   0 - read, not write
  1260. ; bits 2-1 (affected disk area)
  1261. ; 0 0 - system area
  1262. ; 0 1 - FAT area
  1263. ; 1 0 - root or sub directory
  1264. ; 1 1 - data area
  1265. ; CX <> 0 if FAT retry possible (critical error should then
  1266. ; be avoided)
  1267. ; exit: SF = 0 if success
  1268. ; SF = 1 if failure (CX was non-zero on call)
  1269. and rwmode,not 1 ;mark it as a read
  1270. mov al,CMD_INPUT
  1271. rdwr_block:
  1272. push cx
  1273. call blockif ;current drive, track,....
  1274. pop cx
  1275.  jns rdwrb5
  1276. jcxz rdwrb10 ; test if any disk error detected
  1277. rdwrb5:
  1278. ret ; skip if yes
  1279. rdwrb10:
  1280. mov ioexerr,al ; save extended error
  1281. test al,al ; is it write protect error ?
  1282.  jnz rdwrb20 ;  we have dirty buffers we can't write
  1283. call discard_dirty ;  out, so throw 'em away
  1284. rdwrb20:
  1285. mov al,adrive ; if error on different drive
  1286. cmp al,physical_drv ;  treat error as media change
  1287.  je generate_critical_error ; if same drive, report error
  1288. call discard_all ; discard all buffers on drive
  1289. call discard_files ;  and flush files
  1290. jmp fdos_restart ; try to restart the instruction
  1291. generate_critical_error:
  1292. ;-----------------------
  1293. ; On Entry:
  1294. ; err_drv, rwmode, ioexerr set up
  1295. ; On Exit:
  1296. ; None - we don't come back
  1297. ;
  1298. mov al,ioexerr ; AL = BIOS error return byte
  1299. cbw ;  make it a word
  1300. cmp ax,15 ; only handle sensible errors
  1301.  jb gen_crit_err10 ;  anything else becomes
  1302. mov ax,12 ;  general failure
  1303. gen_crit_err10:
  1304. neg ax ; convert to our negative errors
  1305. add ax,ED_PROTECT ;  and start with write protect
  1306. jmp fdos_error ;  now return with error
  1307. eject
  1308. clus2sec: ; convert from cluster/offset to sector/offset
  1309. ;--------
  1310. ; On Entry:
  1311. ; AX = cluster
  1312. ; BX = byte offset in cluster
  1313. ; On Exit:
  1314. ; DX:AX = sector
  1315. ; BX = byte offset in sector
  1316. ;
  1317. xchg ax,cx ; remember cluster in CX
  1318. xor dx,dx
  1319. xchg ax,bx ; DX:AX = byte offset
  1320. div psecsiz ; AX = sector offset, DX = byte offset
  1321. mov bx,dx ; BX = byte offset in sector
  1322. xchg ax,cx ; AX = cluster, CX = sector offset
  1323. dec ax
  1324. dec ax ; forget about 2 reserved clusters
  1325. mul secperclu ; DX:AX = offset of cluster
  1326. add ax,datadd
  1327. adc dx,0 ; DX:AX = offset of start of dir
  1328. add ax,cx ; DX:AX - add in sector offset
  1329. adc dx,0
  1330. ret
  1331. end