如何确定两个文件是否硬链接到相同的数据?

How to determine if two file are hard-linked to the same data?

我已经为 System.IO.FileInfo class 编写了一个扩展方法来创建硬 link,它是这样的:

[DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);

public static void CreateHardLink(this FileInfo file, string destination) {
    CreateHardLink(destination, file.FullName, IntPtr.Zero);
}

// Usage:
fileInfo.CreateHardLink(@".\hardLinkCopy.txt");

该方法工作正常,但我想为此做一些单元测试。那么我如何断言文件 x 和另一个文件 y linked 到相同的数据?

我想出了一些方法来测试它:

但是,这些方法有味道。 OS 中的某处必须至少有一种内置方法来检查两个文件是否指向磁盘上的相同数据!

有人可以分享线索吗?

按照 Bennett Yeo 的建议,我发现了以下内容:

没有直接的方法来检查两个文件是否链接到相同的数据,但我们可以通过比较文件的唯一 ID(或基于 UNIX 的系统中的 inode)来创建我们自己的方法。据我了解,此值用作磁盘上实际内容的索引。

Bennett 还链接了 This thread,这给了我两种获取文件唯一 ID 的方法:

  1. 链接的答案建议从 kernel32.dll 调用 GetFileInformationByHandle。正如该方法的名称所暗示的那样,我必须首先获取文件的句柄,但每当我尝试获取一个句柄时,都会抛出一个异常,指出目标文件已被另一个进程使用。
  2. 最后,使用命令 fsutil file queryfileid <filename> (Credit to this answer).

第二种方法对我有用,所以我写了下面的代码:

private static string InvokeShellAndGetOutput(string fileName, string arguments) {
    Process p = new Process();
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.FileName = fileName;
    p.StartInfo.Arguments = arguments;
    p.Start();
    string output = p.StandardOutput.ReadToEnd();
    p.WaitForExit();
    return output;
}

public static long GetFileId(this FileInfo fileInfo) {
    // Call "fsutil" to get the unique file id
    string output = InvokeShellAndGetOutput("fsutil", $"file queryfileid {fileInfo.FullName}");

    // Remove the following characters: "File ID is " and the EOL at the end. The remaining string is an hex string with the "0x" prefix.
    string parsedOutput = output.Remove(0, 11).Trim();
    return Convert.ToInt64(parsedOutput, 16); ;
}

public static bool IsHardlinkedToSameData(this FileInfo fileInfo, FileInfo otherFileInfo) {
    return fileInfo.GetFileId() == otherFileInfo.GetFileId();
}

它是零散的,但我觉得它已经比我以前的想法更可靠了。只要主机 运行 测试安装了 "fsutil",它就应该可以工作。

仍然欢迎任何更可靠的解决方案。