在Linux/C中如何确定两个文件路径是否指向同一个文件?

8

在Linux系统中,我有两个文件路径A和B:

const char* A = ...;
const char* B = ...;

我现在想确定,是否我应该 open(2) 它们两个...
int fda = open(A, ...);
int fdb = open(B, ...);

如果我在文件系统中打开同一个文件,会得到两个文件句柄吗?

为了确定这一点,我想到了使用stat(2)

struct stat
{
    dev_t st_dev;
    ino_t st_ino;
    ...
}

类似以下伪代码:

bool IsSameFile(const char* sA, const char* sB)
{
    stat A = stat(sA);
    stat B = stat(sB);

    return A.st_dev == B.st_dev && A.st_ino == B.st_ino;
}

是否存在这样的情况,A和B是同一个文件,但IsSameFile返回false?

是否存在这样的情况,A和B是不同的文件,但IsSameFile返回true?

有没有更好的方法来完成我想做的事情?


你可以拥有多个文件描述符指向同一个文件。 - teppic
@teppic:是的,你也可以有多个文件描述符指向不同的文件。我的问题是如何确定我处于哪个宇宙中(或将要处于哪个宇宙中)。 - Andrew Tomazos
如果您有文件描述符打开,可以直接在它们上面使用 fstat - 如果i节点和设备号相等,则这两个路径不可能引用不同的文件。 - teppic
2个回答

4
您的程序可以在所有情况下正常工作,因为A.st_ino会返回系统中文件的inode编号。由于inode编号是唯一的,因此您的程序将正确地识别打开的两个文件是否相同。
您还可以检查A.st_mode的值,以确定该文件是否为符号链接

3
只有当名称为破损软链接时,通过stat()才能发现它是破损的软链接。 如果它不是破损的话,stat()会报告链接末端的文件或设备;如果名称是符号链接,则lstat()会报告第一个符号链接。 - Jonathan Leffler

0

这取决于你为什么要避免两次打开同一个文件。通常你的解决方案是正确的,但有些情况下,如果两个文件具有相同的绝对路径但不是相同的 inode 链接,则应将它们视为相同的文件。在这种情况下,您需要将路径转换为绝对路径并进行比较...请参见Getting absolute path of a file

您还需要决定是否将指向文件的符号链接视为等效于该文件或另一个指向它的符号链接。对于 inode 等价性,这决定了是否使用 statlstat。对于路径等价性,它决定了是否可以使用 realpath 或者需要获取不跟随符号链接的绝对路径。


2
使用stat(),代码将无法察觉符号链接(除非它们损坏)。您能详细说明“某些情况下,如果文件具有相同的绝对路径但不是指向相同inode的链接,则应将它们视为相同的文件”吗? - Jonathan Leffler
@JonathanLeffler “使用stat(),代码将不会注意到符号链接” - 但是不使用lstat - 这正是我所做的区别。具体来说:一些备份方案要求每个路径都复制一次文件(特别是如果恢复将在不支持硬链接的文件系统上进行),而保存相同路径两次是没有意义的。它们可能有其他用例。但正如我所说,inode等价通常是想要的。 - Jim Balter
@JonathanLeffler 实际上是 lstat 对符号链接不知情,而 stat 对它们执行有效的 readlink 并跟随它们。事实上,在有符号链接之前,lstat 的实现就是 stat 的实现(天哪,我当时正在编写 UNIX 内核代码)。 - Jim Balter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接