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

标签 linux assembly x86 nasm

我正在努力学习汇编,所以如果我的问题很初级,请多多包涵

以下代码扫描目录并打印出其中的所有文件和目录,除了以点开头的文件和目录。它似乎工作正常。

但是,一旦我取消对 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/

相关文章:

c++ - 如何在 Linux(Ubuntu OS)中检测 C++ 应用程序的内存泄漏?

linux - 在 ARM 机器上的 Linux 中如何处理系统调用

c - 将地址弹出到寄存器中

x86 - 你会从 DOS 挂断什么中断来获取实时时钟

assembly - 为什么 x86 FP 像无符号整数一样比较 set CF,而不是使用有符号条件?

c - 为什么管道可以使用的进程之间的关系在 Linux API 和 Bash 中不同

java - 如何对 Linux 上的 Apache Accumulo 安装进行故障排除?

assembly - AARCH64 上不存在 MCR 和 MRC?

c - 使用 SSE 加速 lower_bound 函数

windows - QueryWorkingSet 在其结果中包含无效页面