⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 utils.fdo

📁 一个dos操作系统DRDOS的源码
💻 FDO
📖 第 1 页 / 共 5 页
字号:

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 + -