notadam
notadam

Reputation: 2854

FAT32 in practice does not conform Microsoft's documentation

I'm working on a project in which I need to read the BPB of a FAT32 partition, then based on that, verify that the partition is indeed valid FAT32 before doing anything else with it.

According to Microsoft's documentation (in the table starting on page 9), the fields BPB_RootEntCnt (located at 0x17, size 2), and BPB_TotSec16 (located at 0x19, size 2) must both be set to 0 in case of any FAT32 partition. Since the official documentation is very clear about this, I assumed that checking if these are zero is a good idea to verify that the partition is valid FAT32 (these two values are not the only ones I'm using for verification, but these are the problematic ones).

I tried a number of different storage devices, each formatted to FAT32 under different operating systems, and in every single case, these two fields have non-zero values!

Why is this? The official documentation of FAT32 clearly states that these fields must be set to zero. So how can all the different formatting tools (including Windows' built-in formatting option) ignore this rule?

First I thought that my program didn't work as expected, but I think there are no problems with that. Here's a short, self-contained example, that simply prints out the value of only these two fields of a FAT32 partition:

#include <iostream>
#include <string>
#include <cstdio>
#include <unistd.h>
using namespace std;

void printFAT32Fields(const string& vol) {
    // Unmount the volume
    system(("sudo umount -f "s + vol + " 1> /dev/null 2>&1"s).c_str());

    // Open
    auto fp = fopen(vol.c_str(), "r");
    if (!fp) {
        perror("Error");
        throw runtime_error("The volume '"s + vol + "' cannot be accessed!"s);
    }
    setbuf(fp, NULL);

    uint16_t BPB_RootEntCnt = 0x0;
    uint16_t BPB_TotSec16   = 0x0;

    fseek(fp, 0x17, SEEK_SET);
    fread(&BPB_RootEntCnt, 1, 2, fp);

    fseek(fp, 0x19, SEEK_SET);
    fread(&BPB_TotSec16, 1, 2, fp);

    fclose(fp);

    cout << BPB_RootEntCnt << " " << BPB_TotSec16 << endl;
}

int main() {

    if (getuid()) {
        cout << "This program needs root privileges to run!" << endl;
        return 0;
    }

    try {
        printFAT32Fields("PATH TO VOLUME GOES HERE");
    } catch(runtime_error err) {
        cout << err.what();
    }

    return 0;
}

This code works on OS X, Linux, and possibly other UNIX-like systems as well, but NOT Windows. "path to volume" has to be of course /dev/..., for example /dev/disk1s1 on OS X, or /dev/sda1 on Linux.

So how can this be? This program always prints out two non-zero values if you give it the path of a FAT32 partition, while (according to the documentation) these values should be zero.

Upvotes: 0

Views: 271

Answers (1)

deviantfan
deviantfan

Reputation: 11414

It is your program :)
The offsets for BPB_RootEntCnt and BPB_TotSec16
are not 0x17 (=23) and 0x19 (=25), but 17 and 19.

To compare the data for such issues in the future, it´s helpful to get the first KB
with dd in a file and view it with an hex editor. (and to read more carefully...)

Upvotes: 1

Related Questions