📄 utils.fdo
字号:
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.
;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -