您的方法存在两个问题(以及 Oren Kishon 指出的解决方案,并标记为已选中):
- 首先是文件没有名称本身。文件名不是文件的一部分。文件名到文件(实际上是到 inode)的映射是由系统为用户的商品而创建的,但名称完全独立于它们指向的文件。这意味着您很容易知道链接指向哪个inode,但是很难进行反向映射(获取指向inode的目录条目,只需知道inode)删除文件是两个相过程。在第一阶段,你调用
unlink(2)系统调用从它所属的目录中删除一个链接(删除一个目录条目),然后释放与该文件有关的所有块,但仅限于引用计数(存储在 inode 本身中)降至零。 这是一个简单的过程,因为一切都从您要删除的目录条目开始。但是,如果您不删除它,那么稍后再搜索它会很痛苦,如下面的第二个问题所示。
- 其次,如果你这样做,比如说,六个链接(硬链接)指向同一个文件,你永远不会知道什么时候需要将空间重新分配给另一个文件(因为你用完了未分配的空间),因为在 inode 上的链接引用计数仍然是 6。更糟糕的是,如果您在 inode 中添加第二个 ref 计数以跟踪尚未分配的真正已擦除文件的(不同)数量,那么问题是您必须搜索整个文件系统。(因为您不知道关于链接应该在哪里)因此您需要维护大量信息(以添加文件在文件系统中占用的空间)首先收集所有指向该文件的链接,然后检查这是否确实必须释放的文件,以防文件系统中需要更多空间。
顺便说一句,不过,您的问题在用户空间中有一个简单的解决方案。只需修改rm 命令,使其永远不会完全擦除文件(例如,永远不会取消链接到文件的最后一个链接),而是将文件移动到文件所在的同一文件系统中某个固定目录中的队列中,以处理最后一个指向它的链接,这将保留仍然分配的文件(但是您会丢失任何引用,或者您可以将其保存在关联文件中,以文件名)。监控进程可以检查可用空间量并从队列中选择第一个(已擦除最旧的),并真正擦除它。请注意,如果您擦除了大文件,这将使您的系统负载在实际擦除您正在释放的文件时随机增长。
还有另一种选择。使用 zfs 作为您的文件系统。这需要大量的内存和cpu,但是对于取消删除文件是一个完整的解决方案,因为zfs保存了文件系统的完整历史,所以你可以及时回到文件存在的快照,然后制作一个它的副本,实际上恢复它。 ZFS 可用于 WORM(一次写入多次读取,作为 DVD)媒体,这使您可以随着时间的推移保存文件系统状态(以不再重复使用相同数据为代价),但您永远不会丢失文件。
编辑
在一种情况下,文件不再可用于打开它的进程之外的任何其他进程。在这种情况下,一个进程打开一个文件,然后将其删除(删除只涉及断开允许将文件名转换为系统中的 inode 的链接)但继续使用该文件,直到它最终关闭。
您可能知道,一个文件可以同时被多个文件打开。除了磁盘 inode 中的引用数量外,内核内存中的 inode 表中还有许多对 inode 的引用。这是磁盘 inode 中文件的引用数(指向文件 inode 的目录条目数)加上每个文件条目的引用,表明文件已打开。
当一个文件被取消链接时(它应该被删除,因为没有更多指向 inode 的链接正在引用它)释放不会立即进行,因为该文件仍在被进程使用。该文件是活动的,尽管它没有出现在文件系统中(在任何目录中都不再引用它)只有当文件的最后一个close(2) 发生时,该文件才会在系统中被释放。
但是引用该文件的目录条目发生了什么。它可以立即被重用(正如我在其中一个 cmets 中告诉你的)它被释放,早在文件被释放之前。将创建一个新文件(它将强制成为不同的 inode,因为旧的 inode 仍在使用中)并将其命名为原始文件(因为您决定将其命名为相同),这没有问题,但是您正在使用不同的文件。旧文件仍在使用中,并且没有名称,因此除了使用它的进程之外,其他进程不可见。这种技术经常用于使用临时文件,您可以在其中使用open(2) 创建一个文件,然后立即使用unlink(2) 它。没有其他进程可以访问该文件,并且只要文件条目为close(2)d,该文件就会被释放。但是,一旦调用了它上的最后一个close(2),这样的文件就会被释放。没有这种特征的文件可以在系统重新启动后继续存在。 (它甚至无法在打开它的过程中存活)
正如问题所述:
是否可以在 linux 中对任何系统调用临时隐藏文件?
该文件对所有需要文件名的系统调用隐藏(它不再有名称)但对其他系统调用不隐藏(例如fstat(2)继续工作,而stat(2)将无法使用在该文件上,与link(2)、rename(2)、open(2) 等相同)