Disk Tutorial · 03

FAT32 Files

A FAT32 partition becomes useful when the disk program can turn a path into a directory entry, find the first cluster of a file, follow the FAT, and print the file bytes on the UART console.

[o-o] |=| /_\

A directory is not a folder icon. It is a file full of records. Each record either names another directory or points at the first cluster of data.

Goal

Add a read-only cat command to the disk program. The test file lives below a subdirectory on the FAT32 boot partition: /ALQ/HELLO.TXT. The command must mount the first FAT32 partition, walk the path component by component, find the directory entry for the file, read its cluster chain, and print the file on the UART console.

cat
cat /ALQ/HELLO.TXT
disk cat /ALQ/HELLO.TXT

Directories Are Files

FAT32 directories are stored in ordinary clusters. Their data is an array of 32-byte entries. A directory entry can describe a regular file, a subdirectory, a volume label, a deleted slot, the end of the used directory area, or part of a long filename. There is no tree object hidden elsewhere. The tree is built by reading one directory file, finding a directory entry inside it, and then reading the cluster chain named by that entry.

root directory cluster
  ALQ          directory, first_cluster=...
    HELLO.TXT  regular file, first_cluster=..., size=...

Short Names

The original FAT directory name is the 8.3 short name: eight bytes for the base name and three bytes for the extension. The bytes are padded with spaces. HELLO.TXT is stored as HELLO TXT. A short-name entry also contains the attribute byte, timestamps, the high and low halves of the first cluster number, and the file size in bytes.

offset size meaning
0      8    short base name
8      3    short extension
11     1    attributes
20     2    first cluster high word
26     2    first cluster low word
28     4    file size in bytes

Long Names

Long filenames are stored as special entries immediately before the real short-name entry. Each long-name slot has attribute 0x0F and carries up to thirteen UTF-16 code units. The slots appear on disk in reverse order, so the reader collects pieces until it reaches the real file entry, then uses the assembled long name for matching and display. The program also keeps the 8.3 fallback, because simple test files and firmware-created names often do not need long-name slots at all.

Walking a Path

A path is a sequence of names separated by slashes. To resolve /ALQ/HELLO.TXT, the disk program starts in the FAT32 root directory cluster, searches for ALQ, checks that it is a directory, then searches inside that directory for HELLO.TXT. The final entry must be a regular file.

directory_cluster = root_cluster
find "ALQ" in directory_cluster
if entry is directory: directory_cluster = entry.first_cluster
find "HELLO.TXT" in directory_cluster
if entry is file: read entry.first_cluster for entry.size bytes

Reading File Data

FAT32 stores file data in clusters. The directory entry gives only the first cluster and the byte size. To continue past the first cluster, the reader indexes the FAT. Each FAT entry says which cluster comes next. Values at or above 0x0FFFFFF8 mark the end of the chain. This lesson reads at most a small bounded amount so a mistaken file cannot flood the console.

cluster_lba = data_lba + (cluster - 2) * sectors_per_cluster
fat_offset = cluster * 4
next_cluster = FAT[fat_offset] & 0x0FFFFFFF

The Code Change

The disk task now accepts a file request. The shell remains responsive because cat only posts work to the disk task. The FAT32 code has a reusable mount step, a directory lookup routine that understands long names and 8.3 names, a path resolver for subdirectories, and a bounded file printer.

> cat /ALQ/HELLO.TXT
cat: requested /ALQ/HELLO.TXT
> cat: initializing disk
cat: path /ALQ/HELLO.TXT
File HELLO.TXT: first_cluster=... size=... bytes
--- file begin ---
Hello from Alquist FAT32.
This file lives in /ALQ/HELLO.TXT.
--- file end ---

This is the first storage lesson where the disk path becomes visibly useful as a file reader: the user types a path, the program resolves the directory entries, follows the cluster chain, and prints the file bytes back to the console. The debug shell still exists for raw SD work, but the lesson itself uses the normal dir and cat commands.

Prepare the Card

Boot Linux on the Raspberry Pi once, mount the FAT32 boot partition, create the subdirectory, and copy a small text file there:

sudo mkdir -p /boot/firmware/ALQ
printf 'Hello from Alquist FAT32.\nThis file lives in /ALQ/HELLO.TXT.\n' | sudo tee /boot/firmware/ALQ/HELLO.TXT
sync

Then install the bare-metal image again and boot it from the SD card. The program remains read-only; Linux creates the test directory and file, Alquist only reads them.

Try It

make
make test-mbr

On hardware, run:

help
tasks
led toggle
dir
cat
cat /ALQ/HELLO.TXT
tasks

The dir command should show the ALQ subdirectory in the FAT32 root. The cat command should print the file contents and return to the prompt while the scheduler heartbeat continues.

Next

The next storage step can turn this into a reusable file loader: choose a path, read a whole file into a caller-provided buffer, and hand that buffer to later kernel lessons that load programs from disk.