📄 utils.fdo
字号:
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. '\DEV\CON', "A:\DEV\CON'
; More complicated forms should be ignored - they will be handled
; after the pathname is parsed.
; eg. 'A:\CON', '\CON', 'SUBDIR\CON.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 '\DEV\name' 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -