I'm doing a little project right now that requires me to know (among other things) the number of hardlinks for a given file. I have a tool that already will tell me the number of hard links for a given file, but I need to collect a bunch more information, and I really hate calling out to an exe and collecting and parsing its output, as part of a larger app. So, I set out to write that slightly larger app.
Having never written an app that cares about hardlinks, I didn't know whether or not the BCL had APIs that exposed this info. It doesn't. Whether it should expose this info is a whole other question. So, I resorted to p/invoke, which is fine. I did a few searches and found that there isn't too much info out there on doing this from .NET, hence my motivation for writing this post.
I started out with NtQueryInformationFile. I'm pretty sure that the p/invoke signature on p/invoke.net is wrong. I wasn't able to get this function working to my satisfaction, but can share where I ended up, in the hope that it might help someone:
[DllImport("ntdll.dll", SetLastError=true)] static extern Int32 NtQueryInformationFile(IntPtr fileHandle, ref IO_STATUS_BLOCK IoStatusBlock, [MarshalAs(UnmanagedType.LPArray)] Byte[] arrayBuffer, uint length, FILE_INFORMATION_CLASS fileInformation);
FWIW, I allocated a byte[2048], and passed in (uint)array.Length as the length paramter. 2k was overkill for what I needed, but at least got me a bunch of bytes. I wasn't too sure what to do next, so decided to look for something easier. I was guessing that I needed to write a struct who fields mapped over that byte[], but I wasn't sure what the meaning of those fields was going to be. I couldn't find any docs that would have that easier, and didn't see any code samples either.
The good news is that I found another function -- GetFileInformationByHandle -- that is much easier to use, and that did work for me.
[DllImport("kernel32.dll", SetLastError = true)] static extern bool GetFileInformationByHandle(IntPtr hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
You can see my app below. For now, it just contains calculates the hard-links, which is the part that I tackled first. I'll now move to writing the rest of my experiment.
using System; using System.Runtime.InteropServices; using System.IO; namespace banff { class Program { static void Main(string[] args) { if (args == null || args.Length == 0) { Console.WriteLine("Please specify a file to check"); return; } else if (!File.Exists(args[0])) { Console.WriteLine("File doesn't exist"); } FileStream fs = null; fs = new FileStream(args[0],FileMode.Open,FileAccess.Read); BY_HANDLE_FILE_INFORMATION fileInfo; Boolean result = GetFileInformationByHandle(fs.Handle, out fileInfo); Console.WriteLine(fileInfo.NumberOfLinks); fs.Close(); } [DllImport("kernel32.dll", SetLastError = true)] static extern bool GetFileInformationByHandle(IntPtr hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation); 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; } } }
Powered by: newtelligence dasBlog 2.3.9074.18820
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.
© Copyright 2010, Rich Lander
E-mail