рекурсивное удаление файлов в сборке x64 - PullRequest
1 голос
/ 10 марта 2019

Так что мне нужно рекурсивно удалять файлы в каталоге, используя сборку x86_64. Вот мой код, и я знаю, что это плохо. Моя проблема в том, что каждый системный вызов работает индивидуально (я могу по отдельности удалять каталоги или документы), но как только я их объединяю, это не работает. #edit: как указал @fuz, вопрос не был достаточно описательным. поэтому я хочу открыть каталог, содержащий файл с именем «test.txt», удалить этот файл, а затем удалить каталог, содержащий файл. Но он просто выходит из программы, когда я компилирую его с помощью nasm. Я использую Linux Mint

global _start

section .text

_start:


;open directory
    mov rax,    2       ;sys_open
    mov rdi,    dir     ;pointer to the directory
    mov rsi,    0       ;read only
    syscall


;delete document
    mov rax,    87      ;sys_unlink
    mov rdi,    doc     ;points to the document
    syscall


;delete directory
    mov rax,    84      ;sys_rmdir
    mov rdi,    dir
    syscall


_exit:
    mov rax,    60
    mov rdi,    80
    syscall


section .data
dir: db 'test',0
doc: db 'test.txt',0

1 Ответ

3 голосов
/ 11 марта 2019

Ваша проблема не в сборке, а в понимании основных системных вызовов POSIX / Unix.open("dir") не делает последующие системные вызовы unlink / rmdir относительно этого каталога, они все еще относятся к вашему текущему рабочему каталогу.Вы можете изменить это с помощью chdir().

(И это проще сделать с C, чем с asm. Для большинства системных вызовов оболочка glibc тривиальна и передает все аргументы без изменений ядру.это не так, в разделе NOTES справочной страницы Linux это указано.)


Там - это системные вызовы, которые выполняют действия, связанные с дескриптором файла открытого каталога (вместо этого)CWD) , чьи имена добавляют суффикс ...at к традиционным именам системных вызовов.Документация использует синтаксис C для описания системных вызовов, но, учитывая ABI, он говорит вам, как вызывать их в asm.

  • unlinkat(int dirfd, const char *pathname, int flags)
  • fd-относительный rmdir фактически выполняется с unlinkat(fd, path, AT_REMOVEDIR).(В противном случае при flags=0 unlinkat ведет себя как обычный unlink).
  • linkat, symlinkat, readlinkat, statat, mkdirat, execveat, ...
  • различные другие, включая renameat, и забавный renameat2, который принимает флаги, позволяющие вам атомарно менять два пути в одной и той же файловой системе.

  • Раздел примечаний справочной страницы openat объясняет, почему эти системные вызовы at существуют в первую очередь, в Rationale for openat() - избегает условий гонкимежду readdir и open, если кто-то еще rename sa компонент каталога пути.А поскольку chdir() для каждого процесса, а не для каждого потока, позволяет разным потокам одновременно выполнять относительные операции в разных каталогах.


Как сказал Шут, используйтеstrace find test -name 'test.txt' -delete или что-то в этом роде, чтобы увидеть, как на самом деле выполнять рекурсию через каталоги с open(O_DIRECTORY), getdents и unlinkat.

getdentsэто необработанный системный вызов, над которым в Linux построен интерфейс POSIX readdir.Страницы руководства документируют это.В asm вы можете использовать вызовы функций libc для readdir, или вам придется использовать getdents самостоятельно.


Или, поскольку вы на самом деле не рекурсивных, просто жестко запрограммировав некоторые относительные пути, вы можете просто сделать unlink("test/test.txt") и rmdir("test") системные вызовы.

...