summaryrefslogtreecommitdiffstats
path: root/private/nw/nw16/tsr/resident.asm
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/nw16/tsr/resident.asm')
-rw-r--r--private/nw/nw16/tsr/resident.asm1039
1 files changed, 1039 insertions, 0 deletions
diff --git a/private/nw/nw16/tsr/resident.asm b/private/nw/nw16/tsr/resident.asm
new file mode 100644
index 000000000..5c95168da
--- /dev/null
+++ b/private/nw/nw16/tsr/resident.asm
@@ -0,0 +1,1039 @@
+page ,132
+if 0
+
+/*++
+
+Copyright (c) 1993-4 Microsoft Corporation
+
+Module Name:
+
+ resident.asm
+
+Abstract:
+
+ This module contains the resident code part of the stub redir TSR for NT
+ VDM NetWare support.
+
+Author:
+
+ Colin Watson (colinw) 08-Jul-1993
+
+Environment:
+
+ Dos mode only
+
+Revision History:
+
+ 08-Jul-1993 colinw
+ Created
+
+--*/
+
+endif
+
+
+
+.xlist ; don't list these include files
+.xcref ; turn off cross-reference listing
+include isvbop.inc ; NTVDM BOP mechanism
+include dosmac.inc ; Break macro etc (for following include files only)
+include dossym.inc ; User_<Reg> defines
+include segorder.inc ; segments
+include mult.inc ; MultNET
+include sf.inc ; SFT definitions/structure
+include pdb.inc ; program header/process data block structure
+
+include debugmac.inc ; DbgPrint macro
+include asmmacro.inc ; language extensions
+
+include nwdos.inc ; NetWare structures and nwapi32 interface
+
+.cref ; switch cross-reference back on
+.list ; switch listing back on
+subttl ; kill subtitling started in include file
+
+
+.286 ; all code in this module 286 compatible
+
+far_segment segment
+far_label label far
+far_segment ends
+
+ResidentCodeStart
+
+ assume cs:ResidentCode
+ assume ds:nothing
+ assume es:nothing
+ assume ss:nothing
+
+ public Old21Handler
+Old21Handler dd ?
+
+;
+; IMPORTANT: the following up to the comment <END NWDOSTABLE> must
+; be kept in the same order as for the NWDOSTABLE structure in NWDOS.H/.INC.
+; Align on 32 bits to make it convenient for nwapi32.dll
+;
+ align 4
+
+ public ConnectionIdTable
+ConnectionIdTable CID MC dup (<>)
+
+ public ServerNameTable
+ServerNameTable db MC * SERVERNAME_LENGTH dup (0)
+
+ public DriveIdTable
+DriveIdTable db MD dup (0)
+
+ public DriveFlagTable
+DriveFlagTable db MD dup (0)
+
+ public DriveHandleTable
+DriveHandleTable db MD dup (0)
+
+ public PreferredServer
+PreferredServer db 0
+
+ public PrimaryServer
+PrimaryServer db 0
+
+ public TaskModeByte
+TaskModeByte db 0
+
+CurrentDrive db 0
+
+ public SavedAx;
+SavedAx dw 0
+
+ public NtHandleHi;
+NtHandleHi dw 0
+ public NtHandleLow;
+NtHandleLow dw 0
+
+ public NtHandleSrcHi; // Used in FileServerCopy
+NtHandleSrcHi dw 0
+ public NtHandleSrcLow;
+NtHandleSrcLow dw 0
+
+ public hVDD
+hVDD dw -1
+
+ public PmSelector
+PmSelector dw 0
+
+ public CreatedJob
+CreatedJob db 0
+ public JobHandle
+JobHandle db 0
+
+NOV_BUFFER_LENGTH equ 256
+
+ public DenovellBuffer
+DenovellBuffer db NOV_BUFFER_LENGTH dup (?)
+
+ public DenovellBuffer2
+DenovellBuffer2 db NOV_BUFFER_LENGTH dup (?)
+
+
+.errnz (size DeNovellBuffer2 - size DenovellBuffer)
+
+Comspec db "COMSPEC="
+COMSPEC_LENGTH equ ($ - Comspec)
+
+;
+; this is the <END NWDOSTABLE> structure.
+;
+
+;
+; data passed from nw16.asm
+;
+ public not_exclusive
+not_exclusive db 0
+
+ page
+
+ public NwInt21
+NwInt21 proc far
+ assume cs:ResidentCode
+ assume ds:nothing
+ assume es:nothing
+ assume ss:nothing
+
+ sti ; make sure ints are still enabled
+
+;
+; check whether we filter this vector; if not, pass it through to previous INT 21
+; handler (DOS or some other TSR)
+;
+; If this is a name based operation, and the caller is passing through a novell
+; format name - SYS:FOO or SERVER\SYS:FOO - then munge the name to be a UNC name
+;
+
+ cmp ah,0eh
+ jne @f
+ jmp select_default_drive
+@@: cmp ah,39h ; create directory
+ je check_name
+ ja @f
+
+;
+; ah less than 39h (mkdir) is definitely for DOS
+;
+
+ public quick_jump_to_dos
+quick_jump_to_dos:
+ jmp far_label
+
+;
+; run any of the following name-based calls through the name check:
+;
+; 3ah remove directory
+; 3bh change directory
+; 3ch create file
+; 3dh open file
+; 41h delete file
+; 43h get/set attributes
+; 4bh exec program
+; 4eh find first file
+; 56h rename
+;
+
+@@: cmp ah,3dh
+ jbe check_name
+ cmp ah,41h ; delete file
+ je check_name
+ cmp ah,43h ; get/set attributes
+ je check_name
+ cmp ah,4bh ; exec program
+ je check_name
+ cmp ah,4eh ; find first file
+ je check_name
+ cmp ah,56h ; rename
+ je rename
+ jmp dispatch_check
+
+
+;
+; Rename function. This has 2 path names: source in ds:dx and
+; destination in es:di. Check the destination first then fall through
+; and check the source.
+;
+rename:
+ push ds
+ push dx
+ push es
+ push di ; user registers saved for after Int21
+
+ push ds ; save ds:dx 'cause we will corrupt them
+ push dx
+
+ mov dx,es
+ mov ds,dx
+ mov dx,di ; ds:dx = destination buffer
+ call IsDosPath
+ je @f ; DOS path, no modification
+ cld
+ push di
+ call DenovellizeName
+ pop di
+ cmp dx,offset DenovellBuffer
+ je swap_buffers
+
+@@:
+ pop dx ; ds:dx points at source again
+ pop ds
+
+ pop di
+ pop es
+ pop dx
+ pop ds
+ jmp check_name
+
+;
+; Destination name was normalized and stored in DeNovellBuffer. put the data
+; in Denovellbuffer2 in-case we need to put the Source name in Denovellbuffer
+;
+
+swap_buffers:
+ push cx
+ push si
+ push ds ; will become es during Dos call
+
+ mov si,dx
+ mov di,cs
+ mov es,di
+ mov di,offset DenovellBuffer2
+ mov cx,NOV_BUFFER_LENGTH / 2
+.errnz (NOV_BUFFER_LENGTH and 1)
+
+ rep movsw
+
+ mov di,offset DenovellBuffer2
+ pop es ; es:di is now Denovellbuffer2
+ pop si
+ pop cx
+
+ pop dx ; make ds:dx source again
+ pop ds
+
+ ; stack has users di,es,dx,ds pushed
+ ; parameters are same as callers except for es:di
+ jmp check_src
+
+check_name: ; ds:dx points at name to examine
+ push ds
+ push dx
+ push es
+ push di
+ ; fall through
+
+check_src: ; only jumped to in rename
+
+ cld
+ call IsDosPath
+ je for_dos_properR ; x: or UNC filename. No more processing
+
+ cmp ah,3dh
+ jne notNETQ ; special NETQ open only applies for create
+ cmp CreatedJob,0
+ jz notNETQ ; don't look at name if no job handle available
+
+ push ax
+ push si
+ mov si,dx
+ cld
+ lodsw
+ cmp ax,"EN"
+ jne @f
+ lodsw
+ cmp ax,"QT"
+ jne @f
+ lodsb
+ or al,al
+ jnz @f
+
+ pop si ; Opening NETQ. Return Dos handle from CreateJob and File
+ pop ax
+ mov CreatedJob,0 ; Only return handle once
+ mov al, JobHandle
+ xor ah, ah
+ pop di
+ pop es
+ pop dx
+ pop ds
+ clc
+ retf 2
+
+@@: pop si
+ pop ax
+ jmp for_dos_properR
+
+notNETQ:push di
+ call DenovellizeName ; munge the name if required
+ pop di ; restore caller DI
+
+;
+; Look for compatibility mode opens that need to change to exlusive mode
+; opens so that they get properly cached. Criteria for opening exclusive
+; is that the application did not specify any sharing modes and the drive
+; being opened is on a netware drive.
+;
+
+ cmp ah, 3ch
+ je @f
+ cmp ah, 3dh
+ jne not_compat
+@@: test al,OF_SHARE_MASK
+ jne not_compat
+
+ cmp not_exclusive, 1 ; open shared mode anyway
+ je not_compat
+
+ mov SavedAx,ax
+ mov ax,hVdd
+ DispatchCall ; 32 bit code decides if compat mode
+
+not_compat:
+ pushf
+ call Old21Handler ; fake int 21 to get to DOS
+
+ pop di
+ pop es
+ pop dx
+ pop ds
+ retf 2 ; return to app (with flags from DOS)
+
+for_dos_properR: ; restore regs and call dos
+ pop di
+ pop es
+ pop dx
+ pop ds
+ cmp ah, 3ch
+ je @f
+ cmp ah, 3dh
+ jne for_dos_proper
+@@: test al,OF_SHARE_MASK
+ jne for_dos_proper
+ cmp not_exclusive, 1 ; open shared mode anyway
+ je for_dos_proper
+ mov SavedAx,ax
+ mov ax,hVdd
+@@: DispatchCall ; 32 bit code decides if compat mode
+ public for_dos_proper
+for_dos_proper:
+ jmp far_label
+
+dispatch_check:
+ cmp ah,04ch
+ jne check_9f
+ jmp process_exit
+
+;
+; 'special' entry point to return the data segment info to the protect-mode code
+; so it can generate an LDT descriptor which refers to this memory.
+;
+
+check_9f:
+ cmp ah,9fh
+ jne check_nw_ep ; is it a Netware call?
+ or al,al
+ jnz check_handle_mapper
+ mov bx,seg ConnectionIdTable; 9f00: return segment info
+ mov dx,offset ConnectionIdTable
+ clc ; if we loaded then it can't fail
+ retf 2
+
+;
+; if the call is 9f01 then we call MapNtHandle for the value in BX. This will
+; update NtHandleHi and NtHandleLow, which we assume will be accessed from the
+; code segment register
+;
+
+check_handle_mapper:
+ cmp al,1
+ jne check_nw_ep ; still not one of ours?
+ call MapNtHandle ; 9f01: call MapNtHandle
+ retf 2
+
+check_nw_ep:
+ cmp ah,0b4h
+ jb for_dos_proper
+ cmp ah,0f3h
+ ja for_dos_proper
+ jne @f
+ jmp file_server_copy
+@@: cmp ah,0BAh
+ jne check_f0
+
+ push bx ; get environment. used by map.exe
+ push ax
+ mov ah,051h ; load current apps PDB into ax
+ int 021h
+
+@@: mov es, bx
+ cmp bx, es:PDB_Parent_PID
+ je @f
+ mov bx, es:PDB_Parent_PID
+ jmp @b
+@@:
+ mov dx, es:PDB_environ ; set DX to environment segment
+ mov es, dx ; set es:di to value of COMSPEC
+
+ push si
+ push ds
+ mov ds, dx
+ xor si, si
+
+; future code to save space
+; es <- env seg
+; di <- env off
+; ds <- cs
+; si <- offset Comspec
+; cx <- .size Comspec / 2
+; cld
+; repz cmpsw
+; jnz no match
+
+; al <- 0
+; cx <- remaining size of env seg
+; rep scasb
+
+ cld
+next_var:
+ lodsb
+ cmp al, "C"
+ jne @f
+ lodsb
+ cmp al, "O"
+ jne @f
+ lodsb
+ cmp al, "M"
+ jne @f
+ lodsb
+ cmp al, "S"
+ lodsb
+ jne @f
+ cmp al, "P"
+ jne @f
+ lodsb
+ cmp al, "E"
+ jne @f
+ lodsb
+ cmp al, "C"
+ jne @f
+ lodsb
+ cmp al, "="
+ je got_comspec
+
+@@: ; Search for null terminating environment
+ or al,al
+ je next_var
+ lodsb
+ jmp @b
+
+got_comspec:
+ pop ds
+ mov di,si
+ pop si
+
+ pop ax
+ pop bx
+ iret
+
+check_f0:
+ cmp ah,0f0h
+ jne for_me
+
+;
+; if we're here then we're doing simple stuff that we don't need to bop fer
+; currently stuff here is ah=f0, al = 00, 01, 04, 05
+;
+; caveat emptor dept #312: However, it came to pass that we needed to bop when
+; the f00x calls were made without any preceding calls that would cause nwapi32
+; to be loaded
+;
+
+dispatch_f0:
+
+.errnz ((offset PrimaryServer - offset PreferredServer) - 1)
+
+ or al,al ; f000 = set preferred server
+ jnz try_01
+ cmp dl,8
+ ja zap_preferred
+ mov PreferredServer,dl
+ iret
+
+zap_preferred:
+ mov PreferredServer,al ; al contains 0 remember
+ iret
+
+try_01: cmp al,1 ; f001 = get preferred server
+ jnz try_02
+ mov al,PreferredServer
+ iret
+
+try_02: cmp al,2 ; f002 = get default server
+ jnz try_04
+ mov al,PreferredServer
+ or al,al
+ jnz @f
+ mov al,PrimaryServer
+@@: iret
+
+try_04: cmp al,4 ; f004 = set primary server
+ jne try_05
+ cmp dl,8
+ ja zap_primary
+ mov PrimaryServer,dl
+ iret
+
+zap_primary:
+ mov PrimaryServer,0
+ iret
+
+try_05: cmp al,5 ; f005 = get primary server
+ jne for_me
+ mov al,PrimaryServer
+ iret
+
+file_server_copy:
+ call FileServerCopy ; f3 - Used by ncopy.exe
+ ;jmp for_me
+
+;
+; if the process exits and the dll is loaded then call the 32 bit code to
+; close any cached handles.
+;
+
+process_exit:
+ ;jmp for_me
+
+;
+; if we're here then the dispatch code is for a NetWare client API. First we
+; check if we have already loaded the 32-bit code. If not, then load it. If we
+; get an error, we will fall through to DOS
+;
+
+for_me:
+ cmp ah,0BCh ; bc,bd,be need handle mapping
+ jb no_mapping
+ cmp ah,0BEh
+ ja no_mapping
+
+;do_mapping_call:
+ call MapNtHandle ; take bx and find the Nt handle
+
+no_mapping:
+ mov SavedAx,ax
+
+ cmp ah,0e3h ; Look for CreateJob NCP
+ jne @f ; try f2 alternative
+
+ mov al,[si+2] ; si is NCP subfunction
+ jmp lookupcode
+
+@@: cmp ax,0f217h
+ jne do_dispatch ; Not CreateJob
+ mov al,[si+2] ; si is NCP subfunction
+
+lookupcode:
+ cmp al,68h
+ je createjob
+ cmp al,79h
+ jne do_dispatch
+
+
+createjob: ; It is a CreateJob and File
+
+ ; Always return the errorcode from the NCP exchange
+ ; regardless of any earlier failures in the NT plumbing.
+ mov ax, SavedAx
+ push ax ; Open \\Server\queue for NCP
+ push ds
+ push dx
+ mov ax, 9f02h
+ mov SavedAx,ax
+
+ mov ax,hVdd
+ DispatchCall ; Set DeNovellBuffer to \\Server\queue
+ ; and registers ready for DOS OpenFile
+
+ pushf
+ call Old21Handler ; Open \\server\queue
+ jc @f
+ mov JobHandle, al
+ mov CreatedJob, 1 ; Flag JobHandle is valid
+ push bx
+ xor ah, ah
+ mov bx, ax ; JobHandle
+ call MapNtHandle ; take bx and find the Nt handle
+ pop bx
+
+@@:
+ pop dx
+ pop ds ; Proceed and send the NCP
+ pop ax
+ mov SavedAx, ax
+
+do_dispatch:
+ mov ax,hVdd
+ DispatchCall
+ retf 2 ; return to the application
+
+ public chain_previous_int21
+chain_previous_int21:
+ jmp far_label
+
+
+;
+; Save new drive so we can conveniently handle compatibility mode opens.
+; also need to return 32 as the number of available drives.
+;
+
+select_default_drive:
+ pushf
+ call Old21Handler ; fake int 21 to get to DOS
+
+ mov ah,19h ; get current drive
+ pushf
+ call Old21Handler ; fake int 21 to get to DOS
+ mov CurrentDrive,al ; current drive
+
+ mov al,32 ; # of drives supported by NetWare
+ retf 2 ; return to app (with flags from DOS)
+
+
+NwInt21 endp
+
+;*******************************************************************************
+;*
+;* FileServerCopy
+;*
+;* Implement preperation for calling
+;* \\...)
+;*
+;* ENTRY applications registers
+;*
+;* EXIT nothing
+;*
+;* RETURNS nothing
+;*
+;* ASSUMES no registers (except flags) can be destroyed
+;*
+;******************************************************************************/
+
+FileServerCopy proc near
+
+ push ax
+ push bx
+
+ mov bx,word ptr es:[di] ; Map Source Handle
+ call MapNtHandle
+
+ mov bx,NtHandleHi
+ mov NtHandleSrcHi,bx
+ mov bx,NtHandleLow
+ mov NtHandleSrcLow,bx
+
+ mov bx,word ptr es:[di+2] ; Map Destination Handle
+ call MapNtHandle
+
+@@: pop bx
+ pop ax
+
+ ret
+FileServerCopy endp
+
+;*******************************************************************************
+;*
+;* IsDosPath
+;*
+;* Checks to see if a path name looks like a Microsoft path (<drive>:... or
+;* \\...)
+;*
+;* ENTRY ds:dx = path name
+;*
+;* EXIT nothing
+;*
+;* RETURNS ZF = 1: path is for MS-DOS
+;*
+;* ASSUMES no registers (except flags) can be destroyed
+;*
+;******************************************************************************/
+
+IsDosPath proc near
+ push ax
+ xchg si,dx ; si = offset of filename; dx = ????
+ mov al,[si+1] ; al = second character of filename
+ cmp al,':'
+ je @f ; looks like a DOS filename
+ cmp al,'\' ; (X\... or \\...)
+ jne tryFirstbyte
+ cmp al,'/' ; (X/... or //...)
+ jne @f ; second char is not "\" or "/"
+
+tryFirstbyte:
+ mov al,[si] ; al = first character of filename
+ cmp al,'\' ; (\\... or \/...)
+ je @f
+ cmp al,'/' ; (\/... or //...)
+
+@@: xchg si,dx ; dx = offset of filename; si = ????
+ pop ax
+ ret
+IsDosPath endp
+
+;*******************************************************************************
+;*
+;* DenovellizeName
+;*
+;* Converts a name from Novell format (SERVER\SHARE:filename or
+;* SHARE:filename) to DOS UNC name. Server name is found by:
+;*
+;* if PreferredServer != 0 then Index = PreferredServer
+;* else if PrimaryServer != 0 then Index = PrimaryServer
+;* else Index = 0
+;* servername = ServerNameTable[Index * sizeof(SERVER_NAME)]
+;*
+;* ENTRY ds:dx = name
+;*
+;* EXIT ds:dx = offset of DenovellBuffer
+;*
+;* RETURNS if success, DI points to last byte+1 in DenovellBuffer, else
+;* DI is garbage
+;*
+;* ASSUMES 1. filename does not wrap in buffer segment
+;* 2. DI register can be trashed
+;* 3. DF = 0
+;*
+;******************************************************************************/
+
+DenovellizeName proc near
+ assume ds:nothing
+ assume es:nothing
+
+ push ax
+ push bx
+ push cx
+ push bp
+ push si
+ push es
+ mov bp,ds
+
+;
+; get the length of the input filename
+;
+
+ mov cx,ds
+ mov es,cx
+ mov di,dx ; es:di = filename
+ xor cx,cx
+ dec cx ; cx = ffff
+ xor al,al
+ repnz scasb
+ not cx
+ dec cx ; cx = strlen(filename)
+ cmp cx,length DenovellBuffer
+ jb @f
+ jmp dnn_ret ; filename too long: give it to DOS
+
+;
+; find the offset of ':' in the filename
+;
+
+@@: mov bx,cx ; remember length
+ mov di,dx ; es:di = filename
+ mov al,':'
+ repnz scasb ; di = strchr(filename, ':')+1
+ jz @f
+go_home:jmp dnn_ret ; no ':' - not novell format name?
+@@: cmp byte ptr [di],0
+ je go_home ; device name? (eg "LPT1:") - to DOS
+ mov si,di ; si = offset of ':' in name, +1
+
+;
+; find the offset of the first '/' or '\'
+;
+
+ mov cx,bx ; cx = length of filename
+ mov di,dx ; di = offset of filename
+ mov al,'\'
+ repnz scasb
+ sub bx,cx
+ mov cx,bx
+ mov bx,di
+ mov di,dx
+ mov al,'/'
+ repnz scasb
+ jnz @f
+ mov bx,di
+
+;
+; if ':' before '\' or '/' then name is SYS:FOO... else SERVER\SYS:FOO...
+;
+
+@@: mov di,cs
+ mov es,di
+ mov di,offset DenovellBuffer
+ mov ax,('\' shl 8) + '\'
+ stosw
+ cmp bx,si
+ jb copy_share_name
+ xor bx,bx
+ mov cl,PreferredServer
+ or cl,cl
+ jnz got_index
+ mov cl,PrimaryServer
+ jcxz get_server_name
+
+got_index:
+ dec cl
+ jz get_server_name
+ mov bx,cx
+
+.errnz SERVERNAME_LENGTH - 48
+
+ shl cx,5
+ shl bx,4
+
+get_server_name:
+ add bx,cx
+ mov cx,ds
+ mov si,es
+ mov ds,si
+ lea si,ServerNameTable[bx]
+ cmp byte ptr [si],0
+ je dnn_ret
+ mov ah,SERVERNAME_LENGTH
+
+copy_server_name:
+ lodsb
+ or al,al
+ jz done_server_name
+ stosb
+ dec ah
+ jnz copy_server_name
+
+done_server_name:
+ mov al,'\'
+ stosb
+ mov ds,cx
+
+copy_share_name:
+ mov si,dx
+
+next_char:
+ lodsb
+ cmp al,':'
+ je @f
+ stosb
+ jmp short next_char
+@@: mov al,'\'
+ stosb
+
+copy_rest:
+ lodsb
+ stosb
+ or al,al
+ jnz copy_rest
+ cmp byte ptr [si-2],':'
+ jne @f
+ mov byte ptr [si-2],0
+@@: mov dx,offset DenovellBuffer
+ mov bp,es
+
+dnn_ret:mov ds,bp
+ pop es
+ pop si
+ pop bp
+ pop cx
+ pop bx
+ pop ax
+ ret
+DenovellizeName endp
+
+
+
+;*** DosCallBack
+;*
+;* Call back into DOS via the int 2f/ah=12 back door. If CALL_DOS defined,
+;* use a call, else s/w interrupt. Using a call means no other TSRs etc.
+;* which load AFTER the redir can hook it, but we DON'T HAVE TO MAKE A
+;* PRIVILEGE TRANSITION ON x86 which speeds things up. This should be safe,
+;* because no other s/w should really be hooking INT 2F/AH=12
+;*
+;* ENTRY FunctionNumber - dispatch code goes in al
+;* DosAddr - if present, variable containing address of
+;* DOS int 2f entry point
+;* OldMultHandler - this variable contains the address of DOSs
+;* int 2f back door. Specific to redir code
+;*
+;* EXIT nothing
+;*
+;* USES ax, OldMultHandler
+;*
+;* ASSUMES nothing
+;*
+;***
+
+DosCallBack macro FunctionNumber, DosAddr
+ mov ax,(MultDOS shl 8) + FunctionNumber
+ifdef CALL_DOS
+ pushf
+ifb <DosAddr>
+if (((.type OldMultHandler) and 32) eq 0) ;; OldMultHandler not defined
+ extrn OldMultHandler:dword
+endif
+ call OldMultHandler
+else
+ call DosAddr
+endif
+else
+ int 2fh
+endif
+endm
+
+;
+; defines for DosCallBack FunctionNumbers
+;
+
+SF_FROM_SFN = 22
+PJFN_FROM_HANDLE= 32
+
+; *** MapNtHandle
+; *
+; * Given a handle in BX, map it to a 32-bit Nt handle store result
+; * in NtHandle[Hi|Low]
+; *
+; *
+; * ENTRY bx = handle to map
+; *
+; * EXIT Success - NtHandle set to 32-bit Nt handle from SFT
+; *
+; * RETURNS Success - CF = 0
+; * Failure - CF = 1, ax = ERROR_INVALID_HANDLE
+; *
+; * USES ax, bx, flags
+; *
+; * ASSUMES nothing
+; *
+; ***
+
+MapNtHandle proc near
+ pusha ; save regs used by Dos call back
+ push ds
+ push es
+
+;
+; call back to Dos to get the pointer to the JFN in our caller's JFT. Remember
+; the handle (BX) is an index into the JFT. The byte at this offset in the JFT
+; contains the index of the SFT structure we want in the system file table
+;
+
+ DosCallBack PJFN_FROM_HANDLE ; pJfnFromHamdle
+ jc @f ; bad handle
+
+;
+; we retrieved a pointer to the required byte in the JFT. The byte at this
+; pointer is the SFT index which describes our 'file' (file to (un)lock in
+; this case). We use this as an argument to the next call back function -
+; get Sft from System File Number.
+;
+
+ mov bl,es:[di]
+ xor bh,bh
+ DosCallBack SF_FROM_SFN ; SfFromSfn
+ jc @f ; oops - bad handle
+
+;
+; Ok. We have a pointer to the SFT which describes this named pipe. Get the
+; 32-bit Nt handle and store it in the shared datastructure.
+;
+
+ mov bx,word ptr es:[di].sf_NtHandle[2]
+ mov NtHandleHi,bx
+ mov bx,word ptr es:[di].sf_NtHandle
+ mov NtHandleLow,bx
+
+;
+; restore all registers used by Dos call back.
+; Carry flag is set appropriately
+;
+
+@@: pop es
+ pop ds
+ popa
+ jnc @f
+
+;
+; finally, if there was an error then return a bad handle indication in ax
+;
+
+ mov ax,ERROR_INVALID_HANDLE
+@@: ret
+MapNtHandle endp
+
+ResidentCodeEnd
+
+end