Get size of the File Allocation Table in an exFAT disk using C#

664 Views Asked by At

I'm writing a program that copies the FAT to a file (and restores it). I'm using CreateFile to open a drive letter as a file, SetFilePointerEx to seek to 0 position, ReadFile to read the contents of the drive, and WriteFile to write to the drive.

Using this strategy I can basically copy the entire drive. However, how should I know where to start and when to stop? Basically, what I want to know is the location of the beginning and the end of File Allocation Table in an exFAT disk.

Here's the code that I use to run the backup for the first 4 GB of data:


    private static void RunBackup(string driveLetter)
    {
        IntPtr handle = CreateFile(
            string.Format("\\\\.\\{0}:", driveLetter),
            FileAccess.Read,
            FileShare.Read,
            IntPtr.Zero,
            (FileMode)OPEN_EXISTING,
            0,
            IntPtr.Zero);
    
        // Set offset
        uint chunks = 100;
        uint bufferSize = 512 * chunks;
        long pt = 0;
        byte[] buffer = new byte[bufferSize];
        SetFilePointerEx(
            handle,
            0,
            ref pt,
            0);
    
        long oneGB = 1073741824;
        var backupSize = oneGB * 4;
        var loops = backupSize / bufferSize;
    
        Console.WriteLine($"Expecting {loops:N0} loops.");
    
        uint read = 0;
        using (var writer = new BinaryWriter(File.OpenWrite(@"D:\\fat.backup")))
        {
            for (int i = 0; i < loops; i++)
            {
                ReadFile(
                    handle,
                    buffer,
                    bufferSize,
                    ref read,
                    IntPtr.Zero);
    
                writer.Write(buffer);
                writer.Flush();
    
                Console.Write($"\rLoop: {i:N0}");
            }
    
            writer.Close();
        }
    
        CloseHandle(handle);
    }

1

There are 1 best solutions below

6
On BEST ANSWER

Reading the exFAT specification is a good start.

In §2 ‘Volume structure’, we have a table:

Sub-region Name Offset (sector) Size (sectors)
First FAT FatOffset FatLength
Second FAT FatOffset + FatLength FatLength × (NumberOfFats − 1)

FatOffset, FatLength and NumberOfFats are fields of the boot sector, as described in §3.1 ‘Main and Backup Boot Sector Sub-regions’:

Field Name Offset (byte) Size (bytes)
FatOffset 80 4
FatLength 84 4
NumberOfFats 110 1

The values are in sector units, so you will have to multiply them by the sector size before calling SetFilePointerEx. The sector size can be obtained from the DeviceIoControl call IOCTL_DISK_GET_DRIVE_GEOMETRY_EX; the returned DISK_GEOMETRY_EX structure contains a Geometry.BytesPerSector (nested) field. The FatOffset and FatLength values are little endian, so you will have to decode them with a function like:

private static uint ReadLE32(byte[] data, uint offset)
{
    return (data[offset + 3] << 24)
         | (data[offset + 2] << 16)
         | (data[offset + 1] << 8)
         | data[offset];
}

It’s also typical to read the whole boot sector to extract information from it, not individual fields. Remember also that any of the Windows API calls may return an error: if you worry about reliability, you should be checking return values and convert them into exceptions as necessary.

Putting it all together: you open the disk as before, read its boot sector, discover the offset and size of the FAT, then seek to the FAT and read it off.