Linux 递归列出目录内容,并检查文件是否为目录

Linux 递归列出目录内容,并检查文件是否为目录,linux,assembly,x86,nasm,Linux,Assembly,X86,Nasm,我正在努力学习组装,所以如果我的问题是基本的,请耐心听我说 下面的代码扫描一个目录并打印出其中的所有文件和目录,除了那些以点开头的文件和目录。它似乎工作得很好 但是,一旦我取消对call scandir行的注释以启用递归,它就会打印出一长串重复的文件名,详情见下文 另外,我想用一种方法来测试文件是否为目录。我该怎么做?据我所知,目前这还不是问题所在,因为如果它不是一个目录,那么对scandir的调用只会返回而不做任何事情,但是检查可能会在以后变得很重要,而且不管怎样,这似乎是一件好事 [SECT

我正在努力学习组装,所以如果我的问题是基本的,请耐心听我说

下面的代码扫描一个目录并打印出其中的所有文件和目录,除了那些以点开头的文件和目录。它似乎工作得很好

但是,一旦我取消对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,这意味着您只需再次重新打开同一测试/目录,从而导致无限递归,直到文件句柄用完为止

解决这个问题的一种方法是在成功的opendir之后调用chdir,并在closedir之后将chdir返回到父目录,这样工作目录将始终指向您当前正在检查的目录

另外,我想用一种方法来测试文件是否为目录

返回的dirent结构在偏移量10处有一个d_类型成员,您可以检查:

...
call readdir
...
cmp byte [eax+10], 4    ; DT_DIR = 4
jne is_not_directory

你的代码看起来很好。问题在于readdir返回的路径名,您希望将其用于下一个递归步骤。返回的路径名与当前工作目录不相关

当test/目录包含一个名为test的文件时,您会看到大量的输出。当循环看到该文件名时,您将把它传递给opendir,这意味着您只需再次重新打开同一测试/目录,从而导致无限递归,直到文件句柄用完为止

解决这个问题的一种方法是在成功的opendir之后调用chdir,并在closedir之后将chdir返回到父目录,这样工作目录将始终指向您当前正在检查的目录

另外,我想用一种方法来测试文件是否为目录

返回的dirent结构在偏移量10处有一个d_类型成员,您可以检查:

...
call readdir
...
cmp byte [eax+10], 4    ; DT_DIR = 4
jne is_not_directory

谢谢我想我现在大部分时间都在工作,但它仍然给我带来一些麻烦。请参阅上面我文章中的编辑。仍然存在相同的问题-您首先列出test/目录,然后将这些路径视为相对于当前工作目录的路径,而它们不是。main中的一个快速修复方法是先将chdir转换为DirName,然后在调用scandirAh之前再转换为mov eax、CurrentDir!或者我只是将chdir部分移到scandir的开头。谢谢你的帮助,现在可以用了,谢谢。我想我现在大部分时间都在工作,但它仍然给我带来一些麻烦。请参阅上面我文章中的编辑。仍然存在相同的问题-您首先列出test/目录,然后将这些路径视为相对于当前工作目录的路径,而它们不是。main中的一个快速修复方法是先将chdir转换为DirName,然后在调用scandirAh之前再转换为mov eax、CurrentDir!或者我只是将chdir部分移到scandir的开头。谢谢你的帮助,它正在工作