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

📄 utils.fdo

📁 一个dos操作系统DRDOS的源码
💻 FDO
📖 第 1 页 / 共 5 页
字号:
	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 + -