use*_*312 38 hard-link inode rm
我按照指定的顺序运行了以下命令:
$ln a b
$ls -i a b
523669 a 523669 b
$rm -f a
$ls -i b
523669 b
Run Code Online (Sandbox Code Playgroud)
我从这个测试中得出结论,该命令rm实际上只删除了文件名(a在这个测试中)而不是文件,因为 inode 仍然存在并且可以通过另一个文件名 ( b)检索。
我的问题是,如果一个文件只硬链接到一个文件名,那么当rm对文件执行时,真正的文件(即inode)是否被完全删除?如果没有,是否可以在没有文件名的情况下仅通过 inode 检索文件 inode?
Gil*_*il' 42
如果您尝试通过其 inode 打开文件,则会绕过任何目录遍历。目录遍历对于确定文件和通向它的目录的权限是必要的。没有目录遍历,内核无法确定是否允许调用进程访问文件。
有一个建议的 Linux 内核补丁允许从文件描述符创建到文件的链接。它被拒绝了,因为安全地实施它会非常困难。
在 Linux 下(可能出于同样的原因在其他 unix 变体上),您无法创建指向已删除文件的链接,因此如果文件不再具有名称,则无法重新添加名称。¹ 您可以打开已删除的文件通过打开/proc/$pid/fd/.
如果文件不再有任何链接并且不再打开,则它不再存在,并且其数据以前使用的空间可能随时被回收。
¹您可以通过以依赖于文件系统的方式直接在文件系统中处理字节来实现此目的,例如使用debugfsext2/ext3/ext4。这需要访问安装文件系统的设备(即通常只有 root 可以尝试它)。然而,虽然 debugfs 可以通过 inode 访问文件,但如果文件被删除,这也无济于事:如果应用程序关闭该文件,该文件将被真正删除,并且在已挂载的文件系统上以读写模式运行 debugfs 是一个秘诀灾难。
Tho*_*man 14
在 Linux 上,debugfs交互式 ext2/ext3/ext4 文件系统调试器提供了一个ln命令,该命令可以将 inode 编号作为filespec并创建到相应文件的新硬链接。但实际上,这要求未链接的文件由进程保持打开状态,在/proc/[pid]/fd/[n]. 尝试在已删除的文件上执行此操作很可能会导致文件系统损坏。
这是因为为了确保 ext3(以及扩展 ext4)在崩溃后可以安全地恢复取消链接,它实际上将 inode 中的块指针清零,而 ext2 只是在块位图中将这些块标记为未使用,并标记inode 被“删除”并留下块指针。即便如此,由于文件系统需要以读写方式挂载以创建硬链接,为删除的文件保留的块可能已经被重新分配。
在内核版本 2.6.39 之前,如果未链接的文件和新的硬链接都驻留在tmpfs文件系统上,则可以使用GNU coreutils v8.0 中引入的选项通过打开的文件描述符来恢复未链接的文件。正如Gilles 所指出的,由于允许直接从文件描述符创建硬链接所涉及的安全考虑,此功能已被禁用。ln -L|--logical/proc/[pid]/fd/[n]
小智 14
自 1970 年代初以来,'ln' 和 'rm' 命令在每个 UNIX 文件系统中的工作方式完全如此。Mac OSX、BSD 和 Linux 都继承了这种原始设计。
UNIX 文件本身没有名称,只有inode编号或 inum。但是你只能通过一个特殊的“目录”文件中的一个条目来访问它,该文件将一个名称与相关的 inum 相关联;您不能直接指定 inum。
目录本身就是一个文件,因此您还必须通过(另一个)目录等访问它,通过一系列由正斜杠 (/) 分隔的目录名,称为“路径名”。路径以进程的“当前工作目录”开头,除非名称以“/”开头,在这种情况下,它以文件系统根目录开头。例如,如果路径名不包含“/”字符,那么它应该是当前目录中的一个条目。
非目录文件可以有任意数量的路径名,称为“硬链接”,它会一直存在,直到它的所有路径名都被删除并且最后一个进程关闭了文件。然后该文件被实际删除,其空间被标记为可重用。也就是说,您可以 creat() 或 open() 一个单链接文件,然后 unlink() 它使其不再出现在文件系统名称空间中,但该文件将继续存在,直到您关闭它。这对于不会被任何其他程序读取的临时临时文件很有用。
尽管目录有 inode 编号,但大多数文件系统不允许硬链接到它们;它们只能出现在另一个目录中。(一个不寻常的例外是 Mac OSX HFS+ 文件系统;这可以让 Time Machine 备份工作。)您仍然可以创建到目录(或任何其他文件)的“软链接”。软链接类似于目录条目,不同之处在于它包含另一个路径名而不是 inum。
每个 UNIX 文件都有一个所有者、组和访问权限。他们让您打开文件是必要的,但还不够;您还必须至少对用于引用它的路径名中的每个目录具有执行权限。这就是为什么没有通过 inode 编号打开 UNIX 文件的标准方法。这将绕过一个重要的、广泛使用的安全机制。
但这并不能解释为什么root(特权)用户无法通过 inode 编号打开文件的标准方法,因为无论如何都会绕过权限检查。这对于某些系统管理功能(例如备份)非常有用。据我所知,这样的机制确实存在,但它们都是特定于文件系统的;对于任何 UNIX 文件系统,没有通用的方法可以做到这一点。
该问题可以从理论上(可以通过debugfs)或务实(紧急情况)来解决。在后一种情况下,我认为目的是节省时间并恢复文件的内容,可能是紧急的(这就是我解决这个问题的方式,所以我认为它仍然相关且有用)。
由于没有内核 API,debugfs不应在实时文件系统上运行,因为它直接操作 FS 结构。因此,要实时进行,您必须获得另一个文件名。假设文件仍然被某个进程(任何进程)打开,人们可以在以下位置获取方便的文件描述符/proc:
$ lsof -F pf "$PWD/a" | sed 's/^p//' # find pid and file descriptor number of any process having the file open
$ pid=1234
$ ls -l /proc/$pid/fd/* | grep "$PWD/a" # find file descriptor number
$ fd=42
$ cat /proc/$pid/fd/$fd > "$PWD/a.restored" # read contents to a new filename
Run Code Online (Sandbox Code Playgroud)
提示:
file在其上运行诸如此类的命令tail -f < /proc/$pid/fd/$fd > /dev/null退出写入进程以使其干净地退出,并使用新进程的 fd。