我一直在寻找这个答案,但没有找到一个。让我们先看一个例子:
$ cd /tmp
$ mkdir foo
$ cd foo
$ pwd
/tmp/foo
$ $SHELL
$ rmdir /tmp/foo
$ exit
$ pwd
/tmp/foo
$ ls
<no output>
$ man ls
man: can't change directory to '': No such file or directory
man: command exited with status 255: (cd && LESS=-ix8RmPm Manual page ls(1) ?ltline %lt?L/%L.:byte %bB?s/%s..?e (END):?pB %pB%.. (press h for help or q to quit)$PM Manual page ls(1) ?ltline %lt?L/%L.:byte %bB?s/%s..?e (END):?pB %pB%.. (press h for help or q to quit)$ MAN_PN=ls(1) pager -s)
$ echo -e '#include<unistd.h>n#include<stdio.h>n#include<stdlib.h>nint main(){char*p=getcwd(NULL,0);printf("%s\n",p);free(p);}' | gcc -x c -
/usr/bin/ld: cannot open output file a.out: No such file or directory
collect2: error: ld returned 1 exit status
$ cd $PWD
cd: no such file or directory: /tmp/foo
内部发生了什么?内核如何处理这种情况?如果假定当前目录仍然作为文件描述符,那么为什么所有这些命令都失败?
而且,(至少对我来说)更重要的是,为什么没有保护来防止这种东西?在我看来,它很容易导致严重的安全问题……
删除目录时,将执行以下步骤:
- 到父目录的链接被删除
- 目录中指向父目录的
..
链接被删除 - 目录中指向自身的
.
链接被删除
当这些发生时,目录的链接计数将被删除。当链接数变为0
时,目录本身将从文件系统中删除。
如果有任何进程访问该目录(作为工作目录,或者因为它们调用了opendir()
),这些进程也会增加目录的链接计数。因此,直到所有这些访问都消失,目录才真正消失。
当目录处于这种状态时,它可以被读取,但是依赖于上述任何链接的任何内容都将失败。当您执行cd $PWD
时,它正在尝试执行cd /tmp/foo
,但foo
链接已被删除。