;SID = @(#)demfile.asm  6.6 92/02/03
;       SCCSID = @(#)demfile.asm        6.6 92/02/03
;
;   Revisions:
;
;Local  DCR/
;Tag    PTM(R)  Who     When/What
;               danno   11-Jan-1989
;                       Created for MVDM
;
; B001  9/26/91 CP20 PTR AA04134  Mark Rogalski
;       Change GetVisDrv function to call DOS for non mapped drives.
;
;***********************************************************************;BN002;
; BN002 - 10/9/91  CP20 AA03991  Mark Rogalski                          ;BN002;
;         Fix Dup handle function to check if handle is for device      ;BN002;
;         before calling SVC_DEMDUP.                                    ;BN002;
;***********************************************************************;BN002;
; BN003 - 1/30/92  CP20 AA04471  Mark Rogalski                          ;BN003;
;         Need to call DOS to get CurrentPDB directly, so that FSFILTER ;BN003;
;         can be somewhat re-entrant.                                   ;BN003;
;***********************************************************************;BN003;
; BN004 - 1/31/92  CP20 B732325  Mark Rogalski                          ;BN004;
;         if call to open_DOS_NULL fails then save rc and close os/2    ;BN004;
;         file that was successfully opened, then return rc.            ;BN004;
;***********************************************************************;BN004;
; BN005 - 5/13/92  CP20 DEFECT 24729  Mark Rogalski                     ;BN005;
;         if call to close new dup handle fails, ignore it.             ;BN005;
;         Also remove unneeded code for handling RM devices.            ;BN005;
;***********************************************************************;BN005;
; BN006 - 9/10/92  defect 46564 (54148)  Mark Rogalski                  ;BN006;
;         For GetVisDrv function, test for both DOS and OS2 drives.     ;BN006;
;***********************************************************************;BN006;
; BN007 - 11/22/92 defect 57397  Mark Rogalski                          ;BN007;
;         In ExtHandles, call OS/2 first and then DOS.                  ;BN007;
;***********************************************************************;BN007;
; BN008 - 01/23/93 defect 46578  Carlos A. Romero                       ;BN008;
;         Added SERVER DOS CALL (5D00H) function to FSFILTER            ;BN008;
;***********************************************************************;BN008;
; BN009 - 04/27/93 defect 67581 Lisa M. Primm                           ;BN009;
;         Added code to fix-up user's registers on the way back out     ;BN009;
;         from 5d00 server call...                                      ;BN009;
;***********************************************************************;BN040;
;  29Jul93 - J.M.Hare    defect 71358                                   ;BN040;
; Add propogating of DOSFLAG through files system for exec_only test.   ;BN040;
;***********************************************************************;BN040;
; CHGTM1 -08/03/93 defect 71518 Change Team                             ;CHGTM1;
;         Incorrect indexing was being used into the saved user stack   ;CHGTM1;
;         for int21 5d00.                                               ;CHGTM1;
;***********************************************************************;CHGTM1;
; BN010 - 08/05/93 defect 71013 Lisa M. Primm                           ;BN010;
;         Changed code so that OPEN_DOS_NULL uses the same open mode    ;BN010;
;         flags as original call; passed open mode into OPEN_DOS_NULL   ;BN010;
;         in BX as it wasn't being used...                              ;BN010;
;***********************************************************************;BN010;
; CHGTM2 -08/09/93 defect 69099 Catherine E. Bundy                      ;CHGTM2;
;         Change $FIND_NEXT to no longer check find_first_flag to       ;CHGTM2;
;         determine whether DOS or OS2 will process findnext, Instead   ;CHGTM2;
;         we check the DTA for validity and allow DOS to process if the ;CHGTM2;
;         drive is non-local or invalid.                                ;CHGTM2;
;***********************************************************************;CHGTM2;
; 73436   09/07/93 defect 73436 Richard Mulder                          ;73436;
;         Change $FIND_FIRST to mark the FindFirstDTA structure whether ;73436;
;         DOS or OS/2 processed the request.  Change $FIND_NEXT to send ;73436;
;         the request to whomever processed the Find First request.     ;73436;
;***********************************************************************;73436;
; 75567   11/18/93 defect 75567 ChangeTeam  (REGR: 75567,71358)         ;75567;
;         Remove unneeded localvar crt_execdw from $Creat procedure to  ;75567;
;         avoid segment load failure when running Excel in a VMB.       ;75567;
;***********************************************************************;75567;
; 74297   12/16/93 defect 74297 ChangeTeam                              ;74297;
;         Change $Open to check for filenames beginning with "/dev/"    ;74297;
;         and change them to "\dev\", so they will be recognized as     ;74297;
;         DOS devices.                                                  ;74297;
;***********************************************************************;74297;
; 75462   12/17/93 changeteam (B Clare )                                ;75462;
;         Add support for wildcard deletes to srv_call_worker. Created  ;75462;
;         flag SrvCallEntFlg which indicates to INT 21h function 41h    ;75462;
;         ($unlink) that it was called from srv_call_worker.            ;75462;
;***********************************************************************;
; 77984   01/28/94 defect 77984 ChangeTeam                              ;77984;
;         Change open_DOS_NULL to turn off the sharing mode bits to     ;77984;
;         avoid problems with file sharing after SHARE is run in a VMB. ;77984;
;***********************************************************************;77984;
; 89980   08/12/94 defect 89980 ChangeTeam                              ;89980
;         Removed VSFNFromHandle call because it was returning the os2  ;89980
;         VSFN rather than the dos SFN, and handle_map was getting      ;89980
;         corrupted in open_DOS_NULL.                                   ;89980
;***********************************************************************;89980
;103570   11/23/94 defect 103570 ChangeTeam                             ;103570
;         Set AX to 6700 in $ExtHandle because SVC_DEMEXTHANDLE may have;103570
;         changed the AX register.                                      ;103570
;***********************************************************************;103570
;   $File_Times

.xlist
include v86seg.inc

.xcref
include dpl.inc                    ;BN008
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include dossymc.inc
include filemode.inc
include opncreat.inc
include error.inc
include mi.inc
include mvdmexp.inc
include demsvc.inc
include dirent.inc
include pdb.inc
include demdbcs.inc
include devhdr.inc
include dos3dev.inc
include syscalls.inc
include extattr.inc
include finddta.inc                ;73436

.cref
.list
        CpuMode 386

;m        ReferV86    ConSwap,BYTE
;m        ReferV86    ConSFT,DWORD
;BD003        ReferV86    CurrentPDB,WORD
        ReferV86    Temp_Var,WORD
        ReferV86    ExtErr_Locus,BYTE
        ReferV86    ExtErr,WORD
        ReferV86    os2_handled,BYTE       ;mdr
;CHGTM2        ReferV86    find_first_flag,BYTE   ;mdr
        ReferV86    search_first_flag,BYTE ;mdr
        ReferV86    pOldInt21,DWORD        ;mdr
        ReferV86    handle_map,BYTE        ;mdr
        ReferV86    handle_count,BYTE      ;mdr
        ReferV86    drivemap,BYTE          ;BN001
        ReferV86    Find_First_DTA         ;73436


V86CODE SEGMENT
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

        EXTRN   JFNFree:NEAR
        EXTRN   RMDevCheckName:NEAR
;BD005     EXTRN   RMDevAllocDI:NEAR
        EXTRN   pJFNFromHandle:NEAR
        EXTRN   Sys_Ret_OK:NEAR
        EXTRN   Sys_Ret_Err:NEAR
        EXTRN   Sys_Return:NEAR
;        EXTRN   RMDevWrite:NEAR
        EXTRN   VSFNFromHandle:NEAR
;        EXTRN   RMDevRead:NEAR
        EXTRN   Get_User_Stack:NEAR
;BD005     EXTRN   SFFromSFN:NEAR
;BD005     EXTRN   RMDevCloseDI:NEAR
;        EXTRN   RMDevOpen:NEAR
;        EXTRN   RMDevClose:NEAR
;        EXTRN   $Alloc:NEAR
;        EXTRN   $Dealloc:NEAR
;BD005     EXTRN   RMDevCheck:NEAR
;BD005     EXTRN   RMDevXFlags:NEAR
        EXTRN   FCB_Return:NEAR
        EXTRN   VMcheck_handle:NEAR     ; mdr
        EXTRN   VMcheck_fname:NEAR      ; mdr
        EXTRN   VMcheck_extended:NEAR   ; mdr
        EXTRN   VMcheck_fcb:NEAR        ; mdr
        EXTRN   check_dos:NEAR          ;BN001
        EXTRN   check_map:NEAR          ;BN001

;***LP  Set_EA_Field - Check if the current PDB process is EA aware.
;       In any casr update the TCB field to let the kernel proper know
;       EA awareness.
;
;       ENTRY
;           None
;
;       EXIT
;           None (TCB field set if EA aware PDB)
;
;       USES
;           None
;
Procedure Set_EA_Field,NEAR

        SaveReg <ds,ax,bx>              ;BC003

        mov     ah,51h                  ;BN003 get currentPDB from DOS
        pushf                           ;BN003
        call    cs:[pOldInt21]          ;BN003
        mov     ds,bx                   ;BN003 move PDB to DS

        xor     ax,ax                   ; by default PDB not EA aware
        test    WORD PTR ds:[PDB_flags],EKNOWEAS
        jz      short not_ea_aware
        inc     ax                      ; Yes, PDB is EA Aware
not_ea_aware:
        SVC     SVC_DEMSETEAFIELD       ; Set the TCB field

        RestoreReg  <bx,ax,ds>          ;BC003
        ret

EndProc   Set_EA_Field

;***LP  $Open - open a file.  Int21 interlude to DemOpen
;***    $OpenExtended - allow the full range of OS/2 open modes
;***LP  $Open_Exec_Only - open a file for execution  Int21 interlude to DemOpen exec_only BN040
;
;       ENTRY
;           DS:DX
;               pointer to ASCIIZ name
;           AL ($OPEN)
;               open mode
;           CX ($OpenExtended)
;               open mode
;
;       EXIT
;           SUCCESS
;               User_Flags.CY = 0
;               User_AX = handle
;           FAILURE
;               User_Flags.CY = 1
;               User_AX = error code
;
;       CONTEXT
;           Executes in V86 mode
;
;       STEPS
;           hFile = JFNFree
;           if handle available -->
;               dev = RMDevCheckName
;               if OS2 Device -->
;                   SFN2 = DemOpen
;                   if device -->
;                       SFN = RMDevAllocDI(SFN2)
;                   else -->
;                       SFN = SFN2
;               else -->
;                   SFN = RMDevAllocDI(dev)
;                   DI.ptr = dev
;               DemSetHandle(hFile, SFN)
;
;       NOTES
;           None
;
;       WARNINGS
;           None
;
;       CALLS
;           DemOpen (SVC)
;           DemClose (SVC)
;           Sys_Ret_OK
;           Sys_Ret_Err
;           JFNFree
;           pJFNFromHandle
;           RMDevAllocDI
;           RMDevCheckName
;
;       USES
;           AX,BX,CX,DX,SI,DI,ES,DS
;

Procedure $OpenExtended,NEAR

LocalVar  pszSpec,DWORD
LocalVar  uMode,WORD
LocalVar  execonly,WORD                 ; DOSflag     exec_only BN040
LocalVar  opx_execdw,DWORD              ; work varb   exec_only BN040

        mov     BL,1                    ; set for not exec_only BN040
        mov     ax,cx                   ; Allow extended open mode
        jmp     short opn1

Entry   $Open_Exec_Only
        mov     BL,2                    ; set for     exec_only BN040
        jmp     short opn0              ; exec_only BN040

Entry   $Open
        mov     BL,3                    ; set for not exec_only BN040
        push    si                      ;                                74297
        mov     si,dx                   ;                                74297
        cmp     dword ptr ds:[si],'ved/'; Does name begin "/dev"?        74297
        jne     opn00                   ;                                74297
        cmp     byte ptr ds:[si+4],'/'  ; Does name begin "/dev/"?       74297
        jne     opn00                   ;   No, continue.                74297
        mov     byte ptr ds:[si],'\'    ;   Yes, change the slashes.     74297
        mov     byte ptr ds:[si+4],'\'  ;                                74297
opn00:  pop     si                      ;                                74297

opn0:   call    VMcheck_fname           ; mdr return if dos drive
Entry   $INTERNAL_OPEN                  ; mdr entry to bypass drive checking
        test    al, open_monitor
        jnz     opn13                   ; Exit if prot-mode flag
        xor     ah,ah                   ; dis-allow extended modes

        call    Set_EA_Field            ; Set the TCBNewFlags be set for EAs

opn1:   EnterProc

        cmp    bl,2                     ; if this was from $open_exec_only    exec_only BN040
        jz     short opn1a              ; then go to preserve open_mode flag  exec_only BN040

; assume $OpenExtended or $Open was called      exec_only BN040

        xor     BH,BH                   ; exec_only BN040
        and     BH, not EXECOPEN        ; exec_only BN040

opn1a:  mov     byte ptr execonly,BH    ; exec_only BN040
        xor     BX,BX                   ; exec_only BN040

        mov     uMode,ax                ; Save the mode for later
        mov     pszSpec.loword,dx
        mov     pszSpec.hiword,ds
        call    JFNFree                 ; Find a free handle
        jc      opn9                    ; Exit if none available
;mdr         mov     hFile,bx                ; Save the handle

opn2:   lds     dx,pszSpec
;m        call    RMDevCheckName          ; See if it's a DOS device
;m        jnc     short OpenDev           ; Skip if a DOS device
        mov     si,dx                   ; ds:si = filespec
        mov     bx,uMode                ; Get mode
        mov     cx,0                    ; Attributes don't matter
        xor     ax,ax
        mov     es,ax                   ; No EA's
        mov     di,ax


;------ initialize Exec_only flag from the loader     exec_only BN040

        push    edx                        ; 112811
        xor     edx,edx                    ; zero temp reg                    exec_only BN040
        mov     opx_execdw,edx             ; zero save area                   exec_only BN040
        mov     dh,byte ptr execonly       ; get DOSFLAG in dh                exec_only BN040
        mov     word ptr opx_execdw+1,dx   ; save dx in hi word               exec_only BN040
        mov     edx,opx_execdw             ; restore edx with edl as DOSFLAG  exec_only BN040
        mov     dx,exist_open+nexist_fail  ; OPEN, fail if does not exist     exec_only BN040

        SVC     SVC_DEMOPEN             ; Open the OS/2 file/device
        pop     edx                     ; 112811
        jc      opn9                    ; exit if error

;BD005     test    bx,RMDI_DEVICE
;BD005     jz      short opn5              ; skip if not a device
;BD005     mov     es,ax                   ; Real handle to ES
;BD005     mov     ax,bx                   ; flags to AX
;BD005     mov     bx,-1                   ; Flag as an OS/2 device
;BD005     jmp     opn4                    ; Jump to common device code
;BD005
;BD005; This is a device.
;BD005;   DOS device - ES:BX points to device header, ax=rmdi_flags
;BD005;   OS2 device - BX = -1, ES=os2 VSFN, AX=rmdi_flags
;BD005;
;BD005opn4:   call    RMDevAllocDI            ; Assign a DevInfo entry (V86 SFT)
;BD005        jc      opn10                   ; exit if none available
;BD005
;BD005;       AX = V86 SFN (e.g. 235..254)

opn5:   push    bx                      ;BN010 save whatever's in BX just in case
        mov     bx,uMode                ;BN010 put open mode into BX
        call    open_DOS_NULL           ; mdr
        pop     bx                      ;BN010 restore BX
        jc      opn10                   ;BC004 exit if error

        LeaveProc NoCheck
        jmp     Sys_Ret_OK

opn9:   LeaveProc NoCheck               ; Return error to the app
        jmp     Sys_Ret_Err

opn10:  push    ax                      ; Save the error code
        SVC     SVC_DEMCLOSE            ; Close the OS2 device
opn11:  pop     ax
        jmp     opn9                    ; error exit

opn13:  mov     ax,ERROR_INVALID_ACCESS
        jmp     Sys_Ret_Err
EndProc   $OpenExtended


;** open_DOS_NULL **************************************************
;
;   FUNCTION: open dos nul device to allocate a DOS SFN
;             use SFN as index and store VSFN in VSFN table (handle_map)
;
;   ENTRY:  AX = OS/2 VSFN
;   EXIT:   AX = JFN (handle returned by DOS)
;

procedure open_DOS_NULL,NEAR

        push    ax                      ; save VSFN on stack
        push    cs                      ; set up parms and open NULL device
        pop     ds                      ; set ds for NUL name
        mov     dx,offset V86GROUP:NULL_DEVICE  ; set dx for NUL name
        mov     ax,bx                   ;BN010 use open mode from original call
        and     al,8fh                  ;77984 turn off sharing mode bits
        mov     ah,3dh                  ;BC010 func code to open file
;BD010  mov     ax,3d00h                        ; func code to open file
        pushf                                   ; push stack frame
        call    cs:[pOldInt21]                  ; let DOS do OPEN
        jc      no_null                ; return if error
        mov     bx,ax                  ; AX is new file handle
;89980  call    VSFNFromHandle         ; get the actual DOS SFN
;---start of 89980--------------------
        SaveReg <es,di>
        call    pJFNFromHandle         ; get JFN entry
        jc      short opdn10
        movzx   bx,byte ptr es:[di]    ; get SFN entry
        cmp     bl,-1                  ; verify SFN is valid
        je      short opdn10
        clc
        jmp     short opdn20
opdn10: stc
opdn20: RestoreReg <di,es>
;---end of 89980----------------------
        jc      no_null                ; return if a problem
                                       ; SFN now in BX for use as index
        pop     cx                     ; get saved VSFN for os2 file
        mov     cs:handle_map[bx],cl   ; put VSFN in handle table
        inc     cs:handle_count[bx]    ; increment ref count
        clc                            ; operation succeeded
        ret                            ; return with JFN in AX
no_null:                               ;
        pop     bx                     ; pop original VSFN off stack into BX  ;BC004
        ret                            ; return (carry already set)

NULL_DEVICE  db 'NUL',0
endproc open_DOS_NULL


;***    $Read - Read from a file handle.  Int21 interlude to w_Read
;
;       Call DemRead to read data into user space, do error
;       processing on return.
;       This is an Int21 dispatcher interlude routine.
;
;       ENTRY   BX    =  handle
;               CX    =  count
;               DS:DX -> buffer
;
;       EXIT    Carry Clear
;                       it worked (must still check ax)
;                       AX has number of bytes read
;               Carry Set
;                       it didn't work
;                       AX = ERROR_INVALID_HANDLE
;                          = ERROR_ACCESS_DENIED
;
;       CALLS
;           DemRead
;           Sys_Ret_OK
;           Sys_Ret_Err
;           VSFNFromHandle
;           RMDevCheck
;           RMDevRead
;
        ASSUME      CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $Read,near
        call    VMcheck_handle          ; mdr convert handle or return
;mdr        call    VSFNFromHandle          ; get the VSFN
;mdr        jc      short rd3               ; exit if bad handle
;mdr        call    RMDevCheck
;mdr        jnz     short rd2               ; skip if an RM device
        SVC     SVC_DEMREAD             ; let OS/2 do the work for files & devs
        jc      short rd3               ; skip if error
rd1:    jmp     Sys_Ret_OK              ; return A-OK

;mdrrd2:    call    RMDevRead               ; let RMDevRead do the read
;mdr        jnc     short rd1
rd3:    jmp     Sys_Ret_Err
EndProc   $Read

;***LP  $Write - write to a file.  Int21 interlude to DemWrite
;
;       ENTRY
;           BX
;               file handle
;           CX
;               number of bytes to write
;           DS:DX
;               Address of data to write
;
;       EXIT
;           SUCCESS
;               AX = # of bytes written
;               exit through Sys_Ret_OK
;           FAILURE
;               exit through Sys_Ret_Err
;
;       CONTEXT
;           Executes in V86 mode
;
;       STEPS
;
;       NOTES
;           None
;
;       WARNINGS
;           None
;
;       CALLS
;
;       USES
;           AX,BX,CX,DX,SI,DI,DS,ES

        ASSUME CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $Write,near
        call    VMcheck_handle          ; mdr convert handle or return
;mdr        call    VSFNFromHandle          ; get the VSFN
;mdr        jc      short wr3               ; exit if bad handle
;mdr        call    RMDevCheck
;mdr        jnz     wr2                     ; skip if an RM device
        SVC     SVC_DEMWRITE            ; let OS/2 do the work for files & devs
        jc      short wr3               ; skip if error
wr1:    jmp     Sys_Ret_OK              ; return A-OK

;mdrwr2:    call    RMDevWrite              ; let RMDevWrite do the write
;mdr        jnc     short wr1
wr3:    jmp     Sys_Ret_Err
EndProc     $Write

;***    $Close - return a handle to the system.  Int21 interlude to DemClose
;
;       Call DemClose to return a handle to the system,
;       do error processing on return.
;       This is an Int21 dispatcher interlude routine.
;
;       ENTRY   BX = handle
;
;       EXIT    Carry Clear
;                       it worked
;               Carry Set
;                       AX = ERROR_INVALID_HANDLE
;
;       CALLS   DemClose, Sys_Ret_Err, Sys_Ret_OK, RMDevCloseDI, VSFNFromHandle
;
;       NOTE:   Jeff Harbers and Multiplan hard disk copy rely on certain
;               values when $Close succeeds even though we document it as
;               trashing AX.
;
;ANOTHERNOTE:   God knows what these certain values are.  I'm not doing
;               anything to provide them -- danno
;
;       USES:   AX,BX,CX,DX,SI,DI,ES,DS
;
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $Close,near
        mov     dx,bx                   ; save handle in dx
        call    VMcheck_handle          ; convert handle or return
        mov     cx,bx                   ; save VSFN

;BD005        call    RMDevCheck              ; (BX) = real handle if OS2 dev or file
;BD005        jnc     clo10                   ; mdr if device go over
        SVC     SVC_DEMCLOSE            ; else close os2 file

;BD005        jmp     short clo30             ; mdr ignore error, finish close
;BDclo10:  mov     bx,cx                   ; mdr get VSFN
;BD005        call    RMDevCloseDI            ; mdr close the DevInfo entry
                                        ; ignore error, finish close
clo30:  mov     bx,dx                   ; get handle to close
        call    pJFNFromHandle          ; get address of JFN entry
        movzx   bx,byte ptr es:[di]     ; get SFN from JFT to use as index
        dec     byte ptr cs:handle_count[bx]   ; mdr decrement ref count
        cmp     byte ptr cs:handle_count[bx],0 ; mdr see if refcnt is 0
        jnz     clo50                          ; mdr no? don't release entry
        mov     byte ptr cs:handle_map[bx],-1  ; mdr empty out VSFN table entry

clo50:  mov     ah,3eh                  ; func code to close file
        mov     bx,dx                   ; get handle to close
        pushf                           ; push stack frame
        call    cs:[pOldInt21]          ; have DOS close NUL file
        jmp     Sys_Ret_OK              ;

clo60:  jmp     Sys_Ret_Err             ;

EndProc   $Close

;***    $LSeek - move r/w pointer.  Int21 interlude to w_LSeek
;
;       Call DemChgFilePtr to perform work.  On return, stash return values
;       in proper user registers (in User_* on user stack), and do error
;       code processing in case of error.
;       This is an int21 dispatcher interlude routine.
;
;       Assembler usage:
;               MOV     DX, offsetlow
;               MOV     CX, offsethigh
;               MOV     BX, handle
;               MOV     AL, method
;               MOV     AH, LSeek
;               INT     int_command
;
;       Return:
;               NC -> no error
;                     DX:AX has the new location of the pointer
;               CY -> error
;                     AX = ERROR_INVALID_HANDLE
;                        = ERROR_INVALID_FUNCTION
;                     Fatal UserError if seek ends up at a negative location
;
;       CALLS   w_LSeek, Sys_Ret_OK, Sys_Ret_Err
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $LSeek,NEAR
        call    VMcheck_handle          ; mdr convert handle or return
;mdr        call    VSFNFromHandle          ; Get the VSFN
;mdr        jc      short lsk2              ; exit if bad handle
;mdr        call    RMDevCheck
;mdr        jnc     short lsk3              ; Skip if RM or OS/2 device
        SVC     SVC_DEMCHGFILEPTR       ; Let OS/2 do all the work for files
        jc      short lsk2              ; Skip if error
lsk1:   call    get_user_stack
        MOV     DS:[SI.User_DX],DX      ; return DX:AX
        jmp     Sys_Ret_OK              ; return A-OK

lsk2:   jmp     Sys_Ret_Err

;mdrlsk3:   xor     ax,ax
;mdr        mov     dx,ax                   ; Return position zero for devices
;mdr        jmp     short lsk1
EndProc   $LSeek

;***    $File_Times - modify write time on handle.
;
;       Call FileTimes or Ext_Information to do work, set up return values,
;       do exit processing. This is an Int21 dispatcher interlude routine.
;
;       Assembler usage:
;               MOV AH, FileTimes
;               MOV AL, func
;               MOV BX, handle
;       ; if AL = 1 then next two are mandatory
;               MOV CX, time
;               MOV DX, date
;       ; if AL = 2 or 3 (query/set EAs) then next four are mandatory
;               MOV CX, cbInfoBuf
;               MOV DX, InfoLevel
;               LDS SI, asciiz filename (if handle = -1)
;               LES DI, InfoBuf
;               INT 21h
;       ; if AL = 0 then CX/DX has the last write time/date
;       ; for the handle.
;
;       Error returns:
;               AX = ERROR_INVALID_FUNCTION
;                  = ERROR_INVALID_HANDLE
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $File_Times,near
        cmp     al,2
        jae     short GetExtAttr        ; Skip if getting extattribute info
;mdr        call    VSFNFromHandle          ; Get the VSFN
;mdr        jc      short ftm3              ; exit if bad handle
;mdr        call    RMDevCheck
;mdr        jnz     short ftm4              ; Skip if a real-mode device
        call    VMcheck_handle          ; mdr convert handle or return
ftm1:   SVC     SVC_DEMFILETIMES        ; Let OS/2 do all the work for files
        jc      short ftm3              ; Skip if error
ftm2:   call    get_user_stack
        mov     [SI.User_CX],CX         ; time
        mov     [SI.User_DX],DX         ; date
        jmp     Sys_Ret_OK              ; return A-OK

ftm3:   jmp     Sys_Ret_Err

;mdrftm4:   xor     ax,ax                   ; it's a DOS device
;mdr        mov     cx,ax
;mdr        mov     dx,ax                   ; zero date and time
;mdr        jmp     short ftm2

GetExtAttr:
        cmp     al,3                    ;mdr  COMMAND.COM calls func 4!?
        jg      ftm6                    ;mdr  just return
        or      cx,cx                   ;mdr  COMMAND.COM passes 0 CX!?
        jz      ftm6                    ;mdr  just return
        cmp     dx,3                    ;mdr  COMMAND.COM passes bad info!?
        jg      ftm6                    ;mdr  just return
        cmp     bx,-1
        je      short ftm5
;mdr        call    VSFNFromHandle          ; Get the VSFN
;mdr        jc      short ftm3              ; exit if bad handle
        call    VMcheck_handle          ;mdr convert handle or return
ftm5:   SVC     SVC_DEMEXTINFO
ftm6:   jmp     Sys_Return
EndProc   $File_Times


;***    $Commit - Flush pending buffers to disk
;
;       Call DemCommit to return a handle to the system,
;       do error processing on return.
;       This is an Int21 dispatcher interlude routine.
;
;       ENTRY   BX = handle
;
;       EXIT    Carry Clear
;                       it worked
;               Carry Set
;                       AX = ERROR_INVALID_HANDLE
;
;       CALLS   DemCommit, Sys_Ret_OK, Sys_Ret_Err
;
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $Commit,near
        call    VMcheck_handle          ; mdr convert handle or return
;mdr        call    VSFNFromHandle          ; Get the VSFN
;mdr        jc      short cm1               ; exit if bad handle
;mdr        call    RMDevCheck
;mdr        jnc     short cm1               ; Skip if RM or OS/2 device
        SVC     SVC_DEMCOMMIT           ; Let OS/2 do all the work for files
cm1:    jmp     Sys_Return
EndProc $Commit


;***    $Dup - Duplicate a handle to any available handle
;
;       Call DemDup to return a handle to the system,
;       do error processing on return.
;       This is an Int21 dispatcher interlude routine.
;
;       ENTRY   BX = handle
;
;       EXIT    Carry Clear
;                   it worked
;                   AX = new handle
;               Carry Set
;                   AX = ERROR_INVALID_HANDLE
;
;       CALLS   DemDup, Sys_Ret_OK, Sys_Ret_Err
;
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $Dup,near

        mov     dx,bx                   ; mdr save handle in dx
        call    VMcheck_handle          ; mdr convert handle or return
        push    bx                      ; mdr save VSFN
        call    short JFNFree           ; Find a free virtual handle
        pop     bx                      ; mdr restore VSFN
        jc      short DupErr            ; Exit if no new handle available


;   $Dup and $Dup2 common code
;
;   BX = VSFN
;   DX   = handle to dup

Entry   Dup_Common,near,local
;BD005     call    RMDevCheck              ; mdr see if file or device     ;BC002
;BD005     jc      dp2                     ; mdr Skip if OS2 file          ;BC002
;BD005     SVC     SVC_DEMDUP              ; Do the OS2 DUP , BX=VSFN      ;BC002
;BD005     jc      short DupErr            ; Skip if error                 ;BC002
;BD005     inc     es:[di].rmdi_refcnt     ; increment reference count     ;BC002
;BD005     jmp     short dos_dup                                           ;BC002

dp2:    SVC     SVC_DEMDUP              ; Do the OS2 DUP , BX=VSFN
        jc      short DupErr            ; Skip if error
        mov     bx,dx                   ; get handle to dup from dx
        call    pJFNFromHandle          ; get pointer into JFT
        movzx   bx,byte ptr es:[di]     ; get SFN from JFT
        inc     cs:handle_count[bx]     ; increment ref count

dos_dup:                                ; DOS will transfer SFN to new slot
        mov     cs:os2_handled,0        ; let DOS do DUP also
        ret

DupErr:
        jmp     Sys_Ret_Err

EndProc $Dup

;***    $Dup2 - $Dup - Duplicate a handle to specified handle
;
;       Close the new handle and transfer to Dup_Common to
;       perform the dup.
;
;       ENTRY   BX = handle
;               CX = new handle
;
;       EXIT    Carry Clear
;                   it worked
;                   AX = new handle
;               Carry Set
;                   AX = ERROR_INVALID_HANDLE
;
;       CALLS   Dup_Common, DupErr
;
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $Dup2,near

        cmp     bx,cx           ; sudeepb PTR B786581
        jne     dupcont
        mov     ax,ERROR_INVALID_HANDLE
        jmp     short DupErr

dupcont:
        mov     dx,bx                   ; mdr save handle to dup in dx
        call    VSFNFromHandle          ; mdr Get the VSFN
        jc      short DupErr            ; mdr exit if bad handle
        jnz     os2_dup                 ; mdr we handle if os2 handle
        mov     bx,cx                   ; mdr check out second handle
        call    VSFNFromHandle          ; mdr Get the VSFN
        jc      short dos_dup           ; mdr if bad handle let DOS do dup
        jz      short dos_dup           ; mdr we do dup if os2 handle


; first thing to do is close the old handle. call int 21 so appropriate
; file system handles call.

os2_dup:                                ; mdr
        mov     bx,cx                   ; mdr Get the new handle
        mov     ah,3eh                  ; mdr close function code
        int     21h                     ; mdr Close the new handle
;BD005        jc      short DupErr            ; mdr Exit if trouble closing new handle

; next thing is to copy old handle to new (really copy old JFN slot contents
; to new slot). So, if old handle is os2 handle then goto DUP common code,
; else let DOS handle dup (which it can do because we closed dest handle).

        mov     bx,dx                   ; mdr get dup handle
        call    VSFNFromHandle          ; mdr Get the VSFN in to BX
        jnz     Dup_Common              ; mdr Jump to common code if os2 handle

        jmp     short dos_dup           ; mdr let DOS finish DUP

EndProc $Dup2,NoCheck

BREAK <$ExtHandle - extend handle count>

;
;   Assembler usage:
;           MOV     BX, Number of Opens Allowed (MAX=65534;66535 is
;           MOV     AX, 6700H                    reserved to mark SFT
;           INT     int_command                  busy )
;
;   Error return:
;           AX = error_not_enough_memory
;                or error_too_many_open_files
;   No registers returned

        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $ExtHandle,NEAR

        SVC     SVC_DEMEXTHANDLE        ; Grow real JFN as well     57397
        jc      exh_bad                 ;                           57397
        pushf                           ; mdr push stack frame
        mov     ax,6700h                ; set ax to correct value  103570
        call    cs:[pOldInt21]          ; mdr let DOS do INT
        jc      exh_bad                 ; mdr return if error from DOS

;                       ;XOR     BP,BP                   ; 0: enlarge   1: shrink  2:psp
;                       ;        CMP     BX,FilPerProc           ;  < 20
;                       ;        JAE     short getpdb            ;  no
;                       ;        MOV     BX,FilPerProc           ;  bx = 20
;                       ;
;                       ;getpdb:
;                       ;        MOV     ES,[CurrentPDB]         ; get user process data block
;                       ;        MOV     CX,ES:[PDB_JFN_Length]  ; get number of handle allowed
;                       ;        CMP     BX,CX                   ; the requested == current
;                       ;        JE      short ok_done           ; yes and exit
;                       ;        JA      short larger            ; go allocate new table
;                       ;
;                       ;        MOV     BP,1                    ; shrink
;                       ;        MOV     DS,WORD PTR ES:[PDB_JFN_Pointer+2] ;
;                       ;        MOV     SI,BX                   ;
;                       ;        SUB     CX,BX                   ; get difference
;                       ;chck_handles:
;                       ;        CMP     BYTE PTR DS:[SI],-1     ; scan through handles to ensure close
;                       ;        JNZ     short too_many_files    ; status
;                       ;        INC     SI
;                       ;        LOOP    chck_handles
;                       ;
;                       ;        SVC     SVC_DEMEXTHANDLE        ; Shrink Real JFN too
;                       ;        CMP     BX,FilPerProc           ; = 20
;                       ;        JA      short larger            ; no
;                       ;
;                       ;        MOV     BP,2                    ; psp
;                       ;        MOV     DI,PDB_JFN_Table        ; es:di -> jfn table in psp
;                       ;        PUSH    BX
;                       ;        JMP     short movhandl
;                       ;
;                       ;larger:
;                       ;        CMP     BX,-1                   ; 65535 is not allowed
;                       ;        LJZ     invalid_func
;                       ;        CLC
;                       ;        PUSH    BX                      ; save requested number
;                       ;        ADD     BX,0FH                  ; adjust to paragraph boundary
;                       ;        MOV     CL,4
;                       ;        RCR     BX,CL                   ; DOS 4.00 fix                          ;AC000;
;                       ;        AND     BX,1FFFH                ; clear most 3 bits
;                       ;
;                       ;;mdr        PUSH    BP
;                       ;;mdr        call    $ALLOC                  ; allocate memory
;                       ;        mov     ah,48h                  ;mdr
;                       ;        int     21h                     ;mdr
;                       ;;mdr        POP     BP
;                       ;        JC      short no_memory         ; not enough meory
;                       ;
;                       ;        MOV     ES,AX                   ; es:di points to new table memory
;                       ;        XOR     DI,DI
;                       ;
;                       ;        POP     BX
;                       ;        PUSH    BX
;       SVC     SVC_DEMEXTHANDLE        ; Grow real JFN as well
;       jc      exh_bad                 ; mdr
;                       ;        jnc     short movhandl          ; PTRB708453
;                       ;;mdr        call    $DEALLOC
;                       ;        mov     ah,49h                  ;mdr
;                       ;        int     21h                     ;mdr
;                       ;        jmp     short no_memory
;                       ;
;                       ;movhandl:
;                       ;        MOV     DS,[CurrentPDB]         ; get user PDB address
;                       ;
;                       ;        TEST    BP,3                    ; enlarge ?
;                       ;        JZ      short enlarge           ; yes
;                       ;        POP     CX                      ; cx = the amount you shrink
;                       ;        PUSH    CX
;                       ;        JMP     short copy_hand
;                       ;ok_done:
;                       ;        mov     cs:os2_handled,0        ; mdr do this function under dos too
         jmp     Sys_Ret_OK
exh_bad: jmp     Sys_Ret_Err
;                       ;too_many_files:
;                       ;        error   error_too_many_open_files
;                       ;enlarge:
;                       ;        MOV     CX,DS:[PDB_JFN_Length]    ; get number of old handles
;                       ;copy_hand:
;                       ;        MOV     DX,CX
;                       ;        LDS     SI,DS:[PDB_JFN_Pointer]   ; get old table pointer
;                       ;ASSUME DS:NOTHING
;                       ;        REP     MOVSB                   ; copy infomation to new table
;                       ;
;                       ;        POP     CX                      ; get new number of handles
;                       ;        PUSH    CX                      ; save it again
;                       ;        SUB     CX,DX                   ; get the difference
;                       ;        MOV     AL,-1                   ; set availability to handles
;                       ;        REP     STOSB
;                       ;
;                       ;        MOV     DS,[CurrentPDB]         ; get user process data block
;                       ;        CMP     WORD PTR DS:[PDB_JFN_Pointer],0 ; check if original table ptr
;                       ;        JNZ     short update_info       ; yes, go update PDB entries
;                       ;;mdr        PUSH    BP
;                       ;;mdr        PUSH    DS                      ; save old table segment
;                       ;        PUSH    ES                      ; save new table segment
;                       ;        MOV     ES,WORD PTR DS:[PDB_JFN_Pointer+2] ; get old table segment
;                       ;;mdr        call    $DEALLOC                ; deallocate old table meomory
;                       ;        mov     ah,49h                  ;mdr
;                       ;        int     21h                     ;mdr
;                       ;        POP     ES                      ; restore new table segment
;                       ;;mdr        POP     DS                      ; restore old table segment
;                       ;;mdr        POP     BP
;                       ;update_info:
;                       ;        TEST    BP,2                    ; psp?
;                       ;        JZ      short non_psp           ; no
;                       ;        MOV     WORD PTR DS:[PDB_JFN_Pointer],PDB_JFN_Table   ; restore
;                       ;        JMP     short final
;                       ;non_psp:
;                       ;        MOV     WORD PTR DS:[PDB_JFN_Pointer],0 ; new table ptr offset always 0
;                       ;final:
;                       ;        MOV     WORD PTR DS:[PDB_JFN_Pointer+2],ES ; update table ptr segment
;                       ;        POP     DS:[PDB_JFN_Length]      ; restore new number of handles
;                       ;        jmp     Sys_Ret_OK
;                       ;no_memory:
;                       ;        POP     BX                      ; clean stack
;                       ;        error   error_not_enough_memory
;                       ;invalid_func:
;                       ;        error   error_invalid_function
EndProc   $ExtHandle

;***    $LockOper - Lock/Unlock file region
;
;       ENTRY   AL = 0 Lock AL = 1 Unlock
;               BX = handle
;               CX:DX - Start address of region to be locked
;               SI:DI - length of region
;
;       EXIT    Carry Clear
;                       it worked
;               Carry Set
;                       AX = ERROR_INVALID_HANDLE
;                          = ERROR_INVALID_FUNCTION
;                          = ERROR_LOCK_VIOLATION
;                          = ERROR_ACCESS_DENIED
;
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $LockOper,near
        call    VMcheck_handle          ; mdr convert handle or return
;mdr        call    VSFNFromHandle          ; Get the VSFN
;mdr        jc      short lk3               ; exit if bad handle
;mdr        call    RMDevCheck
;mdr        jnc     short lk3               ; Skip if a device
        xor     ah,ah
        SVC     SVC_DEMLOCKOPER         ; Let OS/2 do all the work for files
        jc      short lk4               ; Skip if error
        jmp     Sys_Ret_OK              ; return A-OK

;mdrlk3:    mov     ax,ERROR_INVALID_HANDLE ; Can't lock a device
lk4:    jmp     Sys_Ret_Err
EndProc   $LockOper

BREAK <$CHMOD - change file attributes>
;
;   Assembler usage:
;           LDS     DX, name
;           MOV     CX, attributes
;           MOV     AL,func (0=get, 1=set)
;           INT     21h
;   Error returns:
;           AX = error_path_not_found
;           AX = error_access_denied
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $CHMOD,NEAR
        call    VMcheck_fname           ; mdr return if a dos drive
;m        push    ax
;m        push    cx
;m        call    RMDevCheckName          ; V86 Device?
;m        pop     cx
;m        pop     ax
;m        jnc     short chm1              ; can't CHMOD a device
        SVC     SVC_DEMCHMOD
        jc      short chm2
        call    get_user_stack
        mov     [si].User_CX,cx
        jmp     Sys_Ret_OK

;mchm1:   mov     ax,ERROR_FILE_NOT_FOUND
;m        mov     EXTERR_LOCUS,errLoc_Unk ; extended error locus
chm2:   jmp     Sys_Ret_Err
EndProc   $CHMOD

BREAK <$Creat - create a brand-new file>

;
;   $Creat - create the directory entry specified in DS:DX and give it the
;       initial attributes contained in CX
;   Inputs:     DS:DX - ASCIZ path name
;               CX - initial attributes
;   Outputs:    Carry set - AX has error code
;               Carry reset - AX has handle
;   Registers modified: all
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $Creat,NEAR
;75567 LocalVar  crt_execdw,DWORD              ; exec_only BN040

        call    VMcheck_fname           ; mdr return if dos drive
;m        push    cx
;m        call    RMDevCheckName
;m        pop     cx
;m        jnc     $OpenExtended           ; error if a device has that name

        call    JFNFree                 ; find a free handle
        jc      Sys_Ret_Err             ; exit if none available

;mdr        push    bx
        mov     si,dx                   ; ds:si = filespec
        mov     bx,sharing_compat+open_for_both ; Open for read/write
        xor     ax,ax
        mov     es,ax                   ; no EA's
        mov     di,ax

;------ initialize Not Exec_only flag from the loader                            exec_only BN040
        push    edx                        ; 112811
        xor     edx,edx                    ; only need Edl part                  exec_only BN040
;75567  mov     crt_execdw,edx             ; zero save area                      exec_only BN040
;75567  and     dh, not EXECOPEN           ; set exec_only bit off               exec_only BN040
;75567  mov     word ptr crt_execdw+1,dx   ; save dx in hi word                  exec_only BN040
;75567  mov     edx,crt_execdw             ; restore edx with edl as DOSFLAG     exec_only BN040
        mov     dx,exist_replace+nexist_create

        SVC     SVC_DEMOPEN             ; open the OS/2 file/device
        pop     edx                     ; 112811
;mdr        pop     bx
open_common:                            ;BN004 start of common open code
        jc      Sys_Ret_Err

        push    bx                      ;BN010 save whatever's in BX
        mov     bx,sharing_compat+open_for_both ;BN010 use open mode from above
        call    open_DOS_NULL           ; mdr save VSFN in handle table
        pop     bx                      ;BN010 restore BX
        jnc     Sys_Ret_OK              ;BC004 everything is fine

        push    ax                      ;BN004 save return code
        SVC     SVC_DEMCLOSE            ;BN004 close file, VSFN is in BX
        pop     ax                      ;BN004 restore return code
        jmp     Sys_Ret_Err             ;BC004
EndProc $Creat

Break <$CreateNewFile - Create a new directory entry>

;
;   CreateNew - Create a new directory entry.  Return a file handle if there
;       was no previous directory entry, and fail if a directory entry with
;       the same name existed previously.
;
;   Inputs:     DS:DX point to an ASCIZ file name
;               CX contains default file attributes
;   Outputs:    Carry Clear:
;                   AX has file handle opened for read/write
;               Carry Set:
;                   AX has error code
;   Registers modified: All
;
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $CreateNewFile,near
        call    VMcheck_fname           ; mdr return if dos drive
;m        push    cx
;m        call    RMDevCheckName
;m        pop     cx
;m        jnc     $OpenExtended           ; open device

        call    JFNFree                 ; find a free handle, (BX) = JFN
        jc      Sys_Ret_Err             ; exit if none available

        SVC     SVC_DEMCREATENEW
        jmp     open_common             ;BN004 jump to common open code
EndProc   $CreateNewFile

Break   <$CreateTempFile - create a unique name>

;
;   $CreateTemp - given a directory, create a unique name in that directory.
;       Method used is to get the current time, convert to a name and attempt
;       a create new.  Repeat until create new succeeds.
;
;   Inputs:     DS:DX point to a null terminated directory name.
;               CX  contains default attributes
;   Outputs:    Unique name is appended to DS:DX directory.
;               AX has handle
;   Registers modified: all
;
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $CreateTempFile,near
        call    VMcheck_fname           ; mdr return if dos drive
        call    JFNFree                 ; find a free handle
        jc      Sys_Ret_Err             ; exit if none available

        SVC     SVC_DEMCREATETEMP
        jmp     open_common             ;BN004 jump to common open code
EndProc   $CreateTempFile

Break   <Extended_Open- Extended open the file>

; Input: AL= 0 (no ext attr) or 1 (ext attr)  AH=6CH
;        BX= mode
;        CL= create attribute  CH=search attribute (from server)
;        DX= flag
;        DS:SI = file name
;        ES:DI = parm list
;                          DD  SET EA list (-1) null
;                          DW  n  parameters
;                          DB  type (TTTTTTLL)
;                          DW  IOMODE
; Function: Extended Open
; Output: carry clear
;                    AX= handle
;                    CX=1 file opened
;                       2 file created/opened
;                       3 file replaced/opened
;         carry set: AX has error code
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $Extended_Open,NEAR                        ;AN000;

LocalVar    usMode,WORD
LocalVar    pExtAttr,DWORD
LocalVar    fExtAttr,WORD
LocalVar    xop_execdw,DWORD              ; exec_only BN040

        call    VMcheck_extended        ; mdr return if dos drive
        EnterProc
        test    bx,open_monitor         ; PTRB708452 SB: 1.2 compatible
        jz      short exo5
        mov     ax,ERROR_INVALID_ACCESS
        jmp     exo50

exo5:   cmp     al,1
        ja      exo40                   ; Exit if reserved mode
;mdr        test    dx,o_flag_reserved      ; mdr COMMAND.COM uses bad flags
;mdr        jnz     exo40                   ; Exit if bad create flags
        xor     dh,dh             ; mdr os2 doesn't like you to touch high bits
        mov     fExtAttr,ax
        mov     usMode,bx
        mov     pExtAttr.Offst,di
        mov     pExtAttr.Segmt,es
        call    JFNFree                 ; Find a free handle
        jc      exo50                   ; Exit if none available
;mdr        mov     hFile,bx                ; Save it for later

        call    Set_EA_Field            ; Set TCBNewFlags for EAs

        mov     bx,usMode
        les     di,pExtAttr

;------ initialize Not Exec_only flag from the loader                            exec_only BN040
        mov     ax,dx                      ; save dx in ax and init ax later     exec_only BN040
        push    edx                        ; 112811
        xor     edx,edx                    ; only need Edl part                  exec_only BN040
        mov     xop_execdw,edx             ; zero save area                      exec_only BN040
        and     dh, not EXECOPEN           ; set exec_only bit off               exec_only BN040
        mov     word ptr xop_execdw+1,dx   ; save dx in hi word                  exec_only BN040
        mov     edx,dword ptr xop_execdw   ; restore edx with edl as DOSFLAG     exec_only BN040
        mov     dx,ax                      ; restore dx part with normal value   exec_only BN040
        mov     ax,fExtAttr                ; init ax with Extended Attrib from up above exec_only BN040


        SVC     SVC_DEMOPEN             ; Open the OS/2 file/device
        pop     edx                     ; 112811
        jc      short exo50

        push    bx                      ;BN010 save whatever's in BX just in case
        mov     bx,usMode               ;BN010 put open mode into BX
        call    open_DOS_NULL           ; mdr save VSFN in handle table
        pop     bx                      ;BN010 restore BX
        jc      short exo60             ;BC004 close OS/2 file

;       (AX) = TRUE JFN = VSFN (e.g. 1..234)

;BD005     test    bx,RMDI_DEVICE
;BD005     jz      short exo10             ; skip if not a device
;BD005     mov     es,ax                   ; Real handle to ES
;BD005     mov     ax,bx                   ; flags to AX
;BD005     mov     bx,-1                   ; Flag as an OS/2 device
;BD005     jmp     short exo30             ; Jump to common device code

exo10:
        call    get_user_stack
        mov     [si].User_CX,cx         ; return open disposition
        LeaveProc NoCheck
        jmp     Sys_Ret_OK

; This is a device.
;   OS2 device - BX = -1, ES=fake SFN, AX=rmdi_flags

;BD005exo30:  mov     cx,usMode
;BD005        and     cx,open_autofail+open_no_inherit
;BD005        shr     ch,4                    ; Prepare for shifting left 5
;BD005        shl     cx,5                    ; Shift both bits into position
;BD005        or      ax,cx                   ; Get new attributes
;BD005        call    RMDevAllocDI            ; Assign a DevInfo entry (V86 SFT)
;BD005        jc      short exo60             ; exit if none available
;BD005
;BD005;       (ax) = V86 SFN (e.g. 235..254)
;BD005
;BD005        mov     cx,file_exist           ; File (device) already existed
;BD005        jmp     short exo10

exo40:  mov     ax,ERROR_INVALID_FUNCTION
exo50:
        LeaveProc NoCheck
        jmp     Sys_Ret_Err
;
;   We opened the device, but cannot allocate a DevInfo entry.
;   Clean up by closing the device.
;

exo60:  push    ax                      ; Save the error code
        SVC     SVC_DEMCLOSE            ; Close the OS2 device
        pop     ax
        jmp     short exo50             ; error exit
EndProc   $Extended_Open

Break <$NameTrans - partially process a name>

;
;   $NameTrans - allow users to see what names get mapped to.  This call
;   performs only string substitution and canonicalization, not splicing.  Due
;   to Transpath playing games with devices, we need to insure that the output
;   has drive letter and :  in it.
;
;   Inputs:     DS:SI - source string for translation
;               ES:DI - pointer to buffer
;   Outputs:
;       Carry Clear
;               Buffer at ES:DI is filled in with data
;               ES:DI point byte after nul byte at end of dest string in buffer
;       Carry Set
;               AX = error_path_not_found
;   Registers modified: all
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $NameTrans,Near
        call    VMcheck_extended       ; mdr return if DOS request
        SVC     SVC_DEMNAMETRANS
        jmp     Sys_Return
EndProc $NameTrans

; Inputs:
;       DS:DX Points to unopenned FCB
; Function:
;       Directory is searched for first matching entry and the directory
;       entry is loaded at the disk transfer address
; Returns:
;       AL = -1 if no entries matched, otherwise 0
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $DIR_SEARCH_FIRST,near
        mov     cs:search_first_flag,0   ; mdr init flag for dos handling
        call    VMcheck_fcb              ; mdr return if for DOS drive
        mov     cs:search_first_flag,1   ; mdr init flag for os2 handling
        SVC     SVC_DEMFINDFIRSTFCB
        jmp     FCB_Return
EndProc $DIR_SEARCH_FIRST

; Inputs:
;       DS:DX points to unopenned FCB returned by $DIR_SEARCH_FIRST
; Function:
;       Directory is searched for the next matching entry and the directory
;       entry is loaded at the disk transfer address
; Returns:
;       AL = -1 if no entries matched, otherwise 0

Procedure $DIR_SEARCH_NEXT,near
        cmp     cs:search_first_flag,1 ; mdr check if last find was handled by os2
        je      snyes                  ; mdr if it was then call os2
        mov     cs:os2_handled,0       ; mdr else clear flag
        ret                            ; mdr and return for dos processing
snyes:                                 ; mdr
        SVC     SVC_DEMFINDNEXTFCB
        jmp     FCB_Return
EndProc $DIR_SEARCH_NEXT

;   Assembler usage:
;           MOV AH, FindFirst
;           LDS DX, name
;           MOV CX, attr
;           INT 21h
;       ; DMA address has datablock
;
;   Error Returns:
;           AX = error_path_not_found
;              = error_no_more_files
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $FIND_FIRST,NEAR

;CHGTM2        mov     cs:find_first_flag,0   ; mdr init flag for dos handling
;73436         call    VMcheck_fname          ; mdr return if dos drive
;CHGTM2        mov     cs:find_first_flag,1   ; mdr init flag for os2 handling

        SaveReg <ax,bx,es>          ; Save registers                 ;73436;

        mov     ax,2f00h            ; Get Disk Transfer Area ( DTA ) ;73436;

        pushf                       ; Save flags to emulate INT 21   ;73436;
        call    cs:[pOldInt21]                                       ;73436;

        mov     WORD PTR cs:Find_First_DTA+0, bx  ; Store DTA offset ;73436;
        mov     WORD PTR cs:Find_First_DTA+2, es  ; Store DTA segment;73436;

;       Set Dos Processed the request as the default                 ;73436;
        mov     es:[bx].FindFirstDTA.OS2_ProcessFlag, DOS_ProcessDTA ;73436;

        RestoreReg <es,bx,ax>       ; Restore registers              ;73436;

        call    VMcheck_fname       ; mdr return if dos drive        ;73436;

        SaveReg <bx,es>             ; Save registers                 ;73436;

        les     bx,DWORD PTR cs:Find_First_DTA   ; Address of DTA    ;73436;

;       Set OS/2 will process the Find First request.                ;73436;
        mov     es:[bx].FINDFirstDTA.OS2_ProcessFlag, OS2_ProcessDTA ;73436;

        RestoreREG <es,bx>          ; Restore registers              ;73436;

        SVC     SVC_DEMFINDFIRST
        jmp     Sys_Return
EndProc $FIND_FIRST

;   Assembler usage:
;       ; dma points at area returned by find_first
;           MOV AH, findnext
;           INT 21h
;       ; next entry is at dma
;
;   Error Returns:
;           AX = error_no_more_files

        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $FIND_NEXT,NEAR
;73436          mov     cs:os2_handled,0       ;  CHGTM2 in case it will be handled by dos
;73436          call    VMcheck_fname          ;  CHGTM2 return if dos drive
;73436          mov     cs:os2_handled,1       ;  CHGTM2 os2 will handle find
;CHGTM2         cmp     cs:find_first_flag,1   ; mdr check if last find was handled by os2
;CHGTM2         je      fnyes                  ; mdr if it was then call os2
;CHGTM2         mov     cs:os2_handled,0       ; mdr else clear flag
;CHGTM2         ret                            ; mdr and return for dos processing
;73436  fnyes:                                 ; mdr

        mov     cs:os2_handled, 0   ;  CHGTM2 in case it will be handled by dos

        SaveReg <ax,bx,es>          ; Save registers                 ;73436;

        mov     ax,2f00h            ; Get Disk Transfer Area ( DTA ) ;73436;

        pushf                       ; Save flags to emulate INT 21   ;73436;
        call    cs:[pOldInt21]                                       ;73436;

;       Did OS/2 process the Find First request?                     ;73436;
        cmp     es:[bx].FindFirstDta.OS2_ProcessFlag, OS2_ProcessDTA ;73436;

        RestoreReg <es,bx,ax>       ; Restore registers              ;73436;

        je      OS2Find             ; OS/2 will process the request  ;73436;

        ret                         ; Let DOS process the request    ;73436;

;73436          call    VMcheck_fname          ;  CHGTM2 return if dos drive

OS2Find:
        mov     cs:os2_handled,1       ;  CHGTM2 os2 will handle find
        SVC     SVC_DEMFINDNEXT
        jmp     Sys_Return
EndProc $FIND_NEXT

BREAK <$JSA - int 21 interface for join/subst>

;***    $JSA - int 21 support for function 0x61
;
; This entry point is used for the int 21 interface for join/subst.
;
; ENTRY:
;       bp = JSA_MAGIC
;       si = JSA_JOIN, JSA_SUBST
;       es:di, al, bx, cx join/subst arguments
;
; EXIT:
;       AX = error code (0 if no error)
;
;       See workers for other exit conditions.
;
; USES:
;       ALL
;

Procedure $JSA
        SVC     SVC_DEMJSA
        jmp     Sys_Return
EndProc $JSA

Break   <GetVisDrv - return visible drive>

;
;   GetVisDrv - correctly map non-spliced inuse drives
;
;   Inputs:     AL has drive identifier (0=default)
;   Outputs:    Carry Set - invalid drive/macro
;               Carry Clear - AL has physical drive (0=A)
;                   ThisCDS points to CDS
;   Registers modified: AL

Procedure GetVisDrv,NEAR
        call    check_map              ;BN001 see if drive is mapped to OS/2
        jnc     gvd_os2                ;BC006 mapped? call OS2
        call    check_dos              ;BC006 see if DOS recognizes drive
        jc      gvd_os2                ;BC006 no? try OS2
        cmp     al,0                   ;BN001 see if drive was current
        je      gvd1                   ;BN001 yes, don't decrement
        dec     al                     ;BN001 decrement AL
gvd1:   clc                            ;BN001 operation was successful
        ret                            ;BC006 carry was set by func call

gvd_os2:                               ;BC006
        SVC     SVC_DEMGETVISDRV       ; else call OS/2
        ret

EndProc   GetVisDrv

Break   <DOS_ABORT -- CLOSE all files for process>

; Inputs:
;       [CurrentPDB] set to PID of process aborting
; Function:
;       Close all files and free all SFTs for this PID
; Returns:
;       None
; All destroyed except stack
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure DOS_ABORT,NEAR

        mov     ah,51h                  ;BN003 get currentPDB from DOS
        pushf                           ;BN003
        call    cs:[pOldInt21]          ;BN003
        mov     es,bx                   ;BN003 move PDB to ES
        mov     cx,es:[PDB_JFN_Length]  ; Number of JFNs
reset_free_jfn:
        mov     bx,cx
        push    cx
        dec     bx                      ; get jfn (start with last one)
        call    $Close
        pop     cx
        loop    reset_free_jfn          ; and do 'em all
;mdr        SVC     SVC_DEMDOSABORT
        ret
EndProc   DOS_ABORT


Break <$srv_call    - Server Call 5d00 >                            ;BN008
;                                                                   ;BN008
; $srv_call and $srv_call_worker provide the SERVER DOS CALL 5D00   ;BN008
; INT 21h function.  This function allows a process to execute      ;BN008
; INT 21H functions using the sharing privileges of another process ;BN008
;                                                                   ;BN008
;                                                                   ;BN008
;   Inputs:   AX=5D00                                               ;BN008
;             DS:DX= &DPL                                           ;BN008
;   Outputs:                                                        ;BN008
;             AX=error code if CF set                               ;BN008
;             Register contain expected values from int 21h func.   ;BN008
;                                                                   ;BN008
;   Registers modified: All                                         ;BN008
;                                                                   ;BN008
        ReferV86 SaveBX,WORD                                        ;BN008
        ReferV86 SaveDS,WORD                                        ;BN008
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING        ;BN008
                                                                    ;BN008
        EXTRN   TableDispatch:near                                  ;BN008
        EXTRN   GET_USER_STACK:near                                 ;BN008
        EXTRN   XCHGP:near                                          ;BN008
        EXTRN   SYS_RET_ERR_AL:near     ;MsCode.asm                 ;BN008
        EXTRN   SYS_RET_ERR:near        ;MsCode.asm                 ;BN008
        EXTRN   SYS_RET_OK:near         ;MsCode.asm                 ;BN008
                                                                    ;BN008
                                                                    ;BN008
        subttl  Int 21h, AH=5Dh                                     ;BN008
        page                                                        ;BN008
                                                                    ;BN008
ServerTab       DW      V86GROUP:Server_Disp                        ;BN008
SERVERLEAVE     DW      V86GROUP:ServerReturn                       ;BN008
SERVER_DISP     DB      (SERVER_DISP_END-SERVER_DISP-1)/2           ;BN008
                DW      OFFSET V86GROUP:$SRV_CALL_WORKER     ; 0    ;BN008
SERVER_DISP_END LABEL   BYTE                                        ;BN008
                                                                    ;BN008
        PUBLIC  $srv_call                                           ;BN008
        assume  cs:V86GROUP, ds:nothing, es:nothing, ss:V86GROUP    ;BN008
$srv_call       proc    near                                        ;BN008
;------ dispatch to the sub-function worker                         ;BN008
          push    SERVERLEAVE             ; push return address     ;BN008
          push    ServerTab               ; push table address      ;BN008
          push    ax                                                ;BN008
          call    TableDispatch                                     ;BN008
ServerReturn:                                                       ;BN008
          ret                                                       ;BN008
$srv_call    endp                                                   ;BN008
                                                                    ;BN008
                                                                    ;BN008
Break   <$srv_call_worker, dos server function>                     ;BN008
                                                                    ;BN008
;   $srv_call_worker - see description for $srv_call above          ;BN008
;                                                                   ;BN008
;   Inputs:    DS:DX &dpl (user registers)                          ;BN008
;                                                                   ;BN008
;   Outputs:   return code and cf from INT 21H                      ;BN008
;                                                                   ;BN008
;   Registers modified: all                                         ;BN008
;                                                                   ;BN008
        ReferV86 PROC_ID,WORD                                       ;BN008
        ReferV86 USER_ID,WORD                                       ;BN008
        ReferV86 SrvCallEntFlg,BYTE                                 ;75462;
                                                                    ;BN008
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING                   ;BN008
Procedure $srv_call_worker, near                                    ;BN008
                                                                    ;BN008
        mov     si,dx         ;DS:SI=&DPL (Dos Parameter List)      ;BN008
        pop     ax                                                  ;BN008
        push    ds                                                  ;BN008
        push    si                                                  ;BN008
        invoke  GET_USER_STACK     ; DS:SI=@user stack!             ;BN008
        pop     di                                                  ;BN008
        pop     es                                                  ;BN008
                                                                    ;BN008
        ;DS:SI = &stack                                             ;BN008
        ;ES:DI = &DPL                                               ;BN008
                                                                    ;BN008
        call    XCHGP                                               ;BN008
                                                                    ;BN008
        ;DS:SI = &DPL                                               ;BN008
        ;ES:DI = &stack                                             ;BN008
                                                                    ;BN008
        ; We now copy the registers from DPL to save stack          ;BN008
        push    si                                                  ;BN008
        mov     cx,6                                                ;BN008
        rep     movsw                   ; Put in AX,BX,CX,DX,SI,DI  ;BN008
        inc     di                                                  ;BN008
        inc     di                      ; Skip user_BP              ;BN008
        movsw                           ; DS                        ;BN008
        movsw                           ; ES                        ;BN008
        pop     si                                                  ;BN008
                                                                    ;BN008
        mov     bx,[si].DPL_UID                                     ;BN008
                                                                    ;BN008
comment ~ DOS 5                                                     ;BN008
; WIN386 updates the USER_ID itself.                                ;BN008
; If WIN386 is present we skip the updating of USER_ID.             ;BN008
                                                                    ;BN008
        assume ss:V86GROUP                                          ;BN008
        test    ss:[IsWin386],1                                     ;BN008
        jnz     skip_win386                                         ;BN008
~                                                                   ;BN008
        mov     ss:[USER_ID],bx         ; Set UID                   ;BN008
skip_win386:                                                        ;BN008
        mov     bx,[si].DPL_PID                                     ;BN008
        mov     ss:[PROC_ID],bx         ; Set process ID            ;BN008
        cmp     [SI.DPL_AX],4100h       ; Func 41h is the only one  ;75462
        jnz     LoadRegs                ; that currently supports   ;75462
          mov     SrvCallEntFlg,TRUE    ; SrvCallEntFlg             ;75462
                                                                    ;BN008
        assume ss:nothing                                           ;BN008
                                                                    ;BN008
LoadRegs:                                                           ;75462
        MOV     AX,[SI.DPL_AX]                                      ;BN008
        MOV     BX,[SI.DPL_BX]                                      ;BN008
        MOV     CX,[SI.DPL_CX]                                      ;BN008
        MOV     DX,[SI.DPL_DX]                                      ;BN008
        MOV     DI,[SI.DPL_DI]                                      ;BN008
        MOV     ES,[SI.DPL_ES]                                      ;BN008
                                                                    ;BN008
        PUSH    [SI.DPL_SI]                                         ;BN008
        MOV     DS,[SI.DPL_DS]                                      ;BN008
        POP     SI                                                  ;BN008
                                                                    ;BN008
        MOV     ss:[SaveDS],DS                                      ;BN008
        MOV     ss:[SaveBX],BX                                      ;BN008
        INT     21H                                                 ;BN008

        push    ds                                                  ;BN009;
        push    si                                                  ;BN009;
        invoke  get_user_stack                                      ;BN009;


;        mov     [si.dpl_ax],ax                                      ;BN009;
;        mov     [si.dpl_bx],bx                                      ;BN009;
;        mov     [si.dpl_cx],cx                                      ;BN009;
;        mov     [si.dpl_dx],dx                                      ;BN009;
;        mov     [si.dpl_di],di                                      ;BN009;
;        mov     [si.dpl_es],es                                      ;BN009;
;        pop     [si.dpl_si]                                         ;BN009;
;        pop     [si.dpl_ds]                                         ;BN009;
        mov     [si.ustack_ax],ax                                   ;CHGTM1;
        mov     [si.ustack_bx],bx                                   ;CHGTM1;
        mov     [si.ustack_cx],cx                                   ;CHGTM1;
        mov     [si.ustack_dx],dx                                   ;CHGTM1;
        mov     [si.ustack_di],di                                   ;CHGTM1;
        mov     [si.ustack_es],es                                   ;CHGTM1;
        pop     [si.ustack_si]                                      ;CHGTM1;
        pop     [si.ustack_ds]                                      ;CHGTM1;


        jnc     short no_carry                                      ;BN009;
        or      [si.user_f],f_Carry                                 ;BN009;
        jmp     short was_carry                                     ;BN009;
no_carry:                                                           ;BN009;
        and     [si.user_f],not f_Carry                             ;BN009;
was_carry:                                                          ;BN009;

        ret                                                         ;BN008
EndProc   $srv_call_worker                                          ;BN008

V86CODE ENDS

        END
