全盘搜索程序


概述:

     不知你编过全盘搜索程序没有,本程序用在消毒程序以及其他需要主动搜索磁盘上所有文件的地方,由于以前我自己的注释都是英文的,所以这次简单加上了一些中文。
   本程序要用到的 DOS 中断很少,仅为 4EH 和 4FH,功能是查找第一个匹配文件名和继续查找,编程难点是要用到类似于堆栈的数据结构,把找到的子目录名暂时存起来,等当前目录找完后在取出来,然后继续查找下一个目录,我用的方法是开一个缓冲区,定义一个指针,用来指向缓冲区结束的地方。用的是先进先出方式,为了节省空间,每个目录项长度不等长,由每项的前 2 个字节来指向前面一条目录项。具体见源程序。
    本程序要用到的 INT 21H 的 4EH 和 4FH 功能如下:

功能号 入口参数 出口参数
AH = 4EH
查找第一个匹配文件项
CX = 文件属性 标志 CF 复位 = 成功
找到文件名在 DTA 内
缺省 DTA 在PSP:0080H 处
DS:DX = 要查找的文件名 ASC 字符串 标志 CF 置位 = 出错
AH = 4FH
查找下一个匹配文件项
  标志 CF 复位 = 成功
找到文件名在 DTA 内
缺省 DTA 在 PSP:0080H 处
标志 CF 置位 = 出错

DTA 的内容如下: 

偏移量 长度 含义
15H 字节 找到文件的属性
16H 文件时间
位11-15:小时
位5-10:分
位0-4:秒/2
18H 文件日期
位9-15:年-1980
位8-5:月
位0-4:日
1AH 双字 文件大小
1EH 13字节 ASC II 文件名+扩展名

源程序:

;Copyright by LuoYunBin
;http://asm.yeah.net

.286p

CODE		SEGMENT
		ASSUME	CS:CODE,DS:CODE
		ORG	100H
START:
		jmp	install
install:
		call	get_com_line	;处理命令行
		call	scan_disk	;全盘查找子程序
		mov	ah,4ch
		int	21h
		
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	search the hole diskette files
;	programmed by LYB
;	include following procedures
;		scan_disk: scan disk and get all filename
;	-----------------------------------------
;	enter 	ds:si = scan drive or path name
;	return 	FIND_FILE = found file name
;		SD_ATTR	= file attribute
;	use	DO_FILE process to file operation
;	the 	data in sd_buffer is like this
;		addr1:	word -1, + path string
;		addr2:	word addr1, + path string
;		addr3:	word addr2, + path string
;		...
;		PATH_SP point to last address
SCAN_DISK	PROC	NEAR
		jmp	scan_start
;	data for do_file process
SD_ATTR		DW	?		;要找的文件属性
FIND_FILE	DB	128 DUP (0)	;找到的文件名
;	data use scan_disk itself
path_ep		dw	?		;目录名缓冲区指针
path_sp		dw	path_buffer	;path buffer stack point
finding_file	db	8 dup (0)
finding_ext	db	3 dup (0)
temp_file	db	8 dup (0)
temp_ext	db	3 dup (0)
scan_start:
		push	cs
		pop	ds
		push	cs
		pop	es			;set ds,es = cs
		mov	si,80h
		call	phase_name		;phase file name
		mov	si,path_sp
sd_lop:
		inc	si
		inc	si
		mov	di,offset find_file
		cld
		call	move_byte
		dec	di
		cmp	byte ptr ds:[di-1],'\'	;path as N:\
		jz	sd1
		mov	al,'\'
		stosb
sd1:
		mov	path_ep,di		;path end point
		mov	ax,'.*'
		stosw				;add *.*
		mov	al,'*'
		stosb
		xor	al,al
		stosb
		mov	ah,4eh
		mov	dx,offset find_file	;找第一个文件
		mov	cx,37h			;找所有文件属性包括子目录
		int	21h
		jb	sd_lop2_end
sd_lop2:
		call	pros_dir		;处理目录项
		mov	ah,4fh			;找下一个文件
		int	21h
		jnb	sd_lop2
sd_lop2_end:
		mov	si,path_sp		;检查目录缓冲区
		cmp	si,offset path_buffer	;如果还有目录要找,则继续
		jnz	sd_new_dir
		ret
sd_new_dir:
		mov	di,[si]			;从缓冲区中取出新目录
		mov	path_sp,di
		jmp	sd_lop
PROS_DIR	PROC
		mov	si,80h			;80H 为 DTA 地址
		xor	ah,ah
		mov	al,ds:[si+0015h]
		mov	sd_attr,ax		;找到的文件属性
		add	si,1eh
		push	si
		mov	di,path_ep		;把文件名加到路径上
		call	move_byte
		pop	si
		test	sd_attr,10h		;是否为子目录
		jnz	pd_is_dir
		call	check_find
		jnz	pd_ret
		call	do_file			;对找到的文件进行处理
;本程序的处理程序仅为打印文件名,实际应用中,如果是用于消毒程序,可以
;在 DO_FILE 子程序中对文件进行检查

pd_ret:
		ret
pd_is_dir:
		cmp	byte ptr ds:[si],'.'	;是 . 或 .. 则忽略
		jz	pd_ret
		mov	di,path_sp		;如果找到新目录
		push	di			;则把它加入目录名缓冲区
		inc	di
		inc	di
		mov	cx,-1
		xor	al,al
		repnz	scasb			;find string end
		pop	[di]			;fill new address
		mov	path_sp,di		;point to previous address
		inc	di
		inc	di			;add path string
		mov	si,offset find_file
		call	move_byte
		ret
PROS_DIR	ENDP
MOVE_BYTE	PROC
		lodsb
		or	al,al
		jz	mb_ret
		stosb
		jmp	short move_byte
mb_ret:
		stosb
		ret
MOVE_BYTE	ENDP
;=================================================
;	check file name in DTA if match
;	the searching file name
;本子程序的作用是,如果命令行指定查找特定文件
;则比较是否找到,如命令行输入找 *.EXE 那么
;就是在这儿比较
;=================================================
CHECK_FIND	PROC
		mov	di,offset temp_file
		mov	cx,11
		xor	al,al
		cld
		rep	stosb
		mov	si,80h+1eh
		mov	di,offset temp_file
cf_lop1:
		lodsb
		or	al,al
		jz	cf_lop2_end
		cmp	al,'.'
		jz	cf_lop1_end
		stosb
		jmp	short cf_lop1
cf_lop1_end:
		mov	di,offset temp_ext
cf_lop2:
		lodsb
		or	al,al
		jz	cf_lop2_end
		stosb
		jmp	short cf_lop2
cf_lop2_end:
		mov	si,offset temp_file
		mov	di,offset finding_file
		mov	cx,11
cf_lop3:
		lodsb
		mov	ah,[di]
		inc	di
		cmp	ah,'?'
		jz	cf_match	;char match
		cmp	ah,al
		jz	cf_match	;char match
cf_end:
		ret
cf_match:
		loop	cf_lop3
		ret
CHECK_FIND	ENDP
;	get .ext and name and path name from com_line
;	input data in DS:SI
;	output scan file name in ES:DI
; 对要找的文件字符串进行预处理,分离路径和文件名
PHASE_NAME	PROC
		mov	di,offset find_file
		mov	bp,di
		xor	ax,ax
		mov	cx,128
		cld
		rep	stosb
		mov	di,bp
		dec	bp			;bp point to find_file-1
pn_lop:
		lodsb
		stosb
		or	al,al
		jz	pn_lop_end
		cmp	al,'?'
		jz	pn_wild
		cmp	al,'*'
		jz	pn_wild
		cmp	al,'\'			;path end point
		jz	pn_para
		cmp	al,':'
		jnz	pn_lop
		cmp	byte ptr [si],'\'
		jz	pn_lop
		mov	al,'\'
		stosb
pn_para:
		mov	bp,di			;save path end
		dec	bp
		jmp	short pn_lop
pn_wild:
		mov	ah,1			;set wild char flag
		jmp	short pn_lop
pn_lop_end:
		or	ah,ah			;=1, then has wild char
		jnz	pn_spar
		mov	ah,4eh
		mov	cx,37h
		mov	dx,offset find_file	;check if is dir
		int	21h
		jb	pn_spar			;sparater path and file name
		test	byte ptr ds:[80h+15h],10h
		jz	pn_spar			;if not dir
		mov	bp,di			;is dir
		dec	bp
		mov	ax,'.*'
		stosw
		mov	al,'*'
		stosb
		xor	al,al
		stosb
pn_spar:
		cmp	bp,offset find_file-1
		jz	pn_spar1
		
		mov	byte ptr ds:[bp],0
		mov	si,offset find_file
		mov	di,offset path_buffer+2
		call	move_byte
pn_spar1:
		inc	bp
		mov	si,bp
		mov	di,offset finding_file
		mov	cx,8
pn_lop1:
		lodsb				;get filename
		cmp	al,'.'
		jz	pn_lop2_1
		or	al,al
		jz	pn_lop3_end
		cmp	al,'*'
		jz	pn_lop1_store
		stosb
		loop	pn_lop1
		jmp	short pn_lop2
pn_lop1_store:
		mov	al,'?'
		rep	stosb
pn_lop2:
		lodsb
pn_lop2_1:
		or	al,al
		jz	pn_lop3_end
		cmp	al,'.'
		jnz	pn_lop2
		mov	di,offset finding_ext
		mov	cx,3
pn_lop3:
		lodsb				;get ext name
		or	al,al
		jz	pn_lop3_end
		cmp	al,'*'
		jz	pn_lop3_store
		stosb
		loop	pn_lop3
		jmp	short pn_lop3_end
pn_lop3_store:
		mov	al,'?'
		rep	stosb
pn_lop3_end:
		mov	al,'?'
		cmp	finding_file,0
		jnz	pn1
		mov	di,offset finding_file
		mov	cx,8
		rep	stosb
pn1:
		cmp	finding_ext,0
		jnz	pn2
		mov	di,offset finding_ext
		mov	cx,3
		rep	stosb
pn2:
		ret
PHASE_NAME	ENDP
SCAN_DISK	ENDP
do_file		proc
		mov	si,offset d_searching
		call	printf
		ret
do_file		endp
d_searching	db	'Searching file: %c%79t',0dh,0
		dw	find_file
GET_COM_LINE	PROC
;	get command line file name
;	to CL_FILE and return CY when no command line
;	return NC when has command line
;	the sub change lower letter to upper letter
; 命令行处理子程序
		mov	si,81h
		mov	di,80h
		cld
cmd_lop:
		lodsb
		cmp	al,0dh
		jz	cmd_lop_end
		cmp	al,' '
		jbe	cmd_lop	;如果是小写字母
		cmp	al,'a'		;则转换到大写
		jb	stos_it	;因为大小写字母 ASC 码值刚好差 20H
		cmp	al,'z'	;所以把 ASC 码减 20H 就换到大写了
		ja	stos_it
		sub	al,20h		;convert to upper case
stos_it:
		stosb
		jmp	short cmd_lop
cmd_lop_end:
		xor	al,al
		stosb
		ret
GET_COM_LINE	ENDP
include		printf.asm	;一个公用的显示程序
FILE_END	EQU	THIS BYTE
path_buffer	db	1000h dup (0)	;path buffer
CODE		ENDS
		END	START




(C) Copyright by LuoYunBin's Win32 ASM Page,http://asm.yeah.net