【问题标题】:Is it possible to temporarily hide a file from any system call in linux?是否可以暂时隐藏 linux 中任何系统调用的文件?
【发布时间】:2021-05-07 15:35:00
【问题描述】:

我正在尝试使用 FUSE 实现文件系统,并且我希望文件在被删除时暂时隐藏。我试图将所有文件的名称或其 inode 存储在一个数组中,并在调用诸如 'open' 、 'getattr' 或 'readdir' 之类的系统调用时检查它们。但是当这个数字变得非常巨大时,它可能会消耗大量的性能。所以我想知道有没有更好的方法来做到这一点?提前致谢!

【问题讨论】:

  • 所以你的问题是“我如何存储和快速搜索一大堆数字”?二叉搜索树或哈希表。在阅读 BST(AVL 树?)之后,您可能可以实现它,对于哈希表,我建议您四处寻找可以为您做到这一点的库。
  • 如果你真的自己实现FS,你可以也许自己实现吗? [这需要额外的 API 调用]
  • 如果你从目录中取消链接一个文件,但它仍然打开,那么它的空间没有被释放,打开调用将找不到它。另一种解决方案可能是将其保留在目录中,但从目录中删除所有权限。
  • 感谢大家的帮助!似乎 'setxattr' 可以完成这项工作

标签: c linux filesystems fuse


【解决方案1】:

如果我理解,当调用 unlink 时,您希望将文件标记为已删除,而不是实际删除。 您可以将此标记实现为扩展属性,具有“系统”命名空间(请参阅https://man7.org/linux/man-pages/man7/xattr.7.html),它未列为文件 xattr 列表的一部分。 在您的“取消链接”中,执行 setxattr(system.markdelete)。在您使用路径 arg 的所有其他调用中,以及在 readdir 中,getxattr 并将其视为已删除。

【讨论】:

  • 谢谢!这正是我一直在寻找的!
【解决方案2】:

您的方法存在两个问题(以及 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) 等相同)

【讨论】:

  • 谢谢。我想到的另一个简单的不一致案例。如果删除后用户创建了一个同名的新文件会怎样?数据存储在哪里?这在您的垃圾文件夹解决方案中得到了解决
  • 通常情况下,如果在删除同名文件后创建一个新文件,它可能会得到一个不同的inode(每个文件只有一个inode)或相同,具体取决于可用的数量索引节点。这个新文件与旧文件无关,它是一个完全不同的文件。删除文件时,inode 被锁定,因此只有一个进程可以对其进行操作。而文件删除可能是系统中成本最高的操作。
  • 就可用性而言(如您的问题所述),不乏可用性,因为即使在旧已删除文件中块的实际释放完成之前,该名称也可以重用。
  • 如果我得到了这个问题的正确情况,后端文件系统是由路径管理的,所以“这个新文件与旧文件无关”的说法不适用 - 在用户调用同名的 open(create)(来自用户 POV 的新),熔断器后端必须在仍未链接的后端路径上调用 open(create)。
  • @OrenKishon,后端文件系统由 inode 管理。所有文件系统都由 inode 管理(一些系统称它们为 vnode),并且名称不属于文件的要求对于提供指向单个文件的多个链接至关重要。您不能open/create 没有路径的文件,并且我在回答中提到的隐藏文件没有路径,因此您无法打开它们。您提出的标记已经在文件系统中,它是 inode 的 st_nref 字段,您可以持有它的方式是实际上有第二个指向私有位置的链接...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-07
  • 1970-01-01
相关资源
最近更新 更多