我正在努力学习汇编,所以如果我的问题很初级,请多多包涵
以下代码扫描目录并打印出其中的所有文件和目录,除了以点开头的文件和目录。它似乎工作正常。
但是,一旦我取消对 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
最佳答案
您的代码看起来几乎没问题。问题出在 readdir
返回的路径名上,您要将其用于下一个递归步骤。返回的路径名与当前工作目录无关。
当 test/
目录包含名为 test
的文件时,您看到的大量输出。当您的循环看到该文件名时,您会将其传递给 opendir
,这意味着您只需再次重新打开相同的 test/
目录,导致无限递归,直到用完文件句柄。
解决这个问题的一种方法是在成功的 opendir
之后调用 chdir
(并且 chdir
在 之后回到父目录closedir
) 这样工作目录将始终指向您当前正在检查的目录。
Also, I'd like a way to test if the file is a directory or not.
readdir 返回的dirent
结构|有一个您可以检查的 d_type
成员(在偏移量 10 处):
...
call readdir
...
cmp byte [eax+10], 4 ; DT_DIR = 4
jne is_not_directory
关于linux - 递归列出目录内容,并检查文件是否为目录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8194466/