//FsctlNssControl //FsctlNssRcontrol //FsctlOpBatchAckClosePending //FsctlOplockBreakAckNo2 //FsctlOplockBreakAcknowledge //FsctlOplockBreakNotify /// <summary><see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa364582(v=vs.85).aspx"/></summary> public FILE_ALLOCATED_RANGE_BUFFER[] FileSystemQueryAllocatedRanges(long offset, long length) { FILE_ALLOCATED_RANGE_BUFFER input = new FILE_ALLOCATED_RANGE_BUFFER(); input.FileOffset = offset; input.Length = offset + length; byte[] res = DeviceIoControlHelper.InvokeIoControlUnknownSize(Handle, IOControlCode.FsctlQueryAllocatedRanges, input, 512); int singleSize = (int)MarshalHelper.SizeOf <FILE_ALLOCATED_RANGE_BUFFER>(); List <FILE_ALLOCATED_RANGE_BUFFER> ranges = new List <FILE_ALLOCATED_RANGE_BUFFER>(); for (int i = 0; i < res.Length; i += singleSize) { FILE_ALLOCATED_RANGE_BUFFER single = new FILE_ALLOCATED_RANGE_BUFFER(); single.FileOffset = BitConverter.ToInt64(res, i); single.Length = BitConverter.ToInt64(res, i + 8); ranges.Add(single); } return(ranges.ToArray()); }
/// <summary> /// Query the sparse file layout. /// </summary> /// <param name="fileName">File name</param> /// <returns></returns> public static bool GetSparseRanges(string fileName) { // Open the file for read using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { // Set the range to be examined (the whole file) FILE_ALLOCATED_RANGE_BUFFER queryRange; queryRange.FileOffset = 0; queryRange.Length = fs.Length; GCHandle hQueryRange = GCHandle.Alloc(queryRange, GCHandleType.Pinned); // Allocated areas info // DeviceIoControl will return as many results as fit into this // buffer and will report error code ERROR_MORE_DATA as long as // more data is available FILE_ALLOCATED_RANGE_BUFFER[] allocRanges = new FILE_ALLOCATED_RANGE_BUFFER[1024]; GCHandle hAllocRanges = GCHandle.Alloc(allocRanges, GCHandleType.Pinned); int nbytes = 0; bool bFinished = false; Console.WriteLine("\nAllocated ranges in the file:"); do { NativeOverlapped lpOverlapped = new NativeOverlapped(); bFinished = NativeMethod.DeviceIoControl(fs.SafeFileHandle, EIoControlCode.FsctlQueryAllocatedRanges, hQueryRange.AddrOfPinnedObject(), Marshal.SizeOf(queryRange), hAllocRanges.AddrOfPinnedObject(), Marshal.SizeOf(typeof(FILE_ALLOCATED_RANGE_BUFFER)) * 1024, ref nbytes, ref lpOverlapped); if (!bFinished) { int error = Marshal.GetLastWin32Error(); // ERROR_MORE_DATA is the only error that is normal if (error != NativeMethod.ERROR_MORE_DATA) { Console.WriteLine("DeviceIoControl failed w/err 0x{0:X}", error); return(false); } } // Calculate the number of records returned int allocRangeCount = nbytes / Marshal.SizeOf(typeof(FILE_ALLOCATED_RANGE_BUFFER)); // Print each allocated range for (int i = 0; i < allocRangeCount; i++) { Console.WriteLine("allocated range: {0} {1}", allocRanges[i].FileOffset, allocRanges[i].Length); } // Set starting address and size for the next query if (!bFinished && allocRangeCount > 0) { queryRange.FileOffset = allocRanges[allocRangeCount - 1].FileOffset + allocRanges[allocRangeCount - 1].Length; queryRange.Length = fs.Length - queryRange.FileOffset; } } while (!bFinished); // Release the pinned GC handles hAllocRanges.Free(); hQueryRange.Free(); } return(true); }