如何知道两个硬链接是否指向同一个inode? (C#)

How to know if two hard links point to the same inode? (C#)

有没有在 C# 中检查两个文件(硬链接)是否指向同一个 inode?还要获取这个 inode 的计数,以防超过两个... ?

您可以使用 GetFileInformationByHandle 函数获取指向节点的硬链接数。例如:

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetFileInformationByHandle(
    SafeFileHandle hFile,
    out BY_HANDLE_FILE_INFORMATION lpFileInformation
);

[StructLayout(LayoutKind.Sequential)]
struct BY_HANDLE_FILE_INFORMATION {
    public uint FileAttributes;
    public FILETIME CreationTime;
    public FILETIME LastAccessTime;
    public FILETIME LastWriteTime;
    public uint VolumeSerialNumber;
    public uint FileSizeHigh;
    public uint FileSizeLow;
    public uint NumberOfLinks;
    public uint FileIndexHigh;
    public uint FileIndexLow;
}

// then in another place
using (var fs = File.OpenRead("path to your file")) {                
    BY_HANDLE_FILE_INFORMATION info;
    GetFileInformationByHandle(fs.SafeFileHandle, out info);
    var numberOfLinks = info.NumberOfLinks;
}

要获取它们指向的文件,您将需要另一个 win api 函数:FindFirstFileNameW and FineNextFileNameW。像这样使用它们:

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr FindFirstFileNameW(
       string lpFileName,
       uint dwFlags,
       ref uint stringLength,
       StringBuilder fileName);

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool FindNextFileNameW(
        IntPtr hFindStream,
        ref uint stringLength,
        StringBuilder fileName);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FindClose(IntPtr fFindHandle);

public static string[] GetFileHardLinks(string filePath) {
    // first get drive letter
    var drive = new DriveInfo(Path.GetPathRoot(filePath));
    var result = new List<string>();
    // buffer for return value
    var sb = new StringBuilder(256);
    // length of buffer
    uint sbLength = 256;
    // third argument contains reference to buffer length (buffer is StringBuilder). 
    // it's a reference because if it's too small, call returns an error and will put required length there instead
    IntPtr findHandle = FindFirstFileNameW(filePath, 0, ref sbLength, sb);
    // returns -1 on error
    if (findHandle.ToInt64() != -1) {
        do {
            // combine the result with drive letter (it comes without it)
            result.Add(Path.Combine(drive.RootDirectory.FullName, sb.ToString().TrimStart(new [] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar})));
            sb.Clear();
            sbLength = 256;
            // and repeat
        } while (FindNextFileNameW(findHandle, ref sbLength, sb));
        FindClose(findHandle);
        return result.ToArray();
    }
    return null;
}

此代码可能尚未准备好投入生产,因此请多加小心。但它至少应该给你一个想法。如果您将使用它 - 仔细阅读这些功能 return 错误并采取相应措施(例如,处理缓冲区长度不足的情况,或者只使用大于 256 的缓冲区)。