Reputation: 7570
Anyway of checking, in C#, that two files (hard links) point to the same inode? And also get the count of this inode, in case there are more than two... ?
Upvotes: 4
Views: 387
Reputation: 101533
You can get count of hard links pointing to the node using GetFileInformationByHandle function. For example:
[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;
}
To get what files they are pointing to, you will need another win api functions: FindFirstFileNameW and FineNextFileNameW. Use them like this:
[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;
}
This code might be not production ready, so take care. But it should at least give you an idea. If you will use it - carefully read what those function return on errors and act accordingly (for example, handle the case when buffer length is not enough, or just use larger buffer than 256).
Upvotes: 3