Reading files from FAT16

Reading files from FAT16

 By Peter Murray, Edited by Don Prefontaine



I spent a few weeks trying to figure out how to read the FAT16 filesystem for my M62 computer as I have a CF interface attached to it.

There was some information spread across the web but nothing I came across with a definitive step-by-step procedure on how it is done so I’ve decided to document it to save other people the time for the journey.

Links to the resources I used to figure out this process are noted on the last page.


Preliminary Steps

In order to begin to read the filesystem, you need to be able to read the sectors from your device. As mentioned in the intro, I’m using CF (Compact Flash) but the information should be the same with SD cards.

I started by writing code to read sectors.  I verified that I was reading everything correctly by using a free disk editor program, Active@Disk Editor:  It also has some template settings that helped me parse information and show me were the information I needed was located.


Step 1 – Reading the boot sector (0x00000000)

Setting the LBA registers to 0x00000000, I read the sector into my buffer and here is what I got:

Active@Disk identifies this sector as a Master Boot Record, some information at offsets we are looking for from this sector is as follows:

  • 0x000B: Bytes per sector (2 bytes)
  • 0x000D: Sectors per cluster (1 byte)
  • 0x000E: Number of reserved sectors (2 bytes)
  • 0x0010: Number of FATs (1 byte)
  • 0x0016: Sectors per FAT (2 bytes)
  • 0x01C6: MBR location (2 bytes) <- This is important to us for the next step
  • 0x01FE: Identification, this should be 2 bytes containing 0x55AA

I was working with three CF cards for my development and one of them seemed to not contain a master boot record but rather a FAT boot record at sector 0x00000000. I’m unsure why this was the case but for now when I identify this happening, I just consider the boot sector to be found at 0x00000000 and move on to parsing it.


Step 2 – Finding the FAT Boot sector

Once we get the MBR location from offset 0x01C6 in the screenshot above, we can find where it resides.

We see the 2 bytes at 0x01C6 read 30 00. This is stored Little Endian so this is to be read 2nd byte first. Therefore our FAT Boot sector should reside at sector 0x0030. Let’s dump that sector:

We can see right away this sector contains some key identifiers of a FAT Boot sector. Things such as the string “MSDOS5.0” and “FAT16” clearly identify this, and the ID of 0x55AA at the end of the sector identifies a boot sector, too.

The relevant offsets from this sector are as follows:

  • 0x000E: Number of reserved sectors (2 bytes)
  • 0x0010: Number of FATs (1 byte)
  • 0x0016: Sectors per FAT (2 bytes)

With this information we can move on to the next step.


Step 3 – Locating the root directory

We are getting closer. Let’s see if we can find the root directory.

Using the information from the previous steps we can calculate the location of the root directory:

Boot Record Sector + Number Reserved sectors + (Number of FATs * Sectors per FAT)

0x0030 + 0x0001 + ( 0x02 * 0x00F5 )

We come up with the sector location of 0x021B.

Dumping of sector 0x021B shows the following:

Each directory entry is 32 bytes long, basically 2 lines of the dump per file.

Let’s have a look at what’s on the disk.

If the first byte of the filename in the directory is 0xE5 this signifies that the file was deleted, hence the reason why there are 10 entries but only 2 items are showing. (Side note: If we change the 0xE5 character in the deleted filenames to some other printable ASCII character, we “undelete” the file. It’s only readable if its data hasn’t been overwritten.)


Step 4 – Locating and reading the files

As mentioned earlier each entry is 32 bytes long, therefore each file entry will be offset by 0x20 hex from the root directory start.

The first 12 bytes of each entry contains the file name; this is stored as 8 characters for the name, then 3 characters for the extension. To look for a specific file we match the filename string to locate its entry.

For this example we are going to look for TEST.TXT. This turns out to be the 4th entry in the list.

3 x 0x20 = 0x60 offset.

Looking at Active@Disk:

The value we are interested in here is “First cluster (low word)”; the high word counterpart is not relevant in FAT12 and FAT16. We take this value and subtract 2 (it’s a quirk of FAT that it starts at 2 rather than 0). The value is 0x0002 after subtracting 2 so it is now 0x0000.

We are using FAT16 so there are up to 512 entries in the root and each entry is 16 bytes (hence FAT16), so the size of our root directory is 512/16=32 sectors long.

This tells us the data starts at Root location + 32 sectors.

In this case data begins at 0x021B + 0x0020 = Sector 0x023B.

Let’s dump that sector:

Let’s compare it to the contents of the file:

It matches!


Resources used: