UTILS.FDO
资源名称:drdossrc.zip [点击查看]
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:68k
源码类别:
操作系统开发
开发平台:
Asm
- ; File : $UTILS.FDO$
- ;
- ; 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$
- ; UTILS.FDO 1.39 94/11/30 13:39:18
- ; added share_delay function
- ; UTILS.FDO 1.37 94/07/13 15:42:01
- ; Change to rename/delete of file open in compatibility modes
- ; UTILS.FDO 1.36 94/06/28 11:10:10
- ; Limit ddsc allocation to 1st 255
- ; UTILS.FDO 1.34 94/04/25 19:33:04
- ; Reject blank names (ie. all spaces) when parsing path
- ; We used to die in rebuild_ldt_curdir (GATEWAY problem)
- ; UTILS.FDO 1.33 93/12/16 13:57:06
- ; Fix path_prep bug when dir in path doesn't exist
- ; UTILS.FDO 1.32 93/12/09 23:56:10
- ; Move non-inherited bit to correct place in file handle
- ; UTILS.FDO 1.31 93/12/08 03:30:03
- ; Add extra check to offer_join: consider JOIN B: FRED, SUBST L: FREDFRED
- ; A CD L: would see FRED at the root of B: and change into it, so we
- ; would end up at FRED, so we only check if ROOTLEN=2
- ; UTILS.FDO 1.27 93/11/19 17:45:14
- ; Fix for SERVER print queue viewing problem
- ; UTILS.FDO 1.26 93/11/08 16:30:12
- ; Get dat/time on device handle returns current date/time
- ; UTILS.FDO 1.25 93/09/14 20:03:42
- ; Trust LFLG_PHYSICAL
- ; UTILS.FDO 1.23 93/09/03 20:26:09
- ; Add "no critical errors" support (int 21/6C)
- ; UTILS.FDO 1.22 93/07/26 18:11:00
- ; re-arrange DHNDL_DCNTHI for the benefit of Geoworks
- ; UTILS.FDO 1.21 93/07/20 22:43:48
- ; Even fewer checks on int 25/26
- ; ENDLOG
- ; General utility include module for FDOS.A86
- select_pb2:
- ;----------
- call get_pb2_drive ; get drive from parameter block
- ; jmp select_unique ; select drive, make HDS unique
- select_unique:
- ;-------------
- ; entry: AL = drive to select (0-15)
- mov byte ptr path_drive,al ; save logical drive
- jmp select_logical_drv ; select the drive
- logical2physical:
- ;----------------
- ; On Entry:
- ; AL = drive to select
- ; On Exit:
- ; AL = appropriate physical drive to select
- ;
- ; This routine is called by low level routines (func_ddio, func_getdpb)
- ; and bypasses the checks for networked/joined drives together with the
- ; normal media change checks. It does however handle SUBST'd drives.
- ;
- call get_ldt_raw ; ES:BX -> LDT for our drive
- jc logical2physical10 ; if we don't have one must be physical
- test es:LDT_FLAGS[bx],LFLG_JOINED
- jnz logical2physical10 ; joined drive - treat as physical
- test es:LDT_FLAGS[bx],LFLG_SUBST
- jz logical2physical10 ; as long as we aren't SUBST'd it OK
- mov al,es:LDT_NAME[bx] ; get the drive from the ascii name
- and al,1fh ; as the drive may require rebuilding
- dec ax ; make it zero based
- logical2physical10:
- ret
- Public dbcs_lead
- dbcs_lead:
- ;---------
- ; Return true if given byte is the first of a double byte character.
- ; Entry
- ; al = byte to be tested
- ; Exit
- ; Z Flag = 1 - byte is a DBCS lead
- ; 0 - byte is not a DBCS lead
- ; Lost
- ; no registers changed
- if KANJI
- push si
- push bx
- push ax
- ; First get a pointer to the double byte lead table in the COUNTRY info.
- mov si, offset DBCS_tbl+2 ; ds:si -> double byte table
- ; Examine each entry in the table to see if it defines a range that includes
- ; the given character.
- mov bl, al ; bl = byte to be tested
- dbcs_loop:
- lods ss:ax ; al/ah = start/end of range
- test ax, ax ; end of table?
- jz dbcs_no ; yes - exit (not in table)
- cmp al, bl ; start <= bl?
- ja dbcs_loop ; no - try next range
- cmp ah, bl ; bl <= end?
- jb dbcs_loop ; no - try next range
- cmp al, al ; return with Z flag set
- jmp dbcs_exit
- dbcs_no:
- cmp al, 1 ; return with Z flag reset
- dbcs_exit:
- pop ax
- pop bx
- pop si
- ret
- else
- test al, al ; force non-0 condition
- ret
- endif
- kanji_eos:
- ;---------
- ; entry: ES:DI -> string to find the end of
- ; exit: ES:DI -> character before NUL byte
- mov dx,di ; in case string is empty
- kanji_eos1:
- mov al,es:[di] ; get next character
- test al,al ; is it the final NUL byte
- jz kanji_eos9 ; return if NUL found
- mov dx,di
- inc di ; move to next character
- if KANJI
- call dbcs_lead ; is this first half of 16-bit char?
- jne kanji_eos1 ; skip if normal character
- inc di ; else skip 2nd half (should really check)
- endif
- jmps kanji_eos1 ; loop back for next character
- kanji_eos9:
- mov di,dx ; ES:DI -> last character
- ret ; end of string found
- path_chop:
- ;---------
- ; entry: ES:DI -> path = "d:level1level2"
- ; exit: path = "d:level1"
- mov al,es:[di] ; get next character
- test al,al ; end of string?
- jz path_chop2 ; yes, string scanned
- inc di ; next character
- if KANJI
- call dbcs_lead ; lead-in of 16-bit character?
- jne path_chop1 ; no, normal 8-bit
- inc di ; skip hi-byte (should really check)
- jmps path_chop ; try again
- path_chop1:
- endif
- call check_slash ; is this a path character
- jne path_chop ; loop back if not path character
- mov dx,cx ; last but one '/' = last '/'
- mov cx,di ; last '/' = current '/'
- jmps path_chop ; repeat
- path_chop2:
- mov di,dx ; ES:DI -> last but one slash + 1
- sub ax,ax ; get a NUL byte
- stosb ; chop off the last level
- ret
- Public rebuild_ldt_root
- rebuild_ldt_root:
- ;----------------
- ; On Entry:
- ; ES:BX -> LDT_ to rebuild
- ; fdos_hds = physical root for this drive
- ; On Exit:
- ; ES:BX preserved
- ; LDT_ROOT rebuilt from ASCII LDT_NAME
- ;
- push ds
- push es ! pop ds ; DS:BX -> LDT_
- push ss ! pop es
- mov di,offset temp_ldt ; ES:DI -> temp LDT_
- lea si,LDT_NAME+3[bx] ; point to start of pathname
- mov cx,LDT_ROOTLEN[bx] ; CX = end of root portion
- xor ax,ax ; assume we want root block
- sub cx,3 ; skip the 'D:'
- jbe rebuild_ldt_root10 ; nothing to do unless SUBST'd
- rep movsb ; copy the root portion of the name
- call select_dir ; select this directory
- jnc rebuild_ldt_root10
- xor ax,ax
- mov LDT_ROOTLEN[bx],2 ; force ourselves into the root
- mov LDT_NAME+3[bx],al ; as the media has changed
- rebuild_ldt_root10:
- push ds ! pop es ; ES:BX -> LDT_
- pop ds
- mov ax,fdos_hds_blk
- mov es:LDT_ROOT[bx],ax ; update our root block
- if JOIN
- mov al,fdos_hds_drv ; and the physical drive
- mov es:LDT_DRV[bx],al
- endif
- ret
- rebuild_ldt_curdir:
- ;------------------
- ; On Entry:
- ; ES:BX -> LDT_ to rebuild
- ; fdos_hds = logical root of this drive
- ; On Exit:
- ; ES:BX preserved
- ; LDT_DRV and LDT_BLK rebuilt from ASCII LDT_NAME
- ;
- push ds
- push es ! pop ds ; DS:BX -> LDT_
- push ss ! pop es
- mov di,offset temp_ldt ; ES:DI -> temp LDT_
- mov si,LDT_ROOTLEN[bx] ; SI = end of root portion
- lea si,LDT_NAME[bx+si] ; point to subdir entry
- lodsb ; get 1st char
- call check_slash ; is it a leading '' ?
- je rebuild_ldt_curdir10 ; yes, discard it
- dec si ; else leave it alone
- rebuild_ldt_curdir10:
- test al,al ; anything to do?
- jz rebuild_ldt_curdir40 ; no, we are already there
- rebuild_ldt_curdir20:
- lodsb ! stosb ; copy the string
- test al,al ; until we hit the terminating NUL
- jnz rebuild_ldt_curdir20
- dec di
- call select_dir ; select this directory
- jnc rebuild_ldt_curdir40
- mov si,LDT_ROOTLEN[bx] ; SI = end of root portion
- cmp si,3 ; is root real root or a subdir ?
- ja rebuild_ldt_curdir30
- mov si,3 ; real root, leave '' alone
- rebuild_ldt_curdir30:
- mov LDT_NAME[bx+si],0 ; move ASCII to root
- rebuild_ldt_curdir40:
- push ds ! pop es ; ES:BX -> LDT_
- pop ds
- mov ax,fdos_hds_blk
- mov es:LDT_BLK[bx],ax ; update our curdir block
- if JOIN
- mov al,fdos_hds_drv ; and the physical drive
- mov es:LDT_DRV[bx],al
- endif
- ret
- select_dir:
- ;----------
- ; On Entry:
- ; DS:BX -> LDT
- ; ES:DI -> end of ASCII path
- ; temp_ldt contains dir to select
- ; On Exit:
- ; DS:BX preserved
- ; CY set on error, root of original drive reselected
- ;
- mov ax,'.' ; append a "." in case it's the root
- stosw ; (and so a NULL path)
- xor ax,ax
- stosb
- push ds ! push bx ; make sure LDT survives
- push ss ! pop ds ; DS back to SYSDAT
- mov si,offset temp_ldt ; ES:SI -> directory to select
- call path_prep_next ; try to move into it
- if JOIN
- call offer_join ; are we opening a JOIN'd drive ?
- jnc select_dir20
- endif
- call finddfcbf ; find the directory entry
- jz select_dir10 ; stop if we can't
- test DATTS[bx],DA_DIR ; check if directory
- jz select_dir10 ; fail if this is a file
- push ds ! pop es
- lea di,DNAME[bx] ; ES:DI -> ASCII name to open
- mov cx,8+3
- mov al,' '
- repe scasb ; is it all spaces ?
- je select_dir10 ; if so reject it
- call open_dir
- jnc select_dir20
- select_dir10:
- mov ax,fdos_hds_root ; move to the virtual root
- mov fdos_hds_blk,ax
- stc ; return error
- select_dir20:
- pop bx ! pop ds
- ret
- eject
- ; Run down the path and parse final name
- ; exit: ds:dx -> info_fcb parsed at path end
- ; cf = 1, and al = code on any error
- path_prep:
- les di,dword ptr fdos_pb+2 ; es:di -> path name
- path_prep_ptr:
- call path_prep_check ; try to prepare path
- jnc path_prep_good ; skip if success
- jmp fdos_error ; return error to application
- path_prep_drive_error:
- ; stc ; return CY set
- mov ax,ED_DRIVE ; with correct error code
- path_prep_good:
- ret
- path_prep_check:
- call get_path_drive ; from asciiz or default
- jc path_prep_drive_error ; continue if drive A: - Z:
- path_prep_cont:
- push di ; DX = drive code (0-15)
- push es ; save string address
- push ds ! pop es ; ES = SYSDAT
- call select_unique ; select the drive and
- pop es
- pop si ; es:si -> past drive
- lods es:al ; get first character
- call check_slash ; if '' or '/' then start at root
- jne path_prep_curdir ; else select current directory
- push es
- call path_prep_root ; fake a '.' entry for the root
- pop es
- lods es:al ; get next char
- dec si ; forget we looked
- test al,al ; if just a '' stop now
- jz path_prep_done
- call check_slash
- jne path_prep_next ; otherwise start processing from root
- mov ax,ED_ACCESS ; get correct error code
- stc ; and return if \
- ret
- path_prep_curdir:
- ; We need to select the current directory as a start for our operations
- dec si ; forget about char we looked at
- push es ! push si ; and save position in name
- mov al,logical_drv ; get the current logical drive
- call get_ldt ; and hence the LDT structures
- jc path_prep_curdir30 ; no LDT, leave at physical root
- if JOIN
- mov al,fdos_hds_drv ; are we on a known drive ?
- sub al,es:LDT_DRV[bx] ; (we may be on joined drive)
- jne path_prep_curdir10 ; if not better rebuild
- cbw ! dec ax ; AX = FFFF
- else
- mov ax,0FFFFh
- endif
- cmp ax,es:LDT_BLK[bx] ; do we need to do a rebuild
- jne path_prep_curdir20 ; or can we trust the media ?
- path_prep_curdir10:
- call rebuild_ldt_curdir ; better reselect current dir
- path_prep_curdir20:
- mov ax,es:LDT_BLK[bx] ; move to current directory block
- mov fdos_hds_blk,ax
- path_prep_curdir30:
- pop si ! pop es ; ES:SI -> name again
- path_prep_next:
- ;--------------
- ; Called by disk change code to rebuild an HDS_ for a drive after
- ; media change detected.
- ; On Entry:
- ; ES:SI -> pathname to rebuild
- ; fdos_hds = HDS_ to rebuild
- ; On Exit:
- ; CY set if problem (AX=error code)
- ; ES=DS
- ;
- cmp es:byte ptr [si],0 ; can't have trailing '/' or ''
- je path_prep_error ; return this as an error
- mov ax,path_drive
- inc ax ; al = drive (one based)
- call parse_path ; set up the info_fcb
- jc path_prep_error ; skip on any parse error
- test al,al ; AL = delimiter
- jz path_prep_done ; are we at the end ?
- cmp word ptr info_fcb+1,' .'
- je path_prep_next ; CHDIR (".") => stay where we are
- call check_no_wild ; no wilds cards in path's
- je path_prep_error ; skip if wild cards found
- if JOIN
- push es
- push si
- call offer_join ; are we opening a JOIN'd drive ?
- pop si
- pop es
- jnc path_prep_next ; if so move on to next stage
- endif
- push es
- push si ; save string address
- push ds ! pop es ; ES = local segment
- call finddfcbf ; locate the directory entry
- pop si
- pop es ; restore string address
- jz path_prep_error ; no, missing directory in path
- test DATTS[bx],DA_DIR ; check if directory
- jz path_prep_error ; fail if this is a file
- push es ! push si ; save string address
- push ds ! pop es ; ES = local segment
- if PASSWORD
- call check_pwd_any ; check if PW req'd & supplied
- endif
- call open_dir ; go down one level
- pop si ! pop es ; restore string address
- jnc path_prep_next ; if open is good, repeat
- path_prep_error:
- mov ax,ED_PATH ; return code in case of error
- stc ; indicate error to caller
- ret
- path_prep_done:
- cmp info_fcb+1,'.' ; is it '.' or '..' ?
- jne path_prep_exit ; if so get its full name
- if JOIN
- call offer_join ; are we opening a JOIN'd drive ?
- jnc path_prep_root ; if so move into the dir
- endif
- call finddfcbf ; find the directory entry
- jz path_prep_exit ; stop if we can't
- call open_dir ; move into the directory
- jc path_prep_error ; stop if we can't
- mov cx,DBLOCK1[bx] ; are we destined for the root ?
- jcxz path_prep_root ; yes, stop - we won't find anything
- push fdos_hds_root
- mov fdos_hds_root,0 ; don't stop at virtual root
- call find_parent ; find the parental entry
- pop fdos_hds_root
- jz path_prep_error ; (shouldn't happen)
- mov ax,DPWD[bx] ; get password hash code from entry
- mov local_password,ax ; ensure we can get back down
- lea si,DNAME[bx] ; point to it's name
- mov cx,11
- push ds ! pop es
- mov di,offset info_fcb+1
- rep movsb ; copy parental name to info_fcb
- path_prep_exit:
- push ds ! pop es ; restore ES to local segment
- clc
- ret
- path_prep_root:
- push ds ! pop es ; ES = local segment
- mov al,info_fcb ; preserve drive setting
- call clear_info_fcb
- mov info_fcb+1,'.' ; fake a '.' directory
- ret
- clear_info_fcb:
- ;--------------
- ; Sets up a clean info_fcb for later use
- ; On Entry:
- ; AL = drive
- ; On Exit:
- ; All regs preserved
- ;
- push di ! push cx ! push ax
- mov di,offset info_fcb
- stosb ; set the drive code
- mov cx,11
- mov al,' '
- rep stosb ; fill name with blanks
- if PASSWORD
- mov cx,8
- mov di,offset password_buffer
- rep stosb ; blank password buffer
- mov es:local_password,cx ; zero out local password
- endif
- pop ax ! pop cx ! pop di
- clc
- ret
- eject
- ; Get drive from path name, or if none, use default drive
- ; On Entry:
- ; es:di -> path name
- ; On Exit:
- ; AL = path_drive = sepcified or default drive
- ; es:di -> past drive name
- ; cf = 1 if illegal drive name
- get_path_drive:
- cmp es:byte ptr [di],0 ; check if string is empty
- je get_path_error ; which isn't O.K. at all
- cmp es:byte ptr 1[di],':' ; if the second char is ':',
- jz get_path_explicit ; then drive is in pathname
- call current_dsk2al
- jmps get_path_ok ; common code from here
- get_path_explicit:
- mov al,es:[di] ; grab the drive designator
- call toupper ; make sure it is upper case
- sub al,'A' ; correct offset. if too
- jb get_path_error ; small, return error
- cmp al,ss:last_drv
- jae get_path_error
- inc di
- inc di ; it's ok, bump the pointer
- get_path_ok:
- xor ah,ah ; zero ah and clc
- mov path_drive,ax ; save for other functions
- ret
- get_path_error:
- stc ; flag the error
- ret
- eject
- asciiz_dev_offer:
- ;----------------
- ; On Entry:
- ; PB+2 -> pathname
- ; On Exit:
- ; Only come back if not a device
- ;
- ; See if the filename is that of a simple device
- ; eg. 'CON', 'A:CON', 'CON.EXT'
- ; We should also accept 'DEV' format
- ; eg. 'DEVCON', "A:DEVCON'
- ; More complicated forms should be ignored - they will be handled
- ; after the pathname is parsed.
- ; eg. 'A:CON', 'CON', 'SUBDIRCON.EXT'
- ;
- push ds
- mov si,2[bp] ; SI -> parameter block
- lds si,ds:2[si] ; DS:SI -> file specification
- cmp ds:byte ptr 0[si],0 ; NUL names are stupid, but
- je asciiz_dev_offer30 ; you do get them....
- cmp ds:byte ptr 1[si],':' ; is a drive specified
- jne asciiz_dev_offer10
- inc si ! inc si ; skip that, but no more
- asciiz_dev_offer10:
- push ss ! pop es ; ES:DI -> scratch FCB in build
- mov di,offset name_buf ; name in pcmode data buffer
- mov al,' '
- mov cx,8+3
- rep stosb ; start by clearing name
- mov al,[si] ; beware of 'DEVname' format..
- call check_slash ; if not slash carry on
- jne asciiz_dev_offer15
- lodsb ; possible, lets look at rest
- lodsb
- call toupper
- cmp al,'D' ; is 'D'possible ?
- jne asciiz_dev_offer30
- lodsb
- call toupper
- cmp al,'E' ; is 'DE' on ?
- jne asciiz_dev_offer30
- lodsb
- call toupper
- cmp al,'V' ; is 'DEV' on ?
- jne asciiz_dev_offer30
- lodsb ; finally how about trailing ''
- call check_slash
- jne asciiz_dev_offer30
- mov al,[si] ; check for delimiter
- asciiz_dev_offer15:
- call check_delim ; if first char = delimiter
- jz asciiz_dev_offer30 ; then it can't be a device
- mov di,offset name_buf ; build name in scratch FCB
- mov cx,8 ; length of name field
- call parse_one ; parse just the name
- cmp al,'.'
- jnz asciiz_dev_offer20 ; do we have to parse an extention ?
- mov di,offset name_buf+8 ; di -> fcb ext field
- mov cx,3 ; length of ext field
- call parse_one ; parse just extension
- asciiz_dev_offer20:
- test al,al ; if not a NUL by now forget it
- jnz asciiz_dev_offer30
- push ss ! pop ds
- mov si,offset name_buf ; DS:SI -> name
- call check_device_common ; try to find the name
- jnc asciiz_dev_accept ; if we can handle it here
- asciiz_dev_offer30:
- pop ds ; DS back to normal
- push ss ! pop es ; ditto with ES
- ret ; not a device - proceed
- asciiz_dev_accept:
- ;----------------
- ; We have found a match in the device at ES:BX
- ;
- mov ss:word ptr current_device,bx
- mov ss:word ptr current_device+WORD,es
- pop ds ; DS = SYSDAT again
- pop ax ; discard return address
- call local_disk ; we need the MX
- les bx,ss:current_device ; ES:BX -> device header
- cmp fdos_pb,FD_EXPAND
- je asciiz_dev_accept20
- cmp fdos_pb,4Eh ; is it FD_FFIRST ?
- je asciiz_dev_accept10
- jmp open_dev ; open the device locally
- asciiz_dev_accept10:
- jmp first_dev ; 'find' the device locally
- asciiz_dev_accept20:
- jmp expand_dev ; 'expand' the device locally
- eject
- chk_no_dev: ; check file is not a character device
- ;----------
- ; On Entry:
- ; info_fcb contains parsed filename
- ; On Exit:
- ; Don't return if it's a character device
- ;
- call check_device ; is this a device ?
- jnc chk_not_dev10
- push ds ! pop es ; ES points to data again
- ret
- chk_not_dev10:
- jmp fdos_ED_ACCESS ; blow caller away
- check_device:
- ;------------
- ; On Entry:
- ; info_fcb contains parsed filename
- ; On Exit:
- ; CY set if not found
- ; else
- ; CY clear if found
- ; ES:BX -> device header
- ;
- mov si,offset info_fcb+1 ; DS:SI -> name to check
- ; jmp check_device_common
- check_device_common:
- ;-------------------
- ; On Entry:
- ; DS:SI -> 8 byte buffer to check
- ; On Exit:
- ; CY set if not found
- ; else
- ; CY clear if found
- ; ES:BX -> device header
- ;
- push ss ! pop es ; Get the PCMODE Data Segment
- mov bx,offset dev_root ; hence the Device List
- mov ax,si ; keep copy of start in AX
- check_device10:
- test es:DH_ATTRIB[bx],DA_CHARDEV
- jz check_device20 ; skip unless it's a character device
- lea di,DH_NAME[bx] ; ES:DI -> device name
- mov cx,8/2 ; compare file name w/o extension
- repe cmpsw ; compare until CX == 0 or mismatch
- je check_device30
- check_device20:
- mov si,ax ; restore starting address
- les bx,es:DH_NEXT[bx] ; get next device driver
- cmp bx,0FFFFh ; end of the chain ?
- jne check_device10
- stc ; indicate character device not found
- check_device30:
- ret
- eject
- no_dir_vol:
- ;----------
- test DATTS[bx],DA_DIR+DA_VOLUME
- jnz dir_vol_err ; return error if label or directory
- ret ; else it's O.K.
- dir_vol_err:
- jmp fdos_ED_ACCESS ; return "access denied"
- eject
- get_pb2_drive:
- ;-------------
- mov al,byte ptr fdos_pb+2 ; get requested drive code
- dec al ; Get the default drive if
- jns get_pb2_drv1 ; the requested drive is 00
- call current_dsk2al ; AL = default drive
- get_pb2_drv1:
- ret
- eject
- mkdir_init:
- ;----------
- push ax ; Init 1st block of the directory
- call zeroblk ; zero the block
- pop ax ! push ax ; get the block number
- xor bx,bx ; seek to beginning of cluster
- call fill_dirbuf ; DI -> directory entry
- pop dx ! push dx ; get our own block #
- mov ax,' .' ; this is the "." directory
- call init_dot ; set name, attrib, time, date, block1
- call flush_dirbuf ; copy '.' entry to sector buffer
- pop ax ; get the block number
- mov bx,1 ; do 2nd entry
- call fill_dirbuf ; DI -> directory entry
- call hdsblk
- xchg ax,dx ; DX = parent directory
- mov ax,'..' ; this is the ".." directory
- ; call init_dot ; fall into INIT_DOT
- ; ret
- init_dot:
- mov dirp,di ; save directory entry for SETPCD
- push di
- mov DBLOCK1[di],dx ; our own block #
- stosw ; store "." or ".."
- mov al,' '
- mov cx,11-2
- rep stosb ; pad the name with spaces
- mov al,DA_DIR
- stosb ; attribute = directory
- call GetTOD ; get time/date of creation
- pop bx
- jmp stamp_date_and_time ; set date DX and time AX in dir BX
- eject
- ; Utility functions for RMDIR and UNLINK
- rmdir_ok: ; make sure directory not in use
- ;--------
- ;
- mov bx,dirp ; get the directory entry
- mov ax,DBLOCK1[bx] ; block number of directory
- xor bx,bx ; start at beginning
- rmdir_ok1:
- push ax ! push bx ; save block, offset
- call fill_dirbuf ; locate directory entry
- pop bx ! pop ax ; restore offset, block
- cmp DNAME[di],0 ; is it virgin entry?
- je rmdir_ok4 ; yes, no entries above here
- cmp DNAME[di],0E5h ; is it deleted entry?
- je rmdir_ok3 ; yes, no problems yet...
- cmp DNAME[di],'.' ; is it "." or ".."?
- je rmdir_ok3
- if DELWATCH
- ; We have found a dir entry - better check if it is a pending delete
- ; and that delwatch is installed. Then we can ignore it.
- test DATTS[di],DA_VOLUME ; is the volume label bit set
- jz rmdir_not_empty ; no, can't be pending delete
- xor dx,dx ; (also sets DH = DELW_RDMASK)
- ; cmp dx,DBLOCK1[di] ; is it really a pending delete ?
- ; jz rmdir_not_empty ; yes, fall thru to delwatch check
- xchg ax,dx ; AH = DELW_RDMASK, DX = dir cluster
- mov si,di ; -> directory buffer (for DELWATCH)
- callf ss:fdos_stub ; is the delwatch TSR installed
- xchg ax,dx ; AX = dir cluster
- jnc rmdir_ok3 ; delwatch will handle pending deletes
- rmdir_not_empty:
- endif
- mov ax,ED_ACCESS ; return "access denied" if not empty
- rmdir_inuse: ; directory not empty or in use:
- jmp fdos_error ; return the error
- rmdir_ok3: ; else this entry O.K.
- inc bx ; check next directory entry
- cmp bx,dirperclu ; cluster completed?
- jb rmdir_ok1 ; loop back if more to come
- call getnblk ; get next block in directory
- sub bx,bx ; start at beginning of block
- cmp ax,lastcl ; end of cluster chain?
- jb rmdir_ok1 ; loop back if not done yet
- rmdir_ok4: ; directory is empty
- mov al,adrive
- call hshdscrd ; discard the hash values
- clc ; "go ahead with RMDIR..."
- ret ; return, ready for the evil deed...
- chkcds: ; check if any process uses directory to delete
- ;------
- ; On Entry:
- ; dirp -> directory entry of DIR to check
- ; On Exit:
- ; CY clear if DIR is in use
- ;
- mov bx,dirp
- mov cx,DBLOCK1[bx] ; block number of directory to delete
- mov dl,physical_drv ; get the drive the subdir is in
- mov al,-1 ; start with drive A:
- chkcds10:
- inc ax ; next drive
- call get_ldt_raw ; ES:BX -> LDT for drive
- jc chkcds20 ; bail if if bad drive
- test es:byte ptr LDT_FLAGS+1[bx],(LFLG_NETWRKD+LFLG_PHYSICAL)/100h
- js chkcds10 ; it can't be a network drive
- jz chkcds10 ; it must be a physical drive
- cmp dl,es:LDT_DRV[bx] ; does the drive match?
- jne chkcds10 ; no, don't bother then
- cmp es:LDT_BLK[bx],0ffffh ; is it valid
- jne chkcds19
- push ax
- push cx
- push dx
- call select_logical_drv ; select with media change check
- call rebuild_ldt_curdir ; rebuild LDT_
- pop dx
- pop cx
- pop ax
- chkcds19:
- if 0
- ; This didn't make the beta, so leave until the next release
- ; We really need to make sure we relog all SUBST's drives before
- ; we can be sure this is valid and fail the rmdir
- cmp cx,es:LDT_ROOT[bx] ; is this our root block ?
- je chkcds20 ; (ie. a SUBST'd drive)
- endif
- cmp cx,es:LDT_BLK[bx] ; does the block match
- jne chkcds10 ; no, try next drive
- chkcds20:
- ret
- eject
- ;
- ; Go down one level in directory
- ; On Entry:
- ; DIRP -> directory to open
- ; PATH_DRIVE = drive to use
- ; On Exit:
- ; AX = fdos_hds_blk (the current directory block)
- ; CY clear on success
- ; CY set on error
- ;
- open_dir:
- mov bx,dirp
- test DATTS[bx],DA_DIR ; check if directory
- stc
- jz open_dir20 ; fail if this is a file
- cmp word ptr info_fcb+1,'..'
- jne open_dir10 ; watch out if going up a level
- mov ax,fdos_hds_blk ; get current block
- cmp ax,fdos_hds_root ; check if at logical root already
- jne open_dir10 ; and if not carry on
- cmp ax,DBLOCK1[bx] ; if we are already at the virtual root
- stc ; and want to stay there that's OK
- jne open_dir20 ; otherwise return an error
- open_dir10:
- mov al,physical_drv ; remember the drive
- mov fdos_hds_drv,al
- mov ax,DBLOCK1[bx] ; remember this directory block
- mov fdos_hds_blk,ax
- clc ; success
- open_dir20:
- ret
- Public hdsblk
- ;======
- hdsblk: ;/* check if we are in subdirectory */
- ;======
- ;
- ; exit: AX = directory block number
- ; ZF = set if at root
- ; regs: others preserved
- mov ax,fdos_hds_blk ; get current directory block
- test ax,ax ; set ZF
- ret
- parent2save_area:
- ;-----------------
- ; On Entry:
- ; AX = cluster number of parent to find
- ; On Exit:
- ; save_area contains parental name (DX = length of name)
- ;
- call find_parent ; locate parent directory
- jz path_error ; stop in case we're in a mess
- lea si,DNAME[bx] ; get parent directory name
- mov di,offset save_area ; ES:DI -> scratch area
- ; jmp unparse ; make it ASCIIZ file name
- ; build ASCIIZ string from directory entry
- ; entry: BX -> directory buffer
- ; ES:DI -> output buffer
- ; exit: ES:DI -> next byte in buffer
- unparse:
- ;-------
- push di ; save base of name
- mov cx,8 ; remainder of up to 7 characters
- lea si,DNAME[bx] ; SI -> directory name
- call unparse_field ; copy name, strip trailing blanks
- mov al,'.'
- stosb ; add the dot for start of extension
- push di ; remember where extention starts
- mov cx,3 ; copy 3-char extension
- lea si,DNAME+8[bx] ; SI -> directory extention
- call unparse_field ; copy extension, strip trailing blanks
- pop ax ; recover start of extension
- cmp ax,di ; did we generate extension?
- jne unparse1 ; skip if we did
- dec di ; else eat the '.'
- unparse1:
- xor ax,ax
- stosb ; NUL-terminate the name
- pop bx ; ES:BX -> base of name
- cmp es:byte ptr [bx],05h
- jne unparse2 ; if not mapped E5 (deleted entry/Kanji)
- mov es:byte ptr [bx],0E5h ; else map back to E5 for Kanji support
- unparse2:
- ret
- unparse_field:
- ;-------------
- ; entry: DS:SI -> disk buffer
- ; ES:DI -> ASCIIZ name to build
- ; CX = field length
- ; On Exit:
- ; ES:DI -> end of name
- ; BX preserved
- push si ; save start of field
- add si,cx ; SI -> end of field
- inc cx ; one extra for LOOPE dec
- unprsf10:
- dec si ; lets look at the previous char
- cmp ds:byte ptr [si],' ' ; trailing space ?
- loope unprsf10
- pop si ; SI = start of field
- rep movsb
- ret
- path_error:
- jmp fdos_ED_PATH ; return "invalid path" error
- mkspace_parent:
- ;--------------
- ; save_area contains the parental name, DX bytes long. We wish to insert it
- ; into an ASCIIZ string so make DX bytes of space at ES:DI.
- ; On Entry:
- ; ES:DI -> ASCIIZ, DX = byte count
- ; On Exit:
- ; DS:SI -> parents name, CX = length of parent (DX on entry)
- ;
- mov al,0 ; find end of name
- mov cx,128 ; max. path length
- repne scasb ; scan for end of path
- neg cx
- add cx,128 ; CX = string length including NUL
- mov ax,cx
- add ax,dx
- cmp ax,64
- ja path_error
- dec di ; ES:DI -> ' '
- mov si,di ; SI -> source of copy
- add di,dx ; point to beyond insertion
- push ds
- push es ! pop ds ; move string backwards to make space
- std ! rep movsb ! cld ; for directory name
- pop ds
- mov cx,dx ; CX = length of new directory name
- mov si,offset save_area ; SI -> unparsed name
- ret
- ; find parent directory starting with cluster AX
- ; entry: AX = cluster of parent to find
- ; exit: ZF = 1 if not found (shouldn't happen)
- ; -or-
- ; ZF = 0 if found, BX=DIRP -> dir entry
- find_parent:
- mov blk,ax ; save the block number
- push ds ! pop es
- mov di,offset info_fcb+1
- mov ax,'..' ! stosw ; file name is '..'
- mov al,' ' ; pad with spaces
- mov cx,9 ! rep stosb
- call finddfcbf ; find pointer to parent
- jz fndpar2 ; shouldn't happen...
- call open_dir ; go up one level
- jc fndpar3 ; screwed up by security...
- call setenddir ; search from beginning
- fndpar1:
- sub cx,cx
- call getdir ; find next directory entry
- jz fndpar2 ; end of directory
- mov al,DNAME[bx] ; check if deleted file
- cmp al,0E5h
- je fndpar1 ; skip empty slots
- cmp al,0
- je fndpar2 ; end of directory
- test DATTS[bx],DA_DIR ; try to find directory
- jz fndpar1 ; skip plain files
- mov ax,DBLOCK1[bx] ; get starting cluster
- cmp ax,blk
- jne fndpar1
- fndpar3:
- or ax,0FFFFh ; force non-zero condition
- fndpar2:
- ret ; ZF = 0 if found
- eject
- path_prep_chk:
- ;-------------
- ; Run down the path and parse final name
- ; exit: ds:dx -> info_fcb parsed at path end
- call path_prep ; prepare the path
- call chk_no_dev ; devices not allowed
- chk_no_dot_or_wild:
- ;------------------
- call chk_no_dot ; no subdirs entries either
- ; jmp chk_no_wild ; wild cards not allowed
- eject
- chk_no_wild: ; make sure path doesn't contain wild cards
- ;----------- ; (or is all spaces)
- call check_no_wild ; error if any wildcards
- jne check_no_wild_ret ; or if all spaces
- jmp fdos_ED_FILE ; return "invalid filename"
- check_no_wild: ; make sure path doesn't contain wild cards
- ;------------- ; (or is all spaces) ZF set on problem
- push es
- push ds ! pop es ; ES -> SYSDAT
- mov di,offset info_fcb+1
- mov cx,11
- mov al,'?' ; scan for wild cards
- repne scasb
- je check_no_wild_exit ; skip if wild cards found
- mov di,offset info_fcb+1
- mov cx,11
- mov al,' ' ; scan for all spaces
- repe scasb ; ZF set if a problem
- check_no_wild_exit:
- pop es
- check_no_wild_ret:
- ret
- chk_for_root:
- ;------------
- ; On Entry:
- ; info_fcb -> name of failed search
- ; fdos_hds -> dir we searched in
- ; On Exit:
- ; ZF set if a search for root (or '.' in root)
- ;
- cmp fdos_hds_blk,0 ; are we in the root ?
- jne chk_for_root10 ; no, no further checks required
- push ds ! pop es
- mov di,offset info_fcb+1
- mov al,'.' ; check for root
- scasb ; is it a '.' entry ?
- jne chk_for_root10
- mov cx,8+3-1
- mov al,' '
- repe scasb ; is it all spaces ?
- chk_for_root10:
- ret
- ; Parse a pathname into an info_fcb
- ; entry: es:si -> asciiz string
- ; AX = drive code
- ; exit: es:si -> next asciiz name in path
- ; dx -> fcb
- ; CY clear, AL = 0 if end of string
- ; CY set, AX = error code
- parse_path:
- ;----------
- push ds ! push es
- pop ds ! pop es
- call clear_info_fcb ; initialise to blanks and drive AL
- mov dx,offset info_fcb ; use a scratch fcb
- mov di,dx ; dx saves initial di
- inc di
- mov ax,[si] ; check first two chars
- cmp al,'.' ; special case: if name = '.'
- jne parse_path20 ; then we parse it differently
- movsb ; copy the '.'
- cmp ah,'.' ; special case: if name = '..'
- jne parse_path10 ; then we parse it differently
- movsb ; copy '..'
- parse_path10:
- lodsb ; get next char
- cmp al,' ' ; skip all spaces
- je parse_path10
- jmps parse_path30 ; now exit as normal
- parse_path20:
- call check_delim ; if first char = delimeter
- je parse_path30 ; then only allow ''
- ; filename begins with a legal char, parse it normally
- mov di,dx
- inc di ; di -> fcb name field
- mov cx,8 ; length of name field
- call parse_one ; parse just the name
- mov di,dx ; DI -> FCB
- cmp es:byte ptr 1[di],0E5h ; is first character E5?
- jne parse_path30 ; skip if not
- mov es:byte ptr 1[di],05h ; else make it internal synonym
- parse_path30:
- cmp al,'.'
- jne parse_path40 ; skip if no extension
- add di,9 ; di -> fcb ext field
- mov cx,3 ; length of ext field
- call parse_one ; parse just extension
- parse_path40:
- if PASSWORD
- cmp al,';' ; check if password specified
- jne parse_path50 ; skip if no password
- mov di,offset password_buffer
- mov cx,8 ; length of password field
- call parse_one ; parse just password
- push ax
- push ds ! push si
- push ss ! pop ds ; DS:SI -> ASCII password
- mov si,offset password_buffer
- call hash_pwd ; AX = encrypted password
- mov local_password,ax ; remember it in case we need it
- pop si ! pop ds
- pop ax
- endif
- parse_path50:
- test al,al ; a NUL is OK
- jz parse_path90
- call check_slash ; if terminator != '' or '/',
- stc ; assume an error
- jne parse_path80 ; report it if so
- parse_path60:
- lodsb ; get next character
- call check_delim ; we expect a normal character
- jne parse_path80 ; here - exit if we've got one
- call check_slash ; swallow ''s at this point and leave
- je parse_path60 ; other delimiters for next time
- cmp al,'.' ; trailing '.' ?
- jne parse_path75
- mov cx,si ; remember position of '.'
- parse_path70:
- lodsb ; now discard trailing spaces
- cmp al,' '
- je parse_path70 ; keep going until we lose all spaces
- test al,al ; stop at a NUL
- jz parse_path50
- call check_slash ; if it's a '' try again
- je parse_path50
- mov si,cx ; retract to the '.'
- parse_path75:
- mov al,'' ; return '' as the delimiter
- clc ; and exit with no problems
- parse_path80:
- dec si ; retract a byte (CY unaffected)
- parse_path90:
- push ds ! push es
- pop ds ! pop es
- ret
- Public parse_one
- ; Parse a single name or extension
- ; On Entry:
- ; DS:SI -> asciiz name
- ; ES:DI -> start of fcb field
- ; CX = field size
- ; On Exit:
- ; AL = last char parsed
- ;
- ; nb. make no assumptions about DS and ES
- ;
- parse_one:
- lodsb ; grab asciiz char
- cmp al,'*' ; if char = *, then fill
- jz parse_one_wild ; rest of field with '?'
- call check_delim ; if char is not delimiter,
- jnz parse_one_char ; then move it to fcb
- ret ; if delimiter, return
- parse_one_wild:
- mov al,'?'
- rep stosb ; after filling
- jmps parse_one_ignore ; skip until a delimiter
- parse_one_char:
- if KANJI
- call dbcs_lead ; is it 1st byte of Kanji pair?
- jnz parse_one_skip ; skip if straight 8-bit
- inc si ; assume both chars discarded
- dec cx ; we will copy 2 bytes
- jcxz parse_one_ignore ; ignore both if only room for one
- stosb ; thats the first byte
- dec si ; point at 2nd again
- lodsb ; get the 2nd byte
- parse_one_skip:
- endif
- stosb ; send char to fcb
- loop parse_one ; get another character from ASCIIZ string
- parse_one_ignore:
- lodsb
- call check_delim ; ignore up to next delimiter
- jnz parse_one_ignore
- ret
- ;
- ;
- ; Check for a path name delimiter
- ; entry: AL = ASCIIZ char
- ; exit: all registers preserved
- ; ZF = 1 if char is a delimeter
- ; ZF = 0 if char is legal in file names
- Public check_delim
- check_delim:
- ;-----------
- cmp al,' ' ; if any printable char,
- jae check_delim_char ; then skip
- cmp al,al ; set zf
- ret
- check_delim_char:
- if KANJI
- call dbcs_lead ; if it's 1st of kanji pair
- jne check_delim10 ; DON'T upper case it
- test al,al ; clear zf
- ret ; (should really check the 2nd byte)
- check_delim10:
- endif
- call toupper ; make it upper case
- push es ! push di ! push cx
- push cs ! pop es
- lea di,delim_string ; es:di -> delimeters
- mov cx,length delim_string
- cld
- repnz scasb ; match al against the list
- pop cx ! pop di ! pop es
- clc ; never return cf set
- ret ; with zf set by scasb
- delim_string db ':.;,=+<>|/"[]' ; DOS delimeters
- ; Check AX for '\'
- Public check_dslash
- check_dslash:
- xchg al,ah
- call check_slash
- xchg al,ah
- jne check_slash_done
- ; jmp check_slash
- ; Check delimeter character for '' or '/'
- ; entry: al = char
- ; exit: zf = 1 if either slash
- check_slash:
- cmp al,'' ; if first char is a backslash
- jz check_slash_done ; or a frontslash, then
- cmp al,'/' ; return with zf set
- check_slash_done:
- clc ; never return cf set
- ret
- ; Convert character to upper case
- ; WARNING - may be called with DS <> SYSDAT
- toupper:
- ;-------
- test al,al
- js toupper_intl
- cmp al,'a'
- jb isupper
- cmp al,'z'
- ja isupper
- sub al,'a'-'A'
- isupper:
- ret
- toupper_intl:
- callf ss:intl_xlat ; call international upper case vector
- ret
- eject
- kill_file: ; release clusters for file/dir and delete entry
- ;---------
- mov bx,dirp ; get pointer to directory entry
- if DELWATCH
- call hdsblk ; AX = directory root cluster
- xchg ax,dx ; DX = dir cluster
- mov cx,dcnt ; CX = directory index for entry
- mov ah,DELW_DELETE ; we are about to delete this dir
- mov al,physical_drv ; directory entry so give delwatch
- callf ss:fdos_stub ; a chance to make it pending delete
- jnc kill_file10 ; delwatch took it - just update dir
- endif
- mov al,0E5h ; deleted file mark
- xchg al,DNAME[bx] ; delete the directory entry
- mov DUNDEL[bx],al ; save 1st letter for UNDEL command
- mov ax,DBLOCK1[bx] ; get starting block #
- call delfat ; release all clusters
- kill_file10:
- jmp flush_dirbuf ; update the directory
- ; done it! (DIR/FAT still dirty)
- eject
- mustbe_nolbl:
- ;------------
- ; On Entry:
- ; None
- ; On Exit:
- ; Only returns if no label exists
- ; forces us to root of drive
- ;
- push ds ! pop es ; ES = DS for string ops
- mov si,offset info_fcb+1
- mov di,offset save_area ; SI->search name, DI->save area
- mov cx,11
- push di ; save save_area
- push si ; save info_fcb+1
- push cx ; save length
- rep movsb ; copy search name into save area
- pop cx ; CX = length (11)
- pop di ; DI = info_fcb+1
- push di
- push cx
- mov al,'?' ; now fill info_fcb with wildcards
- rep stosb
- call find_labelf ; look for a volume label
- pop cx ; CX = length (11)
- pop di ; DI = info_fcb+1
- pop si ; SI = save_area
- push ds ! pop es ; ES = DS for string ops
- rep movsb ; restore info_fcb
- jnz mustbe_nolbl10 ; if we found a label bail out
- ret
- mustbe_nolbl10:
- jmp fdos_ED_ACCESS ; return access denied
- find_labelf: ; find label only
- ;----------- ; forces us to root
- ; On Entry:
- ; None
- ; On Exit:
- ; ZF clear if volume label found
- ; dirp/dcnt tell where label is
- ;
- call setenddir ; start from beginning
- ; jmp find_label
- find_label: ; find label only
- ;---------- ; forces us to root
- ; On Entry:
- ; dcnt -> location to search from
- ; On Exit:
- ; ZF clear if volume label found
- ; dirp/dcnt tell where label is
- ;
- mov chdblk,0 ; don't assume sequential access
- mov fdos_hds_blk,0 ; look for labels in the root
- mov finddfcb_mask,000ffh ; return VOL labels, not pending dels
- find_label30:
- call finddfcb ; find matching file name
- jz find_label40 ; skip if not found
- test DATTS[bx],DA_VOLUME
- jz find_label30 ; try again if not a volume label
- find_label40:
- mov finddfcb_mask,DA_VOLUME*256
- ret ; back to no VOL labels or pending dels
- if UNDELETE
- find_pending_delete: ; find pending delete only
- ;-------------------
- ; On Entry:
- ; dcnt -> location to search from
- ; On Exit:
- ; ZF clear if pending delete entry found
- ; dirp/dcnt tell where entry is
- ;
- mov finddfcb_mask,0h ; return pending delete entries
- find_pending_delete10:
- mov al,05h ; replace 1st char with 05h
- xchg al,info_fcb+1 ; saving char we really want
- push ax
- call finddfcb ; find matching file name
- pop ax
- mov info_fcb+1,al ; restore original 1st letter
- jz find_pending_delete30 ; skip if not found
- test DATTS[bx],DA_VOLUME ; Is it a pending delete entry
- jz find_pending_delete10 ; No, try again if not a volume label
- cmp word ptr DBLOCK1[bx],0 ; Is this a pending delete entry
- jz find_pending_delete10 ; No, try again if not correct
- cmp al,'?' ; wildcard is OK
- je find_pending_delete20
- cmp al,DUNDEL[bx] ; does saved char match what we want?
- jne find_pending_delete10
- find_pending_delete20:
- and DATTS[bx],not DA_VOLUME ; mask out volume bit
- mov al,DUNDEL[bx] ; move deleted character to normal
- mov DNAME[bx],al ; position for return
- or al,al ; clear the zero flag (assumes al!=0)
- find_pending_delete30:
- mov finddfcb_mask,DA_VOLUME*256
- ret ; back to no VOL labels or pending dels
- endif
- eject
- find_xfn: ; find spare external file number
- ;--------
- ; exit: DI = new handle
- push es ; save ES while we play
- xor di,di ; return handle 0 if don't have PSP
- call get_xftptr
- jc fndxfn2
- mov bx,di ; save the offset
- mov al,0FFh ; look for unused slot
- repne scasb ; loop while CX != 0 and *ES:DI != 0FFh
- jne fndxfn3 ; ZF = 1 if match, else none found
- dec di ; DI = matching offset
- sub di,bx ; DI = handle index
- fndxfn2:
- pop es
- clc ; indicate no error
- ret
- fndxfn3:
- pop es
- stc ; indicate an error
- ret
- Public alloc_dhndl
- alloc_dhndl:
- ;-----------
- ; provisionally allocate a spare DHNDL_, do not return without one
- ; On Entry:
- ; None
- ; On Exit:
- ; AX = IFN of handle
- ; ES:BX -> DHNDL_ structure
- ; (All other regs preserved)
- call find_dhndl ; try to find a spare DHNDL_
- jc fdos_ED_HANDLE ; bail out if we can't
- ret
- mustbe_free_handle:
- ;------------------
- ; return an error to user if either an XFN or an IFN is unavailable
- ; On Entry:
- ; None
- ; On Exit:
- ; None
- ;
- call alloc_dhndl ; make sure we can allocate a DHNDL
- mov es:DHNDL_COUNT[bx],0 ; free it in case open/creat fails
- ; (we are protected by local_disk)
- ; jmp alloc_xfn ; make sure an XFN is also free
- Public alloc_xfn
- alloc_xfn: ; find spare external file number
- ;--------
- ; exit: DI = new handle
- call find_xfn ; try to find spare slot in XFT
- jc fdos_ED_HANDLE ; "out of handles" if no luck
- mov fdos_ret,di ; else save the resulting handle
- ret
- fdos_ED_HANDLE:
- mov ax,ED_HANDLE ; out of user file #s, all 20 in use
- jmp fdos_error
- ; Allocate & initialize file handle:
- ; entry: AX = open mode
- ; DIRP -> directory entry
- ; exit: ES:BX = CURRENT_DHNDL = file handle
- ; AX = fdos_ret = IFN
- ; -or-
- ; System call fails with ED_HANDLE
- open_handle:
- ;-----------
- mov bx,dirp ; else get directory entry
- test DATTS[bx],DA_RO ; check if file is r/o - if so
- jz creat_handle ; make handle r/o too
- and ax,not DHM_RWMSK
- creat_handle:
- ;------------
- ; entry point for create file - when you create a read-only file
- ; you still get a handle you can write with !
- push ax ; save open mode
- xchg ax,si ; SI = open mode
- mov di,S_OM_COMPAT ; check if open/sharing modes are compatible
- call check_with_share ; does SHARE approve ?
- call alloc_dhndl ; allocate a DHNDL_ structure
- mov fdos_ret,ax ; remember IFN in case it's FCB
- pop dx ! push dx ; DX = open mode
- push es ! push bx ; save DHNDL_ pointer
- test dh,DHM_FCB/100h ; FCB call?
- jne creat_handle10 ; skip XFN allocation if FCB
- push ax ; save IFN
- call alloc_xfn ; allocate spare XFN
- pop ax ; recover IFN
- mov bx,di ; BX = XFN
- call get_xftptr ; ES:DI -> user file table
- jc creat_handle10 ; skip if we don't have one
- mov es:[di+bx],al ; set IFN in PSP
- creat_handle10:
- pop bx ! pop es
- lea di,DHNDL_COUNT[bx] ; point at open count
- mov ax,1
- stosw ; open by one
- pop ax ; recover open mode
- mov cx,DHAT_TIMEOK+DHAT_CLEAN
- test al,DHM_LOCAL ; is it private ?
- jz creat_handle20
- or ch,DHAT_LOCAL/256 ; rememmber it's local
- and al,not DHM_LOCAL ; clear inherit bit
- creat_handle20:
- ; lea di,DHNDL_MODE[bx] ; update the mode
- stosw
- mov si,dirp
- mov al,DATTS[si] ; get file attribute byte
- lea di,DHNDL_DATRB[bx] ; now copy file attribute
- stosb ; to DHNDL_
- xchg ax,cx ; AX = attributes
- or al,physical_drv ; get physical drive
- ; lea di,DHNDL_WATTR[bx] ; make as clean disk file
- stosw
- ; lea di,DHNDL_DEVOFF[bx] ; ES:DI -> dd entry in DHNDL_
- mov ax,ss:word ptr current_ddsc
- stosw ; point to DDSC_
- mov ax,ss:word ptr current_ddsc+WORD
- stosw
- mov ax,DBLOCK1[si] ; get starting cluster of file
- ; lea di,DHNDL_BLK1[bx]
- stosw
- lea si,DTIME[si]
- ; lea di,DHNDL_TIME[bx]
- movsw ; copy the time
- ; lea di,DHNDL_DATE[bx]
- movsw ; and the date
- lodsw ; skip 1st cluster (already done)
- ; lea di,DHNDL_SIZE[bx]
- movsw ! movsw ; copy the file size
- ; lea di,DHNDL_POS[bx]
- xor ax,ax ; zero current position
- stosw ! stosw
- ; lea di,DHNDL_IDX[bx]
- stosw ; zero block index
- if DOS5
- call hdsblk ; get directory block
- ; lea di,DHNDL_DBLK[bx]
- stosw
- xor ax,ax
- stosw
- else
- ; lea di,DHNDL_BLK[bx]
- stosw ; and current block
- call hdsblk ; get directory block
- ; lea di,DHNDL_DBLK[bx]
- stosw
- endif
- mov ax,dcnt ; set DCNT of file
- ; lea di,DHNDL_DCNTLO[bx]
- stosb ; store low byte of DCNT
- mov es:DHNDL_DCNTHI[bx],ah ; and hi byte
- ; lea di,DHNDL_NAME[bx] ; copy name from dir entry
- mov si,dirp
- mov cx,11
- rep movsb
- xor ax,ax
- stosw ; zero DWORD
- stosw
- lea di,DHNDL_SHARE[bx] ; zero sharing record
- stosw
- if DOS5
- stosw ! stosw ! stosw ; zero DHNDL_BLK + IFS
- endif
- callf ss:share_stub+S_OPEN ; we have opened this handle
- ; ask SHARE to register it
- jc create_handle30
- mov ax,fdos_ret ; AX = handle to return
- ret
- create_handle30: ; free the handle again
- push ax
- mov ax,fdos_ret
- call release_handle2
- pop ax
- jmp fdos_error
- Public verify_handle
- verify_handle:
- ;-------------
- ; On Exit:
- ; ES:BX = DHNDL_
- ; CY set if bad file handle (nb. device handle is bad)
- ;
- call check_handle ; make sure we can access it
- jc vfy_hnd9 ; return if character device
- select_handle: ; select directory of current handle
- ;-------------
- ; On Entry:
- ; ES:BX -> DHNDL_
- ; On Exit:
- ; ES:BX preserved
- ;
- mov al,es:DHNDL_ATTR[bx] ; get physical drive
- and al,DHAT_DRVMSK ; from attrib field
- push es ! push bx
- call select_physical_drv ; select the drive
- pop bx ! pop es
- mov ax,es:DHNDL_DBLK[bx]
- mov fdos_hds_blk,ax ; copy HDS_BLK
- clc ; handle is OK file
- vfy_hnd9:
- ret ; good handle
- ; Checks if parameter is a legal file handle:
- ; Entry: CURRENT_DHNDL = handle to verify
- ; Exit: ES:BX = DHNDL_ if O.K.
- ; CY clear if local disk file
- ; CY set if device/network handle
- ; Note: doesn't return on error
- check_handle:
- ;------------
- les bx,current_dhndl
- test es:DHNDL_WATTR[bx],DHAT_REMOTE+DHAT_DEV
- stc ; assume device/network file
- jnz chkhnd10 ; return with CY = 0 if disk file
- callf ss:share_stub+S_UPDATE ; make sure DHNDL_ info valid
- jc chkhnd20 ; if not close it down
- chkhnd10:
- ret
- chkhnd20:
- call get_xftptr ; ES:BX -> XFT
- jc fdos_ED_H_MATCH ; skip if not handle
- mov bx,fdos_pb+2 ; get XFN so we can poke
- mov es:byte ptr [di+bx],0ffh
- ; PSP handle to closed
- ; jmp fdos_ED_H_MATCH ; return "invalid handle"
- fdos_ED_H_MATCH:
- mov ax,ED_H_MATCH ; "invalid handle"
- jmp fdos_error ; return an error
- public vfy_dhndl_ptr
- vfy_dhndl_ptr:
- ;=============
- ; Verifies file handles at FDOS_xxxx calling level
- ; before MXdisk is locked.
- ; On Entry:
- ; SS:BP -> func #, parm off, parm seg
- ; stack holds two ret addresses + above values
- ; On Exit:
- ; ES:BX -> DHNDL_
- mov si,2[bp] ; SI -> parameter block
- mov ax,2[si] ; get file handle from parameter block
- test ss:byte ptr remote_call+1,DHM_FCB/100h; if we are doing an FCB operation
- jnz vfy_dhndl10 ; deal only with IFN, forget PSP
- mov es,ss:current_psp
- cmp ax,PSP_XFNMAX ; CX = # entries in table
- jae vfy_dhndl_err
- les di,PSP_XFTPTR ; ES:DI -> user file table
- mov bx,ax ; get user file number (0-19)
- mov al,es:[bx+di] ; get IFN for this handle
- vfy_dhndl10:
- cmp al,0ffh ; invalid handle?
- je vfy_dhndl_err ; 00h-FEh only
- les bx,ss:file_ptr ; get the address of the first entry
- vfy_dhndl20:
- cmp ax,es:DCNTRL_COUNT[bx] ; handle in this block?
- jae vfy_dhndl50 ; skip to try next block if not
- mov ah,DHNDL_LEN
- mul ah
- add ax,DCNTRL_LEN ; skip the header
- add bx,ax ; add to start of structure
- mov cx,es:DHNDL_COUNT[bx] ; fail if the handle is not in use
- jcxz vfy_dhndl_err
- inc cx ; FFFF = pre-allocated is also failed
- jz vfy_dhndl_err
- cmp ss:WindowsHandleCheck,26h
- ; have we been patched
- jne vfy_dhndl30 ; yes, don't check owner
- mov ax,ss:machine_id ; get current process
- cmp ax,es:DHNDL_UID[bx] ; are we the owning process
- jne vfy_dhndl_err ; no, return an error
- vfy_dhndl30:
- mov ss:word ptr current_dhndl,bx
- mov ss:word ptr current_dhndl+WORD,es
- test es:DHNDL_MODE[bx],DHM_NOCRIT
- jnz vfy_dhndl40 ; are critical errors allowed ?
- ret
- vfy_dhndl40:
- or valid_flg,NO_CRIT_ERRORS
- ret ; remember no critical errors possible
- vfy_dhndl50:
- sub ax,es:DCNTRL_COUNT[bx] ; update the internal file number
- les bx,es:DCNTRL_DSADD[bx] ; get the next entry and check
- cmp bx,0FFFFh ; for the end of the list
- jnz vfy_dhndl20
- vfy_dhndl_err:
- add sp,WORD ; pop return addr - return to caller
- mov bx,ED_H_MATCH ; with "invalid handle" error
- ret
- ; On Entry:
- ; FDOS_PB+2 = external file handle to release
- ; On Exit:
- ; ES:BX -> DHNDL_
- release_handle:
- ;--------------
- mov ax,fdos_pb+2 ; get user file number (0-19)
- release_handle2:
- ;---------------
- call get_xftptr ; ES:DI -> XFN table
- jc release_ifn ; IFN = XFN if no PSP
- cmp ax,cx ; more than in handle table?
- jae rlshnd_err ; return error if too large
- xchg ax,bx ; BX = external file number
- mov al,0FFh ; get old IFN, release XFN
- xchg al,es:[bx+di] ; get IFN for this handle
- cmp al,0FFh
- je rlshnd_err
- release_ifn:
- call ifn2dhndl ; ES:BX -> DHNDL_
- jnc check_no_dir_ret ; return if no error
- rlshnd_err: ; else bad handle
- jmp fdos_ED_H_MATCH ; return the error
- eject
- check_no_dir: ; check if entry is directory
- ;--------
- ; entry: BX -> directory entry
- test DATTS[bx],DA_DIR ; test if directory
- jnz chk_ro_err ; skip if a directory
- check_no_dir_ret:
- ret ; else return to caller
- check_ro: ; check if file write protected
- ;--------
- ; entry: BX -> directory entry
- test DATTS[bx],DA_RO ; test if file r/o
- jnz chk_ro_err ; skip if file r/o
- ret ; else return to caller
- chk_ro_err:
- jmp fdos_ED_ACCESS ; return "access denied" if r/o
- discard_files: ; discard all handles on adrive
- ;-------------
- mov al,adrive
- callf ss:share_stub+S_DISCARD ; tell share to forget about files
- ret
- ; Close file if it's us in compatibility modes
- close_if_same_psp:
- ;-----------------
- ; Note: We first check if the file is open by anyone other
- ; than the same UID and PSP, or is open in shared mode.
- ; In either case we deny the operation.
- ; Otherwise we fall through and close the file.
- ; We could do it in one with a new share, but this way means
- ; less changes.
- ;
- mov di,S_DENY_IF_OPEN ; check if file already open
- call check_with_share ; and stop if it is
- ; jmp close_if_open
- ; Make sure our file is not open
- close_if_open:
- ;-------------
- ; entry: HDSADR->BLK = block # of directory
- ; HDSADR->DRV = drive number
- ; DCNT = directory position
- ; Note: If the file is open by any other process,
- ; error ED_SHAREFAIL is returned from the system call
- ; If open by us (same UID, any PSP) in compatibility mode,
- ; close it and allow us to proceed.
- mov di,S_CLOSE_IF_OPEN ; check if file already open
- ; jmps check_with_share
- check_with_share:
- ;----------------
- ; On Entry:
- ; DI = S_ share query
- ; On Exit:
- ; Come back if share says it's OK.
- ;
- call hdsblk ; get directory block in AX
- xchg ax,dx ; directory block
- mov cx,dcnt ; get the directory count in CX
- mov al,physical_drv ; get physical drive in AL
- callf ss:share_stub[di] ; ask SHARE if it knows of anyone open
- jc check_with_share10
- ret ; must be OK.
- check_with_share10:
- jmp fdos_error ; bail out with an error
- eject
- eject
- ;
- ; Return a pointer to the DOS Handle corresponding to the internal
- ; handle number passed in AX
- ;
- ; On Entry:
- ; AL = IFN
- ;
- ; On Exit:
- ; ES:BX -> DOS handle (All other Regs preserved)
- ; CY set if no corresponding valid DHNDL_
- ;
- Public ifn2dhndl
- ifn2dhndl:
- push ax
- xor ah,ah ; make IFN a word
- les bx,ss:file_ptr ; get the address of the first entry
- ifn2dh10:
- cmp ax,es:DCNTRL_COUNT[bx] ; handle in this block?
- jae ifn2dh20 ; skip if not
- mov ah,DHNDL_LEN ; calculate offset of the DOS Handle
- mul ah
- add bx,ax ; add structure offset (should be 0)
- add bx,DCNTRL_LEN ; and then skip the header
- pop ax
- clc
- ret ; ES:BX -> valid DHDNL_
- ifn2dh20:
- sub ax,es:DCNTRL_COUNT[bx] ; update the internal file number
- les bx,es:DCNTRL_DSADD[bx] ; get the next entry and check
- cmp bx,0FFFFh ; for the end of the list
- jnz ifn2dh10
- ifn2dh15:
- pop ax
- stc
- ret ; invalid file handle number
- ;
- ; Allocate a DHNDL_ structure
- ;
- ; On Entry:
- ; None
- ;
- ; On Exit:
- ; CY clear if handle allocated
- ; AX = IFN of handle
- ; ES:BX -> DOS handle
- ; (All other Regs preserved)
- ;
- Public find_dhndl
- find_dhndl:
- push cx ! push dx ! push di ! push si
- mov ax,ss:machine_id ; get current process
- mov dx,ss:owning_psp ; DX = owining PSP
- xor si,si ; SI = IFN
- les di,ss:file_ptr ; get the address of the first entry
- find_dh10:
- mov cx,es:DCNTRL_COUNT[di] ; get # handles in this block
- jcxz find_dh40 ; skip if none
- lea bx,DCNTRL_LEN[di] ; ES:BX -> 1st DHNDL_
- find_dh20:
- push cx
- cli ; be alone while looking at handles
- mov cx,es:DHNDL_COUNT[bx]
- jcxz find_dh50 ; if handle free grab it
- inc cx ; FFFF = allocated but unused
- jnz find_dh30
- cmp ax,es:DHNDL_UID[bx] ; was it allocated to us
- jne find_dh30
- cmp dx,es:DHNDL_PSP[bx] ; if so use it again
- je find_dh60
- find_dh30:
- sti ; finished with this handle
- pop cx
- inc si ; onto next IFN
- cmp si,0FFh ; only handles 00-FE are valid
- jae find_dh45 ; so bail if out of range
- add bx,DHNDL_LEN ; onto next handle in the block
- loop find_dh20
- find_dh40:
- les di,es:DCNTRL_DSADD[di] ; get the next entry and check
- cmp di,0FFFFh ; it's valid
- jne find_dh10
- find_dh45:
- stc ; no more handles,
- jmps find_dh70 ; exit in failure..
- find_dh50:
- mov es:DHNDL_COUNT[bx],0FFFFh
- mov es:DHNDL_UID[bx],ax ; allocate it to us
- mov es:DHNDL_PSP[bx],dx
- find_dh60:
- sti ; safe again
- pop cx ; discard handle count
- xchg ax,si ; AX = IFN
- mov ss:word ptr current_dhndl,bx
- mov ss:word ptr current_dhndl+WORD,es
- mov ss:current_ifn,ax
- clc ; we have found and allocated a handle
- find_dh70:
- pop di ! pop si ! pop dx ! pop cx
- ret
- Public get_xftptr
- get_xftptr:
- ;----------
- ; On Entry:
- ; None
- ; On Exit:
- ; ES:DI -> PSP_XFTPTR for current_psp
- ; CX = # entries in it
- ; CY set if not PSP operation (eg. FCB's)
- ; (all other regs preserved)
- ;
- test ss:byte ptr remote_call+1,DHM_FCB/100h; if we are doing an FCB operation
- jnz get_xftptr_err ; deal only with IFN, forget PSP
- mov es,ss:current_psp
- mov cx,PSP_XFNMAX ; CX = # entries in table
- les di,PSP_XFTPTR ; ES:DI -> user file table
- ret
- get_xftptr_err:
- stc ; forget about XFN's
- ret
- Public current_dsk2al
- current_dsk2al:
- ;--------------
- ; AL = current default drive
- mov al,ss:current_dsk
- ret
- Public lds_si_dmaptr
- lds_si_dmaptr:
- ;-------------
- ; On Entry:
- ; None
- ; On Exit:
- ; DS:SI -> current DMA address
- ; (All other regs preserved)
- lds si,ss:dword ptr dma_offset
- ret
- public les_di_dmaptr
- les_di_dmaptr:
- ;-------------
- ; On Entry:
- ; None
- ; On Exit:
- ; ES:DI -> current DMA address
- ; (All other regs preserved)
- les di,ss:dword ptr dma_offset
- ret
- Public copy_asciiz
- copy_asciiz:
- ;----------
- ; Copy an ASCIIZ string from DS:SI to ES:DI
- lodsb ! stosb
- test al,al
- jnz copy_asciiz
- ret
- if JOIN
- check_join:
- ;----------
- ; On Entry:
- ; fdos_hds -> HDS we wish to check
- ; On Exit:
- ; AH = drive (zero based) from fdos_hds_drv
- ; AL = drive (zero based) of the JOIN root
- ; if JOINed drive
- ; ZF clear
- ; else
- ; ZF set
- ; (All other regs presrved)
- ;
- push es ! push bx
- mov al,fdos_hds_drv ; get drive from HDS_
- mov ah,al ; save HDS_DRV in AH
- cmp join_drv,0 ; need we do anything ?
- je check_join30 ; not if we haven't JOIN'd
- cmp fdos_hds_root,0 ; is virtual root the physical one ?
- jne check_join10 ; if not we can't be JOIN'd
- call get_ldt ; ES:BX -> LDT for this drive
- jc check_join10 ; bad LDT - we can't be joined
- test es:LDT_FLAGS[bx],LFLG_JOINED
- jz check_join30
- mov al,es:LDT_NAME[bx] ; get drive letter
- sub al,'A' ; make drive letter zero based
- mov bl,byte ptr path_drive ; get the logical drive we are on
- push ax
- mov al,bl ; AL = logical drive we are using
- call get_ldt ; ES:BX -> LDT for this drive
- pop ax
- jc check_join10 ; no valid LDT..
- cmp es:LDT_NAME+2[bx],'' ; are we at the root ?
- jne check_join10 ; no, it can't be match
- mov bl,es:LDT_NAME[bx] ; get the root drive for this drive
- sub bl,'A' ; make drive letter zero based
- cmp al,bl ; are we on the JOIN'd drive ?
- mov bl,0ffh ; assume we are
- je check_join20 ; were we ?
- check_join10:
- mov al,ah ; restore HDS_DRV
- xor bl,bl ; return with ZF clear
- check_join20:
- test bl,bl ; set ZF appropriately
- check_join30:
- pop bx ! pop es
- ret
- offer_join: ; are we opening a JOIN'd drive ?
- ;----------
- ; If we are at the root of a JOIN'd drive moving up ("..") fiddle HDS
- ; onto parental JOIN drive root.
- ; If we are at the root of a non-JOIN'd drive see if we are searching for
- ; a JOIN'd drive directory
- ; On Entry:
- ; info_fcb = entry we are searching for
- ; On Exit:
- ; CY set if not a JOIN'd drive
- ;
- cmp join_drv,0 ; need we do anything ?
- jne oj_dochecks ; not, if we haven't JOIN'd
- oj_rejected:
- stc ; not a JOIN drive
- ret
- oj_dochecks:
- ;-----------
- ; Before we do anything else we must be at the physical root of a drive
- ; with a valid LDT. We then check for two cases
- ; 1) Doing a '..' from a JOIN'd drive to it's parental root
- ; 2) Opening a directory correpsonding to a JOIN'd drive
- ;
- mov al,info_fcb ; AL -> drive we are looking for
- call get_ldt ; ES:BX -> LDT for this drive
- jc oj_rejected ; bad LDT - we can't be joined
- cmp es:LDT_ROOTLEN[bx],2 ; is root at top level ?
- ja oj_rejected ; no, skip the rest
- cmp fdos_hds_blk,0 ; are we at the root ?
- jne oj_rejected ; if not we needn't do anything
- ; We have validated HDS_, so now check for case 1)
- call check_join ; is it a joined drive ?
- jz oj_dir ; if not skip to case 2)
- cmp word ptr info_fcb+1,'..'; else is it a '..' in JOIN'd root?
- jne oj_rejected ; if not we needn't do anything
- call mvhds_drvroot ; do '..' from root -> real root
- clc ; we handled it it !
- ret
- oj_dir:
- ;------
- ; We are in the physical root of a non-joined drive. We now need to see if
- ; the dir we are searching for corresponds with a joined drive
- ;
- push si ! push di
- call build_match_name ; join_name = what we are looking for
- call look_for_match ; see if we can find it
- jc oj_dir10
- call mvhds_drvroot ; we have a match - move into it
- clc ; say we handled it
- oj_dir10:
- pop di ! pop si
- ret
- look_for_match:
- ;--------------
- ; Compare join_name against available JOIN drives.
- ; Return with CY clear if we found it, ES:BX -> LDT, AL the drive
- xor ch,ch
- mov cl,join_drv ; search this many drives
- xor ax,ax ; start with drive A:
- mov ah,last_drv
- call get_ldt ; ES:BX -> LDT for this drive
- jnc lfm20
- ret ; no LDT's...
- lfm10:
- inc al ; next drive
- cmp al,ah ; paranioa - check if we have reached
- jae lfm50 ; last_drv and exit if so
- add bx,LDT_LEN ; next LDT
- lfm20:
- test es:LDT_FLAGS[bx],LFLG_JOINED
- jz lfm10 ; if not JOIN'd try next candidate
- lea di,LDT_NAME[bx] ; ES:DI -> JOIN info
- mov si,offset join_name ; lets see if it matches the
- push ax
- lfm30:
- lodsb ; get a byte
- scasb ; does it match ?
- jne lfm40 ; no, forget it
- test al,al ; end of the string yet ?
- jnz lfm30 ; no, keep trying
- lfm40:
- pop ax
- je lfm60 ; did we match ?
- loop lfm10 ; no, if any JOIN's left try them
- lfm50:
- stc ; we didn't find it
- lfm60:
- ret
- build_match_name:
- ;----------------
- ; Fill join_name with the "C:JOIN" we want to find
- ;
- mov al,info_fcb ; AL -> drive we are looking for
- dec al ; make it zero based
- call get_ldt ; ES:BX -> LDT for this drive
- mov al,es:LDT_NAME[bx] ; get the drive "D"
- push ds ! pop es ; ES -> SYSDAT
- mov di,offset join_name ; construct the target name
- stosb ; plant the drive letter
- mov ax,':'
- stosw ; now we have "d:"
- mov bx,offset info_fcb+1 ; DS:SI -> name we are looking for
- jmp unparse ; unparse the name
- BDOS_DATA dseg word
- join_name db 'd:filename.ext',0
- BDOS_CODE cseg
- Public mv_join_root
- mv_join_root:
- ;------------
- ; Poke the fdos_hds to be the root. If it's the physical root we then
- ; see if it is a JOIN'd drive. If it is we poke the drive and reselect
- ; the disk so we are at the real root of the drive.
- ;
- push bx ! push si ! push di ; save index registers
- mov ax,fdos_hds_root
- mov fdos_hds_blk,ax ; move us to virtual root
- test ax,ax ; is it the real root ?
- jnz mvj_root10 ; if not forget about JOIN'd drives
- call check_join ; are we joined ?
- jz mvj_root10 ; no, we've done enough
- call mvhds_drvroot ; make it real root
- mvj_root10:
- pop di ! pop si ! pop bx ; restore index registers
- ret
- mvhds_drvroot:
- ;-------------
- ; On Entry:
- ; AL = Drive (0 based physical)
- ; On Exit:
- ; None
- ;
- ; Poke the HDS to be at the root of drive AL and select that drive
- ;
- mov fdos_hds_drv,al ; change to joined drive
- xor dx,dx
- mov fdos_hds_blk,dx ; put us back to the root again
- mov fdos_hds_root,dx
- cmp al,physical_drv ; already there ?
- je mvhds_drvroot10 ; then skip the selection
- call select_physical_drv ; select the drive
- mvhds_drvroot10:
- jmp path_prep_root ; info_fcb = '.'
- ; ret
- endif ;JOIN
- eject
- stamp_dir_entry:
- ;---------------
- ; On Entry:
- ; DIRP -> None
- ; On Exit:
- ; None
- ;
- ; Apply current date/time stamp to a directory, along with any other
- ; security information required.
- ;
- if PASSWORD
- mov cx,local_password ; were we given a password ?
- jcxz stamp_dir_entry10 ; if so apply it
- mov bx,dirp
- mov DPWM[bx],PWM_ANY ; deny all for compatibility
- or DATTS[bx],DA_HIDDEN ; make dir entry hidden
- mov DPWD[bx],cx ; with this password
- stamp_dir_entry10:
- endif
- call ReadTOD ; get current time/dat
- mov bx,dirp
- ; jmp stamp_date_and_time
- stamp_date_and_time:
- ; On Entry:
- ; BX -> directory entry
- ; AX = time
- ; DX = date
- ; On Exit:
- ; None
- ; stamp a directory entry with a given date and time
- mov DDATE[bx],dx
- mov DTIME[bx],ax
- mov ah,PASSWD_CREAT ; call out to SECURITY TSR
- callf ss:fdos_stub
- jc stamp_date_and_time10
- jmp fdos_error ; return an error if required
- stamp_date_and_time10:
- ret
- public ReadTOD
- ReadTOD:
- ;-------
- ; On Entry:
- ; None
- ; On Exit:
- ; DX = internal date format
- ; AX = internal time format
- ;
- call ReadTimeAndDate ; get current time/date from BIOS
- ; jmp GetTOD
- GetTOD:
- ;-------
- ; On Entry:
- ; None
- ; On Exit:
- ; DX = internal date format
- ; AX = internal time format
- ;
- mov ax,yearsSince1980 ; year is bits 9-15
- mov cl,4
- shl ax,cl
- add al,month ; month is bits 4-8
- mov cl,5
- shl ax,cl
- add al,dayOfMonth ; day is bits 0-3
- xchg ax,dx ; DX = date
- mov al,hour ; hour is bits 11-15
- mov cl,6
- shl ax,cl
- add al,minute ; minute is bits 5-10
- mov cl,5
- shl ax,cl
- mov cl,second ; second/2 is bits 0-4
- shr cl,1 ;
- add al,cl
- ret
- select_from_DTA:
- ;----------------
- ; called by search next/undelete/purge to select a disk and prepare for
- ; a directory search based upon DTA contents.
- ;
- push ds
- call lds_si_dmaptr ; DS:SI -> DMA address
- lodsb ; get search drive
- pop ds
- dec ax ; (stored 1-relative)
- mov path_drive,ax ; restore path drive
- call select_physical_drv ; select the drive in AL
- push ds
- push ds ! pop es ; ES = local segment
- call lds_si_dmaptr ; DS:SI -> DMA address
- inc si ; skip the drive #
- mov di,offset info_fcb+1 ; copy FCB back to INFO_FCB
- mov cx,11
- rep movsb
- lodsb ; get search attribute
- mov es:attributes,al
- lodsw ; get directory count
- mov es:dcnt,ax
- lodsw ; get the directory block
- pop ds ; restore data segment
- mov fdos_hds_blk,ax
- ret
- if PASSWORD
- check_pwd_d: ; check if PW protected in any mode
- ;-----------
- mov ax,PWM_D
- jmps check_pwd
- check_pwd_any: ; check if PW protected in any mode
- ;-------------
- mov ax,PWM_ANY
- ; jmps check_pwd
- check_pwd: ; check for password mismatch
- ;---------
- ; entry: AX = password mode to be checked
- ; DIRP -> directory entry for file
- ; exit: BX, SI preserved
- push ax
- push bx
- mov bx,dirp ; BX -> file to be opened/deleted/etc.
- xchg ax,cx ; password mode in CX
- mov ah,PASSWD_CHECK ; call out to SECURITY TSR
- callf ss:fdos_stub
- jnc check_pwd20
- mov ax,DPWD[bx] ; get password hash code from entry
- jcxz check_pwd10 ; exit if no password
- cmp ax,global_password ; compare with default password
- je check_pwd10 ; yes, go ahead
- cmp ax,local_password ; is it one we've just parsed ?
- je check_pwd10 ; yes, go ahead
- ; else we've got a password mismatch
- test cx,DPWM[bx] ; test if password mode affects us
- jz check_pwd10 ; skip if attempted access O.K.
- mov ax,ED_PASSWORD ; return password error
- check_pwd20:
- jmp fdos_error
- check_pwd10:
- pop bx
- pop ax
- ret
- Public hash_pwd
- hash_pwd: ; compute 16-bit hash code for 1st COMMON_DMA password
- ;--------
- ; On Entry:
- ; DS:SI -> 8 character password
- ; On Exit:
- ; AX = password hash code or 0000 if none (ZF set)
- ; SI corrupted, all other regs preserved
- ;
- push cx
- push bp
- mov cx,8 ; ch = 0, cl = 8
- mov bp,sp ; reverse and upper-case the name
- sub sp,cx ; using temp buffer on the stack
- xor ax,ax ; zero null password flag
- hash_pwd1:
- lodsb ; get next ASCII character
- call toupper ; international upper case
- dec bp
- mov ss:[bp],al ; copy password char to encrypted buff
- or al,al ; is password char zero?
- jz hash_pwd2 ; yes
- cmp al,' ' ; is password char blank?
- je hash_pwd2 ; yes
- inc ah ; password is not null
- hash_pwd2:
- add ch,al ; add password char to encrypt CRC
- dec cl
- jnz hash_pwd1
- mov al,ch ; AL = password CRC
- mov cx,8 ; encrypt 8 characters
- or ah,al ; if CRC = 0 and all 00 or ' '
- jz hash_pwd6 ; then there is no password
- hash_pwd3:
- xor ss:[bp],al ; encrypt password on stack
- inc bp
- loop hash_pwd3
- xor bp,bp ; initialize hash code
- mov cx,4 ; 8 bytes = 4 words
- hash_pwd4:
- pop ax ; get two encrypted characters
- rol ax,cl ; juggle them about a bit
- xor bp,ax ; "add" them into hash code
- loop hash_pwd4 ; repeat for whole password
- jnz hash_pwd5 ; skip if result is non-zero
- inc bp ; else force it to be non-zero
- hash_pwd5:
- xchg ax,bp ; return hash code in AX
- hash_pwd6:
- add sp,cx ; tidy up stack if buffer not poped
- test ax,ax ; set ZF flag appropriately
- pop bp
- pop cx
- ret
- endif
- public share_delay
- ; waste time before retrying operation that failed due to SHARE intervention
- share_delay:
- cmp ss:byte ptr remote_call,0
- jne share_delay_30
- push cx
- mov cx,ss:net_delay
- jcxz share_delay_20
- share_delay_10:
- push cx
- xor cx,cx
- loop $
- pop cx
- loop share_delay_10
- share_delay_20:
- pop cx
- share_delay_30:
- ret