; File : $DISK.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$ ; DISK.A86 1.26 94/12/01 10:05:21 ; added attribute support for open/move/unlink during server call ; DISK.A86 1.24 93/11/16 13:46:21 ; Generate critical error on int21/36 (get free space) ; DISK.A86 1.23 93/10/25 21:58:02 ; Tighten up error checks on int21/6C modes (DL bits 0-3 = 3 rejected) ; DISK.A86 1.22 93/10/18 17:40:51 ; fix for >255 open files (PNW Server) ; DISK.A86 1.21 93/09/03 20:28:02 ; Add "no critical errors" support (int 21/6C) ; DISK.A86 1.20 93/08/04 15:15:15 ; Int21/6C allows DH=1 ; DISK.A86 1.19 93/07/22 20:32:12 ; don't check AL on int 21/6c ; DISK.A86 1.18 93/07/22 19:28:02 ; correct bug in extended open/create ; DISK.A86 1.15 93/06/23 04:05:38 ; more int21/6C - we still need no critical errors support ; DISK.A86 1.14 93/06/23 03:00:27 ; fix bug in int21/6C ; DISK.A86 1.13 93/05/07 15:09:29 ; Move delwatch free space adjust call inside the MXDisk ; DISK.A86 1.12 93/03/16 22:33:49 ; UNDELETE support changes ; DISK.A86 1.11 93/03/05 18:10:55 ; Add UNDELETE definition ; ENDLOG ; ; All FCB based PCMODE functions are translated to FDOS function ; calls in this file. ; ; 22 May 87 Support the extended CHMOD function to get/set the ; password mode. ; 28 May 87 Support the Update Handle Count Function ; 5 Nov 87 Remove MAJOR_VER reference from func0D ; 15 Mar 88 Return Attributes in CX and AX ; 3 May 88 Return correct disk size from functions 1B, 1C and 36 ; 17 May 88 Add valid drive check routine used by FUNC29 and FUNC4B ; 30 Jun 88 Call FDOS to build DDSC for INT21/53 ; 18 Aug 88 FUNC67 correctly fill new handle table with 0FFh ; Sorcim ACCPAC Plus ; 27 Sep 88 Return error codes from Read and Write Random. ; 19 Feb 89 Allowing SHARE to be disabled with DR DOS ; 16 May 89 Include Random Record field on func23 (file size) ; 23 May 89 func3F (Read) now allows Ignore on errors (CopyIIpc) ; 11 Sep 89 MSNET Flush hook added ; 20 Sep 89 func3B "d:=" form fills in LDT (func4B support) ; 24 Oct 89 func32 (getdpb) sets top bit of drive on fdos_getdpb ; to indicate free space count not required ; 27 Oct 89 mutilate the code to save space ; 24 Jan 90 valid_drive uses dos_entry, doesn't peek at HDS's ; 8 Feb 90 func_43 updated for new password support ; 27 Feb 90 func57 gives ED_FUNCTION if not get/set (HEADROOM bug) ; 7 Mar 90 Convert to register preserved function calls ; 14 Mar 90 Share func3D_mask bodge move to FDOS ; 28 Sep 90 Return sectors xfered on Int21/27 even if error (CALC.EXE>64k) ; 14 mar 91 add delwatch hook to func36 (disk free space) ; 14 jun 91 correct error codes from func3F during func4B ; 8 aug 91 func3B (chdir) now maintains LDT name for all cases ; 1 oct 91 Valdivar it ; 27 feb 92 func3E returns previous open count ; 3 mar 92 fill in default search attribute in Func3D for future ; 23 mar 92 func67 will now shrink #handles ; include pcmode.equ include fdos.def include i:doshndl.def include i:fdos.equ include i:psp.def include i:msdos.equ include i:mserror.equ include i:redir.equ FCB_LEN equ 32 XFCB_LEN equ FCB_LEN+7 PCM_CODE CSEG BYTE extrn dbcs_lead:near extrn dos_entry:near extrn fdos_nocrit:near extrn fdos_crit:near, fdos_ax_crit:near extrn fcbfdos_crit:near extrn set_retry:near extrn set_retry_RF:near extrn error_exit:near extrn error_ret:near extrn fcberror_exit:near extrn reload_registers:near extrn reload_ES:near extrn return_AX_CLC:near extrn return_BX:near extrn return_CX:near extrn return_DX:near ; ***************************** ; *** DOS Function 0D *** ; *** Disk Reset *** ; ***************************** ; Public func0D func0D: mov FD_FUNC,FD_FLUSH call fdos_nocrit ; flush buffers mov ax,0FFFFh push ax mov ax,I2F_FLUSH int 2fh ; magic INT2F flush remote buffers pop ax push ss ! pop ds ret ; ***************************** ; *** DOS Function 0E *** ; *** Select Disk *** ; ***************************** ; Public func0E func0E: ; ; Entry: ; DL == drive to set as default (0 == A:) ; Exit: ; AL == Number of Drives in System (from SYSDAT) ; mov FD_FUNC,FD_SELECT xchg ax,dx ; drive in AL cbw ; make that AX mov FD_DRIVE,ax call fdos_nocrit ; ask the FDOS to try to select it mov al,last_drv ; Return the number of valid drives ret ; ; Return with the ZERO flag set if the drive passed in AL is ; valid. This function is used to set the initial AX value ; when a program is loaded. ; ; On Entry:- AL 00 - Default Drive ; 01 to 26 - A: to Z: ; ; On Exit:- ZF If AL referenced a valid drive ; Public valid_drive valid_drive: push dx mov dl,al ; get drive in DL dec dl ; make drive zero based js valid_drive10 ; if current drive always OK mov ah,MS_DRV_GET call dos_entry ; get current drive push ax ; save for later mov ah,MS_DRV_SET call dos_entry ; try and select new drive mov ah,MS_DRV_GET ; if we can select it call dos_entry ; then it's valid sub al,dl ; AL = 0 if drive valid pop dx ; recover old drive push ax ; save result mov ah,MS_DRV_SET call dos_entry ; reset to original drive pop ax ; recover result valid_drive10: pop dx test al,al ; set ZF if valid drive ret eject ; ***************************** ; *** DOS Function 0F *** ; *** Open File (FCB) *** ; ***************************** ; Public func0F func0F: ; ***************************** ; *** DOS Function 10 *** ; *** Close File (FCB) *** ; ***************************** ; Public func10 func10: ; ***************************** ; *** DOS Function 11 *** ; *** Search First (FCB) *** ; ***************************** ; Public func11 func11: ; ***************************** ; *** DOS Function 12 *** ; *** Search Next (FCB) *** ; ***************************** ; Public func12 func12: ; ***************************** ; *** DOS Function 13 *** ; *** Delete File (FCB) *** ; ***************************** ; Public func13 func13: ; ***************************** ; *** DOS Function 14 *** ; *** Sequential Read (FCB) *** ; ***************************** ; Public func14 func14: ; ***************************** ; *** DOS Function 15 *** ; *** Sequential Write (FCB)*** ; ***************************** ; Public func15 func15: ; ***************************** ; *** DOS Function 16 *** ; *** Create File (FCB) *** ; ***************************** ; Public func16 func16: ; ***************************** ; *** DOS Function 17 *** ; *** Rename File (FCB) *** ; ***************************** ; Public func17 func17: ; ***************************** ; *** DOS Function 21 *** ; *** Random Read (FCB) *** ; ***************************** ; Public func21 func21: ; ***************************** ; *** DOS Function 22 *** ; *** Random Write (FCB) *** ; ***************************** ; Public func22 func22: ; ***************************** ; *** DOS Function 23 *** ; *** File Size (FCB) *** ; ***************************** ; Public func23 func23: ; ***************************** ; *** DOS Function 24 *** ; *** Set Relative Record *** ; ***************************** ; Public func24 func24: ; ***************************** ; *** DOS Function 27 *** ; *** Random Block Read *** ; ***************************** ; Public func27 func27: ; ***************************** ; *** DOS Function 28 *** ; *** Random Block Write *** ; ***************************** ; Public func28 func28: ; All FCB function come through here call set_retry_RF ; Valid to RETRY or FAIL mov ax,FD_FCB ; FCB file function xchg ax,FD_FUNC ; recover function number mov FD_FCBFUNC,ax ; pass FCB function number mov FD_FCBOFF,dx ; Initialise the FCB Pointer mov FD_FCBSEG,es mov FD_FCBCNT,cx ; we may need record count call fcbfdos_crit ; Execute the function jc fcb_error ; Check for an Error mov cx,FD_FCBCNT ; Get the number of records jmp return_CX ; processed and return in CX fcb_error: jmp fcberror_exit ; Use default Error handler eject ; ***************************** ; *** DOS Function 19 *** ; *** Current Disk *** ; ***************************** Public func19 func19: mov al,current_dsk ; Get the current logical disk ret ; and return ; ***************************** ; *** DOS Function 1A *** ; *** Set Disk Trans Adr *** ; ***************************** Public func1A func1A: mov dma_offset,dx ; set the PCMODE DMA Offset mov dma_segment,es ; and then the DMA Segment ret ; ***************************** ; *** DOS Function 1B *** ; *** Def. Disk Info *** ; ***************************** ; Public func1B func1B: ; ***************************** ; *** DOS Function 1C *** ; *** Sel. Disk Info *** ; ***************************** ; Public func1C func1C: call set_retry_RF ; Valid to RETRY or FAIL xor dh,dh ; Pass the drive requested call fdos_DISKINFO ; find out about drive jc fdos_DI_error mov cx,es:DDSC_SECSIZE[bx] ; Get the Physical Sector Size call return_CX ; in bytes mov dx,es:DDSC_NCLSTRS[bx] ; Convert the last cluster no dec dx ; returned in DDSC to maximum call return_DX ; number of clusters and return mov al,es:DDSC_CLMSK[bx] ; get (sectors per cluster)-1 inc ax ; return sectors per cluster lea bx,DDSC_MEDIA[bx] ; return address of media byte f1B1C1F32_common: push ds lds di,int21regs_ptr mov reg_DS[di],es mov reg_BX[di],bx pop ds ret ; ***************************** ; *** DOS Function 1F *** ; *** Get Default DPB *** ; ***************************** ; Public func1F func1F: ; ***************************** ; *** DOS Function 32 *** ; *** Get Requested DPB *** ; ***************************** ; Public func32 func32: call set_retry_RF ; Valid to RETRY or FAIL mov dh,80h ; set top bit - free space not needed call fdos_DISKINFO ; and make the function call jnc f1B1C1F32_common ; exit using common code fdos_DI_error: jmp fcberror_exit ; exit thru FCB error ; ***************************** ; *** DOS Function 36 *** ; *** Disk Free Space *** ; ***************************** ; Public func36 func36: call set_retry_RF ; Valid to RETRY or FAIL xor dh,dh ; clear out DH call fdos_DISKINFO ; find out about drive jnc f36_OK ; CY set if we had a problem push es push bx call error_exit ; generate a critical error pop bx pop es mov ax,0FFFFh ; Invalid Drive Return 0FFFFh jc f36_exit ; No Carry f36_OK: mov cx,es:DDSC_SECSIZE[bx] ; Get the Physical Sector Size call return_CX ; in bytes mov dx,es:DDSC_NCLSTRS[bx] ; Convert the last cluster no dec dx ; returned in DDSC to maximum call return_DX ; number of clusters mov cx,es:DDSC_FREE[bx] ; get number of free clusters if DELWATCH add cx,FD_ADJUST ; now add in DELWATCH adjustment endif xor ax,ax mov al,es:DDSC_CLMSK[bx] ; get the sectors per cluster -1 inc ax ; AX = sectors per cluster mov bx,cx call return_BX ; return free clusters f36_exit: jmp return_AX_CLC fdos_DISKINFO: ;------------- ; Called by func1B, func1C, func1F, func32, func36 ; Even number functions have drive in DL ; Odd numbered function use default drive (0) ; mov ax,FD_DISKINFO ; get information about drive xchg ax,FD_FUNC ; while getting orginal function # test al,1 ; is it func1B/func1F ? jz fdos_DI10 ; if so these use the default xor dl,dl ; drive so zero DL fdos_DI10: mov FD_DRIVE,dx ; drive in DX call fdos_crit les bx,FD_DPB ; get the DPB pointer ret eject ; ***************************** ; *** DOS Function 2F *** ; *** Get Disk Trans Adr *** ; ***************************** Public func2F func2F: les bx,dword ptr dma_offset ; current dma address push ds lds di,int21regs_ptr mov reg_ES[di],es mov reg_BX[di],bx pop ds ret eject ; ***************************** ; *** DOS Function 41 *** ; *** Delete File(s) *** ; ***************************** ; Public func41 func41: cmp ss:remote_call,0 jne fdos_common41 mov cl,06h ; ***************************** ; *** DOS Function 39 *** ; *** Create SubDirectory *** ; ***************************** ; Public func39 func39: ; ***************************** ; *** DOS Function 3A *** ; *** Delete SubDirectory *** ; ***************************** ; Public func3A func3A: ; ***************************** ; *** DOS Function 3B *** ; *** Change SubDirectory *** ; ***************************** ; Public func3B func3B: ; ***************************** ; *** DOS Function 4E *** ; *** Find First File *** ; *** DOS Function 4F *** ; *** Find Next File *** ; ***************************** ; Public func4E func4E: Public func4F func4F: ; Func 4F has no parameters, but using the same routine saves code fdos_common41: call set_retry_RF ; Valid to RETRY or FAIL ; jmps fdos_name fdos_name: mov FD_NAMEOFF,dx ; Initialise Pointer mov FD_NAMESEG,es mov FD_ATTRIB,cx ; and attributes jmp fdos_ax_crit eject ; ***************************** ; *** DOS Function 5B *** ; *** Create New File *** ; ***************************** ; Public func5B func5B: ; ***************************** ; *** DOS Function 3C *** ; *** Create a File *** ; ***************************** ; Public func3C func3C: call set_retry_RF ; Valid to RETRY or FAIL cmp FD_FUNC,MS_X_CREAT ; is it a standard create ? je f3C_10 mov FD_FUNC,FD_NEW ; no, create a new file f3C_10: mov FD_MODE,DHM_RW ; create as read/write jmps fdos_name ; go do it ; ***************************** ; *** DOS Function 3D *** ; *** Open a File *** ; ***************************** ; Public func3D func3D: call set_retry_RF ; Valid to RETRY or FAIL cmp ss:remote_call,0 jne funcExtendedOpenCreate mov cl,06h ; default search mode for local ; jmp funcExtendedOpenCreate ; calls (remote it's in CL) funcExtendedOpenCreate: ; On Entry: ; FD_FUNC = function to carry out ; ES:DX -> name ; AX = open mode ; CX = file attributes ; push ax and al,DHM_SHAREMSK cmp al,DHM_DENY_NONE ; any funny share bits ? pop ax ja open_mode_err push ax and al,DHM_RWMSK cmp al,DHM_RW ; check RW bits are valid pop ax ja open_mode_err mov FD_MODE,ax ; Set Open Mode jmps fdos_name open_mode_err: mov ax,ED_ACC_CODE ; This is an illegal open mode jmp error_exit ; return an error ; ***************************** ; *** DOS Function 3F *** ; *** Read from Handle *** ; ***************************** ; Public func3F func3F: ; ***************************** ; *** DOS Function 40 *** ; *** Write to a Handle *** ; ***************************** ; Public func40 func40: mov al,OK_RIF ; Valid to RETRY,IGNORE or FAIL call set_retry mov FD_BUFOFF,dx mov FD_BUFSEG,es mov FD_COUNT,cx call fdos_handle mov dx,FD_COUNT jnc f40_10 ; no error, return # xfered push FD_HANDLE push dx ; an error, try critical error call error_exit ; and if we get back here that pop dx ; means we Fail/Ignore it pop bx jc f40_20 ; are we returning an error ? push dx ; no, we are ignoring it xor cx,cx ; CX:DX offset to skip mov ax,(MS_X_LSEEK*256)+1 ; seek to current+offset call dos_entry pop dx ; finally return # we wanted f40_10: ; to xfer xchg ax,dx ; AX = return code jmp return_AX_CLC f40_20: ret ; ***************************** ; *** DOS Function 42 *** ; *** Move R/W Pointer *** ; ***************************** ; Public func42 func42: call set_retry_RF ; Valid to RETRY or FAIL mov word ptr FD_OFFSET+0,dx mov word ptr FD_OFFSET+2,cx mov FD_METHOD,ax call fdos_handle jc f42_error ; Do not return the current mov ax,word ptr FD_OFFSET+0 ; file position if mov dx,word ptr FD_OFFSET+2 ; an error occurs call return_DX jmp return_AX_CLC f42_error: jmp error_exit fdos_handle: mov FD_HANDLE,bx jmp fdos_crit ; ***************************** ; *** DOS Function 43 *** ; *** Change File Mode *** ; ***************************** ; ; Concurrent Password Support:- ; ; *WO* *GR* *OW* This is the format of the Password ; P---$RWED$RWED$RWED mode word which is compatible with ; the FlexOS F_PROTECT field. ; *WO* World (Ignored) ; *GR* Group (Ignored) The P flag is only used to designate ; *OW* Owner (Used) that the password is being updated. ; Public func43 func43: call set_retry_RF ; Valid to RETRY or FAIL mov FD_FLAG,ax ; Requested Attributes ignored call fdos_name ; if flags are not being set jc f42_error call reload_registers ; get back AL test al,81h jnz f43_exit mov cx,FD_ATTRIB call return_CX ; Return Attribs/Password xchg ax,cx ; Also in AX f43_exit: jmp return_AX_CLC ; ***************************** ; *** DOS Function 46 *** ; *** Force Dup Handle *** ; ***************************** ; Public func46 func46: xchg bx,cx ; destination handle in BX mov ah,MS_X_CLOSE ; try to close it but ignore call dos_entry ; errors as it may be already xchg bx,cx ; now fall thru to handle func mov ah,MS_X_DUP2 ; do do the duplicate ; ***************************** ; *** DOS Function 45 *** ; *** Duplicate Handle *** ; ***************************** ; Public func45 func45: ; ***************************** ; *** DOS Function 3E *** ; *** Close a File *** ; ***************************** ; Public func3E func3E: mov al,OK_FAIL call set_retry ; Valid to FAIL mov FD_NEWHND,cx ; (in case it's force dup) ; jmps fdos_ax_handle fdos_ax_handle: mov FD_HANDLE,bx jmp fdos_ax_crit ; ***************************** ; *** DOS Function 5C *** ; ***Lock/Unlock File Access*** ; ***************************** ; Public func5C func5C: call set_retry_RF ; Valid to RETRY or FAIL mov FD_FUNC,FD_LOCK ; Lock/Unlock File mov word ptr FD_OFFSET+0,dx ; Lock Offset (LOW) mov word ptr FD_OFFSET+2,cx ; Lock Offset (HIGH) mov word ptr FD_LENGTH+0,di ; Lock Length (LOW) mov word ptr FD_LENGTH+2,si ; Lock Length (HIGH) mov FD_LFLAG,ax ; Lock Type jmps fdos_ax_handle ; ***************************** ; *** DOS Function 47 *** ; *** Get Current Dir *** ; ***************************** ; Public func47 func47: call set_retry_RF ; Valid to RETRY or FAIL mov FD_PATHOFF,si ; Initialise Pointer mov FD_PATHSEG,es xchg ax,dx ; drive in AL cbw ; make that AX mov FD_DRIVE,ax jmp fdos_ax_crit ; return garbage in AH (SPJ bug) ; ***************************** ; *** DOS Function 53 *** ; *** Build DPB from BPB *** ; ***************************** ; ; This function takes the BPB at DS:SI and builds a DDSC at ES:BP ; Public func53 func53: call set_retry_RF ; Valid to RETRY or FAIL mov FD_BPBOFF,si ; Segment and Offset of BPB mov FD_BPBSEG,es mov FD_DDSCOFF,bp ; Segment and Offset of DDSC call reload_ES mov FD_DDSCSEG,es jmp fdos_nocrit ; ; ***************************** ; *** DOS Function 56 *** ; *** Rename/Move a File *** ; ***************************** ; Public func56 func56: call set_retry_RF ; Valid to RETRY or FAIL mov FD_NNAMEOFF,di ; New FileName push es call reload_ES ; callers ES:DI mov FD_NNAMESEG,es ; point to new filename pop es mov FD_ONAMEOFF,dx ; Old FileName mov FD_ONAMESEG,es cmp ss:remote_call,0 jne func56_10 mov cl,17h func56_10: mov FD_ATTRIB,cx jmp fdos_crit ; ***************************** ; *** DOS Function 57 *** ; *** Get/Set File Time *** ; ***************************** ; Public func57 func57: call set_retry_RF ; Valid to RETRY or FAIL mov FD_DATE,dx mov FD_TIME,cx mov FD_SFLAG,ax cmp al,1 ; allow get/set only mov ax,ED_FUNCTION ; all else fails horribly ja f57_error call fdos_handle jc f57_error call reload_registers test al,al jnz f57_exit mov cx,FD_TIME call return_CX ; return TIME in CX mov dx,FD_DATE jmp return_DX ; and DATE in DX f57_exit: ret f57_error: jmp error_exit ; ***************************** ; *** DOS Function 5A *** ; *** Create Unique File *** ; ***************************** ; Public func5A func5A: mov ax,ED_ACCESS ; assume we will have an error test cx,DA_FIXED ; because of silly attributes jnz func5A_40 ; did we ? mov si,dx ; find end of pathname xor ax,ax ; no previous char func5A_10: xchg ax,bx ; BL = previous char lods es:al ; get next char test al,al ; is it the end of the string? jz func5A_20 call dbcs_lead ; is it a KANJI char? jnz func5A_10 inc si ; skip 2nd char of pair jmps func5A_10 func5A_20: dec si ; SI -> NUL cmp bl,'\' ; was last char a '\' ? je func5A_30 cmp bl,'/' ; (or a '/' for unix freaks) je func5A_30 mov es:byte ptr [si],'\' ; append a '\' to name inc si func5A_30: ; Here ES:DX -> start of name, ES:SI -> position to append ,0 ; CX = attribute for file. ; We generate a unique name based upon the time and date - if this already ; exists we keep retrying knowing the number of files is finite and we must ; succeed eventually push cx ! push dx ! push si ; append a unique'ish name call func5A_append_unique_name pop si ! pop dx ! pop cx mov ah,MS_X_MKNEW ; try to create unique file call dos_entry jnc func5A_50 ; exit if we succeeded mov es:byte ptr [si],0 ; else forget extention cmp ax,ED_EXISTS ; we only retry if it already exists je func5A_30 func5A_40: jmp error_exit ; return error to caller func5A_50: jmp return_AX_CLC ; return handle to caller func5A_append_unique_name: ;------------------------- ; On Entry: ; ES:DX -> start of name ; ES:SI -> position to append ,0 ; CX = attribute for file. ; On Exit: ; None ; ; We append a unique 8 character filename to this based upon the current ; date/time. push si mov ax,120dh int 2fh ; get date/time in AX & DX pop di add ax,unique_name_seed ; randomise the date otherwise we would inc unique_name_seed ; have one second wait between names call func5A_app_AX ; store 4 ascii bytes xchg ax,dx ; was DX = time call func5A_app_AX ; store 4 ascii bytes xor ax,ax stosb ; and a terminating NUL ret func5A_app_AX: ; On Entry AX = word, ES:DI -> string ; Store 4 ASCII chars at ES:DI, based upon value in AX call func5A_app_AL ; do low byte, falling thru to do high func5A_app_AL: call func5A_app_NIB ; low nibble, falling thru for high func5A_app_NIB: push ax and al,0fh ; mask out a nibble add al,'A' ; make it ASCII character stosb ; plant the string pop ax mov cl,4 shr ax,cl ; shift nibble ret ; ***************************** ; *** DOS Function 60 *** ; ***Perform Name Processing*** ; ***************************** ; ; DS:SI point to a source string which contains a relative path ; specification ES:DI points to a buffer which is at least 80 ; bytes longer than the source string. ; ; The carry flag is set and AX contains an error code if the ; source string is mal formed. This function is used by the ; Ryan-McFarland COBOL compiler. ; Public func60 func60: call set_retry_RF ; Valid to RETRY or FAIL mov FD_FUNC,FD_EXPAND ; Expand a relative Path mov FD_ONAMEOFF,si ; Initialise Source Pointer mov FD_ONAMESEG,es mov FD_NNAMEOFF,di ; Initialise Destination call reload_ES ; pointer mov FD_NNAMESEG,es jmp fdos_crit ; ***************************** ; *** DOS Function 67 *** ; *** Set/Handle Count *** ; ***************************** ; ; We impose a minimum of 20 handles regardless of what the caller ; requests. If the request is <=20 we use the default handle table in ; the PSP, else we allocate a memory block for the new table. ; If the old handle table was in a memory block (ie. zero offset) we ; will free that block up afterwards. ; When shrinking the handle count the error ED_HANDLE will be given if ; open files would have been lost. ; Public func67 func67: push ds mov ds,current_psp ; DS -> current PSP blk cmp bx,20 ; force to minimum value of 20 jae f67_10 mov bx,20 ; never have less than 20 handles f67_10: mov cx,ds:PSP_XFNMAX ; we have this many handles sub cx,bx ; are we growing ? jbe f67_20 ; if shrinking make sure none open les di,ds:PSP_XFTPTR ; point to existing handle table lea di,[di+bx] ; point to 1st handle we will lose mov al,0FFh ; they must all be closed repe scasb ; or we fail mov ax,ED_HANDLE ; fail if we are in danger of losing jne f67_error ; open handles f67_20: push bx ; save # of handles wanted push ds ! pop es mov di,offset PSP_XFT ; ES:DI -> new handle table cmp bx,20 ; if we are setting to the je f67_30 ; default size add bx,15 ; calculate memory required mov cl,4 ! shr bx,cl ; num of paragraphs required xor di,di ; offset will be zero mov ah,MS_M_ALLOC ; allocate the memory call dos_entry mov es,ax ; ES:DI -> new handle table f67_30: pop bx ; BX = # handles wanted jc f67_error ; ES:DI -> new handle table mov cx,bx ; CX = new # handles xchg cx,ds:PSP_XFNMAX ; Update the Handle Count mov si,di ; Update the Table Offset xchg si,ds:PSP_XFTOFF mov ax,es xchg ax,ds:PSP_XFTSEG ; Update the Table Segment mov ds,ax ; DS:SI -> old handle table ; ES:DI -> new handle table ; CX = # old handles to copy ; BX = # new handles desired sub bx,cx ; BX = # extra "closed" handles jae f67_40 ; negative if we are shrinking add cx,bx ; CX = # handles we inherit xor bx,bx ; BX = no extra "closed" handles f67_40: push si ; save offset old handle table rep movsb ; Copy the existing Handles pop si ; SI = offset old handle table mov al,0FFh ; AL = unused handle mov cx,bx ; mark extra handles as unused rep stosb ; mark as unused test si,si ; do we have memory to free ? jnz f67_50 mov ah,MS_M_FREE call dos_entry ; free up old handle table DMD f67_50: pop ds jmp return_AX_CLC ; clear carry on return f67_error: pop ds ; restore DS jmp error_exit ; and return error AX to caller ; ***************************** ; *** DOS Function 68 *** ; *** Commit File *** ; ***************************** ; Public func68 func68: call set_retry_RF ; Valid to RETRY or FAIL mov FD_FUNC,FD_COMMIT ; Close a File Handle jmp fdos_handle ; ***************************** ; *** DOS Function 6C *** ; *** Extended Open *** ; ***************************** ; Public func6C func6C: mov al,OK_RF ; Valid to RETRY or FAIL test bh,20h ; should we allow critical errors ? jz f6C10 or al,NO_CRIT_ERRORS ; no, so remember that f6C10: call set_retry mov ax,ED_FUNCTION ; assume an illegal action code test dx,not 0113h ; now check for sensible bits jnz f6C_error inc dx test dl,4 ; also reject bits 0-3 = 3 jnz f6C_error dec dx xchg ax,si ; ES:AX -> name xchg ax,dx ; AX = action, ES:DX -> name xchg ax,bx ; AX = open mode, BX = action test bl,010h ; should we create if not there ? jz f6C_open ; no, skip the attempt at make new and ah,(DHM_COMMIT+DHM_NOCRIT)/100h mov FD_FUNC,FD_NEW ; create only if not there call funcExtendedOpenCreate ; try to open/create the file mov cx,2 ; CX = file created jnc f6C_exit ; return this if we succeeded f6C_open: call reload_registers ; all registers as per entry xchg ax,si ; ES:AX -> name xchg ax,dx ; AX = action, ES:DX -> name xchg ax,bx ; AX = open mode, BX = action push bx ; save action and ah,(DHM_COMMIT+DHM_NOCRIT)/100h mov FD_FUNC,MS_X_OPEN ; try an open an existing file call funcExtendedOpenCreate pop bx ; recover action jc f6C_error ; return error if we can't open file mov cx,1 ; CX = file opened test bl,001h ; should we open if it exists ? jnz f6C_exit ; yes, return the handle xchg ax,bx ; BX = handle, AX = action test al,002h ; should we replace the file ? mov ax,ED_EXISTS ; if not close and return error jz f6C_close_on_error mov ah,MS_X_WRITE xor cx,cx ; write zero bytes to truncate file call dos_entry jc f6C_close_on_error ; on error AX = error code, return it xchg ax,bx ; AX = handle mov cx,3 ; CX = file replaced f6C_exit: jmp return_CX ; return CX to caller f6C_close_on_error: ; File exits, but open should be failed (error code in AX) push ax mov ah,MS_X_CLOSE call dos_entry ; close that file pop ax f6C_error: jmp error_exit ; generate critical error PCMODE_DATA DSEG WORD extrn current_psp:word extrn current_dsk:byte extrn dma_offset:word extrn dma_segment:word extrn int21regs_ptr:dword extrn last_drv:byte extrn remote_call:word if DELWATCH extrn fdos_stub:dword endif GLOBAL_DATA dseg word ; When creating unique files we use the date/time to make the name. ; We add this seed value to "randomise" things, INCing on failure so the next ; attempt usually succeeds. unique_name_seed dw 0 ; so we don't have to wait 1 second end