我正在努力学习集会,所以如果我的问题是基本的话,请耐心等待。
以下代码扫描目录并打印出其中的所有文件和目录,但以点开头的那些文件和目录除外。它似乎工作正常。
但是,一旦我取消注释call scandir
行以打开递归,它就会打印出一长串重复的文件名(详见下文)。
另外,我想要一种测试文件是否是目录的方法。我该怎么办?据我所知,这不是问题,现在,因为如果它不是一个目录,那么对scandir的调用只会在没有做任何事情的情况下返回,但是检查可能会在以后变得很重要(这似乎是件好事)反正)。
[SECTION .data]
DirName db 'test', 0
[SECTION .bss]
[SECTION .text]
extern puts ; Externals from glibc standard C library
extern opendir ; Externals from dirent.h
extern closedir
extern readdir
global main
scandir:
pushad ; Save caller's registers
push eax ; Directory is passed in eax
call opendir ; Open directory
add esp, 4
cmp eax, 0 ; opendir returns 0 on failure
je .done
mov ebx, eax ; Move directory handle to ebx
.read:
push ebx ; Push directory handle
call readdir ; Read a file from directory
add esp, 4 ; Clean up the stack
cmp eax, 0 ; readdir returns 0 on failure or when done
je .close
add eax, 11 ; File name is offset at 11 bytes
mov cl, byte [eax] ; Get first char of filename
cmp cl, 46 ; Ignore files and dirs which begin with a dot
je .read ; (., .., and hidden files)
;call scandir ; Call scandir recursively
; If file is not a dir opendir will simply fail
push eax
call puts
add esp, 4
jmp .read
.close:
push ebx ; Close directory
call closedir
add esp, 4
jmp .done
.done:
popad ; Restore caller's registers
ret
main:
push ebp ; Set up stack frame for debugger
mov ebp, esp
push ebx ; Must preserve ebp, ebx, esi and edi
push esi
push edi
; start
mov eax, DirName
call scandir
; end
pop edi ; Restore saved registers
pop esi
pop ebx
mov esp, ebp ; Destroy stack frame
pop ebp
ret
测试目录的目录结构如下:
bar [directory]
bas.c
test1.c
test2.c
test3.c
foo.txt
test
没有递归,它会打印出测试目录中的文件,但是通过递归,它似乎打印出以下内容:
test1.c
bar
test3.c
[repeat 3 lines ~1000 times]
test
foo.txt
test2.c
[repeat 3 lines ~1000 times]
编辑:我认为现在大部分都可以使用了,除了它似乎最初跳回到'test'下面的目录,导致它列出那里的文件和'test'中的文件两次
[SECTION .data]
ParentDir db '..', 0
CurrentDir db '.', 0
DirName db 'test', 0
[SECTION .bss]
[SECTION .text]
extern puts ; Externals from glibc standard C library
extern opendir ; Externals from dirent.h
extern closedir
extern readdir
extern chdir
global main
scandir:
pushad ; Save caller's registers
push eax ; Directory is passed in eax
call opendir ; Open directory
add esp, 4
cmp eax, 0 ; opendir returns 0 on failure
je .done
mov ebx, eax ; Move directory handle to ebx
.read:
push ebx ; Push directory handle
call readdir ; Read a file from directory
add esp, 4 ; Clean up the stack
cmp eax, 0 ; readdir returns 0 on failure or when done
je .close
add eax, 11 ; File name is offset at 11 bytes
mov cl, byte [eax] ; Get first char of filename
cmp cl, 46 ; Ignore files and dirs which begin with a dot
je .read ; (., .., and hidden files)
cmp byte [eax-1], 4
jne .notdir
push eax
call chdir
add esp, 4
mov eax, CurrentDir
call scandir ; Call scandir recursively
jmp .read
.notdir:
push eax
call puts
add esp, 4
jmp .read
.close:
push ebx ; Close directory
call closedir
add esp, 4
push ParentDir
call chdir
add esp, 4
jmp .done
.done:
popad ; Restore caller's registers
ret
main:
push ebp ; Set up stack frame for debugger
mov ebp, esp
push ebx ; Must preserve ebp, ebx, esi and edi
push esi
push edi
; start
mov eax, DirName
call scandir
; end
pop edi ; Restore saved registers
pop esi
pop ebx
mov esp, ebp ; Destroy stack frame
pop ebp
ret
答案 0 :(得分:0)
你的代码看起来很好。问题在于readdir
返回的路径名,您希望将其用于下一个递归步骤。返回的路径名与当前工作目录无关。
您看到的大量输出是test/
目录包含名为test
的文件。当您的循环看到该文件名时,您将其传递给opendir
,这意味着您只需再次重新打开相同的test/
目录,从而导致无限递归,直到您用完文件句柄。
解决此问题的一种方法是在成功chdir
之后调用opendir
(以及chdir
后closedir
回到父目录),以便工作目录将总是指向你正在检查的那个。
另外,我想要一种测试文件是否是目录的方法。
readdir返回的dirent
结构有d_type
成员(偏移10),您可以查看:
...
call readdir
...
cmp byte [eax+10], 4 ; DT_DIR = 4
jne is_not_directory