【问题标题】:Why can a directory be removed when my shell is using that directory?为什么当我的 shell 使用该目录时可以删除该目录?
【发布时间】:2020-05-17 10:05:41
【问题描述】:

我不知道我遇到的是错误还是预期的行为,但幸运的是我很快就弄清楚了发生了什么。

我在 git repo 的子目录中对 shell 进行了 cd,并执行了 git rebase -i squash 操作,其中涉及的提交包括创建此目录。

在该操作顺利完成后,shell 处于孤立状态,git status(在 zsh 主题帮助程序 RPROMPT 和运行时都没有)表明我什至不在 git 存储库中。

一旦我运行cd ..,一切都很好,这一切都说得通。在变基操作过程中,Git 拥有rm'd 我所在的目录(在变基的第一步),然后将其放回原处。既然它被放回去了,我也可以跑cd $(pwd)一步去那里。

这是一些令人困惑的行为。虽然,尚不清楚 git 在技术上做错了什么。我的问题是这会是git 中的一个错误,还是应该期望用户知道如何处理这种情况?

另外,更广泛的实际根本问题:为什么允许删除我的 shell 所在的目录,而如果我在已安装的目录上有 shell,则不允许弹出磁盘?这对我来说似乎不一致。

例如:fuser <directory> 显示当前目录使用情况。如果一个程序“在”一个目录,它就是在“使用”它。

【问题讨论】:

  • 我必须假设像this answer 声明,在使用时删除某些东西的能力正是它应该工作的方式,这必然会产生与程序仍然可以访问已删除的内容。 (在这种情况下:shell 保留了已删除目录的句柄,因为操作系统允许 git 删除该目录)

标签: linux shell unix directory


【解决方案1】:

1号航站楼:

$ cd tmp/
$ mkdir test
$ cd test

2号航站楼:

$ rmdir tmp/test 

1号航站楼:

$ ls 
sh: 0: getcwd() failed: No such file or directory

不一致,是的。但允许。

附言。而这与git无关。

【讨论】:

  • 是的。很好地指出,这与 git 本质上没有任何关系;我只是认为有人在使用 git 时会遇到这种情况,我的关键字可能会对他们有所帮助。
  • 不需要第二个终端。 mkdir test; cd test; rmdir ../test; pwd 会做到的。而且我不同意这是不一致的,她的 shell 将 CWD 维护为“状态”而不需要在目录上保留打开的文件句柄是完全合理的。
  • 当有进程cd进入FS时不允许卸载文件系统是不一致的。
【解决方案2】:

回答你的第一个问题:

这不是一个错误,它是 Unix 系统(包括 Linux)一直以来的工作方式。

POSIX spec 中甚至还有一些不错的文字:

[EBUSY]要删除的目录当前正在被系统或某个进程使用,实现认为这是一个错误。

也就是说,某些实现(例如 Windows...)可以将其称为错误,但大多数实现。即 Unix 变体,不要。

在文件系统中实现这一点的方式是让进程持有对代表目录的对象的引用。拥有这种引用的另一件事是父目录。 git rebase 删除了后者的引用,但前者仍然存在。即使重新创建了目录,它也是一个新的文件系统对象,而您的 shell 持有对旧对象的引用。

这就是 cd ..cd $(pwd) 仍然有效的原因 - 它们重新查找目录并获取新引用,然后释放旧引用。

在旧的引用被释放之前,旧的对象不会被清理。这意味着在进程释放旧的工作目录之前,不会从磁盘中删除目录的元数据。

回答你的第二个问题:

为了弹出驱动器,您必须卸载挂载点,如上所述,您使用fuser 找到的进程持有对该挂载点的引用。

与目录引用一样,在删除所有对它的引用之前,无法清除数量点。这就是为什么您无法弹出具有引用的驱动器的原因。

一致的做法是允许从目录树中分离文件系统而无需实际清理。您仍然无法弹出驱动器,但至少您可以随意使用目录树。

嗯,这实际上可以与umount --lazy 做。

【讨论】:

    猜你喜欢
    • 2016-07-15
    • 1970-01-01
    • 2014-03-15
    • 1970-01-01
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-23
    相关资源
    最近更新 更多