잠시 동안 뭔가 혼란스러웠습니다.
[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 +++
디렉토리와 파일을 삭제하기 위해 별도의 시스템 호출이 있는 이유는 무엇입니까? 이 두 작업이 의미적으로 다른 이유는 무엇입니까?
답변1
디렉터리의 특별한 점은 디렉터리 내에서 여러 파일과 디렉터리를 참조할 수 있다는 것입니다. 따라서 상위 디렉터리를 삭제하면 해당 파일은 모두 액세스 가능한 참조 지점을 잃게 되며 프로세스도 마찬가지입니다. 이 경우에는 다음과 같은 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)
원하는 경로에 따라 동작이 있습니다 .
답변2
내 개인 위키 페이지에서 복사함unlink("/") 및 rmdir("/")이 실패하는 이유는 무엇입니까?:
그러나 특별한 파일 형식이 있습니다.목차. 파일 시스템의 올바른 작동을 보장하려면 디렉토리에 대한 하드 링크를 일관된 방식으로 유지해야 합니다. 예를 들어 디렉토리를 생성하거나 삭제할 때 여러 하드 링크가 자동으로 생성되거나 삭제됩니다 /var/tmp/foo
. 새 디렉터리(inode)를 참조하는 2개의 하드 링크가 다음 위치에 생성됩니다.
/var/tmp/foo
– 귀하가 생성을 요청한 이름 자체/var/tmp/foo/.
–.
이 새 디렉토리의 이름
또한 상위 디렉터리를 참조하는 또 다른 하드 링크가 생성되므로 /var/tmp/foo/..
새로 생성된 디렉터리의 링크 수는 2가 됩니다.
이전 Unix 시스템에서는 디렉터리 하드 링크를 수동으로 조작할 수 있었습니다. 이는 주로 디렉터리 이름을 바꾸는 데 사용되었습니다.이름 바꾸기(2)그 당시에는 시스템 호출이 존재하지 않았습니다. 디렉터리 또는 다른 파일 형식의 파일 이름을 수동으로 바꾸려면 다음 명령을 사용하여 새 이름을 만듭니다.링크(2)을 누른 다음 다음을 사용하여 이전 이름을 삭제합니다.연결 해제(2);그러나 이 방법을 사용하여 디렉터리를 조작하는 것은 지나치게 강력한 경우가 많습니다. 사용자는 디렉터리를 부적절하게 연결하거나 연결 해제하여 파일 시스템에 쉽게 불일치를 초래할 수 있습니다. 예를 들어, 상위 디렉토리를 참조하지 않고 하드 링크를 생성하면 무한 디렉토리 루프가 발생하거나, 먼저 다른 위치에 링크를 생성하지 않고 디렉토리 하드 링크를 삭제하면 "해당 디렉토리 아래의 모든 파일이 나머지 파일과 연결이 끊어집니다." " 시스템 트리, 이러한 불일치가 발생할 것으로 예상됩니다.시스템 점검(8)다음 번 시스템 시작 시 문제가 올바르게 수정될 것이라는 보장은 없습니다.
유닉스 시스템에서 제공목차(2)이 시스템을 사용하여 기본 하드 링크뿐만 아니라 디렉토리, inode를 올바르게 제거하려면 하드 링크를 참조하는 통과 경로가 .
또는 이 아니고 ..
, 하드 링크가 디렉토리 유형 inode를 참조하고 디렉토리가 비어 있어야 합니다. . 포함 .
및 ..
링크만 호출에 성공하면 이 2개의 하드 링크, 경로에 지정된 디렉터리 하드 링크 및 디렉터리 inode가 삭제됩니다.