;    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 <unique name>,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 <unique name>,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
