Skip to content

FAT Filesystem

Levente Santha edited this page May 31, 2026 · 2 revisions

FAT Filesystem

JNode's FAT12/FAT16/FAT32 filesystem implementation with Long File Name (LFN) support.

Overview

The FAT (File Allocation Table) filesystem in JNode provides read-write support for FAT12, FAT16, and FAT32 variants. It integrates with JNode's VFS layer through the FatFileSystemType factory and uses the block device layer for sector-level I/O. The implementation includes support for Long File Names (VFAT) to overcome the 8.3 filename limitation.

Key Components

fat Package (Legacy Implementation)

Class / File Purpose
fs/src/fs/org/jnode/fs/fat/ Original FAT12/FAT16/FAT32 implementation — legacy, less actively maintained

jfat Package (Active Implementation)

Class / File Purpose
FatFileSystemType.java Factory implementing FileSystemType, probes block devices to determine FAT type
FatFileSystem.java Main filesystem, extends AbstractFileSystem, manages FAT and root entries
BootSector.java BPB parsing (offsets 11-64), FAT type detection via RootEntCnt==0 && FATSz16==0, computes CountOfClusters, DataSec, FirstDataSector
Fat.java Abstract FAT table, cluster chain operations, size() returns CountOfClusters + 2
Fat32.java FAT32 variant — 4 bytes per entry, EOF mask 0x0FFFFFFF
Fat16.java FAT16 variant — 2 bytes per entry, EOF threshold 0xFFF8
Fat12.java FAT12 variant — 1.5 bytes per entry, EOF threshold 0xFF8
FatChain.java Cluster chain traversal, allocateAndClear(), read(), write() methods
FatFile.java File I/O via cluster chain reads/writes
FatDirectory.java Directory iteration via FatEntriesFactory
FatRootDirectory.java FAT32 root dir stored in cluster (not fixed-size like FAT12/16)
FatEntriesFactory.java Scans directory entries, handles chain errors gracefully
FatShortDirEntry.java, FatLongDirEntry.java Short 8.3 and Long File Name directory entries

Architecture

Filesystem Type Registration

The FatFileSystemType class implements the FileSystemType interface, allowing the VFS to probe block devices and instantiate FatFileSystem instances. This follows the plugin extension point pattern used throughout JNode.

Boot Sector Parsing

The BootSector class parses the BIOS Parameter Block (BPB) from the first sector:

  • getBytesPerSector(), getSectorsPerCluster() — cluster size calculation
  • getNrFats() — number of FAT copies
  • getSectorsPerFat() — FAT size
  • getNrRootDirEntries() — root directory size (FAT12/FAT16 only)
  • getMediumDescriptor() — determines FAT12 vs FAT16

FAT Table Management

The Fat class handles cluster chain operations:

  • Read/Write: Binary encoding for each FAT variant (1.5 bytes/entry for FAT12, 2 bytes for FAT16, 4 bytes for FAT32)
  • Cluster allocation: allocNew(), allocAppend() for file growth
  • Chain traversal: getChain(), getNextCluster() for file I/O
  • EOF detection: Uses variant-specific EOF markers from FatType

Directory Structure

FatDirectory extends AbstractDirectory and handles:

  • Root directory vs subdirectory (root has fixed size, subdirectories are cluster-based)
  • Entry iteration via FSEntry interface
  • Label (volume name) management in root directory
  • LFN sequence handling via FatLfnDirectory

LFN Support

Long File Names are stored in special directory entries (FatLfnDirEntry) preceding the 8.3 alias entry:

  • Unicode name storage (up to 255 characters)
  • Checksum-based association with the short name
  • Unicode conversion via LfnEntry utilities

How It Works

Mounting a FAT Volume

FatFileSystem constructor:
1. Read boot sector (512 bytes)
2. Determine FAT type from medium descriptor (0xf8 = FAT16)
3. Create Fat instances for each FAT copy
4. Read root directory (fixed-size for FAT12/16, cluster-based for FAT32)
5. Validate FAT consistency across copies

File Access

FatFile.getData():
1. Get starting cluster from directory entry
2. Fat.getChain(startCluster) → array of cluster numbers
3. Map clusters to sector offsets
4. Read data from block device

Writing Changes

FatFileSystem.flush():
1. Write dirty boot sector
2. Flush all open FatFile instances
3. Write dirty FAT copies
4. Flush dirty root/subdirectories

Gotchas & Non-Obvious Behavior

  • Root directory: FAT12/FAT16 root has fixed size from BPB; FAT32 root is a cluster chain like any directory
  • Cluster size: Derived from bytesPerSector * sectorsPerCluster, used for all allocation
  • Dirty tracking: Files, FAT, and directories track changes independently; flush must handle all three
  • FAT consistency: On mount, JNode logs warnings if FAT copies differ (first FAT is used)
  • LFN ordering: LFN entries must immediately precede their 8.3 alias; deletion disrupts the chain
  • FAT32 detection (jfat): Must use RootEntCnt==0 && FATSz16==0 BEFORE computing type — Microsoft spec. Some mkfs.fat versions set TotSec16 with actual value while TotSec32=0, breaking naive detection
  • FAT32 CountOfClusters (jfat): Must be computed in FAT32 branch of compute()DataSec = TotSec - FirstDataSector, not including RootDirSectors which is 0 for FAT32

Related Pages

Clone this wiki locally