一尘不染

在Unix中删除后为什么可以访问文件?

linux

我想到了一个并发问题( 在Solaris中 ),如果在读取某人时尝试删除同一文件会发生什么。我有一个关于 Solaris / Linux中
文件存在的查询。假设我有一个文件test.txt,已经在vi编辑器中将其 打开 ,然后打开了一个重复的会话并 删除了
该文件,但是即使删除了该文件,我仍然可以读取该文件。所以这是我的问题:

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

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

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

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


阅读 312

收藏
2020-06-07

共1个答案

一尘不染

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

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

E211: File "filename" no longer available

此警告不仅针对Unix。如果您删除正在编辑的文件,Windows上的gvim会为您提供。它提醒您,如果您不想丢失文件,则需要在退出之前保存正在处理的版本。

(注意:警告不会立即出现-vim仅在离开原始文件后将其放回前台时才检查原始文件的存在。)

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

问题2,为什么某些Windows编辑器会保持文件打开和锁定状态?我不知道,Windows人士对此感到很困惑。

问题3,实际上是关于unix的问题,为什么打开的文件在删除后仍可访问-这是最有趣的一个。答案,当直接出现时一定会让您震惊:

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

rm系统调用包括底层和删除文件的任何其他命令unlink。它被称为unlink,不是removedeletefile或类似名称,因为它不会删除文件。它删除一个
链接 (又名目录条目),该 链接 是文件和目录中名称之间的关联。(注: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用于此的工具。)

2020-06-07