SchOS/include/fat.h
Nexoniarz edb560de66 fat: FAT12, FAT16 and FAT32 with long names, read and write
The filesystem every other system can read: a USB stick, an SD card, the
EFI system partition. It is here first for the hardware report, which has
to leave a machine on something that can be read on another one.

  mount -t vfat /dev/usb0p1 /mnt        (msdos and fat work too; -o ro)

Written from Microsoft's specification, and matched to Linux vfat where
the specification leaves a choice: 8.3 names with the NT lowercase bits,
long-name entries otherwise, Linux's alias rule (REPORTS, then BIGNUM~1),
case-insensitive lookup, UTC times, the boot-sector dirty bit, every FAT
copy and FSInfo kept up to date. It uses its own sector cache over the
new blkdev_xfer, since a partition need not be a whole number of 4 KB
blocks, and every operation that changes something reaches the disk
before it returns. Inode numbers come from the entry position, or the
first cluster for a directory, plus a small table for entries that moved.

Around it:
- /dev lists every disk and partition the block layer found (major 8,
  minor = block device), and raw reads and writes on them go by sector.
- The ESP and MBR FAT partitions are registered, typed so the root probe
  passes over them. MBR entries with a bad status byte are skipped, so a
  superfloppy's boot code is not read as a partition table.
- statfs, sync, fsync, umount (EBUSY while in use), shutdown, reboot and
  the power button all know about FAT.
- create undoes and reports a failed ialloc or dirlink (ENOSPC, EINVAL,
  EPERM) instead of panicking; fs_ops gains refuse_types and no_hardlinks.
- filewrite returns a short write instead of panicking on it.
- utimensat is implemented. As a stub returning 0 it made toybox touch
  believe the file existed, so `touch newfile` created nothing on any
  filesystem.

Tested in QEMU against mkfs.vfat images (FAT12 floppy, FAT16 on MBR,
FAT32 superfloppy and GPT ESP) by writing, renaming, deleting, filling to
ENOSPC and truncating there, then checking with fsck.fat -n and mtools on
the host: all clean, contents match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
2026-10-23 09:33:35 +02:00

30 lines
1.3 KiB
C

#pragma once
// FAT12, FAT16 and FAT32, with VFAT long names: the filesystem every other
// operating system can read, which is the whole reason to have it. A USB
// stick, an EFI system partition, an SD card. See kernel/fs/fat/fat.c.
//
// Mounted the way Linux mounts it -- `mount -t vfat /dev/usb0p1 /mnt` -- and
// "msdos" and "fat" are accepted as the same thing.
// Filesystem device numbers for mounted FAT volumes. Like SCHFS_DEV, runtime
// identities for the inode cache that nothing on disk records.
#define FAT_VOL_SLOTS 4
#define FAT_DEV 104
#define FAT_IS_DEV(d) ((d) >= FAT_DEV && (d) < FAT_DEV + FAT_VOL_SLOTS)
// The root directory's inode number on every FAT volume.
#define FAT_ROOT_INO 1
// Mount the FAT volume on block device `bdev`. Returns its filesystem device
// number, or a negative errno: -ENODEV for no FAT there, -EBUSY for no free
// slot or already mounted.
int fat_kmount(uint bdev, int readonly);
// Flush it, mark it cleanly unmounted, and let it go.
int fat_kumount(uint dev);
int fat_readonly(uint dev);
// Write out everything dirty on every mounted volume. `final` also marks each
// one clean, for a shutdown that will not get to unmount them.
void fat_ksync_all(int final);
// Cluster size, clusters and free clusters, for statfs. -1 if not FAT.
int fat_kstatfs(uint dev, uint64 *bsize, uint64 *total, uint64 *freec);