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 .
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 -bit entries. * FAT16: Uses -bit entries. * FAT32: Uses -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 -bit entry: * : Bits * : Bits * : Bits * : Bits
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:
Reserved Region: Contains the first sector of the volume (Sector 0), which houses the BIOS Parameter Block (BPB).
FAT Region: Stores the File Allocation Table data structures.
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.
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 or .
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: , , , or . is recommended for maximum compatibility.
BPB_SecPerClus (Offset 13, Size 1): Sectors per cluster. Must be a power of 2 (). Resulting cluster size (sectors bytes per sector) must not exceed .
BPB_RsvdSecCnt (Offset 14, Size 2): Reserved sectors. Must be non-zero. Typically for FAT12/FAT16 and for FAT32.
BPB_NumFATs (Offset 16, Size 1): Count of FATs. Recommended value is for redundancy.
BPB_RootEntCnt (Offset 17, Size 2): Number of root directory entries for FAT12/16. Must be set to for FAT32.
BPB_TotSec16 (Offset 19, Size 2): 16-bit total sector count. Set to if the count exceeds (in which case use
BPB_TotSec32). Must be for FAT32.BPB_Media (Offset 21, Size 1): Media descriptor. is standard for fixed media; for removable media.
BPB_FATSz16 (Offset 22, Size 2): Sectors per FAT for FAT12/16. Must be 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_TotSec16is 0.
FAT12 and FAT16 Specific Fields (Starting at Offset 36)
BS_DrvNum (Offset 36, Size 1): Int 0x13 drive number ( for floppy, for hard disk).
BS_Reserved1 (Offset 37, Size 1): Reserved for Windows NT; set to .
BS_BootSig (Offset 38, Size 1): Extended boot signature ().
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 = active FAT; Bit = (mirrored) or (not mirrored).
BPB_FSVer (Offset 42, Size 2): FAT32 version. This document defines it as .
BPB_RootClus (Offset 44, Size 4): Cluster number of the first cluster of the root directory (usually ).
BPB_FSInfo (Offset 48, Size 2): Sector number of the FSINFO structure (usually ).
BPB_BkBootSec (Offset 50, Size 2): Sector number of the backup boot sector (usually ).
BPB_Reserved (Offset 52, Size 12): Reserved; set to .
BS_DrvNum, BS_Reserved1, BS_BootSig, BS_VolID, BS_VolLab, BS_FilSysType: Same definitions as FAT12/16 but located at offsets respectively.
Sector 0 Signature Requirement
Regardless of sector size, sector[510] must be and sector[511] must be .
FAT Type Determination
Method: The FAT type is determined EXCLUSIVELY by the count of clusters () on the volume.
Step 1: Calculate Root Directory Sectors: *
Step 2: Calculate Data Region Sectors: * If
BPB_FATSz16is non-zero, ; else . * IfBPB_TotSec16is non-zero, ; else . *Step 3: Calculate Cluster Count: *
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 is identified as: *
Sector for Cluster N: *
FAT Entry Offsets: * For FAT16: * For FAT32: * \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 -bit. The high bits (bits ) must be ignored when reading and preserved when writing.
FAT Sector Boundary Cases
FAT12 Complexity: Since entries are 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: (Standard: ) * FAT16: (Standard: ) * FAT32: (Standard: )
Bad Cluster Mark: * FAT12: * FAT16: * FAT32:
Reserved Clusters: FAT[0] stores many aspects of the
BPB_Mediabyte. 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 ( = clean). * Bit 14 (FAT16) / Bit 26 (FAT32): Hard error bit ( = disk error occurred).
FAT32 Features: FSInfo and Backup Boot Sector
FSInfo Structure (Usually Sector 1)
FSI_LeadSig (Offset 0):
FSI_StrucSig (Offset 484):
FSI_Free_Count (Offset 488): Last known free cluster count or if unknown.
FSI_Nxt_Free (Offset 492): Hint for where to start looking for free clusters or .
FSI_TrailSig (Offset 508):
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 -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 (). |
DIR_CrtTimeTenth | 13 | 1 | Millisecond creation stamp (). |
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 (Japanese Kanji support).
Long Directory Entries (LFN)
Attribute:
ATTR_LONG_NAMEis defined asATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID().Structure: LFN entries store the name in Unicode (-bit). Each entry stores 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 .
LDIR_Chksum: An -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
Convert long name to uppercase and OEM character set.
Strip spaces and leading periods.
Truncate to characters and add extension ( characters).
If a collision occurs or lossy conversion happened, append a numeric tail (e.g., "~1").
File and Directory Limits
Max File Size: bytes (approx. ).
Max Directory Size: bytes. * This limit exists because many utilities use a -bit word to count entries, and to prevent massive performance slowdowns due to lack of indexing.