rmdir이 왜 두 개의 개별 시스템 호출을 연결 해제합니까?


10

한동안 궁금해하는 것이 있습니다.

[15:40:50][/tmp]$ mkdir a
[15:40:52][/tmp]$ strace rmdir a
execve("/usr/bin/rmdir", ["rmdir", "a"], [/* 78 vars */]) = 0
brk(0)                                  = 0x11bb000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff3772c3000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=245801, ...}) = 0
mmap(NULL, 245801, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff377286000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\36\3428<\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2100672, ...}) = 0
mmap(0x3c38e00000, 3924576, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3c38e00000
mprotect(0x3c38fb4000, 2097152, PROT_NONE) = 0
mmap(0x3c391b4000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b4000) = 0x3c391b4000
mmap(0x3c391ba000, 16992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3c391ba000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff377285000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff377283000
arch_prctl(ARCH_SET_FS, 0x7ff377283740) = 0
mprotect(0x609000, 4096, PROT_READ)     = 0
mprotect(0x3c391b4000, 16384, PROT_READ) = 0
mprotect(0x3c38c1f000, 4096, PROT_READ) = 0
munmap(0x7ff377286000, 245801)          = 0
brk(0)                                  = 0x11bb000
brk(0x11dc000)                          = 0x11dc000
brk(0)                                  = 0x11dc000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=106070960, ...}) = 0
mmap(NULL, 106070960, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff370d5a000
close(3)                                = 0
rmdir("a")                              = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++
[15:40:55][/tmp]$ touch a
[15:41:16][/tmp]$ strace rm a
execve("/usr/bin/rm", ["rm", "a"], [/* 78 vars */]) = 0
brk(0)                                  = 0xfa8000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3b2388a000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=245801, ...}) = 0
mmap(NULL, 245801, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3b2384d000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\36\3428<\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2100672, ...}) = 0
mmap(0x3c38e00000, 3924576, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3c38e00000
mprotect(0x3c38fb4000, 2097152, PROT_NONE) = 0
mmap(0x3c391b4000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b4000) = 0x3c391b4000
mmap(0x3c391ba000, 16992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3c391ba000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3b2384c000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3b2384a000
arch_prctl(ARCH_SET_FS, 0x7f3b2384a740) = 0
mprotect(0x60d000, 4096, PROT_READ)     = 0
mprotect(0x3c391b4000, 16384, PROT_READ) = 0
mprotect(0x3c38c1f000, 4096, PROT_READ) = 0
munmap(0x7f3b2384d000, 245801)          = 0
brk(0)                                  = 0xfa8000
brk(0xfc9000)                           = 0xfc9000
brk(0)                                  = 0xfc9000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=106070960, ...}) = 0
mmap(NULL, 106070960, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3b1d321000
close(3)                                = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
newfstatat(AT_FDCWD, "a", {st_mode=S_IFREG|0664, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
geteuid()                               = 1000
newfstatat(AT_FDCWD, "a", {st_mode=S_IFREG|0664, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
faccessat(AT_FDCWD, "a", W_OK)          = 0
unlinkat(AT_FDCWD, "a", 0)              = 0
lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

디렉토리와 파일을 제거하기 위해 별도의 시스템 호출이 필요한 이유는 무엇입니까? 이 두 작업이 의미 상 구별되는 이유는 무엇입니까?


3
여기에 답변했습니다 : superuser.com/questions/430313/…
— jlliagre

답변:


9

디렉토리는 디렉토리 내에서 여러 파일 및 디렉토리에 대한 참조를 가질 수 있다는 점에서 특별합니다. 따라서 상위 디렉토리를 제거하면 모든 파일은 프로세스와 동일하게 액세스 할 수있는 위치에서 해당 참조 지점을 잃게됩니다. 이러한 경우 다음과 rmdir()다른 검사가 다릅니다 unlink().

  • 디렉토리가 비어 있지 않은 경우 디렉토리가 비어 있지 않은 경우 내용을 제거하거나 제거 할 때까지 디렉토리를 제거 할 수 없습니다 unlink.

       ENOTEMPTY
          pathname contains entries other than . and .. ; or, pathname has
          ..  as its final component.  POSIX.1-2001 also allows EEXIST for
          this condition.
    
  • 디렉토리가 사용중인 경우 프로세스가 현재 디렉토리를 잃으면 문제와 정의되지 않은 동작으로 이어질 수 있습니다. 그들을 방지하는 것이 좋습니다.

       EBUSY  pathname  is currently in use by the system or some process that
          prevents its removal.  On Linux this means pathname is currently
          used  as  a  mount point or is the root directory of the calling
          process.
    

unlink()이러한 확인이 존재하지 않는 경우 . 실제로 파일 이름을 삭제하고 파일을 unlink()계속 사용 / 참조하는 프로세스를 문제없이 수정할 수 있습니다. 파일은 디스크립터가 존재할 때까지 존재하며 새로운 프로세스에 액세스 할 수 없습니다 (검색 위치를 알지 못하는 경우). 이것은 * NIX 파일 시스템의 무지개색 손 마법의 일부입니다.

이제, unlinkat()둘 다로 작동 unlink()하거나 rmdir(2)원하는 경로에 따라 행동 하는 것이 있습니다.


잘 rm -rf "$PWD"작동하고 현재 디렉토리를 제거합니다. 나는 그것이 존재하는 이유 rmdir()는 아마도 역사적 일 것입니다 (초기 디렉토리는 unlinked () 였고 rmdir (명령)은 dir /., dir / ..와 dir을 연결 해제하고 있었고, 그것이 커널로 옮겨 졌을 때, 그것은 새로운 syscall은 적어도 전환 기간 또는 이와 유사한 상황에서 3 가지를 모두 수행합니다)
— Stéphane Chazelas

@ StéphaneChazelas는 동의하지 않기 때문에 링크를 추가하지 않았습니다.
— Braiam

대답을 올바르게 읽으면 사용 중이 rmdir(dir)면 작동하지 않는다는 것 dir입니다. Linux에서는 적어도 사실이 아닙니다 rmdir(getcwd())(현재 디렉토리가 비어있는 경우).
— Stéphane Chazelas

@ StéphaneChazelas 올바름, 프로세스 또는 마운트 포인트로 사용 : EBUSY pathname 은 현재 시스템 또는 일부 프로세스에서 제거를 방해하고 있습니다. Linux에서 이는 경로 이름이 현재 마운트 지점으로 사용되거나 호출 프로세스의 루트 디렉토리임을 의미합니다.
— Braiam

나는 그들이 무엇을 의미하는지 또는 호출 프로세스의 루트 디렉토리 인지 확실하지 않습니다 . mkdir test; sudo strace -e chroot,rmdir perl -e 'chroot("test"); rmdir("test")'chroot와 rmdir 성공을 표시합니다.
— Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.