具有相同根目录的两个子目录是否保证位于同一安装的文件系统上?

具有相同根目录的两个子目录是否保证位于同一安装的文件系统上?

cpp我正在使用的文件创建一个目录,即,mkdir( path, ... )其中路径来自环境变量(例如getenv( "FOO" );)。

例如,上面创建的$FOOis/foopath是 `/foo/newPath/'。

对于我的问题场景,可能/foo/oldPath/存在并具有内容(假设没有其他子目录),在这种情况下,我想将文件从 移动/foo/oldPath//foo/newPath.

我的问题是:因为 是/foo/newPath/作为 ie 的子目录创建的$FOO/foo/newPath/并且/foo/oldPath/具有相同的父目录,那么是否可以保证两个目录位于同一“已安装的文件系统”上?我对 Linux 上的挂载点和文件系统的理解充其量是微不足道的。

这个问题背后的上下文是:如果/foo/newPath//foo/oldPath/保证位于同一个安装的文件系统上,我可以使用rename()比其他替代方案更轻松地执行文件移动。该函数的手册页指出,如果oldPathnewPath不在同一个“已安装的文件系统”上,它将失败。

答案1

他们不能保证这一点。这可能/foo/oldPath是一个挂载点。

mount | grep 'on /foo/oldPath' 不过,可以通过运行“无输出应表明该oldPath目录不是挂载点”来轻松检查这一点。

如果您使用嵌套目录,则需要更加小心,因为您可以在任何地方拥有挂载点。

我不确定这是否是自动的,但值得注意的是,安装中的第三个字段(以空格分隔)是每行的安装点,因此 cut -d ' ' -f 3可以使用 an 来提取路径(如果您需要验证它是不仅仅是另一个挂载点的子字符串,例如/foo/oldPath/nested/mountPoint

如果您想将其转换为 C/C++ 代码,您也许可以使用system("mount | grep 'on /foo/oldPath'"),但我不会对此发誓。如果您需要的话,您可能会在 StackOverflow 上获得更多实现细节。

答案2

您不应该尝试这样做,原因有多种(其他答案中有详细说明):/foo/oldPath本身可能是一个挂载点,或者可能存在覆盖文件系统并阻止移动文件。您甚至可能会遇到单个文件上的绑定挂载,这在重命名文件时也会导致问题。

您不应尝试提前确定文件是否可以重命名,而应尝试重命名它们并处理错误。rename如果发生错误,将返回 -1;如果由于交叉安装问题而无法重命名,errno则将设置为。EXDEV然后您可以以另一种方式继续(复制和删除)。

一般来说,要确定两个文件系统对象是否位于同一文件系统上,您应该运行stat在它们上并查看设备标识符(st_dev中的字段struct stat)。同一文件系统上的两个文件系统对象将具有相同的设备标识符。

答案3

请注意,当您在overlayfs上运行时,您不能依赖rename()预先存在的目录。

我认为如果您不编写通用文件管理工具,您通常可以忽略这种可能性......例如,包管理器...在这种情况下,您显然可能不认为它是可修复的(出于原子性原因)并希望依赖redirect_diroverlayfs的新格式。

所以这更像是一个迂腐的说明,让你知道这是 Linux,如果我们不愿意,我们就不会遵守 POSIX,而且“保证”是一个非常强烈的词:)。


https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt

除非启用“redirect_dir”功能,否则在较低目录或合并目录上重命名(2) 将因 EXDEV 失败。

Overlayfs 在其他细节上已经不符合 unix 文件系统的通常期望:

非目录的对象(文件、符号链接、设备专用文件等)根据需要从上层或下层文件系统中呈现。当以需要写访问的方式访问下层文件系统中的文件时,例如打开写访问、更改某些元数据等,该文件首先从下层文件系统复制到上层文件系统(copy_up)...

copy_up 操作本质上是创建一个新的、相同的文件并将其移至旧名称。 任何引用此索引节点的打开文件都将访问旧数据。

相关内容