Skip to content

Instantly share code, notes, and snippets.

@mjs3339
Created September 4, 2018 21:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjs3339/414872bf3a61c7fdbe823a13066b7fdd to your computer and use it in GitHub Desktop.
Save mjs3339/414872bf3a61c7fdbe823a13066b7fdd to your computer and use it in GitHub Desktop.
C# FileFragments Class Get a Files Physical Fragment Information
public class FileFragments
{
private const int FSCTL_GET_RETRIEVAL_POINTERS = 0x00090073;
private const uint FileAccess_GenericRead = 0x80000000;
private const uint FileAccess_GenericWrite = 0x40000000;
private const uint FileShare_Read = 0x00000001;
private const uint FileShare_Write = 0x00000002;
private const uint FileShare_ReadWrite = FileShare_Read | FileShare_Write;
private const uint FileMode_OpenExisting = 0x00000003;
private const uint FileAttributes_Normal = 0x00000080;
private const int ERROR_HANDLE_EOF = 0x00000026;
private const int ERROR_MORE_DATA = 0x000000EA;
private const int NO_ERROR = 0x00000000;
private static readonly int BytesReturned = 0x00000000;
private static long SectorsPerCluster;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern SafeFileHandle CreateFile(
string lpFileName,
[MarshalAs(UnmanagedType.U4)] uint dwDesiredAccess,
[MarshalAs(UnmanagedType.U4)] uint dwShareMode,
IntPtr lpSecurityAttributes,
[MarshalAs(UnmanagedType.U4)] uint dwCreationDisposition,
[MarshalAs(UnmanagedType.U4)] uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
private static SafeFileHandle GetSafeHandle(string path)
{
return CreateFile(path, FileAccess_GenericRead, FileShare_ReadWrite, IntPtr.Zero,
FileMode_OpenExisting, FileAttributes_Normal, IntPtr.Zero);
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeviceIoControl(
SafeFileHandle hFile,
uint ioctl,
ref StartingVcnInputBuffer invalue,
int InSize,
out RetrievalPointersBuffer outvalue,
int OutSize,
int BytesReturned,
IntPtr zerovalue
);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool GetDiskFreeSpace(
string lpRootPathName,
out long lpSectorsPerCluster,
out long lpBytesPerSector,
out long lpNumberOfFreeClusters,
out long lpTotalNumberOfClusters);
[SecurityCritical]
public static long GetSectorsPerCluster(string FilePath)
{
var info = new FileInfo(FilePath);
long dummy, sectorsPerCluster, bytesPerSector;
var result = GetDiskFreeSpace(info.Directory.Root.FullName, out sectorsPerCluster, out bytesPerSector, out dummy, out dummy);
return sectorsPerCluster;
}
[SecurityCritical]
public static long GetBytesPerCluster(string FilePath)
{
var info = new FileInfo(FilePath);
long dummy, sectorsPerCluster, bytesPerSector;
var result = GetDiskFreeSpace(info.Directory.Root.FullName, out sectorsPerCluster, out bytesPerSector, out dummy, out dummy);
return sectorsPerCluster * bytesPerSector;
}
[SecurityCritical]
public static long GetBytesPerSector(string FilePath)
{
var info = new FileInfo(FilePath);
long dummy, sectorsPerCluster, bytesPerSector;
var result = GetDiskFreeSpace(info.Directory.Root.FullName, out sectorsPerCluster, out bytesPerSector, out dummy, out dummy);
return bytesPerSector;
}
public static FileFragment GetFileAllocation(string path)
{
var VcnBuffer = new StartingVcnInputBuffer();
var rpBuffer = new RetrievalPointersBuffer();
var ThisFilePointer = new FileFragment();
var FileFragment = new PhysicalFileFragment();
var BytePerSector = GetBytesPerSector(path);
var MoreDataAvailable = false;
var extentNumber = 1;
SectorsPerCluster = GetSectorsPerCluster(path);
VcnBuffer.StartingVcn = 0L;
ThisFilePointer.TotalClusters = 0;
ThisFilePointer.TotalSectors = 0;
ThisFilePointer.FileAllocation = new List<PhysicalFileFragment>();
var errorLevel =0;
using(var handle = GetSafeHandle(path))
{
do
{
DeviceIoControl(
handle, FSCTL_GET_RETRIEVAL_POINTERS,
ref VcnBuffer, StartingVcnInputBuffer.Size,
out rpBuffer, RetrievalPointersBuffer.Size,
BytesReturned, IntPtr.Zero
);
errorLevel = Marshal.GetLastWin32Error();
switch(errorLevel)
{
case ERROR_HANDLE_EOF:
break;
case NO_ERROR:
case ERROR_MORE_DATA:
MoreDataAvailable = true;
VcnBuffer.StartingVcn = rpBuffer.NextVcn;
ThisFilePointer.TotalClusters += rpBuffer.NextVcn - rpBuffer.StartingVcn;
ThisFilePointer.TotalSectors = ThisFilePointer.TotalClusters * (uint) SectorsPerCluster;
ThisFilePointer.Length = ThisFilePointer.TotalSectors * BytePerSector;
break;
default:
throw new Win32Exception(errorLevel);
}
if(MoreDataAvailable && rpBuffer.Lcn >= 0)
{
FileFragment.FragmentNumber = extentNumber;
FileFragment.StartCluster = rpBuffer.Lcn;
FileFragment.StartingSector = FileFragment.StartCluster * SectorsPerCluster;
FileFragment.NumberOfClusters = rpBuffer.NextVcn - rpBuffer.StartingVcn;
FileFragment.NumberOfSectors = FileFragment.NumberOfClusters * SectorsPerCluster;
ThisFilePointer.FileAllocation.Add(FileFragment);
extentNumber++;
MoreDataAvailable = false;
}
} while(errorLevel != ERROR_HANDLE_EOF);
ThisFilePointer.TotalFragments = (uint) ThisFilePointer.FileAllocation.Count;
}
return ThisFilePointer;
}
[StructLayout(LayoutKind.Sequential)]
private struct StartingVcnInputBuffer
{
public static readonly int Size;
static StartingVcnInputBuffer()
{
Size = Marshal.SizeOf(typeof(StartingVcnInputBuffer));
}
public long StartingVcn;
}
[StructLayout(LayoutKind.Sequential)]
private struct RetrievalPointersBuffer
{
public static readonly int Size;
static RetrievalPointersBuffer()
{
Size = Marshal.SizeOf(typeof(RetrievalPointersBuffer));
}
public readonly int ExtentCount;
public readonly long StartingVcn;
public readonly long NextVcn;
public readonly long Lcn;
}
[StructLayout(LayoutKind.Sequential)]
public struct PhysicalFileFragment
{
public long FragmentNumber;
public long StartCluster;
public long StartingSector;
public long NumberOfClusters;
public long NumberOfSectors;
}
[StructLayout(LayoutKind.Sequential)]
public struct FileFragment
{
public long TotalClusters;
public long TotalSectors;
public long TotalFragments;
public List<PhysicalFileFragment> FileAllocation;
public long Length;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment