; File : $ERROR.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$ ; ERROR.A86 1.17 94/12/02 11:01:03 ; added logical error entry ; ERROR.A86 1.16 93/11/26 15:51:29 ; Update char_error so ES:SI -> device driver header itself ; ERROR.A86 1.14 93/09/09 22:36:26 ; Int 21/59 uses error stack (for benefit of Lantastic) ; ERROR.A86 1.13 93/09/03 20:28:11 ; Add "no critical errors" support (int 21/6C) ; ENDLOG ; ; This file contains the Error handling routines for PCMODE ; When a function encounters an error it jumps to the ERROR_EXIT ; function which will process the error consistantly. FCB_ERROR_EXIT ; is a special case of ERROR_EXIT where the error code is not returned ; directly to the user but is still saved for func59 ; include pcmode.equ include fdos.def include i:msdos.equ include i:mserror.equ include i:psp.def include i:char.def include i:reqhdr.equ ; ERR_TBL_CODE equ byte ptr 0 ; Error Code in Table ERR_TBL_CLASS equ byte ptr 1 ; Error Class entry in Table ERR_TBL_ACTION equ byte ptr 2 ; Error Action entry in Table ERR_TBL_LOCUS equ byte ptr 3 ; Locus entry in table ERR_TBL_LEN equ 4 ; 4 bytes per entry ; PCM_CODE CSEG BYTE extrn get_dseg:near extrn do_int24:near extrn reload_registers:near extrn return_AX_CLC:near ; ; ***************************** ; *** DOS Function 59 *** ; *** Get Extended Error *** ; ***************************** ; Public func59 func59: les di,error_dev ; Return device driver address mov bh,error_class ; return the Error Class mov bl,error_action ; the Action Code mov ch,error_locus ; the Locus Code mov ax,error_code ; the Error Code lds si,int21regs_ptr ; point to user stack mov reg_ES[si],es mov reg_DI[si],di mov reg_BX[si],bx mov reg_CX[si],cx push ss ! pop ds jmp return_AX_CLC eject ; On Entry:- AX == Internal Error Number ; ; On Exit:- None ; CY set if error should be returned ; CY clear if it should be ignored ; Public error_exit error_exit: cmp internal_flag,0 ; If this is an internal jnz error_ret ; do not generate a critical call disk_error ; error jnz error_r10 ; No Error Occured or Ignored ret ; in critcal error handler ; ; Return the error code to the user and DO NOT generate any ; critical errors. ; ; On Entry:- AX == Internal Error Number ; ; On Exit:- None ; Public error_ret error_ret: call set_error ; the internal error code error_r10: ; otherwise negate les di,int21regs_ptr or es:reg_FLAGS[di],CARRY_FLAG ; set the "users" carry Flag stc ; also set real one if offset reg_AX EQ 0 stosw ; save return code else mov es:reg_AX[di],ax endif ret ; ; On Entry:- AX == Internal Error Number ; ; On Exit:- None ; Public fcberror_exit fcberror_exit: call disk_error ; Process the error code generating jz fe_e10 ; a critical error is required mov al,0FFh ; on FCB error return AL = FF fe_e10: ret eject ; WARNING - may be called from FDOS with DS = SYSDAT ; ; CHAR_ERROR is called when any character device function generates ; an error. First CHAR_ERROR sets the correct parameters for Get ; Extended Error. Then it generates a Critical Error by calling ; DO_INT24. ; ; Entry:- ES:SI -> device driver header ; SS:BX -> RH_ ; AX = RH_STATUS ; ; Exit AL Error Action ; Public char_error char_error: test ss:valid_flg,NO_CRIT_ERRORS jz char_e10 mov al,ERR_FAIL ; no critical errors allowed ret ; so just fail things char_e10: push ds push es push bx push cx push dx push si push di push ss ! pop ds ; DS -> our data now mov word ptr error_dev+0,si ; save the device driver address mov word ptr error_dev+2,es ; and then initialise the FUNC59 push es ; data areas and ax,007Fh ; Mask the Unused Bits or ah,80h+OK_RIF ; Retry/Ignore/Abort/Fail allowable cmp ss:RH_CMD,CMD_OUTPUT ; is this a read or write failure ? jne char_e20 inc ah ; 01 is a Write Failure char_e20: mov rwmode,ah ; push ax ; save for int 24 cbw ; zero AH again neg ax ; convert to an internal error add ax,ED_PROTECT ; code for set_error mov cl,LOC_CHAR call set_error add ax,ED_PROTECT ; convert to hardware error xchg ax,di ; DI == hardware error pop ax pop es call do_int24 ; execute INT 24 pop di pop si pop dx pop cx pop bx pop es pop ds ret eject ; ; DISK_ERROR gains control after any DOS disk based function ; has been executed which generates an error. First ERROR set the ; correct parameters for Get Extended Error. Then it determines if ; the current error should generate a Critical Error and calls ; DO_INT24 if TRUE. ; ; ; On Entry: ; AX Internal Error Code ; ; On Exit: ; AX 0 if no error to return (Ignore) ; AX DOS Error Code ; ZF reflects AX ; disk_error: mov cl,LOC_CHAR ; assume character device ; determine if the error is test rwmode,80h ; caused by a character or jnz disk_e10 ; block device and set the mov cl,LOC_BLOCK ; the critical error locus disk_e10: call set_error ; record error information jz disk_e50 ; just return a logical error. add ax,ED_PROTECT ; Convert to HardWare Error mov di,ax ; DI == HardWare Error ; Now get the information mov ah,rwmode ; about the error location and ah,not OK_RIF ; mask the all responses ; mov al,valid_flg ; valid flag contains no crit ; and al,not NO_CRITICAL_ERRORS ; errors bit, but if that was ; or ah,al ; set we wouldn't be here or ah,valid_flg ; or in valid responses cmp bx,ED_GENFAIL ; if it's general failure jne disk_e20 ; we cannot Ignore the error and ah,not OK_IGNORE ; but must Abort/Fail/Retry disk_e20: ; as appropriate mov al,err_drv ; get the failing drive mov error_drive,al ; and save locally les si,error_dev ; get device driver header ; are we are a character device test ah,80h ; as these have handled at a jnz disk_e40 ; lower level and just need ; to be FAILed back to caller call do_int24 ; Execute INT 24 mov bl,al ; Copy reponse into BL xor ax,ax ; Assume Ignore Error cmp bl,ERR_IGNORE ! jz disk_e50 ; Ignore the Error cmp bl,ERR_FAIL ! jz disk_e40 ; If not FAIL then RETRY call reload_registers ; get back entry registers mov FD_FUNC,ax ; save AX for a moment mov al,ah ; set up function number xor ah,ah ; in AX xchg ax,FD_FUNC ; save for use by FDOS xor ah,ah ; zero AH 'cause it's handy mov sp,retry_sp ; Must be RETRY so reset the jmp retry_off ; STACK and IP disk_e40: ; ; When a Critical Error is FAILED then we do the following ; if (extended error_code <= ED_SHAREFAIL) then ; ret = ED_ACCESS; ; else ; ret = ED_FAIL; ; extended error_code = ED_FAIL; ; return(ret); ; ; nb. above proto-code is at the request of ant ; mov ax,-(ED_FAIL) ; always return ED_FAIL in the xchg ax,error_code ; extended error_code cmp ax,-(ED_SHAREFAIL) ; did we FAIL on sharing conflict ? mov ax,-(ED_ACCESS) ; assume we did and prepare to return jae disk_e50 ; ED_ACCESS mov al,-(ED_FAIL) ; woops, return ED_FAIL after all disk_e50: or ax,ax ; NZ if error return required ret eject ; ; On Entry:- AX Internal Error Code ; CL Critical Error Locus ; ; On Exit:- AX DOS Error Code ; BX Internal Error Code ; ZF set on logical error set_error: mov bx,ax ; by default we return the raw error mov di,offset critical_error; Scan for critical Errors First call scan_error_table ; look for a matching error jc set_logical_error mov locus,cl ; Save the critical error LOCUS cmp ax,ED_SHAREFAIL ; watch out for SHAREFAIL - the action jne set_e10 ; depends on the caller ; ; ED_SHAREFAIL will return ED_ACCESS if the result of an attempt to open ; a file in shared mode, otherwise (FCB's and compatibility) it will ; generate a critical error. ; mov bx,ED_GENFAIL ; assume we want a critical error cmp FD_FUNC,MS_X_OPEN ; is it a shared open ? jnz set_error_data test FD_MODE,0$111$0$000b ; mode jz set_error_data jmps set_e30 ; return a logical "access denied" set_e10: cmp ax,ED_LOCKFAIL ; have we a lockfail error ? jne set_e20 ; ; ED_LOCKFAIL returns ED_ACCESS if a lock attempt fails, but a critical error ; on an attempt to read/write a locked region. ; cmp FD_FUNC,FD_LOCK ; was it a result of specific lock je set_logical_error ; call ? yes, it's a logical error mov bx,ED_GENFAIL ; no, generate a critical error jmps set_error_data set_e20: test valid_flg,NO_CRIT_ERRORS jz set_error_data ; do we allow critical errors ? mov ax,ED_ACCESS ; extended error code is Access Denied set_e30: mov bx,ED_ACCESS ; return access denied to caller ; jmps set_logical_error set_logical_error: xor di,di mov word ptr error_dev+0,di ; must be a logical error so force mov word ptr error_dev+2,di ; the ERROR_DEV to 0000:0000 mov di,offset logical_error ; scan the Logical error table call scan_error_table cmp ax,ED_NETACCESS ; if it's a networked access denied jne set_error_data ; turn it into ordinary one mov bx,ED_ACCESS ; return a logical "access denied" ; jmps set_error_data set_error_data: ; On Entry: ; AX = Internal Error Code for extended error ; BX = Internal Error Code for returned error ; CS:DI -> error table entry ; On Exit: ; AX = DOS Error Code ; BX = Internal Error Code ; ZF set on logical error ; neg ax mov error_code,ax ; Save the Error Code mov al,cs:ERR_TBL_CLASS[di] mov error_class,al ; Save the Class mov al,cs:ERR_TBL_ACTION[di] mov error_action,al ; Save the Action mov al,cs:ERR_TBL_LOCUS[di] ; Get the Locus mov error_locus,al ; Save the Locus and then check test al,al ; if the function overrides jnz set_d10 ; this value mov al,locus ; Get the Global Locus value mov error_locus,al ; set by the calling function set_d10: ; and save for FUNC 59 mov ax,bx ; Return to the caller with neg ax ; the DOS error code. mov di,word ptr error_dev ; set ZF if logical error or di,word ptr error_dev+2 ; error_dev = 0:0 ret scan_error_table: cmp cs:ERR_TBL_CODE[di],0 je scan_et10 ; Check for the end of the list cmp al,cs:ERR_TBL_CODE[di] je scan_et20 add di,ERR_TBL_LEN jmps scan_error_table scan_et10: stc scan_et20: ret eject PCM_RODATA CSEG WORD logical_error rb 0 ; ; Internal Code Error Class Error Action Error Locus ; ============= =========== ============ =========== db ED_FUNCTION, CLASS_APPLIC, ACT_ABORT, 00 db ED_FILE, CLASS_LOST, ACT_USER, LOC_BLOCK db ED_PATH, CLASS_LOST, ACT_USER, LOC_BLOCK db ED_HANDLE, CLASS_RESOURCE, ACT_ABORT, LOC_UNKNOWN db ED_ACCESS, CLASS_AUTHOR, ACT_USER, 00 db ED_NETACCESS, CLASS_AUTHOR, ACT_USER, 00 db ED_H_MATCH, CLASS_APPLIC, ACT_ABORT, LOC_UNKNOWN db ED_DMD, CLASS_APPLIC, ACT_TERM, LOC_MEMORY db ED_MEMORY, CLASS_RESOURCE, ACT_ABORT, LOC_MEMORY db ED_BLOCK, CLASS_APPLIC, ACT_ABORT, LOC_MEMORY db ED_ENVIRON, CLASS_APPLIC, ACT_ABORT, LOC_MEMORY db ED_FORMAT, CLASS_FORMAT, ACT_USER, LOC_UNKNOWN db ED_ACC_CODE, CLASS_APPLIC, ACT_ABORT, LOC_UNKNOWN db ED_DATA, CLASS_FORMAT, ACT_ABORT, LOC_UNKNOWN db ED_DRIVE, CLASS_LOST, ACT_USER, LOC_BLOCK db ED_DIR, CLASS_AUTHOR, ACT_USER, LOC_BLOCK db ED_DEVICE, CLASS_UNKNOWN, ACT_USER, LOC_BLOCK db ED_ROOM, CLASS_LOST, ACT_USER, LOC_BLOCK db ED_EXISTS, CLASS_EXISTS, ACT_USER, LOC_BLOCK db ED_STRUCT, CLASS_RESOURCE, ACT_ABORT, 00 db ED_PASSWORD, CLASS_AUTHOR, ACT_USER, LOC_UNKNOWN db ED_MAKE, CLASS_RESOURCE, ACT_ABORT, LOC_BLOCK ;; db ED_NET, CLASS_FORMAT, ACT_USER, LOC_NET db ED_ASSIGN, CLASS_EXISTS, ACT_USER, LOC_NET db ED_PARAM, CLASS_FORMAT, ACT_USER, LOC_UNKNOWN db ED_FAIL, CLASS_UNKNOWN, ACT_ABORT, LOC_UNKNOWN db ED_SHAREFAIL, CLASS_LOCKED, ACT_DELAY, LOC_BLOCK db ED_LOCKFAIL, CLASS_LOCKED, ACT_DELAY, LOC_BLOCK db ED_NOLOCKS, CLASS_RESOURCE, ACT_ABORT, LOC_MEMORY db 00, CLASS_SYSTEM, ACT_TERM, LOC_UNKNOWN critical_error rb 0 ; ; Internal Code Error Class Error Action Error Locus ; ============= =========== ============ =========== db ED_PROTECT, CLASS_MEDIA, ACT_URETRY, LOC_BLOCK db ED_BADUNIT, CLASS_INTERNAL, ACT_TERM, LOC_UNKNOWN db ED_NOTREADY, CLASS_HARDWARE, ACT_URETRY, 00 db ED_BADCMD, CLASS_INTERNAL, ACT_TERM, LOC_UNKNOWN db ED_BADDATA, CLASS_MEDIA, ACT_ABORT, LOC_BLOCK db ED_BADSEEK, CLASS_HARDWARE, ACT_RETRY, LOC_BLOCK db ED_BADMEDIA, CLASS_MEDIA, ACT_URETRY, LOC_BLOCK db ED_RNF, CLASS_MEDIA, ACT_ABORT, LOC_BLOCK db ED_NOPAPER, CLASS_TEMP, ACT_URETRY, LOC_CHAR db ED_WRFAIL, CLASS_HARDWARE, ACT_ABORT, 00 db ED_RDFAIL, CLASS_HARDWARE, ACT_ABORT, 00 db ED_GENFAIL, CLASS_UNKNOWN, ACT_ABORT, 00 db ED_SHAREFAIL, CLASS_LOCKED, ACT_DELAY, LOC_BLOCK db ED_LOCKFAIL, CLASS_LOCKED, ACT_DELAY, LOC_BLOCK db ED_NOFCBS, CLASS_APPLIC, ACT_ABORT, LOC_UNKNOWN default_error rb 0 db 00, CLASS_SYSTEM, ACT_TERM, LOC_UNKNOWN PCMODE_DATA DSEG WORD extrn indos_flag:byte extrn internal_flag:byte extrn int21regs_ptr:dword extrn current_psp:word extrn retry_off:word, retry_sp:word extrn valid_flg:byte extrn error_locus:byte ; Error Locus extrn error_code:word ; DOS format error Code extrn error_action:byte ; Error Action Code extrn error_class:byte ; Error Class extrn error_dev:dword ; Failing Device Header extrn error_drive:byte ; Failing Disk Drive extrn err_drv:byte extrn locus:byte extrn rwmode:byte end