1 ; SCCSID = @(#)disk.asm 1.1 85/04/10
2 ; SCCSID = @(#)disk.asm 1.1 85/04/10
3 TITLE DISK
- Disk utility routines
5 ; Low level Read and write routines for local SFT I/O on files and devs
22 ; A000 version 4.00 Jan. 1988
26 ; get the appropriate segment definitions
30 include fastseek
.inc ;AN000;
31 include fastxxxx
.inc ;AN000;
33 CODE SEGMENT BYTE PUBLIC 'CODE'
34 ASSUME
SS:DOSGROUP
,CS:DOSGROUP
46 I_Need CONSft
,DWORD ; SFT for swapped console In/Out
58 i_need SecClusPos
,BYTE
59 i_need DirSec
,DWORD ;AN000;
61 i_need NxtClusNum
,WORD
65 i_need EXTERR_LOCUS
,BYTE
66 i_need FastSeekflg
,BYTE ;AN000;
67 i_need HIGH_SECTOR
,WORD ;AN000;
68 I_need JShare
,DWORD ;AN000;
69 i_need DOS34_FLAG
,WORD ;AN000;
73 i_need BUF_EMS_MODE
,BYTE
74 i_need BUF_EMS_LAST_PAGE
,BYTE
75 I_need BUF_EMS_FIRST_PAGE
,DWORD
76 I_need BUF_EMS_SAFE_FLAG
,BYTE
77 I_need BUF_EMS_NPA640
,WORD
78 I_need BUF_EMS_PAGE_FRAME
,WORD
79 I_need BUF_EMS_PFRAME
,WORD
80 I_need LASTBUFFER
,DWORD
82 extrn save_user_map
:near
83 extrn restore_user_map
:near
84 extrn Setup_EMS_Buffers
:near
88 Break <SwapCon
, Swap Back
- Old
-style I
/O to files
>
89 ; * * * * Drivers for file input from devices * * * *
91 ; Indicate that ther is no more I/O occurring through another SFT outside of
94 ; Inputs: DS is DOSGroup
95 ; Outputs: CONSWAP is set to false.
96 ; Registers modified: none
98 procedure SWAPBACK
,NEAR
99 DOSAssume
CS,<DS>,"SwapBack"
101 MOV BYTE PTR [CONSWAP
],0 ; signal no conswaps
105 ; Copy ThisSFT to CONSFT for use by the 1-12 primitives.
107 ; Inputs: ThisSFT as the sft of the desired file
109 ; Outputs: CONSWAP is set. CONSFT = ThisSFT.
110 ; Registers modified: none
111 procedure SWAPCON
,NEAR
112 DOSAssume
CS,<DS>,"SwapCon"
115 MOV BYTE PTR [CONSWAP
],1 ; CONSwap = TRUE;
117 Assert ISSFT
,<ES,DI>,"SwapCon"
118 MOV WORD PTR CONSFT
,DI
119 MOV WORD PTR CONSFT
+2,ES
124 Break <DOS_READ
-- MAIN READ ROUTINE
AND DEVICE
IN ROUTINES
>
128 ; [THISSFT] set to the SFT for the file being used
129 ; [DMAADD] contains transfer address
130 ; CX = No. of bytes to read
132 ; Perform read operation
135 ; SFT Position and cluster pointers updated
136 ; CX = No. of bytes read
142 ; DS preserved, all other registers destroyed
144 procedure DOS_READ
,NEAR
145 DOSAssume
CS,<DS>,"DOS_Read"
149 cmp [BUF_EMS_MODE
], -1
161 Assert ISSFT
,<ES,DI>,"DOS_Read"
163 ; Verify that the sft has been opened in a mode that allows reading.
165 MOV AL,BYTE PTR ES:[DI.sf_mode
]
167 CMP AL,open_for_write
168 JNE READ_NO_MODE
;Is read or both
173 JCXZ NoIORet
; no bytes to read - fast return
177 ; invoke OWN_SHARE ;AN000;;IFS. IFS owns share ?
178 ; JZ IFS_HAS_SHARE ;AN000;;IFS. yes
179 ; EnterCrit critDisk ;AN000;;IFS. enter critical section
180 ; CALL CHECK_READ_LOCK ;AN000;;IFS. check read lock
181 ; JNC READ_OK2 ;AN000;;IFS. lock check ok
182 ; JMP SHORT critexit ;AN000;;IFS. fail
184 ; LeaveCrit critDisk ;AN000;;IFS. leave critical section
185 IFS_HAS_SHARE: ;AN000;
190 MOV AX,(multNET
SHL 8) OR 8
196 ; The user ended up requesting 0 bytes of input. We do nothing for this case
197 ; except return immediately.
204 TEST ES:[DI.sf_flags
],devid_device
; Check for named device I/O
206 MOV [EXTERR_LOCUS
],errLOC_Disk
208 TEST [FastSeekflg
],Fast_yes
; FastSeek installed ?
210 OR [FastSeekflg
],FS_begin
; set fastseek mode
214 AND CS:[FastSeekflg
],FS_end
; reset fastseek mode
221 ; We are reading from a device. Examine the status of the device to see if we
222 ; can short-circuit the I/O. If the device in the EOF state or if it is the
223 ; null device, we can safely indicate no transfer.
226 DOSAssume
CS,<DS>,"DISK/ReadDev"
228 MOV [EXTERR_LOCUS
],errLOC_SerDev
229 MOV BL,BYTE PTR ES:[DI.sf_flags
]
231 TEST BL,devid_device_EOF
; End of file?
233 TEST BL,devid_device_null
; NUL device?
235 XOR AL,AL ; Indicate EOF by setting zero
240 ; We need to hit the device. Figure out if we do a raw read or we do the
241 ; bizarre std_con_string_input.
244 TEST BL,devid_device_raw
; Raw mode?
245 JNZ DVRDRAW
; Yes, let the device do all local editing
246 TEST BL,devid_device_con_in
; Is it console device?
251 DOSAssume
CS,<DS>,"DISK/DvRdRaw"
253 POP DS ; Xaddr to DS:DI
256 MOV BX,DI ; DS:BX transfer addr
257 XOR AX,AX ; Media Byte, unit = 0
258 MOV DX,AX ; Start at 0
260 PUSH DS ; Save Seg part of Xaddr
262 Assert ISSFT
,<DS,SI>,"DOS_Read/DvRdRawR"
264 MOV DX,DI ; DS:DX is preserved by INT 24
265 MOV AH,86H
; Read error
266 MOV DI,[DEVCALL
.REQSTAT
]
268 JZ CRDROK
; No errors
270 MOV DI,DX ; DS:DI is Xaddr
275 POP DS ; Recover saved seg part of Xaddr
276 JMP ReadRawRetry
; Retry
279 ; We have encountered a device-driver error. We have informed the user of it
280 ; and he has said for us to fail the system call.
286 Assert ISSFT
,<ES,DI>,"DOS_Read/DEVIOFERR"
287 transfer SET_ACC_ERR_DS
290 POP DI ; Chuck saved seg of Xaddr
292 ADD DI,[CALLSCNT
] ; Amount transferred
295 ; We are going to do a cooked read on some character device. There is a
296 ; problem here, what does the data look like? Is it a terminal device, line
297 ; CR line CR line CR, or is it file data, line CR LF line CR LF? Does it have
298 ; a ^Z at the end which is data, or is the ^Z not data? In any event we're
299 ; going to do this: Read in pieces up to CR (CRs included in data) or ^z (^z
300 ; included in data). this "simulates" the way con works in cooked mode
301 ; reading one line at a time. With file data, however, the lines will look
302 ; like, LF line CR. This is a little weird.
316 Assert ISSFT
,<DS,SI>,"DOS_Read/NotRdCon"
317 LDS SI,[SI.sf_devptr
]
321 PUSH DI ; Save "count" done
323 MOV DI,[DEVCALL
.REQSTAT
]
333 XOR AL,AL ; Ignore, Pick some random character
341 MOV DS,WORD PTR [CALLXAD
+2]
342 MOV AL,BYTE PTR [DI] ; Get the character we just read
345 INC WORD PTR [CALLXAD
] ; Next character
346 MOV [DEVCALL
.REQSTAT
],0
347 INC DI ; Next character
349 JZ ENDRDDEVJ2
; Yes, done zero set (EOF)
351 LOOPNZ DVRDLP
; Loop if no, else done
352 INC AX ; Resets zero flag so NOT EOF, unless
353 ; AX=FFFF which is not likely
357 ASSUME
DS:NOTHING
,ES:NOTHING
362 CMP AL,c_CR
; Check for carriage return
364 MOV BYTE PTR [SI],c_LF
369 XOR SI,SI ; Cause a new buffer to be read
370 invoke OUTT
; Transmit linefeed
371 OR AL,1 ; Clear zero flag--not end of file
379 JNZ SETSFTC
; Zero set if Ctrl-Z found in input
381 Assert ISSFT
,<ES,DI>,"DOS_Read/EndRdDev"
382 AND BYTE PTR ES:[DI.sf_flags
],NOT devid_device_EOF
; Mark as no more data available
387 ASSUME
DS:NOTHING
,ES:NOTHING
390 DOSAssume
CS,<DS>,"ReadCon"
395 CMP BYTE PTR [CONBUF
],128
397 MOV WORD PTR [CONBUF
],0FF80H ; Set up 128-byte buffer with no template
402 MOV DX,OFFSET DOSGROUP
:CONBUF
403 invoke $STD_CON_STRING_INPUT
; Get input buffer
407 MOV SI,2 + OFFSET DOSGROUP
:CONBUF
408 CMP BYTE PTR [SI],1
AH ; Check for Ctrl-Z in first character
414 invoke OUTT
; Send linefeed
420 Break <DOS_WRITE
-- MAIN WRITE ROUTINE
AND DEVICE
OUT ROUTINES
>
424 ; [THISSFT] set to the SFT for the file being used
425 ; [DMAADD] contains transfer address
426 ; CX = No. of bytes to write
428 ; Perform write operation
429 ; NOTE: If CX = 0 on input, file is truncated or grown
430 ; to current sf_position
433 ; SFT Position and cluster pointers updated
434 ; CX = No. of bytes written
440 ; DS preserved, all other registers destroyed
442 procedure DOS_WRITE
,NEAR
443 DOSAssume
CS,<DS>,"DOS_Write"
447 cmp [BUF_EMS_MODE
], -1
459 Assert ISSFT
,<ES,DI>,"DosWrite"
460 MOV AL,BYTE PTR ES:[DI.sf_mode
]
463 JNE Check_FCB_RO
;Is write or both
468 ; NOTE: The following check for writting to a Read Only File is performed
470 ; We ALLOW writes to Read Only files via handles to allow a CREATE
471 ; of a read only file which can then be written to.
472 ; This is OK because we are NOT ALLOWED to OPEN a RO file via handles
473 ; for writting, or RE-CREATE an EXISTING RO file via handles. Thus,
474 ; CREATing a NEW RO file, or RE-CREATing an existing file which
475 ; is NOT RO to be RO, via handles are the only times we can write
476 ; to a read-only file.
479 TEST ES:[DI.sf_mode
],sf_isfcb
480 JZ WRITE_NO_MODE
; Not an FCB
481 TEST ES:[DI].sf_attr
,attr_read_only
482 JNZ BadMode
; Can't write to Read_Only files via FCB
488 ; invoke OWN_SHARE ;AN000;;IFS. IFS owns share ?
489 ; JZ IFS_HAS_SHARE2 ;AN000;;IFS. yes
490 ; EnterCrit critDisk ;AN000;;IFS. enter critical section
491 ; CALL CHECK_WRITE_LOCK ;AN000;;IFS. check write lock
492 ; JC nocommit ;AN000;;IFS. lock error
494 ; LeaveCrit critDisk ;AN000;;IFS. leave critical section
495 IFS_HAS_SHARE2: ;AN000;
501 MOV AX,(multNET
SHL 8) OR 9
503 ; JC nomore ;AN000;;IFS. error
504 ; invoke OWN_SHARE ;AN000;;IFS. IFS owns share ?
505 ; JZ nomore ;AN000;;IFS. yes
507 ; MOV AX,1 ;AN000;;IFS. update all SFT for new size
508 ; call JShare + 14 * 4 ;AN000;;IFS. call ShSu
516 TEST ES:[DI.sf_flags
],devid_device
; Check for named device I/O
518 MOV [EXTERR_LOCUS
],errLOC_Disk
520 TEST [FastSeekflg
],Fast_yes
;AN000;FO. FastSeek installed ?
521 JZ FS_no2
;AN000;FO. no
522 OR [FastSeekflg
],FS_begin
;AN000;FO. set fastseek mode
525 PUSHF ;AN000;FO. save flag
526 AND CS:[FastSeekflg
],FS_end
;AN000;FO. reset fastseek mode
527 POPF ;AN000;FO. restore flag
529 JC nocommit
;AN000;EO.
530 LES DI,[THISSFT
] ;AN000;EO.
531 TEST ES:[DI.sf_mode
],auto_commit_write
;AN000;EO.
532 JZ nocommit
;AN000;EO.
534 invoke DOS_COMMIT
;AN000;EO.
543 XOR AX,AX ; Media Byte, unit = 0
545 PUSH DS ; Save seg of transfer
547 Assert ISSFT
,<DS,SI>,"DosWrite/DvWrtRaw"
548 invoke DEVIOCALL
; DS:SI -> DEVICE
549 MOV DX,DI ; Offset part of Xaddr saved in DX
551 MOV DI,[DEVCALL
.REQSTAT
]
555 MOV BX,DX ; Recall transfer addr
560 POP DS ; Recover saved seg of transfer
561 JMP DVWRTRAW
; Try again
564 POP AX ; Chuck saved seg of transfer
565 JMP CRDFERR
; Will pop one more stack element
568 POP AX ; Chuck saved seg of transfer
570 DOSAssume
CS,<DS>,"DISK/CWrtOK"
571 MOV AX,[CALLSCNT
] ; Get actual number of bytes transferred
574 Assert ISSFT
,<ES,DI>,"DosWrite/EndWrDev"
580 MOV DX,CX ;Entire transfer done
585 DOSAssume
CS,<DS>,"DISK/WrtDev"
586 MOV [EXTERR_LOCUS
],errLOC_SerDev
587 OR BYTE PTR ES:[DI.sf_flags
],devid_device_EOF
; Reset EOF for input
588 MOV BL,BYTE PTR ES:[DI.sf_flags
]
590 JCXZ ENDWRDEV
; problem of creating on a device.
593 LDS BX,[DMAADD
] ; Xaddr to DS:BX
595 MOV DI,BX ; Xaddr to DS:DI
596 XOR DX,DX ; Set starting point
597 TEST AL,devid_device_raw
; Raw?
602 TEST AL,devid_device_con_out
; Console output device?
604 TEST AL,devid_device_null
607 CMP BYTE PTR [BX],1
AH ; ^Z?
608 JZ WRTCOOKJ
; Yes, transfer nothing
614 OR CS:[DOS34_FLAG
],X25_Special
;AN000;;PTM. bad x25 driver
615 MOV AH,3 ;AN000;;PTM. prompt critical error ASAP
616 invoke IOFUNC
;AN000;;PTM.
617 Assert ISSFT
,<DS,SI>,"DosWrite/TestDevCon"
618 LDS SI,[SI.sf_devptr
]
624 MOV DI,[DEVCALL
.REQSTAT
]
634 JMP CRDFERR
; Fail, pops one stack element
642 INC WORD PTR [CALLXAD
]
645 MOV DS,WORD PTR [CALLXAD
+2]
646 CMP BYTE PTR [DI],1
AH ; ^Z?
649 MOV [DEVCALL
.REQSTAT
],0
672 SUB AX,CX ; Amount actually written
674 DOSAssume
CS,<DS>,"DISK/ConEOF"
679 ; Convert JFN number in BX to sf_entry in DS:SI We get the normal SFT if
680 ; CONSWAP is FALSE or if the handle desired is 2 or more. Otherwise, we
681 ; retrieve the sft from ConSFT which is set by SwapCon.
683 procedure get_io_sft
,near
684 ASSUME
DS:NOTHING
,ES:NOTHING
705 Assert ISSFT
,<DS,SI>,"GetIOSft"
710 Break <DIRREAD
-- READ A DIRECTORY SECTOR
>
713 ; AX = Directory block number (relative to first block of directory)
714 ; ES:BP = Base of drive parameters
715 ; [DIRSEC] = First sector of first cluster of directory
716 ; [CLUSNUM] = Next cluster
717 ; [CLUSFAC] = Sectors/Cluster
719 ; Read the directory block into [CURBUF].
721 ; [NXTCLUSNUM] = Next cluster (after the one skipped to)
724 ; [CURBUF] Points to Buffer with dir sector
725 ; Carry set if error (user said FAIL to I 24)
726 ; DS preserved, all other registers destroyed.
728 procedure DirRead
,NEAR
729 DOSAssume
CS,<DS>,"DirRead"
731 Assert ISDPB
,<ES,BP>,"DirRead"
734 ; Note that ClusFac is is the sectors per cluster. This is NOT necessarily
735 ; the same as what is in the DPB! In the case of the root directory, we have
736 ; ClusFac = # sectors in the root directory. The root directory is detected
745 ; Convert the sector number in AX into cluster and sector-within-cluster pair
749 AND DL,ES:[BP.dpb_cluster_mask
]
751 ; DX is the sector-in-cluster
753 MOV CL,ES:[BP.dpb_cluster_shift
]
756 ; DX is position in cluster
757 ; AX is number of clusters to skip
764 ; CX is number of clusters to skip.
767 MOV DX,WORD PTR [DIRSEC
+2] ;AN000;>32mb
768 MOV [HIGH_SECTOR
],DX ;AN000;>32mb
769 MOV DX,WORD PTR [DIRSEC
]
772 ADC [HIGH_SECTOR
],0 ;AN000;>32mb
781 invoke IsEOF
; test for eof based on fat size
792 MOV [ALLOWED
],allowed_RETRY
+ allowed_FAIL
793 XOR AL,AL ; Indicate pre-read
798 DOSAssume
CS,<DS>,"SET_BUF_AS_DIR"
800 ; Set the type of CURBUF to be a directory sector.
801 ; Only flags are modified.
806 Assert ISBUF
,<DS,SI>,"SetBufAsDir"
807 OR [SI.buf_flags
],buf_isDIR
; Clears carry
813 Break <FATSECRD
-- READ A FAT SECTOR
>
817 ; DS:BX = Transfer address
818 ; CX = Number of sectors
819 ; DX = Absolute record number
820 ; ES:BP = Base of drive parameters
822 ; Calls BIOS to perform FAT read.
826 procedure FATSecRd
,NEAR
827 ASSUME
DS:NOTHING
,ES:NOTHING
829 Assert ISDPB
,<ES,BP>,"FATSecRd"
830 MOV [ALLOWED
],allowed_RETRY
+ allowed_FAIL
832 MOV CL,ES:[BP.dpb_FAT_count
]
833 MOV AX,ES:[BP.dpb_FAT_size
] ;AN000;>32mb
835 XOR CH,CH ;AN000;>32mb
838 MOV [HIGH_SECTOR
],0 ;AN000;>32mb FAT sectors cannot exceed
845 JZ RET41P
; Carry clear
853 Break <DREAD
-- DO A DISK READ
>
856 ; DS:BX = Transfer address
857 ; CX = Number of sectors
858 ; DX = Absolute record number (LOW)
859 ; [HIGH_SECTOR]= Absolute record number (HIGH)
860 ; ES:BP = Base of drive parameters
861 ; [ALLOWED] must be set in case call to HARDERR needed
863 ; Calls BIOS to perform disk read. If BIOS reports
864 ; errors, will call HARDERRRW for further action.
866 ; Carry set if error (currently user FAILED to INT 24)
867 ; DS,ES:BP preserved. All other registers destroyed.
870 ASSUME
DS:NOTHING
,ES:NOTHING
872 Assert ISDPB
,<ES,BP>,"DREAD"
875 MOV BYTE PTR [READOP
],0
877 CMP AL,1 ; Check for retry
879 CMP AL,3 ; Check for FAIL
891 Break <CHECK_WRITE_LOCK
>
902 procedure CHECK_WRITE_LOCK
,NEAR ;AN000;
903 ASSUME
DS:NOTHING
,ES:NOTHING
;AN000;
905 TEST ES:[DI].sf_attr
,attr_volume_id
;AN000;;MS. volume id
906 JZ write_cont
;AN000;;MS. no
907 invoke SET_ACC_ERR_DS
;AN000;;MS.
910 PUSH CX ;AN000;;MS. save reg
912 JNZ Not_Truncate
;AN000;;MS.
913 MOV CX,0FFFFH ;AN000;;MS. check for lock on whole file
914 Not_Truncate: ;AN000;
915 MOV AL,80H
;AN000;;MS. check write access
916 invoke LOCK_CHECK
;AN000;;MS. check lock
917 POP CX ;AN000;;MS. restore reg
918 JNC WRITE_OK
;AN000;;MS. lock ok
919 invoke WRITE_LOCK_VIOLATION
;AN000;;MS. issue I24
920 JNC CHECK_WRITE_LOCK
;AN000;;MS. retry
923 EndProc CHECK_WRITE_LOCK
;AN000;
926 Break <CHECK_READ_LOCK
>
937 procedure CHECK_READ_LOCK
,NEAR ;AN000;
938 ASSUME
DS:NOTHING
,ES:NOTHING
;AN000;
940 TEST ES:[DI].sf_attr
,attr_volume_id
;AN000;;MS. volume id
941 JZ do_retry
;AN000;;MS. no
942 invoke SET_ACC_ERR
;AN000;;MS.
945 MOV AL,0 ;AN000;;MS. check read access
946 invoke LOCK_CHECK
;AN000;;MS. check lock
947 JNC READ_OK
;AN000;;MS. lock ok
948 invoke READ_LOCK_VIOLATION
;AN000;;MS. issue I24
949 JNC CHECK_READ_LOCK
;AN000;;MS. retry
952 EndProc CHECK_READ_LOCK
;AN000;
956 ;-------------------------------------------------------------------------
957 ; Function name : choose_buf_page
958 ; Inputs : DMAADD = Xaddr
959 ; cx = # of bytes to transfer
962 ; SAFE_FLAG - 0 ==> page is safe. no need to
963 ; detect collision between
964 ; user & system buffer.
965 ; SAFE_FLAG - 1 ==> page is unsafe. Must check
971 ; High Level Alogrithm:
973 ; 1. If Xaddr. is above the first physical page above 640K
974 ; 2. choose that page
977 ; 5. choose highest page above 640K
978 ; 6. If 6 or more pages above 640k
981 ; 9. if Xaddr. + # of bytes to transfer does not spill into the
985 ; 12. clear safe flag
990 ;----------------------------------------------------------------------------
991 Procedure choose_buf_page
,near
993 assume
cs:dosgroup
, ds:nothing
, es:nothing
, ss:dosgroup
1002 mov ax, word ptr [DMAADD
+2]
1003 and ax, 0fc00h ; page segment of transfer segment
1005 cmp ax, word ptr [BUF_EMS_FIRST_PAGE
]
1008 cmp [BUF_EMS_NPA640
], 6
1011 add cx, word ptr [DMAADD
] ; get final offset
1015 shr bx, cl ; get # of paragraphs
1016 mov ax, word ptr [DMAADD
+2] ; get initial segment
1017 add ax, bx ; get final segment
1020 cmp ax, word ptr [BUF_EMS_LAST_PAGE
]
1023 mov [BUF_EMS_SAFE_FLAG
], 0
1027 mov [BUF_EMS_SAFE_FLAG
], 1
1031 ; mov ax, word ptr [BUF_EMS_LAST_PAGE]
1032 ; mov [BUF_EMS_PFRAME], ax
1033 ; mov ax, word ptr [BUF_EMS_LAST_PAGE+2]
1034 ; mov [BUF_EMS_PAGE_FRAME], ax
1036 ; jmp fin_choose_page
1039 mov ax, word ptr [BUF_EMS_FIRST_PAGE
]
1040 cmp [BUF_EMS_PFRAME
], ax
1042 call restore_user_map
1043 mov word ptr [LASTBUFFER
], -1
1044 mov [BUF_EMS_PFRAME
], ax
1045 mov ax, word ptr [BUF_EMS_FIRST_PAGE
+2]
1046 mov [BUF_EMS_PAGE_FRAME
], ax
1047 mov [BUF_EMS_SAFE_FLAG
], 1
1048 call Setup_EMS_Buffers
1066 EndProc choose_buf_page