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.