; SCCSID = @(#)disk3.asm 1.3 85/07/26 ; SCCSID = @(#)disk3.asm 1.3 85/07/26 TITLE DISK3 - Disk utility routines NAME Disk3 ; Low level Read and write routines for local SFT I/O on files and devs ; ; DISKWRITE ; WRTERR ; ; Revision history: ; ; AN000 version 4.00 Jan. 1988 ; ; ; get the appropriate segment definitions ; .xlist include dosseg.asm CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME SS:DOSGROUP,CS:DOSGROUP .xcref INCLUDE DOSSYM.INC INCLUDE DEVSYM.INC include version.inc .cref .list Installed = TRUE i_need THISSFT,DWORD i_need DMAADD,DWORD i_need SecClusPos,BYTE i_need ClusNum,WORD i_need Trans,BYTE i_need BytPos,4 i_need SecPos,DWORD ;F.C. >32mb ;AN000; i_need BytSecPos,WORD i_need BytCnt1,WORD i_need BytCnt2,WORD i_need SecCnt,WORD i_need ThisDPB,DWORD i_need LastPos,WORD i_need ValSec,WORD ;F.C. >32mb ;AN000; i_need GrowCnt,DWORD i_need ALLOWED,BYTE I_need JShare,DWORD I_need FSeek_drive,BYTE ; DOS 4.00 ;AN000; I_need FSeek_firclus,WORD ; DOS 4.00 ;AN000; I_need FSeek_logclus,WORD ; DOS 4.00 ;AN000; I_need HIGH_SECTOR,WORD ;F.C. >32mb ;AN000; I_need HIGH_SECTOR_TEMP,WORD ;F.C. >32mb ;AN000; I_need EXTERR,WORD ; DOS 4.00 ;AN000; I_need EXTERR_LOCUS,BYTE ; DOS 4.00 ;AN000; I_need EXTERR_ACTION,BYTE ; DOS 4.00 ;AN000; I_need EXTERR_CLASS,BYTE ; DOS 4.00 ;AN000; I_need EXITHOLD,DWORD ; DOS 4.00 ;AN000; I_need DISK_FULL,BYTE ; DOS 4.00 ;AN000; I_need SC_DRIVE,BYTE ; DOS 4.00 ;AN000; I_need SC_CACHE_COUNT,WORD ; DOS 4.00 ;AN000; I_need ThisDRV,BYTE ; DOS 4.00 ;AN000; I_need User_In_AX,WORD ; DOS 4.00 ;AN000; I_need DOS34_FLAG,WORD ; DOS 4.00 ;AN000; I_need FIRST_BUFF_ADDR,WORD ; DOS 4.00 ;AN000; IF BUFFERFLAG EXTRN SAVE_MAP:NEAR EXTRN RESTORE_MAP:NEAR EXTRN SAVE_USER_MAP:NEAR EXTRN RESTORE_USER_MAP:NEAR i_need BUF_EMS_SAFE_FLAG,BYTE i_need BUF_EMS_MODE,BYTE ENDIF Break ; Inputs: ; Outputs of SETUP ; Function: ; Perform disk write ; Outputs: ; Carry clear ; CX = No. of bytes read ; ES:DI point to SFT ; SFT offset and cluster pointers updated ; Carry set ; CX = 0 ; ES:DI point to SFT ; AX has error code procedure DISKWRITE,NEAR DOSAssume CS,,"DiskWrite" ASSUME ES:NOTHING Assert ISSFT,,"DiskWrite" PUSH ES:[DI.sf_firclus] ; set up 1st cluster # for FastSeek POP [FSeek_firclus] invoke CHECK_WRITE_LOCK ;IFS. check write lock ;AN000; JNC WRITE_OK ;IFS. lock check ok ;AN000; return WRTEOFJ: JMP WRTEOF WRITE_OK: AND ES:[DI.sf_flags],NOT (sf_close_nodate OR devid_file_clean) ; Mark file as dirty, clear no date on close LES BP,[THISDPB] Assert ISDPB,,"DiskWrite/WriteOk" MOV AL,ES:[BP.dpb_drive] ; set up drive # for FastSeek MOV [FSeek_drive],AL ; 11/5/86 DOS 4.00 invoke BREAKDOWN MOV AX,WORD PTR [BYTPOS] MOV DX,WORD PTR [BYTPOS+2] JCXZ WRTEOFJ ;Make the file length = sf_position ADD AX,CX ADC DX,0 ; AX:DX=byte after last byte accessed ; ; Make sure divide won't overflow ; MOV BX,ES:[BP.dpb_sector_size] ; CMP DX,BX ;F.C. >32mb 16 bit sector check ;AN000; ; JAE WrtErr ;F.C. >32mb ;AN000; CALL DIV32 ;F.C. perform 32 bit divide ;AN000; MOV BX,AX ; Save last full sector OR DX,DX JNZ CALCLUS SUB AX,1 ; AX must be zero base indexed ;AC000; SBB [HIGH_SECTOR],0 ;F.C. >32mb ;AN000; CALCLUS: PUSH [HIGH_SECTOR] ;F.C. >32mb ;AN000; CALL SHR32 ;F.C. >32mb ;AN000; POP [HIGH_SECTOR] ;F.C. >32mb ;AN000; ; SHR AX,CL ; Last cluster to be accessed PUSH AX PUSH DX ; Save the size of the "tail" PUSH ES LES DI,[THISSFT] Assert ISSFT,,"DiskWrite/CalClus" MOV AX,WORD PTR ES:[DI.sf_size] MOV DX,WORD PTR ES:[DI.sf_size+2] POP ES PUSH AX ;F.C. >32mb ;AN000; MOV AX,DX ;F.C. >32mb ;AN000; XOR DX,DX ;F.C. >32mb ;AN000; DIV ES:[BP.dpb_sector_size] ;F.C. >32mb ;AN000; MOV [HIGH_SECTOR_TEMP],AX ;F.C. >32mb ;AN000; POP AX ;F.C. >32mb ;AN000; DIV ES:[BP.dpb_sector_size] MOV CX,AX ; Save last full sector of current file OR DX,DX JZ NORNDUP ADD AX,1 ; Round up if any remainder ;AC000; ADC [HIGH_SECTOR_TEMP],0 ;F.C. >32mb ;AN000; NORNDUP: PUSH [HIGH_SECTOR_TEMP] ;F.C. >32mb ;AN000; POP WORD PTR [VALSEC+2] ;F.C. >32mb ;AN000; MOV WORD PTR [VALSEC],AX ;Number of sectors that have been written XOR AX,AX MOV WORD PTR [GROWCNT],AX MOV WORD PTR [GROWCNT+2],AX POP AX MOV DI,[HIGH_SECTOR] ;F.C. >32mb ;AN000; CMP DI,[HIGH_SECTOR_TEMP] ;F.C. >32mb ;AN000; JB NOGROW ;F.C. >32mb ;AN000; JZ lowsec ;F.C. >32mb ;AN000; SUB BX,CX ;F.C. >32mb ;AN000; SBB DI,[HIGH_SECTOR_TEMP] ;F.C. >32mb di:bx no. of sectors ;AN000; JMP yesgrow ;F.C. >32mb ;AN000; lowsec: MOV DI,0 ;F.C. >32mb SUB BX,CX ; Number of full sectors JB NOGROW JZ TESTTAIL yesgrow: MOV CX,DX XCHG AX,BX MUL ES:[BP.dpb_sector_size] ; Bytes of full sector growth MOV [HIGH_SECTOR],DX ;F.C. >32mb save dx ;AN000; MOV [HIGH_SECTOR_TEMP],AX ;F.C. >32mb save ax ;AN000; MOV AX,DI ;F.C. >32mb ;AN000; MUL ES:[BP.dpb_sector_size] ;F.C. >32mb do higher word multiply ;AN000; ADD AX,[HIGH_SECTOR] ;F.C. >32mb add lower value ;AN000; MOV DX,AX ;F.C. >32mb DX:AX is the result of ;AN000; MOV AX,[HIGH_SECTOR_TEMP] ;F.C. >32mb a 32 bit multiply ;AN000; SUB AX,CX ; Take off current "tail" SBB DX,0 ; 32-bit extension ADD AX,BX ; Add on new "tail" ADC DX,0 ; ripple tim's head off JMP SHORT SETGRW HAVSTART: ;int 3 MOV CX,AX invoke SKPCLP JCXZ DOWRTJ ;;; 11/5/86 FastSeek MOV [FSeek_logclus],DX ; delete EOF (FFFFH) INC [FSeek_logclus] invoke FastSeek_Truncate ; ;;; 11/5/86 FastSeek invoke ALLOCATE JNC DOWRTJ entry WRTERR DOSAssume CS,,"DiskWrite/WrtErr" ASSUME ES:NOTHING MOV AH,0FH ;MS. write/data/fail/abort ;AN000; entry WRTERR22 MOV AL,[THISDRV] ;MS. ;AN000; CALL File_Handle_Fail_Error ;MS. issue disk full I24 MOV CX,0 ;No bytes transferred ; XOR CX,CX ; will be deleted LES DI,[THISSFT] Assert ISSFT,,"DiskWrite/WrtErr" ; CLC return DOWRTJ: JMP DOWRT ACC_ERRWJ: JMP SET_ACC_ERRW TESTTAIL: SUB AX,DX JBE NOGROW XOR DX,DX SETGRW: MOV WORD PTR [GROWCNT],AX MOV WORD PTR [GROWCNT+2],DX NOGROW: POP AX MOV CX,[CLUSNUM] ; First cluster accessed invoke FNDCLUS JC ACC_ERRWJ MOV [CLUSNUM],BX MOV [LASTPOS],DX ;;; 11/5/86 FastSeek MOV [FSeek_logclus],AX ; set up last position SUB AX,DX ; Last cluster minus current cluster JZ DOWRT ; If we have last clus, we must have first JCXZ HAVSTART ; See if no more data PUSH CX ; No. of clusters short of first MOV CX,AX ;;; 11/5/86 FastSeek CMP [CLUSNUM],0 ;FS. null file ;AN000; JZ NULL_FILE ;FS. yes ;AN000; MOV [FSeek_logclus],DX ;FS. delete EOF (FFFFH) ;AN000; INC [FSeek_logclus] ;FS. ;AN000; invoke FastSeek_Truncate ;FS. ;AN000; NULL_FILE: ;;; 11/5/86 FastSeek invoke ALLOCATE POP AX JC WRTERR MOV CX,AX MOV DX,[LASTPOS] INC DX DEC CX JZ NOSKIP ;;; 11/5/86 FastSeek MOV [FSeek_logclus],DX ; ADD [FSeek_logclus],CX ; set up last position invoke SKPCLP JC ACC_ERRWJ NOSKIP: MOV [CLUSNUM],BX MOV [LASTPOS],DX DOWRT: CMP [BYTCNT1],0 JZ WRTMID MOV BX,[CLUSNUM] invoke BUFWRT JC ACC_ERRWJ WRTMID: MOV AX,[SECCNT] OR AX,AX JNZ havemid JMP WRTLAST havemid: ADD WORD PTR [SECPOS],AX ADC WORD PTR [SECPOS+2],0 ;F.C. >32mb ;AN000; invoke NEXTSEC JNC gotok JMP ACC_ERRWJ gotok: MOV BYTE PTR [TRANS],1 ; A transfer is taking place MOV DL,[SECCLUSPOS] MOV BX,[CLUSNUM] MOV CX,[SECCNT] WRTLP: invoke OPTIMIZE JNC wokok JMP ACC_ERRWJ wokok: PUSH DI PUSH AX PUSH DX PUSH BX Assert ISDPB,,"DiskWrite/WrtLp" MOV AL,ES:[BP.dpb_drive] MOV [SC_DRIVE],AL ;LB. save it for INVALIDATE_SC ;AN000; PUSH CX ;LB. ;AN000; PUSH [HIGH_SECTOR] ;LB. ;AN000; SCANNEXT: ;LB. ;AN000; invoke GETCURHEAD ;LB. ;AN000; ASSUME DS:NOTHING NEXTBUFF: ; Search for buffers CMP [SC_CACHE_COUNT],0 ;LB. SC support ? ;AN000; JZ nosc ;LB. no ;AN000; PUSH AX ;LB. save reg ;AN000; PUSH CX ;LB. save reg ;AN000; PUSH DX ;LB. save reg ;AN000; invoke INVALIDATE_SC ;LB. invalidate SC ;AN000; POP DX ;LB. save reg ;AN000; POP CX ;LB. save reg ;AN000; POP AX ;LB. save reg ;AN000; nosc: CALL BUFF_RANGE_CHECK ;F.C. >32mb ;AN000; JNC inrange2 ;F.C. >32mb ;AN000; mov DI,[DI.buf_next] ;LB. get next buffer 1/19/88 ;AN000; JMP DONEXTBUFF ;LB. ;AN000; inrange2: TEST [DI.buf_flags],buf_dirty ;LB. if dirty ;AN000; JZ not_dirty ;LB. ;AN000; invoke DEC_DIRTY_COUNT ;LB. then decrement dirty count ;AN000; not_dirty: MOV WORD PTR [DI.buf_ID],(buf_visit SHL 8) OR 0FFH ; Free the buffer, it is being over written invoke SCANPLACE DONEXTBUFF: CMP DI,[FIRST_BUFF_ADDR] ;LB. end of chain ;AN000; JNZ NEXTBUFF ;LB. no ;AN000; ADD DX,1 ;LB. next sector number ;AN000; ADC [HIGH_SECTOR],0 ;LB. ;AN000; LOOP SCANNEXT ;LB. check again ;AN000; POP [HIGH_SECTOR] ;LB. ;AN000; POP CX ;LB. get count back ;AN000; POP BX POP DX MOV DS,WORD PTR [DMAADD+2] MOV [ALLOWED],allowed_RETRY + allowed_FAIL + allowed_IGNORE IF BUFFERFLAG pushf cmp [BUF_EMS_MODE], -1 je safe_write call save_map call restore_user_map safe_write: popf ENDIF invoke DWRITE IF BUFFERFLAG pushf cmp [BUF_EMS_MODE], -1 je safe_map call save_user_map call restore_map safe_map: popf ENDIF POP CX POP BX Context DS JC SET_ACC_ERRW JCXZ WRTLAST MOV DL,0 INC [LASTPOS] ; We'll be using next cluster JMP WRTLP WRTLAST: MOV AX,[BYTCNT2] OR AX,AX JZ FINWRT MOV [BYTCNT1],AX invoke NEXTSEC JC SET_ACC_ERRW MOV [BYTSECPOS],0 invoke BUFWRT JC SET_ACC_ERRW FINWRT: LES DI,[THISSFT] Assert ISSFT,,"DiskWrite/FinWrt" MOV AX,WORD PTR [GROWCNT] MOV CX,WORD PTR [GROWCNT+2] OR AX,AX JNZ UPDATE_size JCXZ SAMSIZ Update_size: ADD WORD PTR ES:[DI.sf_size],AX ADC WORD PTR ES:[DI.sf_size+2],CX ; ; Make sure that all other SFT's see this growth also. ; MOV AX,1 if installed call JShare + 14 * 4 else Call ShSU endif SAMSIZ: transfer SETCLUS ; ES:DI already points to SFT SET_ACC_ERRW: transfer SET_ACC_ERR_DS WRTEOF: MOV CX,AX OR CX,DX JZ KILLFIL SUB AX,1 SBB DX,0 PUSH BX MOV BX,ES:[BP.dpb_sector_size] ;F.C. >32mb ;AN000; CALL DIV32 ;F.C. >32mb ;AN000; POP BX ;F.C. >32mb ;AN000; CALL SHR32 ;F.C. >32mb ;AN000; ; SHR AX,CL MOV CX,AX invoke FNDCLUS SET_ACC_ERRWJ2: JC SET_ACC_ERRW ;;; 11/5/86 FastSeek MOV [FSeek_logclus],DX ; truncate clusters starting from DX invoke FastSeek_Truncate ;;; 11/5/86 FastSeek JCXZ RELFILE invoke ALLOCATE JC WRTERRJ ;;;;;;;;; disk full UPDATE: LES DI,[THISSFT] Assert ISSFT,,"DiskWrite/update" MOV AX,WORD PTR [BYTPOS] MOV WORD PTR ES:[DI.sf_size],AX MOV AX,WORD PTR [BYTPOS+2] MOV WORD PTR ES:[DI.sf_size+2],AX ; ; Make sure that all other SFT's see this growth also. ; MOV AX,2 if installed Call JShare + 14 * 4 else Call ShSU endif XOR CX,CX transfer ADDREC WRTERRJ: JMP WRTERR ;;;;;;;;;;;;;;;; 7/18/86 ;;;;;;;;;;;;;;;;; RELFILE: MOV DX,0FFFFH invoke RELBLKS Set_Acc_ERRWJJ: JC SET_ACC_ERRWJ2 JMP SHORT UPDATE KILLFIL: XOR BX,BX PUSH ES LES DI,[THISSFT] Assert ISSFT,,"DiskWrite/KillFil" MOV ES:[DI.sf_cluspos],BX MOV ES:[DI.sf_lstclus],BX XCHG BX,ES:[DI.sf_firclus] POP ES ;; 11/5/86 FastSeek invoke Delete_FSeek ; delete fastseek entry OR BX,BX JZ UPDATEJ ;; 10/23/86 FastOpen update PUSH ES ; since first cluster # is 0 PUSH BP ; we must delete the old cache entry PUSH AX PUSH CX PUSH DX LES BP,[THISDPB] ; get current DPB MOV DL,ES:[BP.dpb_drive] ; get current drive MOV CX,BX ; first cluster # MOV AH,2 ; delete cache entry by drive:firclus invoke FastOpen_Update ; call fastopen POP DX POP CX POP AX POP BP POP ES ;; 10/23/86 FastOpen update invoke RELEASE JC SET_ACC_ERRWJJ UpDateJ: JMP UPDATE EndProc DISKWRITE Break ; Inputs: ; DX:AX = 32 bit dividend BX= divisor ; Function: ; Perform 32 bit division ; Outputs: ; [HIGH_SECTOR]:AX = quotiend , DX= remainder procedure DIV32,NEAR ASSUME DS:NOTHING,ES:NOTHING PUSH AX ;F.C. >32mb ;AN000; MOV AX,DX ;F.C. >32mb ;AN000; XOR DX,DX ;F.C. >32mb ;AN000; DIV BX ;F.C. >32mb ;AN000; MOV [HIGH_SECTOR],AX ;F.C. >32mb ;AN000; POP AX ;F.C. >32mb ;AN000; DIV BX ; AX=last sector accessed return EndProc DIV32 Break ; Inputs: ; [HIGH_SECTOR]:AX = 32 bit sector number ; Function: ; Perform 32 bit shift right ; Outputs: ; AX= cluster number procedure SHR32,NEAR ASSUME DS:NOTHING,ES:NOTHING MOV CL,ES:[BP.dpb_cluster_shift] XOR CH,CH entry ROTASHFT ;F.C. >32mb ;AN000; OR CX,CX ;F.C. >32mb ;AN000; JZ norota ;F.C. >32mb ;AN000; ROTASHFT2: CLC ;F.C. >32mb ;AN000; RCR [HIGH_SECTOR],1 ;F.C. >32mb ;AN000; RCR AX,1 ;F.C. >32mb ;AN000; LOOP ROTASHFT2 ;F.C. >32mb: ;AN000; norota: return EndProc SHR32 ; Issue File Handle Fail INT 24 Critical Error ; Input: Disk_Full=0 ok ; 1 disk full or EOF ; Function: issue critical error for disk full or EOF error ; ; OutPut: carry clear , no I24 ; carry set, fail from I24 procedure File_Handle_Fail_Error,NEAR ;AN000; ASSUME ES:NOTHING,DS:NOTHING ;AN000; ;AN000; CMP [DISK_FULL],0 ;MS. disk full or EOF ;AN000; JZ Fexit ;MS. no ;AN000; TEST [DOS34_FLAG],Disable_EOF_I24 ;MS. check input status ? ;AN000; JNZ Fexit ;MS. yes ;AN000; ;AN000; LES DI,[THISSFT] ;MS. get current SFT ;AN000; ; LES DI,ES:[DI.sf_DEVPTR];MS. get device header ;AN000; TEST ES:[DI.sf_flags],Handle_Fail_I24 ;MS. gen I24 ? ;AN000; JZ Fexit ;MS. no ;AN000; PUSH DS ;MS. save DS ;AN000; TEST AH,1 ;MS. READ ? ;AN000; JZ readeof ;MS. yes ;AN000; MOV [EXTERR],error_Handle_Disk_Full ;MS. set extended error ;AN000; JMP SHORT errset ;MS. set extended error ;AN000; readeof: MOV [EXTERR],error_Handle_EOF ;MS. set extended error ;AN000; errset: MOV [EXTERR_CLASS],errCLASS_OutRes ;MS. set class ;AN000; MOV [EXTERR_ACTION],errACT_Abort ;MS. set action ;AN000; MOV [EXTERR_LOCUS],errLOC_Unk ;MS. set locus ;AN000; MOV word ptr [EXITHOLD + 2],ES ;MS. save es:bp in exithold ;AN000; MOV word ptr [EXITHOLD],BP ;MS. ;AN000; TEST ES:[DI.sf_flags],devid_device ;MS. device ? ;AN000; JNZ chardev2 ;MS. yes ;AN000; LDS SI,ES:[DI.sf_DEVPTR] ;MS. get dpb ;AN000; LDS SI,[SI.dpb_driver_addr] ;MS. get drive device haeder ;AN000; JMP SHORT doi24 ;MS. gen I24 ? ;AN000; chardev2: LDS SI,ES:[DI.sf_DEVPTR] ;MS. get chr dev header ;AN000; doi24: MOV BP,DS ;MS. bp:si -> device header ;AN000; MOV DI,error_I24_gen_failure ;MS. general error ;AN000; invoke NET_I24_ENTRY ;MS. issue I24 ;AN000; STC ;MS. must be fail ;AN000; POP DS ;MS. restore DS ;AN000; MOV AX,[EXTERR] ;MS. set error ;AN000; JMP SHORT Fend ;MS. exit ;AN000; Fexit: ;AN000; CLC ;MS. clear carry ;AN000; Fend: ;AN000; return ;MS. ;AN000; ;AN000; EndProc File_Handle_Fail_Error ;AN000; Break ; Inputs: ; DS:DI -> buffer. AL= drive # ; [HIGH_SECTOR]:DX = sector # ; Function: ; check if sector is in the buffer ; Outputs: ; carry clear= in the range ; set = not in the range procedure BUFF_RANGE_CHECK,NEAR ASSUME DS:NOTHING,ES:NOTHING CMP WORD PTR [DI.buf_sector],DX ;AN000; JNZ DONEXTBUFF2 ; not this sector ;F.C. >32mb ;AN000; MOV SI,[HIGH_SECTOR] ;F.C. >32mb ;AN000; CMP WORD PTR [DI.buf_sector+2],SI ;F.C. >32mb ;AN000; JNZ DONEXTBUFF2 ; Not for this drive CMP AL,[DI.buf_ID] JZ secfound ; Buffer has the sector ;AN000; DONEXTBUFF2: STC secfound: return EndProc BUFF_RANGE_CHECK CODE ENDS END