//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());
        }
Beispiel #2
0
    /// <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);
    }