【问题标题】:Why file is accessible after deleting in unix?为什么在unix中删除后可以访问文件?
【发布时间】:2014-04-10 09:10:33
【问题描述】:

我想到了一个并发问题(在 Solaris 中),如果在读取某人试图删除同一个文件时会发生什么。我对 Solaris/Linux 中的文件存在有疑问。假设我有一个文件 test.txt,我在 vi 编辑器中 打开 它,然后我打开了一个重复的会话并 删除 该文件,但即使在删除该文件之后我能够读取该文件。所以这是我的问题:

  • 我是否需要在阅读时考虑任何锁定机制,所以没有人能够在阅读时删除同一个文件。

  • 显示与 windows 不同的行为的原因是什么(例如在 windows 中,如果文件在某些​​编辑器中打开,我们无法删除该文件)

  • 删除该文件后,如果我没有从 vi 编辑器关闭文件,我如何仍然能够读取该文件。

我问的是一般文件,但是是特定于平台的,即 unix。如果我使用java程序(缓冲区读取器)读取文件并且文件在读取时被删除,会发生什么,缓冲区读取器是否仍然能够读取下一个块的文件?

【问题讨论】:

  • 由于 Unix 早于 Windows,我认为更好的问题是“为什么 Windows 工程师未能实现这种行为?”因为 Unix 的行为要好得多...
  • 当你打开一个文件进行读取时(比如vi),它的内容在内存中。同时它可以被删除,所以每当你退出vi它就会从你的视线中消失。但是如果从vi 内部保存:w,那么它将被重新创建。
  • 您是专门询问vi,还是一般询问文件?至少 linux 上的 vim 在您编辑时不会保持原始文件处于打开状态。
  • 我问的是一般文件,但是是特定于平台的。就像我使用 java 程序(缓冲区读取器)读取文件并且文件在读取时被删除,缓冲区读取器是否仍然能够读取下一个块的文件?

标签: linux file unix filesystems


【解决方案1】:

那里基本上有 2 或 3 个不相关的问题。文本编辑器喜欢在编辑会话开始时将整个文件读入内存。想象一下,您键入的每个字符都会立即保存到磁盘,文件中的所有字符都将被重写到更远的位置以腾出空间。那将是可怕的。更好的是,您实际编辑的是文件的内存表示(指向行的指针数组,可能附加了一些元数据),只有在您明确保存时才会转换回线性流。

如果您正在编辑的文件从其原始位置删除,任何相对较新的 vim 版本都会通知您并显示消息

E211: File "filename" no longer available

此警告不仅适用于 unix。如果您删除正在编辑的文件,Windows 上的 gvim 会将其提供给您。如果您不希望文件消失,它会提醒您在退出之前需要保存正在处理的版本。

(注意:警告不会立即出现 - vim 仅在您从原始文件切换到前台后才检查原始文件是否存在。)

这就是问题 1,文本编辑器的行为 - 他们没有理由在整个会话期间保持文件打开,因为除了在启动和保存操作期间,他们实际上并没有使用它。

问题 2,为什么有些 Windows 编辑器保持文件打开和锁定 - 我不知道,Windows 人是疯子。

问题 3,实际上是关于 unix 的问题,为什么打开的文件在被删除后仍然可以访问 - 这是最有趣的问题。答案,直接呈现肯定会让你大吃一惊:

没有实际请求删除文件的命令、函数、系统调用或任何其他方法。

rm 和任何其他可能会删除文件的命令是系统调用 unlink。它被称为unlink,而不是removedeletefile 或类似名称,因为它不会删除文件。它删除了一个 link (也称为目录条目),它是文件和目录中名称之间的关联。 (注意:ANSI C 添加了remove 作为一个更通用的函数来安抚那些无意实现unix 文件系统语义的非unix 人,但在unix 上,remove 只是一个rmdir,如果目标是一个目录,和unlink 其他所有内容。)

一个文件可以有多个链接(参见ln 命令了解它们的创建方式),这意味着同一个文件有多个名称。如果您rm 其中一个,其他人会留下来,并且不会删除该文件。当您删除最后一个链接时会发生什么?好吧,现在你有一个没有名字的文件。但是名称只是对文件的一种引用。至少还有另外两个:文件描述符和 mmap 区域。当文件的最后一个引用消失时,文件就被删除了。

由于引用有多种形式,因此有多种事件会导致文件被删除。以下是一些示例:

  • 取消链接(rm 等)
  • 关闭文件描述符
    • dup2(可以在将文件描述符替换为不同文件描述符的副本之前隐式关闭它)
    • exec(可以通过 close-on-exec 标志关闭文件描述符)
  • munmap(取消映射内存区域)
    • mmap(如果您在已映射的地址上创建新的内存映射,则旧映射将被取消映射)
  • 进程死亡(关闭所有文件描述符并取消映射进程的所有内存映射)
    • 正常退出
    • 内核产生的致命信号 (^C, segfault)
    • 另一个进程发送的致命信号(杀死)

我不会称其为完整列表。而且我不鼓励任何人尝试建立一个完整的列表。只要知道rm 是“删除名称”,而不是“删除文件”,文件一旦不使用就会消失。

如果您想立即销毁文件的内容,请将其截断。所有已经在使用它的进程都会发现它的大小突然变成了0。(就正常的文件访问方法而言,这是破坏。更彻底地破坏它,以至于即使有原始磁盘访问权限的人也无法读取过去的内容。在那里,你需要覆盖它。有一个名为 shred 的工具。)

【讨论】:

    【解决方案2】:

    我认为您的问题与 Windows/Linux 之间的区别无关。这是关于 VI 的工作原理。

    使用 VI 编辑文件时。 VI 将创建一个 .swp 文件。 .swp 文件是您实际编辑的文件。同时,如果其他用户删除了原始文件,也不会影响您的编辑。 而当你在VI中输入:w时,VI会使用.swp文件覆盖原来的文件。

    【讨论】:

    • 我不使用 VI,这就是我不回答这个问题的原因,但我怀疑答案要简单得多。只要文件有一个打开的句柄,您就可以从驱动器中删除它,但它仍然存在,直到所有句柄都被销毁。
    • @krowe 虽然这在 unix 上通常是正确的,但 vim 在编辑文件时不会保持文件句柄打开。
    • 是否仅在 vi 编辑器的情况下创建 .swp 文件?阅读时删除一般会发生什么?
    • @Sanjay:在阅读时?这取决于操作系统和/或文件系统。尽管可以,但 Windows 通常 (*) 拒绝弄乱打开的文件。另一方面,Linux 更好地分离文件和文件名;大多数 FS 都有一个 inode 表(文件列表)和一个目录(文件名树),文件名只是文件的硬链接。 Linux 将尝试(*)忘记文件名,但会推迟忘记文件,直到没有硬链接打开它的句柄。 ((*)文件系统、权限、打开模式标志等可能会影响并改变操作系统的行为。)
    • @krowe 另请注意,此行为在某种程度上取决于文件系统 - 有些文件系统不支持“文件已删除但未净释放”语义。虽然,正如 nos 指出的那样,大多数 Unix/Linux 文件系统都可以使用这个......
    猜你喜欢
    • 2013-04-12
    • 2021-09-01
    • 2013-08-30
    • 2013-07-19
    • 1970-01-01
    • 2022-10-16
    • 2015-12-13
    • 2018-04-01
    相关资源
    最近更新 更多