Skip to content

patterns/fs: Add FAT12/FAT16 pattern - #597

Open
ImadC9 wants to merge 1 commit into
WerWolv:masterfrom
ImadC9:feat/fs-fat12-fat16
Open

ImadC9 wants to merge 1 commit into
WerWolv:masterfrom
ImadC9:feat/fs-fat12-fat16

Conversation

@ImadC9

@ImadC9 ImadC9 commented Oct 9, 2026 •

Copy link
Copy Markdown

Pattern

Closes #108.

Adds patterns/fs/fat16.hexpat for FAT12 and FAT16 volumes, the two FAT variants that were still missing next to fat32.hexpat and exfat.hexpat.

  • Boot sector with BPB and extended BPB (0x28 and 0x29 boot signatures)
  • Every FAT, with FAT12's packed 12-bit entries decoded and each entry labelled: free, next cluster, end of chain, bad, reserved
  • The fixed root directory, then every subdirectory and file followed through its FAT chain, including fragmented files and directories spanning several cluster runs
  • VFAT long file name entries, deleted entries, volume labels and the Windows NT lowercase flags for 8.3 names
  • The FAT type is chosen from the cluster count, as fatgen103 requires, not from the informational FAT12 string. FAT32 volumes are rejected with a pointer to fat32.hexpat.
  • Cluster chains are walked iteratively, one array element per run of consecutive clusters, so a long or fragmented chain cannot exhaust the native stack. A chain is never followed for more clusters than the volume has, so cycles in the FAT end with a warning.
  • Guards for corrupted images:
    • a directory already open further up the tree is not entered again
    • nesting deeper than 64 levels and more than 10000 directories are not followed
    • a BPB claiming more clusters than its FAT can hold is clamped
  • Images cut off part way (partial dumps) parse up to where they end.

fs/pattern.hexpat now dispatches MBR partition types 0x01, 0x04, 0x06 and 0x0E (and their hidden variants) to the new pattern. Previously a disk with a FAT16 partition stopped with Unknown MBR Partition Type MBRPartitionType::FAT16_32MBPlus. Output for the existing fs.hexpat.img is byte-identical.

Verification

Every file the pattern finds was rebuilt from its data runs and compared byte-for-byte with what mcopy -s (mtools) extracts:

Image Type Result
64 KiB volume FAT12, 512 B clusters 4 files, 2 dirs, identical
2.2 MB volume FAT16, 512 B clusters 4 files, 2 dirs, identical
360 KiB, random churn FAT12 44 files, 3 dirs, identical
1.44 MB, 2 KiB clusters, churn FAT12 44 files, 3 dirs, identical
4 MB, churn FAT16 46 files, 3 dirs, identical
16 MB, 4 KiB clusters, churn FAT16 35 files, 3 dirs, identical
Standard 1.44 MB floppy FAT12 identical
One file in 3,000 fragments FAT16 identical
65,439 clusters (near max) FAT16 parses in 0.09 s
  • Fragmentation: besides the 3,000-fragment file, the churn images exercise 16 fragmented files and 5 multi-run directories.
  • Type boundary: at the FAT12/FAT16 limit, the detected type matches mkfs.fat on both sides.
  • MBR disk: an image with a FAT16 and a FAT12 partition parses through fs/pattern.hexpat, and file bytes inside both partitions match.
  • Corruption: 500 corrupted images all parse, in under 0.1 s each, with every formatted value valid. They include broken and cyclic FAT chains, cycles combined with 4 GiB file sizes, and random bytes. Specific cases that also pass: a file chain looping on itself with size 0xFFFFFFFF, a looping directory chain, and 80 nested directories (stopped at 64 with a warning).
  • Truncation: 3,888 truncated prefixes of the test images all parse.

Test data

tests/patterns/test_data/fat16.hexpat/ holds two images made with mkfs.fat and mtools from generated data:

  • fat12.img, 64 KiB
  • fat16.img, a FAT16 volume cut off after its last allocated cluster to keep it at 25 KiB; it parses identically to the full 2.2 MB image

Note: tests/patterns/CMakeLists.txt only globs patterns/*.hexpat, so nothing under patterns/fs/ runs in CI today, including the existing ext4 and fs test files. The images follow the naming convention so they will be picked up if subfolders are added. A recursive glob currently collides on 8 duplicate test names, so that needs its own change; happy to send one.

Checklist

  • A pattern for this format doesn't exist yet
  • The new pattern has been added to the relevant table in the Readme
  • The new pattern has a description pragma
  • MIME types: libmagic reports bare FAT volumes as application/octet-stream, so detection uses #pragma magic on the FAT12 / FAT16 signature instead, like fat32.hexpat and exfat.hexpat
  • A test file for this pattern has been added to /tests/patterns/test_data
  • Unit tests pass (311/311 locally, PatternLanguage 300d738)

Adds fs/fat16.hexpat, covering both FAT12 and FAT16 volumes:

- Boot sector with BPB and extended BPB (0x28 / 0x29 boot signatures)
- All FATs, with packed 12 bit entries decoded for FAT12 and every
  entry labelled (free, next cluster, end of chain, bad, reserved)
- The fixed root directory, then every subdirectory and file followed
  through its FAT cluster chain, including fragmented chains and
  directories spanning several cluster runs
- VFAT long file name entries, deleted entries, volume labels and the
  Windows NT lowercase flags for 8.3 names
- FAT type chosen from the cluster count as the specification requires;
  FAT32 volumes are rejected with a pointer to fs/fat32.hexpat
- Cluster chains are walked iteratively, one array element per run of
  consecutive clusters, so a long or fragmented chain cannot exhaust the
  stack; a chain is never followed for more clusters than the volume has
- Guards for corrupted images: directory loops, nesting deeper than 64
  levels, more than 10000 directories, and a BPB claiming more clusters
  than its FAT can hold
- Images cut off part way (partial dumps) are parsed up to where they
  end: FATs, root directory and data runs are clamped to the file

fs/pattern.hexpat now dispatches MBR partition types 0x01, 0x04, 0x06,
0x0E and their hidden variants to the new pattern instead of failing
with "Unknown MBR Partition Type".

Test images were made with mkfs.fat and mtools and contain only
generated data. The FAT16 image is cut off after its last allocated
cluster to keep it at 25 KiB.

Closes WerWolv#108
@ImadC9
ImadC9 force-pushed the feat/fs-fat12-fat16 branch from 2e2e9bd to 96b4b2a Compare October 9, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Pattern for the FAT (FAT16, FAT32 and exFAT) File System

1 participant