mirror of
https://github.com/SEPPDROID/DR-DOS-OpenDOS.git
synced 2025-10-22 16:04:20 +00:00
1723 lines
44 KiB
Plaintext
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
|