簡體   English   中英

遞歸列出目錄內容,並檢查文件是否為目錄

[英]Recursively list directory content, plus check if file is directory

我正在嘗試學習匯編,所以如果我的問題很簡單,請多包涵

以下代碼掃描目錄並打印出其中的所有文件和目錄,但以點開頭的文件和目錄除外。 似乎工作正常。

但是,一旦取消注釋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]

編輯:我認為,這現在大多數情況下都有效,除了它似乎最初會跳回到“測試”下面的目錄中,導致它兩次列出該文件和“測試”中的文件

[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/目錄,就可以進行無限遞歸,直到用完文件句柄為止。

解決方法之一就是打電話chdir成功后opendir (也chdir后回父目錄closedir ),這樣的工作目錄將始終指向您當前正在檢查一個。


另外,我想一種方法來測試文件是否是目錄。

readdir返回的dirent結構具有一個d_type成員(偏移量為10),您可以檢查該成員:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM