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

时间:2016-11-13 14:18:49

标签: c# ntfs inode hardlink

无论如何在C#中检查两个文件(硬链接)是否指向同一个inode?并且还得到这个inode的数量,如果有两个以上......?

1 个答案:

答案 0 :(得分:2)

您可以使用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函数:FindFirstFileNameWFineNextFileNameW。像这样使用它们:

[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;
}

此代码可能未准备好生产,因此请注意。但它至少应该给你一个想法。如果您将使用它 - 仔细阅读这些函数返回错误并采取相应措施(例如,处理缓冲区长度不够时的情况,或者使用大于256的缓冲区)。