Files
DR-DOS-OpenDOS/IBMDOS/REDIR.A86
2020-11-04 23:59:28 +01:00

1723 lines
44 KiB
Plaintext

title 'REDIR - DOS file system network redirector interace support'
; File : $REDIR.A86$
;
; Description :
;
; Original Author : DIGITAL RESEARCH
;
; Last Edited By : $CALDERA$
;
;-----------------------------------------------------------------------;
; Copyright Work of Caldera, Inc. All Rights Reserved.
;
; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
; CIVIL LIABILITY.
;-----------------------------------------------------------------------;
;
; *** Current Edit History ***
; *** End of Current Edit History ***
; $Log: $
; REDIR.A86 1.30 94/12/01 10:05:21
; added attribute support for open/move/unlink
; REDIR.A86 1.29 94/11/11 15:10:03
; Code at redir_lseek30 changed to ensure that the file offset is
; updated. Previously, this did not happen when INT 21/4202 (seek from
; end of file) was called, and consequently the game MYST could not
; be installed under NWDOS7.
; REDIR.A86 1.28 94/10/03 15:41:12
; fix problem where VLM network mapping gets deleted if you try to access
; a path greater than 66 characters long on a network drive.
; REDIR.A86 1.27 94/02/22 18:05:09
; fix problem with "d:\\filename.ext" (Netware 4 LOGIN)
; REDIR.A86 1.26 94/01/10 16:42:16
; File delete uses file attributes of 06, not 16 (no directory bit)
; REDIR.A86 1.25 93/12/10 00:03:09
; Move non-inherited bit to correct place in file handle
; REDIR.A86 1.22 93/11/19 23:59:00
; If a read/write returns ED_LOCKFAIL turn into ED_ACCESS on shared files
; REDIR.A86 1.21 93/09/24 19:50:50
; Tidy up code on rename
; REDIR.A86 1.15 93/06/16 16:22:21
; Always initialise file search attributes to 16h (ie. sys+hidden+dir)
; REDIR.A86 1.14 93/06/11 15:08:09
; Return 0 from search first/next
; REDIR.A86 1.13 93/06/11 02:06:53
; zero space adjust on getddsc
; ENDLOG
eject ! include i:psp.def
eject ! include i:fdos.equ
eject ! include i:msdos.equ
eject ! include i:mserror.equ
eject ! include i:doshndl.def ; DOS Handle Structures
eject ! include i:f52data.def ; DRDOS Structures
eject ! include i:redir.equ
FD_EXPAND equ 55h
eject
PCMODE_DATA dseg
extrn current_dsk:byte
extrn current_ddsc:dword
extrn current_dhndl:dword
extrn current_filepos:dword
extrn current_ldt:dword
extrn dma_offset:word
extrn dma_segment:word
extrn err_drv:byte
extrn file_attrib:word
extrn ldt_ptr:dword
extrn last_drv:byte
extrn phys_drv:byte
extrn pri_pathname:byte
extrn remote_call:word
extrn sec_pathname:byte
extrn srch_buf:byte
; Data for some int2f commands
extrn int2f_cmd:word
extrn int2f_stack:word
extrn file_mode:word
BDOS_CODE cseg
Public islocal
Public redir_asciiz_dev_offer
Public redir_asciiz_offer
Public redir_asciiz_file_offer
Public redir_drv_offer
Public redir_dhndl_offer
Public redir_move_offer
Public redir_snext_offer
extrn toupper:near
extrn check_delim:near
extrn check_slash:near
extrn check_dslash:near
extrn copy_asciiz:near
extrn unparse:near
extrn find_xfn:near
extrn find_dhndl:near
extrn ifn2dhndl:near
extrn get_xftptr:near
if KANJI
extrn dbcs_lead:near
endif
redir_dhndl_offer:
;================
; The FDOS has called this hook to see if we are operating on an MSNET drive.
; We return if we are not, or stay and process function here if we are
test es:byte ptr DHNDL_WATTR+1[bx],DHAT_REMOTE/100h
jnz redir_dhndl_accept
ret
redir_dhndl_accept:
; copy some info from DHNDL_ to local variables
push ds
push ss ! pop ds
mov ax,es:DHNDL_DEVOFF[bx]
mov word ptr current_ddsc,ax
mov ax,es:word ptr DHNDL_DEVSEG[bx]
mov word ptr current_ddsc+WORD,ax
mov ax,es:word ptr DHNDL_POS[bx]
mov word ptr current_filepos,ax
mov ax,es:word ptr DHNDL_POS+2[bx]
mov word ptr current_filepos+2,ax
pop ds
jmps redir_accept ; now we can process the call
redir_asciiz_dev_offer:
;======================
; The FDOS has called this hook to see if we are opening a redirected device.
; We return if we are not, or stay and process function here if we are
; Before we build it all ourselves do the appropriate INT 2F to allow
; other people to process the path themselves
call redir_dev_check ; is it a device ?
jnc redir_accept ; it's been recognised
ret
redir_move_offer:
;================
; The FDOS has called this hook to see if the rename operation is on a
; redirected drive. Lantastic relies on the path check broadcast's being
; done in the order new_name, old_name.
mov word ptr current_ldt,0ffffh
mov err_drv,DHAT_DRVMSK
push ds
mov si,2[bp] ; SI -> parameter block
lds si,10[si] ; DS:SI -> user supplied name
push ss ! pop es
mov di,offset sec_pathname ; DI -> where to build pathname
push ds ! push si ! push di ! push bp
mov ax,I2F_PPATH
int 2fh ; offer path build to someone else
pop bp ! pop di ! pop si ! pop ds
mov cx,0 ; if accepted then it's a remote drive
jnc redir_move_offer10
call build_remote_path ; build path if it a remote drive
redir_move_offer10:
pop ds
jc redir_asciiz_error ; return error's if we have any
jcxz redir_asciiz_offer ; it's a valid remote path
ret ; it's not a remote path
redir_asciiz_offer:
;==================
; The FDOS has called this hook to see if we are operating on an redirected
; drive. We return if we are not, or stay and process function here if we are.
call redir_dev_check ; is it a device ?
jnc redir_accept ; it's been recognised
; jmp redir_asciiz_file_offer ; now try offering as a file
redir_asciiz_file_offer:
;=======================
; entry: SS:BP -> function #, parameter address
; 1st level call (MXdisk not owned)
; exit: ZF = 1 if not networked
;
; This function is only called after an Int 2F/I2F_PPATH callout has been
; made and failed. On some functions (Open/Create) we do a check for devices
; between the redir_dev_offer and redir_asciiz_file offer
; We look for a "\\" as the start of "\\server\dir\file" form
push ds ; save DS
mov si,2[bp] ; SI -> parameter block
lds si,2[si] ; get ASCIIZ # from parameter block
mov di,offset pri_pathname ; SS:DI -> path buffer
call build_remote_path ; build path if it a remote drive
pop ds ; restore DS
jc redir_asciiz_error ; return error's if we have any
jcxz redir_accept ; it's a valid remote path
ret ; it's not a remote path
redir_asciiz_error:
; On Entry:
; BX = error code
; DS on stack
; On Exit:
; DS restored, BX preserved
; near return on stack discarded, and error returned to fdos_entry
;
pop ax ; discard "offer" near ret
ret ; drop straight back to caller
redir_drv_offer:
;===============
; The FDOS has called this hook to see if we are operating on an MSNET drive.
; We return if we are not, or stay and process function here if we are
;
; entry: SS:BP -> function #, parameter address
; (MXdisk not owned)
; exit: return if not networked
mov dl,current_dsk ; assume it's the default drive
mov si,2[bp] ; SI -> parameter block
mov ax,2[si] ; get drive # from parameter block
test al,al ; test if default drive
jz redir_drv_offer10 ; skip if default drive
dec ax ; else decrement for 0..26
xchg ax,dx ; and use that
redir_drv_offer10:
call isremote
jnz redir_accept
ret ; return if not
redir_snext_offer:
;=================
; The FDOS has called this hook to see if we are operating on an MSNET drive.
; We return if we are not, or stay and process function here if we are
call redir_restore_srch_state
test al,80h ; MSNET drive ?
jnz redir_accept
ret
redir_accept:
;============
; We have decided to accept an FDOS function.
; Note by this time the functions have been validated as legal
mov file_attrib,16h ; default search attribs to all
pop si ; discard the near return address
mov si,2[bp] ; SI -> parameter block
mov si,ds:[si] ; fdos code number
add si,si ; make it a word offset
jmp cs:redir_tbl-(39h*WORD)[si] ; call the relevant function
redir_badfunc:
;-------------
mov bx,ED_FUNCTION ; bad function number
ret ; (shouldn't get here...)
redir_tbl dw redir_mkdir ; 39-make directory
dw redir_rmdir ; 3A-remove directory
dw redir_chdir ; 3B-change directory
dw redir_creat ; 3C-create file
dw redir_open ; 3D-open file
dw redir_close ; 3E-close file
dw redir_read ; 3F-read from file
dw redir_write ; 40-write to file
dw redir_unlink ; 41-delete file
dw redir_lseek ; 42-set file pointer
dw redir_chmod ; 43-get/set file attributes
dw redir_badfunc ; 44-IOCTL emulation
dw redir_badfunc ; 45-duplicate handle
dw redir_badfunc ; 46-force duplicate handle
dw redir_badfunc ; 47-get current directory
dw redir_getdpb ;*48*disk information
dw redir_badfunc ;*49*flush buffers
dw redir_badfunc ;*4A*drive select
dw redir_badfunc ;*4B*create child PSP
dw redir_badfunc ;*4C*close child PSP
dw redir_badfunc ;*4D*generic FCB call
dw redir_first ; 4E-find first matching file
dw redir_next ; 4F-find next matching file
dw redir_commit ;*50*commit file
dw redir_mknew ;*51*make new file
dw redir_lock ;*52*lock/unlock block
dw redir_badfunc ; 53 build DDSC from BPB
dw redir_badfunc ;*54*Int 25/26 emulation
dw redir_expand ; 55 expand file name
dw redir_move ; 56-rename file
dw redir_dattim ; 57-get/set file name
Public get_ldt
; To support func5D00 remote server calls we must bypass the LDT and
; go directly to the physical drive. To allow support of CDROM's etc
; on servers we do use the LDT's where no corresonding physical drive
; exists.
get_ldt:
;-------
; On Entry:
; AL = drive (0 based)
; On Exit:
; ES:BX -> LDT for that drive, set CY if no valid LDT
; (All other regs preserved)
;
cmp al,ss:phys_drv ; if there is no conflict with
jae get_ldt_raw ; physical drives it's OK
test ss:remote_call,0ffh ; remote calls must get to physical
jz get_ldt_raw ; for server support
mov bx,ED_DRIVE ; invalid drive
stc ; no-go
ret
Public get_ldt_raw
get_ldt_raw:
;-----------
; On Entry:
; AL = drive (0 based)
; On Exit:
; ES:BX -> LDT for that drive, set CY if no valid LDT
; (All other regs preserved)
;
push ax
mov bx,ED_DRIVE ; assume invalid drive
cmp al,ss:last_drv ; do we have an LDT for this drive ?
jae get_ldt10 ; if not we can't have an LDT
cmp ss:word ptr ldt_ptr+2,0 ; are the LDT's allocated yet ?
je get_ldt10 ; if not return an error
mov bl,LDT_LEN
mul bl ; AX = offset of LDT entry for drive
les bx,ss:ldt_ptr ; get base of LDT's
add bx,ax ; DS:BX -> LDT for this drive
stc ; ie. CLC on exit
get_ldt10:
cmc
pop ax
ret
get_ldt_flags:
;-------------
; entry: DL = drive number
; exit: AX = LDT_FLAGS entry for that drive
; (All other regs preserved)
;
push es
push bx
xor ax,ax ; assume no LDT around...
xchg ax,dx ; AL = drive number
call get_ldt ; ES:BX -> LDT
xchg ax,dx ; restore drive to DX
jc glf10 ; AX = zero if no LDT
mov ss:word ptr current_ldt,bx ; set current_ldt
mov ss:word ptr current_ldt+2,es
mov ax,es:LDT_FLAGS[bx] ; return real flags
glf10:
pop bx
pop es
ret
islocal:
;-------
; entry: AL = drive number (zero based)
; exit: CY = set if drive is remote
; (All other regs preserved)
;
push ax
push dx
xchg ax,dx
call get_ldt_flags
if JOIN
test ax,LFLG_JOINED+LFLG_NETWRKD
; are REMOTE/JOINED bits set ?
else
test ax,LFLG_NETWRKD ; is REMOTE bit set ?
endif
jz islocal10
stc ; indicate it's not local
islocal10:
pop dx
pop ax
ret
isremote:
;--------
; entry: DL = drive number
; exit: ZF = clear if drive is remote
; CY = set if drive is JOIN'd
; (Only AX corrupted)
;
call get_ldt_flags
if JOIN
test ax,LFLG_JOINED ; is JOINED bit set ?
jnz isremote10
endif
test ax,LFLG_NETWRKD ; is REMOTE bit set ?
ret
if JOIN
isremote10:
test ax,LFLG_NETWRKD ; is REMOTE bit set ?
stc ; STC to indicate JOIN'd
ret
endif
redir_dev_check:
;---------------
; Offer the name to the network as a device
; On Entry:
; PB+2 = dword ptr to ascii name
; DI -> buffer to parse into
; On Exit:
; CY set if not recognised
;
mov word ptr current_ldt,0ffffh
mov err_drv,DHAT_DRVMSK
push ds ! push bp
mov si,2[bp] ; SI -> parameter block
lds si,2[si] ; DS:SI -> user supplied name
mov dx,si ; DS:DX as well..
push ss ! pop es
mov di,offset pri_pathname ; DI -> where to build pathname
mov ax,I2F_PPATH
int 2fh ; offer path build to someone else
pop bp ! pop ds
ret
build_remote_path:
;-----------------
; On Entry:
; DS:SI -> path to check
; SS:DI -> position to build remote path
; On Exit:
; CY clear, CX == 0 if it's a valid remote path
; CY clear, CX <> 0 if it's a local path
; CY set if there is an error to be returned (BX = error code)
;
mov cx,si ; save source path in CX
mov dl,ss:current_dsk ; assume current disk
lodsw ; get 1st two characters
test al,al ; make sure it's not a NUL string
jz build_remote_path10 ; before we check it it's a
cmp ah,':' ; drive specified
jne build_remote_path10 ; we want to find "d:\\" format too
mov bx,ED_DRIVE ; assume "invalid drive" error
and al,not 'a'-'A' ; cheap upper case
sub al,'A'
jb build_remote_path30 ; return "invalid drive" if error
cmp al,ss:last_drv ; check if > 'Z'
ja build_remote_path30 ; return "invalid drive" if error
xchg ax,dx ; DL = ASCIIZ supplied drive
lodsw ; get possible '\\'
build_remote_path10:
mov ss:word ptr current_ldt,0ffffh
call check_dslash ; is it "\\"
je build_remote_path20 ; if so forget about the drive #
call isremote ; test if drive DL is remote
if JOIN
jb build_remote_path30 ; return "invalid drive" if JOINed
endif
jnz build_remote_path20 ; it's remote, go build a path
xor cx,cx ; CY clear (no error)
inc cx ; CX <> 0, (non-remote drive)
ret
build_remote_path20:
; Build a path from the CSD and the pathname in the parameter block
mov si,cx ; DS:SI -> source ASIIZ name
push ss ! pop es ; ES:DI -> MSNET buffer
call redir_build_path
jc build_remote_path30
xor cx,cx ; CY clear, CX == 0
ret ; it's a valid remote path
build_remote_path30:
stc ; CY set, we have error BX
ret
eject
; MAKE DIRECTORY (MKDIR)
; +----+----+----+----+----+----+
; | 39 | name |
; +----+----+----+----+----+----+
; entry:
; ------
; name: segmented address of ASCIIZ name
; exit:
; -----
; BX: 0000 or error code ( < 0)
redir_mkdir:
mov ax,I2F_MKDIR ; it's a make dir
jmps redir_pathop_common
eject
; REMOVE DIRECTORY (RMDIR)
; +----+----+----+----+----+----+
; | 3A | name |
; +----+----+----+----+----+----+
; entry:
; ------
; name: segmented address of ASCIIZ name
; exit:
; -----
; BX: 0000 or error code ( < 0)
redir_rmdir:
mov ax,I2F_RMDIR ; it's a remove dir
; jmp redir_pathop_common
redir_pathop_common:
push ds
push ss ! pop ds
call int2f_ldt
pop ds
jc redir_pathop_common10
xor ax,ax ; no problems
redir_pathop_common10:
xchg ax,bx ; return result in BX
ret
eject
; CHANGE DIRECTORY (CHDIR)
; +----+----+----+----+----+----+
; | 3B | name |
; +----+----+----+----+----+----+
; entry:
; ------
; name: segmented address of ASCIIZ name
; exit:
; -----
; BX: 0000 or error code ( < 0)
redir_chdir:
;------------
; The following code throws out the ASSIGN/SUBST form "f:=d:\"
; The alternative is to allow the Extentions to throw it out as a bad path
; but this is safer, and doesn't cost us much.
push ds
mov bx,ED_PATH ; assume we have a problem
; BX = ED_PATH ready for error
mov si,2[bp] ; SI -> parameter block
lds si,ds:2[si] ; DS:SI -> ASCIIZ string
cmp ds:word ptr 1[si],'=:' ; 'd:=' specification?
je redir_chdir40
push ss ! pop ds ; DS = PCMODE
cmp word ptr current_ldt,-1
je redir_chdir40 ; we reject any chdir of the form
; "\\server\path"
mov ax,I2F_CHDIR
call int2f_ldt ; is this a valid path ?
jc redir_chdir30
push ds ! pop es
mov si,offset pri_pathname
; DGM - don't allow path greater than 66 chars
mov cx, LDT_FLAGS-LDT_NAME ; calculate max pathlen from LDT
mov di, si
sub ax,ax
repne scasb
mov ax, ED_PATH ; assume path too long
jne redir_chdir30 ; jump if path too long
les di,current_ldt ; ES:DI -> path for this drive
call copy_asciiz ; copy new path to LDT current dir
xor ax,ax ; no errors
redir_chdir30:
xchg ax,bx ; return result in BX
redir_chdir40:
pop ds
ret
eject
; CREATE FILE (CREAT)
; +----+----+----+----+----+----+----+----+
; | 3C | name | mode |
; +----+----+----+----+----+----+----+----+
; entry:
; ------
; name: segmented address of ASCIIZ name
; mode: attribute for file
; exit:
; -----
; BX: file handle or error code ( < 0)
redir_creat:
call get_attrib_mode ; AX = mode, CX = attrib
xchg ax,cx
or ax,20h ; set the ARCHIVE bit on create
mov file_attrib,ax
mov int2f_stack,ax ; attrib on stack
mov int2f_cmd,I2F_CREATE
cmp word ptr current_ldt,-1 ; valid LDT ?
jne redir_creat10 ; no, modify create function
mov int2f_cmd,I2F_XCREATE
redir_creat10:
jmp redir_open_create_common
eject
; OPEN FILE (OPEN)
; +----+----+----+----+----+----+----+----+----+----+
; | 3D | name | mode | attrib |
; +----+----+----+----+----+----+----+----+----+----+
; entry:
; ------
; name: segmented address of ASCIIZ name
; mode: open mode
; attrib: file attrib for search (default = 16h)
; exit:
; -----
; BX: file handle or error code ( < 0)
redir_open:
;----------
;
call get_attrib_mode ; AX = mode, CX = attrib
and ax,7fh ; remove inheritance bit
mov int2f_stack,ax
mov int2f_cmd,I2F_OPEN
redir_open_create_common:
call find_xfn ; get external file handle in DI
mov bx,ED_HANDLE ; assume no handles
jc redir_open20
push di
call redir_openfile ; now do the open
pop di
jc redir_open20
; On Entry:
; AL = IFN
; DI = XFN
; ES:BX -> DHNDL_
; On Exit:
; PSP fixed up
;
mov bx,di
call get_xftptr ; ES:DI -> XFN table
jc redir_open10 ; no PSP, skip xfn stuff
add di,bx ; add external file #
stosb ; update table entry
ret
redir_open10:
xchg ax,bx ; no PSP, return XFN in BX
redir_open20:
ret
redir_openfile:
;--------------
; On Entry:
; pri_pathname and file_attrib have been set up
; On Exit:
; AL = IFN
; ES:BX = DHNDL_
; CY set on error, BX = error code
; We should set up COUNT, MODE, UID, PSP, and SHARE
call find_dhndl ; find DHNDL_
jc redir_openf40 ; return if a problem with this
push ax ; save IFN
push es ! push bx ; save DHNDL_
mov ax,file_mode
and al,not DHM_LOCAL
mov es:DHNDL_MODE[bx],ax ; save mode in DOSHNDL
mov es:DHNDL_SHARE[bx],0 ; zero share record
mov ax,int2f_cmd ; either open or create
call int2f_dhndl ; lets try the command
pop bx ! pop es ; recover DHNDL_
pop dx ; recover IFN
jc redir_openf30 ; on error discard the handle
xchg ax,dx ; return AL = IFN
mov es:DHNDL_COUNT[bx],1 ; handle now properly in use
mov cx,file_mode
test ch,DHM_FCB/256 ; is this an FCB open ?
jz redir_openf10
or es:byte ptr DHNDL_MODE+1[bx],DHM_FCB/100h
redir_openf10:
test cl,DHM_LOCAL ; is it a "private" file ?
jz redir_openf20
or es:byte ptr DHNDL_WATTR+1[bx],DHAT_LOCAL/100h
redir_openf20:
ret
redir_openf30:
xchg ax,bx ; returning error in BX
ret
redir_openf40:
mov bx,ED_HANDLE ; no handles are left
ret
eject
; CLOSE FILE (CLOSE)
; +----+----+----+----+
; | 3E | handle |
; +----+----+----+----+
; entry:
; ------
; handle: open file handle to be closed
; exit:
; -----
; BX: 0000 or error code ( < 0)
redir_close:
;------------
;
mov si,2[bp] ; SI -> parameter block
mov ax,2[si] ; get external file #
call get_xftptr ; ES:DI -> xft table
jc redir_close10
add di,ax ; add in XFN
mov ax,0FFh ; get "unused" value for XFT
xchg al,es:[di] ; release file & get internal #
redir_close10: ; we can now do the actual close
call ifn2dhndl ; ES:BX -> DHNDL_
jc redir_close30 ; exit if error occurrs
mov ax,es:DHNDL_COUNT[bx]
mov ah,3eh ; count, AH = 3E
push ax
mov ax,I2F_CLOSE
call int2f_dhndl ; close it
pop bx
jnc redir_close20 ; errors ?
xchg ax,bx ; recover return code
redir_close20:
ret
redir_close30:
mov bx,ED_H_MATCH ; assume invalid IFN
ret
eject
; READ FROM FILE (READ)
; +----+----+----+----+----+----+----+----+----+----+
; | 3F | handle | buffer | count |
; +----+----+----+----+----+----+----+----+----+----+
; entry:
; ------
; handle: open file handle
; buffer: buffer to read into
; count: max. number of bytes to read
; exit:
; -----
; BX: error code ( < 0)
redir_read:
;----------
mov ax,I2F_READ
redir_rw_handle:
mov si,2[bp] ; SI -> parameter block
mov cx,8[si] ; CX = Count
push ds
lds dx,4[si] ; DS:DX = DMA address
call redir_rw
pop ds
mov si,2[bp] ; SI -> parameter block
mov 8[si],cx ; CX = Count
ret
eject
; WRITE TO FILE (WRITE)
; +----+----+----+----+----+----+----+----+----+----+
; | 40 | handle | buffer | count |
; +----+----+----+----+----+----+----+----+----+----+
; entry:
; ------
; handle: open file handle
; buffer: buffer to be wriiten
; count: max. number of bytes to write
; exit:
; -----
; BX: error code ( < 0)
redir_write:
;-----------
mov ax,I2F_WRITE
jmps redir_rw_handle
redir_rw:
;--------
; On Entry:
; AX = command code
; ES:BX = DHNDL_
; CX = count
; DS:DX = buffer
; On Exit:
; CX = count transferred
; BX = zero or error code
;
cmp ax,I2F_WRITE ; is it a write ?
jne redir_rw10
and es:DHNDL_WATTR[bx],not (DHAT_CLEAN+DHAT_TIMEOK)
redir_rw10:
push ss:dma_offset
push ss:dma_segment
push cx
mov cl,4
mov di,dx ; save dma offset
and dx,15 ; make offset within para
shr di,cl ; convert offset to para offset
mov si,ds ; add to segment
add di,si ; DI:DX -> DMA address
ja redir_rw15 ; are we within normal TPA ?
inc di ; no adjust to offset within
shl di,cl ; magic segment FFFF
add dx,di
mov di,0ffffh ; use magic segment
redir_rw15:
pop cx
mov ss:dma_offset,dx ; save for xfer
mov ss:dma_segment,di
call int2f_dhndl ; try the xfer
pop ss:dma_segment
pop ss:dma_offset
mov bx,0 ; assume no error
jnc redir_rw20
xchg ax,bx ; return error code
cmp bx,ED_LOCKFAIL ; is it a lockfail error ?
jne redir_rw20 ; no, just return it
les di,ss:current_dhndl ; compatibility modes should generate
test es:DHNDL_MODE[di],DHM_SHAREMSK
jz redir_rw20 ; critical errors fro ED_LOCKFAIL
mov bx,ED_ACCESS ; sharing modes return access denied
redir_rw20:
ret
eject
; DELETE FILE (UNLINK)
; +----+----+----+----+----+----+
; | 41 | name |
; +----+----+----+----+----+----+
; entry:
; ------
; name: segmented address of ASCIIZ name
; exit:
; -----
; BX: 0000 or error code ( < 0)
redir_unlink:
mov ax,I2F_DEL ; it's a delete
; mov file_attrib,6 ; only delete files
redir_unlink_move_common:
push ax
call get_attrib_mode ; allow overrides for server calls
pop ax
jmp redir_pathop_common
eject
; GET/SET FILE POSITION (LSEEK)
; +----+----+----+----+----+----+----+----+----+----+
; | 42 | handle | offset | method |
; +----+----+----+----+----+----+----+----+----+----+
; On Entry:
; ES:BX = DHDNL_
; method: 0 = begin, 1 = current, 2 = end of file
;
; On Exit:
; BX = Error Code, offset updated with new value
;
redir_lseek:
;-----------
mov di,bx ; ES:DI -> DHNDL_
mov si,2[bp] ; SI -> parameter block
mov dx,4[si] ; get 32-bit file offset
mov cx,6[si] ; into CX,DX
mov ax,8[si] ; get seek mode
test ax,ax
jz redir_lseek20 ; seek from beginning
dec ax
jz redir_lseek10 ; seek from current position
dec ax
jz redir_lseek30 ; seek from end
mov bx,ED_DATA ; else invalid seek mode
ret
redir_lseek10: ; seek mode 1: relative to position
add dx,es:DHNDL_POSLO[di] ; add position + offset
adc cx,es:DHNDL_POSHI[di]
; jmps redir_lseek20
redir_lseek20: ; seek mode 0: set absolute position
mov es:DHNDL_POSLO[di],dx ; set new file offset
mov es:DHNDL_POSHI[di],cx ; SI = error code/0 at this point
; jmps redir_lseek90
redir_lseek90:
mov 4[si],dx ; set 32-bit file offset
mov 6[si],cx ; for return
xchg ax,bx ; error code in BX
ret
redir_lseek30: ; seek mode 2: relative to end
mov bx,es:DHNDL_MODE[di] ; ask MSNET if anyone else can write
and bl,DHM_SHAREMSK ; isolate sharing bits
cmp bl,DHM_DENY_READ ; Only DENY_READ and DENY_NONE a
jb redir_lseek40 ; problem - others might write to
push si ; the file so we must ask the server
; how long the file is now
mov ax,I2F_LSEEK ; CX:DX = position now
call int2f_dhndl ; do a remote seek
pop si ; DX:AX = EOF relative position
jc redir_lseek90 ; (unless we have an error)
xchg ax,dx ; AX:DX = new EOF relative position
xchg ax,cx ; and finally get into CX:DX
xor ax,ax ; no problems...
;jmps redir_lseek90 ; MYST-removed,file offset wasn't updated
jmps redir_lseek20 ; MYST-added,go and update the new file offset.
redir_lseek40:
add dx,es:DHNDL_SIZELO[di] ; add file size + offset
adc cx,es:DHNDL_SIZEHI[di]
jmps redir_lseek20
eject
; GET/SET FILE ATTRIBUTES (CHMOD)
; +----+----+----+----+----+----+----+----+----+----+
; | 43 | name | flag | attrib |
; +----+----+----+----+----+----+----+----+----+----+
; | size |
; +----+----+----+----+
; entry:
; ------
; name: pointer to ASCIIZ file name
; flag: 0 = get attribute,
; 1 = set attribute,
; 2-5 = passwords (ignored)
; attrib: new attribute if flag = 1
; password mode if flag = 3
;
; exit:
; -----
; BX: 0000 or error code ( < 0)
; attrib: file's attribute if flag = 0
; size: file's size
redir_chmod:
;-----------
;
mov bx,2[bp] ; BX -> parameter block
mov cx,8[bx] ; get attribs
mov bx,6[bx] ; get access flag
mov ax,I2F_SET_ATTR ; assume it's a set
cmp bl,1 ; is it a set ?
je redir_chmod10 ; if not then
mov ax,I2F_GET_ATTR ; assume it's a get
mov cx,16h ; with everything attribs
jb redir_chmod10 ; was it ?
mov ax,ED_ACCESS ; no, return access denied
jmps redir_chmod20 ; cause it DR password stuff
redir_chmod10:
mov int2f_stack,cx ; attribs on the stack
call int2f_ldt ; do the Int 2F
jc redir_chmod20
mov si,2[bp] ; SI -> parameter block
mov 8[si],ax ; return attribute
mov 10[si],di
mov 12[si],bx
xor ax,ax ; success
redir_chmod20:
xchg ax,bx ; return result in BX
ret
eject
; GET DISK PARAMETER BLOCK
; +----+----+----+----+----+----+----+----+----+----+
; | 48 | drive | dpb | adjust |
; +----+----+----+----+----+----+----+----+----+----+
; entry:
; ------
; drive: drive to get information about
; exit:
; -----
; BX: 0000 or error code ( < 0)
; dpb: address of DOS DPB (offset/segment)
; adjust: delwatch adjustment of free space
; NB. We only fill in the fields required by the Disk Free Space call.
redir_getdpb:
;------------
mov ax,I2F_SPACE
call int2f_ldt ; get the info
jnc redir_getdpb10 ; if we get an error then make CLMSK=FE
mov al,0ffh
redir_getdpb10:
mov si,offset sec_pathname ; let's re-use this as a temp DPB
dec al ; make cluster mask
mov ds:DDSC_CLMSK[si],al ; and stuff into DPB
mov ds:DDSC_FREE[si],dx
mov ds:DDSC_SECSIZE[si],cx
inc bx ; inc number of clusters
mov ds:DDSC_NCLSTRS[si],bx
mov al,err_drv ; also fill in drive number
mov ds:DDSC_UNIT[si],al
mov si,2[bp] ; DI -> parameter block
mov 4[si],offset sec_pathname
mov 6[si],ds ; point to my dummy DPB
mov word ptr 8[si],0 ; zero adjust value
mov bx,0ffh ; return 0xFF (ie. bad drive)
ret
eject
; FIND FIRST FILE
; +----+----+----+----+----+----+----+----+----+----+
; | 4E | name | ***** | attrib |
; +----+----+----+----+----+----+----+----+----+----+
; entry:
; ------
; name: pointer to ASCIIZ file name
; attrib: attribute to be used in search
;
; exit:
; -----
; BX: 0001 or error code ( < 0)
; Note: This call returns matching files in
; the current DMA address and also saves
; the BDOS state in the there.
;
; If there is space for multiple file names we
; could return as many as will fit into the DTA
; but it's easier just to return 1 file
;
redir_first: ; 13-find first matching file
;----------
; ONLY 1 file returned for now.....
;
call get_attrib_mode ; AX = mode, CX = attrib
mov ax,I2F_SFIRST ; srch first, valid LDT
les di,current_ldt
cmp di,-1 ; valid LDT ?
jne redir_first10
mov ax,I2F_XSFIRST ; srch first, no valid LDT
redir_first10:
jmps srch_buf_common
eject
; FIND NEXT FILE
; +----+----+
; | 4F |
; +----+----+
;
; entry:
; ------
;
; exit:
; -----
; BX: 0000 or error code ( < 0)
; Note: This call returns matching files in
; the current DMA address and also saves
; the BDOS state in the there.
redir_next: ; 14-find next matching file
;---------
; ONLY 1 file returned for now.....
;
push ss ! pop es
mov di,offset srch_buf ; point ES:DI -> search buffer
mov ax,I2F_SNEXT
srch_buf_common:
push dma_offset
push dma_segment
mov dma_offset,offset srch_buf
mov dma_segment,ds
call int2f_op
pop dma_segment
pop dma_offset
jc srch_buf_common10
call redir_save_srch_state ; if no error save state
xor ax,ax ; return AX = 1 file found
srch_buf_common10:
xchg ax,bx ; return code in BX
ret
redir_save_srch_state:
; On entry DS=PCMODE
les di,dword ptr dma_offset ; ES:DI -> search state in DMA address
mov si,offset srch_buf
mov cx,21 ; save 1st 21 bytes
rep movsb
push si ; save name/ext
add si,11 ; skip to name/ext
movsb ; copy the attribute
add si,10 ; skip reserved bytes
movsw ; copy the time
movsw ; copy the date
add si,2 ; skip starting cluster
movsw ; copy the file size
movsw
pop bx ; recover name
jmp unparse ; unparse the name
; Restore DOS search area from user DTA
;
redir_restore_srch_state:
;------------------------
; On Entry:
; DS = SYSDAT
; On Exit:
; AL = 1st byte of srch buf
; DS preserved
;
push ss
pop es
mov di,offset srch_buf ; ES:DI -> internal state
push ds
lds si,ss:dword ptr dma_offset
lodsb ; DS:SI -> search state in DMA address
stosb
mov cx,20 ; copy 1st 21 bytes
rep movsb
pop ds
ret
eject
; COMMIT FILE (COMMIT)
; +----+----+----+----+
; | 50 | handle |
; +----+----+----+----+
; entry:
; ------
; handle: open file handle to be flushed
; exit:
; -----
; BX: 0000 or error code ( < 0)
redir_commit:
test es:DHNDL_MODE[bx],DHM_WO+DHM_RW
jz redir_commit10 ; we don't need to commit it
mov ax,I2F_COMMIT
call int2f_dhndl ; commit this file
jc redir_commit20
redir_commit10:
xor ax,ax ; success
redir_commit20:
xchg ax,bx ; return result in BX
ret
eject
; CREATE NEW FILE
; +----+----+----+----+----+----+----+----+
; | 51 | name | mode |
; +----+----+----+----+----+----+----+----+
; entry:
; ------
; name: segmented address of ASCIIZ name
; mode: attribute for file
; exit:
; -----
; BX: file handle or error code ( < 0)
; Note: The function is identical to CREATE FILE
; with the exception that an error is returned
; if the specified file already exists.
redir_mknew:
call get_attrib_mode ; AX = mode, CX = attrib
xchg ax,cx
or ax,120h ; set ARCHIVE + MKNEW bits
mov file_attrib,ax
mov int2f_stack,ax
mov int2f_cmd,I2F_CREATE
mov file_mode,DHM_RW ; Open Compatibility mode, Read/Write
jmp redir_open_create_common
eject
; LOCK/UNLOCK FILE DATA (LOCK/UNLOCK)
; +----+----+----+----+----+----+----+----+
; | 52 | handle | offset |
; +----+----+----+----+----+----+----+----+
; | length | lock |
; +----+----+----+----+----+----+
; entry:
; ------
; handle: open file handle
; offset: long integer offset
; length: long integer byte count
; lock: 0 = lock, 1 = unlock
; exit:
; -----
; BX: byte count or error code ( < 0)
redir_lock:
; Lock uses I2F_LOCK, with CX,DX,SI as per INT 21, DI on stack
; Unlock uses I2F_UNLOCK with same.
mov bx,2[bp] ; BX -> parameter block
if DOS5
push bp
lea bp,4[bx] ; BP -> parameter block
mov dx,bp ; as does DX
mov ax,I2F_LOCK
mov bl,ds:byte ptr 12[bx]
mov bh,5Ch ; lock/unlock in BX
call int2f_dhndl ; try the operation
pop bp
else
mov dx,ds:4[bx] ; get low word of offset in DX
mov cx,ds:6[bx] ; and the hi word in CX
mov di,ds:8[bx] ; get low word of length in DI
mov si,ds:10[bx] ; and high in SI
mov int2f_stack,di ; length low is on stack
mov ax,I2F_LOCK ; assume lock
cmp ds:word ptr 12[bx],0
je redir_lock10
mov ax,I2F_UNLOCK ; no, it must be unlock
redir_lock10:
call int2f_dhndl ; try the operation
endif
jc redir_lock20
xor ax,ax ; success
redir_lock20:
xchg ax,bx ; return result in BX
ret
eject
; EXPAND FILE
; +----+----+----+----+----+----+----+----+----+----+
; | 55 | old name | new name |
; +----+----+----+----+----+----+----+----+----+----+
; entry:
; ------
; old name: segmented address of ASCIIZ name
; new name: segmented address of ASCIIZ name
; exit:
; -----
; BX: 0000 or error code ( < 0)
; If we got here pri_pathname already contains expanded name - just copy it
; back to the users buffer.
redir_expand:
;------------
mov si,2[bp] ; SI -> parameter block
les di,10[si] ; ES:DI -> user supplied name
mov si,offset pri_pathname
call copy_asciiz
xor bx,bx ; no errors
ret
eject
; RENAME FILE
; +----+----+----+----+----+----+----+----+----+----+
; | 56 | old name | new name |
; +----+----+----+----+----+----+----+----+----+----+
; entry:
; ------
; old name: segmented address of ASCIIZ name
; new name: segmented address of ASCIIZ name
; exit:
; -----
; BX: 0000 or error code ( < 0)
; Note: R/O files can be renamed.
; ---
redir_move:
mov ax,I2F_REN ; it's a rename
jmp redir_unlink_move_common
eject
; GET/SET FILE DATE/TIME
; +----+----+----+----+----+----+----+----+----+----+
; | 57 | handle | mode | date | time |
; +----+----+----+----+----+----+----+----+----+----+
; entry:
; ------
; handle: open file handle
; mode: 0 = get date/time, 1 = set date/time
; date: date as in directory FCB
; time: time as in directory FCB
; exit:
; -----
; BX: 0000 or error code ( < 0)
; date: date of last modification if mode = 0
; time: date of last modification if mode = 0
redir_dattim:
;------------
mov si,2[bp] ; DS:SI -> param block
cmp ds:word ptr 4[si],1 ; is it set ?
ja redir_dattim30 ; if illegal say so
je redir_dattim10
mov ax,es:DHNDL_DATE[bx] ; we need to copy the file date
mov word ptr 6[si],ax ; into the parameter block
mov ax,es:DHNDL_TIME[bx]
mov word ptr 8[si],ax ; and the time
jmps redir_dattim20
redir_dattim10:
mov ax,word ptr 6[si] ; copy the date we are given
mov es:DHNDL_DATE[bx],ax ; into the DOSHNDL
mov ax,word ptr 8[si] ; and the time
mov es:DHNDL_TIME[bx],ax
or es:DHNDL_WATTR[bx],DHAT_TIMEOK
and es:DHNDL_WATTR[bx],not DHAT_CLEAN
redir_dattim20:
xor bx,bx ; all went OK
jmps redir_dattim40
redir_dattim30:
mov bx,ED_FUNCTION ; bad function number
redir_dattim40:
ret
Public redir_build_path
; AH contains state of path processing, and is normally zero
BP_DOT equ 1 ; we have had a DOT end are processing the .EXT
BP_WILD equ 2 ; we have encountered a wild card
BP_BSLASH equ 4 ; the last character was a BSLASH
; May be called with or without MXDisk
redir_build_path:
;----------------
; On Entry:
; DS:SI -> source name
; ES:DI -> destination name (in PCMODE data segment)
; current_ldt -> LDT_ for specified drive
; On Exit:
; CY clear if we could build the path
;
; firstly we discard any drive portion
lodsw ; get 1st two characters
cmp ah,':' ; is a drive specified ?
jne redir_bp10 ; discard "d:" if so
lodsw
redir_bp10:
; Is it a "\\server\sharename\subdir\filename.ext" format ?
call check_dslash ; if it is \\
je redir_bp20 ; then just copy the lot
; it's a normal "A:\subdir\filename.ext" pathname format
dec si ; we have swallowed the 1st two
dec si ; chars - now we change our mind
push ds ! push si
lds si,es:current_ldt
mov cx,ds:LDT_ROOTLEN[si] ; copy the root portion of the name
rep movsb ; copy the server stub name
mov dx,di ; ES:DX -> root position
call check_slash ; do we start from the root ?
je redir_bp11 ; yes, then that's all
call copy_asciiz ; no, copy the rest of the path
call redir_bp_append_slash ; append '\' for our path processing
redir_bp11:
pop si ! pop ds
jmps redir_bp_next_level ; continue processing given path
redir_bp20:
; It is a "\\server\sharename\subdir\filename.ext" format
stosw ; copy the "\\"
xor ax,ax ; clear "flags" in AH
redir_bp21:
lodsb ; work along the name
test al,al ; unexpected end of name ?
jz redir_bp_exit20 ; go with what we've got....
call check_slash ; have we found the root '\' ?
je redir_bp23
if KANJI
call dbcs_lead ; is it the 1st of a kanji pair
jne redir_bp22 ; no, onto next char
stosb ; copy the 1st character
movsb ; copy 2nd byte of KANJI pair
jmps redir_bp21 ; now we can move onto next char
redir_bp22:
endif
call toupper ; upper case the character
stosb ; copy the character
jmps redir_bp21 ; go and do another one
redir_bp23:
mov dx,di ; bodge root to the top
; mov al,'\'
stosb ; put in a '\'
jmps redir_bp_next_level ; yes, this is the new "root"
; We have reached the terminating NUL
redir_bp_exit:
test ah,BP_WILD ; did we get any wildcards ?
je redir_bp_exit10
mov si,2[bp] ; SS:SI -> parameter block
mov al,ss:[si] ; fdos code number
cmp al,MS_X_FIRST ; search first ?
je redir_bp_exit10
cmp al,FD_EXPAND ; expand pathname
je redir_bp_exit10
cmp ss:remote_call,0 ; should we wildcard REN/DEL ?
je redir_bp_ED_PATH ; reject as not allowed here
cmp al,MS_X_RENAME ; rename ?
je redir_bp_exit10
cmp al,MS_X_UNLINK ; delete ?
jne redir_bp_ED_PATH ; reject as not allowed here
redir_bp_exit10:
xor al,al ; make sure our string is zero
stosb ; terminated
call redir_bp_append_slash ; append a trailing '\' if we don't
dec di ; have one so we can remove it
cmp di,dx ; are we talking about the root ?
jne redir_bp_exit20
cmp es:byte ptr 0FFFFh[di],':'
jne redir_bp_exit20 ; if we have a trailing ':' allow
inc di ; a '\' at the root
redir_bp_exit20:
xor al,al ; KANJI aware way of removing trailing
stosb ; '\' from the path....
; clc
ret
redir_bp_next_level:
; DS:SI -> source pathname, ES:DI -> destination pathname, ES:DX -> root
; AH = current status
mov cx,8 ; expansion count ready
xor ax,ax
redir_bp_next_char:
lodsb
test al,al ; end of the line ?
jz redir_bp_exit ; do the exit
; Is it a '\' ?
redir_bp40:
call check_slash ; was it a seperator ?
jne redir_bp50
test ah,BP_WILD ; have we encountered wildcards ?
jnz redir_bp_ED_PATH ; reject as not allowed here
mov al,'\' ; make sure it's a BSLASH
stosb
jmps redir_bp_next_level ; start at a new level
; Is it a '.' ?
redir_bp50:
cmp al,'.' ; seperator ?
jne redir_bp60
lodsb ; get next letter
test al,al ; is it trailing '.' ?
je redir_bp_exit ; then exit now
cmp cx,8 ; check for '.' and '..'
je redir_bp52 ; if at start of field
redir_bp51: ; othewise it's a ".EXT"
mov bx,ED_FILE ; assume we have a problem
test ah,BP_DOT ; have we had an extention before ?
jnz redir_bp_err ; we've got a problem
dec si ; rewind a character
mov ax,'.'+256*BP_DOT ; so we are back to the '.'
stosb ; store the '.' in destination
mov cx,3 ; expand the extention
jmps redir_bp_next_char
redir_bp52: ; It might be a "." or ".."
call check_slash ; is it '.\'
je redir_bp_next_char ; discard them both
cmp al,'.' ; is it '..' ?
jne redir_bp51 ; no, must be an extention after all
call redir_bp_ddot ; rewind a level
jnc redir_bp_next_level ; onto next level
redir_bp_ED_PATH:
; set CY flag to indicate error then return
mov bx,ED_PATH ; return "invalid path" error
redir_bp_err:
stc
ret
; Is it a '*' ?
redir_bp60:
call check_delim ; is it a delimiter ?
jz redir_bp_ED_PATH ; thats illegal at this point
cmp al,'*' ; wildcards ?
jne redir_bp70
mov al,'?'
rep stosb ; expand it
; or ah,BP_WILD ; remember wild-card encountered
; jmps redir_bp_next_char ; check for wildcards
;
; ; we can just fall through
;
redir_bp70:
cmp al,'?' ; wild card is possibly OK
jne redir_bp80
or ah,BP_WILD ; remember wild-card encountered
redir_bp80:
; Normal Character
; AL contains a normal character for us to process.
; Uppercase the character, look out for KANJI etc
jcxz redir_bp_next_char ; discard if no space is left
dec cx ; one less to expand
if KANJI
call dbcs_lead ; is it the 1st of a kanji pair
jne redir_bp90
inc si ; skip 2nd byte
jcxz redir_bp_next_char ; discard if no room for kanji char
dec cx ; one less to expand
stosb ; store 1st byte of kanji character
dec si ; point at 2nd byte again
movsb ; copy 2nd byte of kanji character
jmps redir_bp_next_char
redir_bp90:
endif
call toupper ; make it upper case
stosb ; plant the character
jmps redir_bp_next_char
redir_bp_ddot:
; We have encountered a '..' in a pathname, so rewind up a level
; On Entry:
; DS:SI -> source position, ES:DI -> destination position
; ES:DX -> root position, AL = Character
; On Exit:
; ES:DI -> start of field one level up, unless we get an error when CY set.
lodsb ; look at char after '..'
call check_slash ; is it '..\'
je redir_bp_ddot10
test al,al ; is it a trailing '..'
jnz redir_bp_ED_PATH ; no, anything else is bad...
dec si ; trailing '..', rewind to NUL
redir_bp_ddot10:
dec di ; move back to last '\'
cmp di,dx ; are we at the root anyway ?
jle redir_bp_ED_PATH ; then don't discard any
; We now start at ES:DX and work along till ES:DI -> char after last '\'
push ds ! push si
push es ! pop ds
mov si,dx ; DS:SI -> char after root
mov cx,dx ; last '\' position in CX
redir_bp_ddot20:
lodsb
cmp si,di ; end of the line yet ?
jae redir_bp_ddot30 ; yes, stop now
if KANJI
call dbcs_lead ; is it 1st of a kanji pair ?
jne redir_bp_ddot25
lodsb ; skip the 2nd too
jmps redir_bp_ddot20 ; then go on to next char
redir_bp_ddot25:
endif
call check_slash ; is it a '\'
jne redir_bp_ddot20 ; no, do next
mov cx,si ; save position after the '\'
jmps redir_bp_ddot20
redir_bp_ddot30:
mov di,cx ; last '\' was here..
pop si ! pop ds
clc ; no errors
ret
redir_bp_append_slash:
; On Entry:
; ES:DX -> ASCIIZ string to append a '\' to
; On Exit:
; ES:DI -> terminating NUL
; All but AX preserved
;
xor ax,ax ; AH = 0, initially no previous char
mov di,dx ; start processing from here
redir_bp_append_slash10:
mov ah,al ; save previous char in AH
mov al,es:[di] ; get a character
inc di ; point to next
test al,al ; is it NUL ?
if KANJI
je redir_bp_append_slash20
call dbcs_lead ; is it 1st of a kanji pair ?
jne redir_bp_append_slash10
inc di ; skip the 2nd too
jmps redir_bp_append_slash10 ; (it might be '\')
redir_bp_append_slash20:
else
jnz redir_bp_append_slash10
endif
mov al,ah ; get previous char
call check_slash ; did we have a '\' ?
je redir_bp_append_slash30
dec di ; ES:DI -> existing NUL
mov ax,'\'
stosw ; new terminating '\'
redir_bp_append_slash30:
dec di ; ES:DI -> NUL
ret
get_attrib_mode:
;---------------
; On Entry:
; SS:2[BP] -> param block
; On Exit:
; AX = file mode
; CX = file attributes
;
mov si,2[bp] ; SI -> parameter block
mov ax,ds:6[si] ; get mode
mov cx,ds:8[si] ; get attribs
mov file_mode,ax ; save open mode
mov file_attrib,cx ; save file attribute
ret
int2f_ldt:
;---------
; On Entry:
; AX = Int2F command
; On Exit:
; CY clear, AX returned unchanged
; CY set, AX = Our Negative Error Code
;
les di,ss:current_ldt
jmps int2f_op
int2f_dhndl:
;----------
; On Entry:
; AX = Int2F command
; On Exit:
; CY clear, AX returned unchanged
; CY set, AX = Our Negative Error Code
;
les di,ss:current_dhndl
int2f_op:
push ds
push ss ! pop ds
push int2f_stack ; put word on stack
int 2fh ; get the info
pop int2f_stack ; clean up the stack
pop ds
jnc int2f_op10
neg ax ; AX = we keep error codes negative
; stc ; we have a problem
int2f_op10:
ret
end