Microsoft FAT File System On-Disk Format Comprehensive Study Guide

General Overview and Historical Context of the FAT File System

  • Origin: The File Allocation Table (FAT) file system originated in the late 1970s and early 1980s.

  • Purpose: It was originally developed to support simple file systems for floppy disk drives smaller than 500KB500\,KB.

  • Primary OS Support: It was the native file system for the Microsoft MS-DOS operating system.

  • Modern Subtypes: There are currently three distinct FAT subtypes distinguished by the size (in bits) of the entries in the FAT structure on the disk:     * FAT12: Uses 1212-bit entries.     * FAT16: Uses 1616-bit entries.     * FAT32: Uses 3232-bit entries.

Notational Conventions and Data Storage Architecture

  • Numerical Notation:     * Hexadecimal (Base 16) numbers are prefixed with "0x".     * Decimal (Base 10) numbers carry no prefix.

  • Programming Language: References or code fragments provided in the specification are written in the 'C' programming language (assuming unsigned data types).

  • Byte Ordering: Designed for the IBM PC architecture, FAT data structures are stored in "little-endian" format.     * For a 3232-bit entry:         * byte[0]byte[0]: Bits 000700-07         * byte[1]byte[1]: Bits 081508-15         * byte[2]byte[2]: Bits 162316-23         * byte[3]byte[3]: Bits 243124-31

  • Warning for Programmers: Never perform FAT computations using signed integer types, as this will lead to errors on certain volumes.

Volume Structure and Regions

A FAT volume consists of four distinct regions laid out in the following consecutive order:

  1. Reserved Region: Contains the first sector of the volume (Sector 0), which houses the BIOS Parameter Block (BPB).

  2. FAT Region: Stores the File Allocation Table data structures.

  3. Root Directory Region: Contains a fixed number of directory entries. Note: This region does not exist on FAT32 volumes; the root directory in FAT32 is stored in the Data Region.

  4. File and Directory Data Region: Holds the actual file contents and sub-directory structures.

The BIOS Parameter Block (BPB) and Boot Sector

  • Location: The BPB is located in the first sector of the volume (Sector 0), also known as the "boot sector," "reserved sector," or "0th sector."

  • Mandatory Status: While MS-DOS 1.x lacked a BPB (and determined media via the first byte of the FAT), all modern FAT volumes must include a BPB.

General Boot Sector Fields (All FAT Types)
  • BS_jmpBoot (Offset 0, Size 3): Jump instruction to operating system bootstrap code. Forms include 0xEB0x??0x900xEB\,0x??\,0x90 or 0xE90x??0x??0xE9\,0x??\,0x??.

  • BS_OEMName (Offset 3, Size 8): Recommended setting is "MSWIN4.1". It is informational; Microsoft OSs generally ignore it, but some third-party drivers do not.

  • BPB_BytsPerSec (Offset 11, Size 2): Bytes per sector. Valid values: 512512, 10241024, 20482048, or 40964096. 512512 is recommended for maximum compatibility.

  • BPB_SecPerClus (Offset 13, Size 1): Sectors per cluster. Must be a power of 2 (1,2,4,8,16,32,64,1281, 2, 4, 8, 16, 32, 64, 128). Resulting cluster size (sectors imesimes bytes per sector) must not exceed 32KB32\,KB.

  • BPB_RsvdSecCnt (Offset 14, Size 2): Reserved sectors. Must be non-zero. Typically 11 for FAT12/FAT16 and 3232 for FAT32.

  • BPB_NumFATs (Offset 16, Size 1): Count of FATs. Recommended value is 22 for redundancy.

  • BPB_RootEntCnt (Offset 17, Size 2): Number of root directory entries for FAT12/16. Must be set to 00 for FAT32.

  • BPB_TotSec16 (Offset 19, Size 2): 16-bit total sector count. Set to 00 if the count exceeds 6553565535 (in which case use BPB_TotSec32). Must be 00 for FAT32.

  • BPB_Media (Offset 21, Size 1): Media descriptor. 0xF80xF8 is standard for fixed media; 0xF00xF0 for removable media.

  • BPB_FATSz16 (Offset 22, Size 2): Sectors per FAT for FAT12/16. Must be 00 for FAT32.

  • BPB_SecPerTrk (Offset 24, Size 2): Sectors per track for Int 0x13 geometry.

  • BPB_NumHeads (Offset 26, Size 2): Number of heads for Int 0x13 geometry.

  • BPB_HiddSec (Offset 28, Size 4): Count of hidden sectors preceding the partition.

  • BPB_TotSec32 (Offset 32, Size 4): 32-bit total sector count. Must be non-zero for FAT32 or if BPB_TotSec16 is 0.

FAT12 and FAT16 Specific Fields (Starting at Offset 36)
  • BS_DrvNum (Offset 36, Size 1): Int 0x13 drive number (0x000x00 for floppy, 0x800x80 for hard disk).

  • BS_Reserved1 (Offset 37, Size 1): Reserved for Windows NT; set to 00.

  • BS_BootSig (Offset 38, Size 1): Extended boot signature (0x290x29).

  • BS_VolID (Offset 39, Size 4): Volume serial number.

  • BS_VolLab (Offset 43, Size 11): Volume label matching the root directory.

  • BS_FilSysType (Offset 54, Size 8): Informational string (e.g., "FAT12 ", "FAT16 ").

FAT32 Specific Fields (Starting at Offset 36)
  • BPB_FATSz32 (Offset 36, Size 4): 32-bit count of sectors per FAT.

  • BPB_ExtFlags (Offset 40, Size 2): Mirroring info. Bits 030-3 = active FAT; Bit 77 = 00 (mirrored) or 11 (not mirrored).

  • BPB_FSVer (Offset 42, Size 2): FAT32 version. This document defines it as 0:00:0.

  • BPB_RootClus (Offset 44, Size 4): Cluster number of the first cluster of the root directory (usually 22).

  • BPB_FSInfo (Offset 48, Size 2): Sector number of the FSINFO structure (usually 11).

  • BPB_BkBootSec (Offset 50, Size 2): Sector number of the backup boot sector (usually 66).

  • BPB_Reserved (Offset 52, Size 12): Reserved; set to 00.

  • BS_DrvNum, BS_Reserved1, BS_BootSig, BS_VolID, BS_VolLab, BS_FilSysType: Same definitions as FAT12/16 but located at offsets 64,65,66,67,71,8264, 65, 66, 67, 71, 82 respectively.

Sector 0 Signature Requirement

Regardless of sector size, sector[510] must be 0x550x55 and sector[511] must be 0xAA0xAA.

FAT Type Determination

  • Method: The FAT type is determined EXCLUSIVELY by the count of clusters (CountofClustersCountofClusters) on the volume.

  • Step 1: Calculate Root Directory Sectors:     * RootDirSectors=extfloor((extBPBRootEntCnt×32)+(extBPBBytsPerSec1)extBPBBytsPerSec)\text{RootDirSectors} = ext{floor}\left(\frac{( ext{BPB_RootEntCnt} \times 32) + ( ext{BPB_BytsPerSec} - 1)}{ ext{BPB_BytsPerSec}}\right)

  • Step 2: Calculate Data Region Sectors:     * If BPB_FATSz16 is non-zero, FATSz=BPBFATSz16FATSz = BPB_FATSz16; else FATSz=BPBFATSz32FATSz = BPB_FATSz32.     * If BPB_TotSec16 is non-zero, TotSec=BPBTotSec16TotSec = BPB_TotSec16; else TotSec=BPBTotSec32TotSec = BPB_TotSec32.     * DataSec=extTotSec(extBPBResvdSecCnt+(extBPBNumFATs×extFATSz)+extRootDirSectors)\text{DataSec} = ext{TotSec} - ( ext{BPB_ResvdSecCnt} + ( ext{BPB_NumFATs} \times ext{FATSz}) + ext{RootDirSectors})

  • Step 3: Calculate Cluster Count:     * CountofClusters=extfloor(extDataSecextBPBSecPerClus)\text{CountofClusters} = ext{floor}\left(\frac{ ext{DataSec}}{ ext{BPB_SecPerClus}}\right)

  • Step 4: Determine Type:     * If \text{CountofClusters} < 4085: FAT12     * Else if \text{CountofClusters} < 65525: FAT16     * Else: FAT32

Cluster Access and Calculation

  • First Data Sector: The first sector of cluster 22 is identified as:     * FirstDataSector=extBPBResvdSecCnt+(extBPBNumFATs×extFATSz)+extRootDirSectors\text{FirstDataSector} = ext{BPB_ResvdSecCnt} + ( ext{BPB_NumFATs} \times ext{FATSz}) + ext{RootDirSectors}

  • Sector for Cluster N:     * FirstSectorofCluster=((extN2)×extBPBSecPerClus)+extFirstDataSector\text{FirstSectorofCluster} = (( ext{N} - 2) \times ext{BPB_SecPerClus}) + ext{FirstDataSector}

  • FAT Entry Offsets:     * For FAT16: FATOffset=extN×2\text{FATOffset} = ext{N} \times 2     * For FAT32: FATOffset=extN×4\text{FATOffset} = ext{N} \times 4     * \text{ThisFATSecNum} = ext{BPB_ResvdSecCnt} + \text{floor}\left(\frac{\text{FATOffset}}{\text{BPB_BytsPerSec}}\right)     * \text{ThisFATEntOffset} = \text{remainder}\left(\frac{\text{FATOffset}}{\text{BPB_BytsPerSec}}\right)

  • FAT32 Entry Bitmask: Entries are 2828-bit. The high 44 bits (bits 283128-31) must be ignored when reading and preserved when writing.

FAT Sector Boundary Cases

  • FAT12 Complexity: Since entries are 1.51.5 bytes, an entry may span sector boundaries. A common strategy is to load sectors in pairs.

  • End of Cluster Chain (EOC): Values marking the end of a file:     * FAT12: 0x0FF8\ge 0x0FF8 (Standard: 0x0FFF0x0FFF)     * FAT16: 0xFFF8\ge 0xFFF8 (Standard: 0xFFFF0xFFFF)     * FAT32: 0x0FFFFFF8\ge 0x0FFFFFF8 (Standard: 0x0FFFFFFF0x0FFFFFFF)

  • Bad Cluster Mark:     * FAT12: 0x0FF70x0FF7     * FAT16: 0xFFF70xFFF7     * FAT32: 0x0FFFFFF70x0FFFFFF7

  • Reserved Clusters: FAT[0] stores many aspects of the BPB_Media byte. FAT[1] stores the EOC mark. In FAT16/FAT32, the high two bits of FAT[1] are used for dirty flags:     * Bit 15 (FAT16) / Bit 27 (FAT32): Clean shutdown bit (11 = clean).     * Bit 14 (FAT16) / Bit 26 (FAT32): Hard error bit (00 = disk error occurred).

FAT32 Features: FSInfo and Backup Boot Sector

FSInfo Structure (Usually Sector 1)
  • FSI_LeadSig (Offset 0): 0x416152520x41615252

  • FSI_StrucSig (Offset 484): 0x614172720x61417272

  • FSI_Free_Count (Offset 488): Last known free cluster count or 0xFFFFFFFF0xFFFFFFFF if unknown.

  • FSI_Nxt_Free (Offset 492): Hint for where to start looking for free clusters or 0xFFFFFFFF0xFFFFFFFF.

  • FSI_TrailSig (Offset 508): 0xAA5500000xAA550000

Backup Boot Sector (Usually Sector 6)

FAT32 provides redundancy by storing a full copy of the first three sectors of the boot record and the FSInfo sector at the sector indicated by BPB_BkBootSec.

Directory Entry Structure

A FAT directory is a list of 3232-byte structures.

Name

Offset

Size

Description

DIR_Name

0

11

Short Name (8.3 format).

DIR_Attr

11

1

Attributes (ReadOnly, Hidden, System, VolID, Directory, Archive).

DIR_NTRes

12

1

Reserved for Windows NT (00).

DIR_CrtTimeTenth

13

1

Millisecond creation stamp (01990-199).

DIR_CrtTime

14

2

Creation time.

DIR_CrtDate

16

2

Creation date.

DIR_LstAccDate

18

2

Last access date.

DIR_FstClusHI

20

2

High word of first cluster (FAT32 only).

DIR_WrtTime

22

2

Last write time.

DIR_WrtDate

24

2

Last write date.

DIR_FstClusLO

26

2

Low word of first cluster.

DIR_FileSize

28

4

32-bit File size in bytes.

Special DIR_Name[0] Values
  • 0xE5: Entry is free.

  • 0x00: Entry is free and all subsequent entries are also free.

  • 0x05: First character of name is actually 0xE50xE5 (Japanese Kanji support).

Long Directory Entries (LFN)

  • Attribute: ATTR_LONG_NAME is defined as ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID (0x0F0x0F).

  • Structure: LFN entries store the name in Unicode (1616-bit). Each entry stores 1313 Unicode characters.

  • Order: LFN entries immediately precede the associated short (alias) entry in reverse order.

  • LDIR_Ord: Sequence number. The last entry (first physically) is OR'd with 0x400x40.

  • LDIR_Chksum: An 88-bit checksum of the short name used to link LFNs to their alias.

  • Transparency: LFNs appear as volume labels or hidden/system files to legacy systems, preventing accidental interference.

Alias (Short Name) Generation
  1. Convert long name to uppercase and OEM character set.

  2. Strip spaces and leading periods.

  3. Truncate to 88 characters and add extension (33 characters).

  4. If a collision occurs or lossy conversion happened, append a numeric tail (e.g., "~1").

File and Directory Limits

  • Max File Size: 0xFFFFFFFF0xFFFFFFFF bytes (approx. 4GB4\,GB).

  • Max Directory Size: 65,536×32=2,097,15265,536 \times 32 = 2,097,152 bytes.     * This limit exists because many utilities use a 1616-bit word to count entries, and to prevent massive performance slowdowns due to lack of indexing.