- C 98.7%
- Python 1%
- Makefile 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| docs | ||
| fatfs | ||
| icons | ||
| misc | ||
| scripts | ||
| src | ||
| tools | ||
| .gitignore | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| THIRD_PARTY_NOTICES | ||
| TODO.md | ||
| VERSION | ||
fatso
Experimental AmigaOS 2.04+ AmigaDOS filehandler for FAT12, FAT16, FAT32, and exFAT filesystems.
fatso presents FAT/exFAT media as normal AmigaDOS volumes, with long filename support, Workbench volume integration, Western filename/label conversion, formatting tools, MBR/RDB hybrid helpers, and Amiga-side regression tests.
About and license
Copyright (c) 2026 Anders Milton/UHC.
fatso-owned source code and documentation are licensed under the MIT License; see LICENSE.
fatso uses Elm-Chan FatFs for FAT/exFAT on-disk filesystem handling. FatFs is Copyright (C) ChaN and is redistributed under the FatFs terms included in the FatFs source files. The upstream FatFs copyright notices are kept in the FatFs source files; see THIRD_PARTY_NOTICES for details.
Architecture
fatso is intended to be mounted by AmigaDOS as a filehandler in L:. It receives DOS packets and translates them to FatFs calls. FatFs reaches the media through src/amiga_diskio.c, which opens the underlying Exec block device described by the FileSysStartupMsg passed in ACTION_STARTUP.
Important NDK structures:
struct DosPacketindos/dosextens.hstruct FileSysStartupMsgindos/filehandler.hstruct DosEnvecindos/filehandler.hstruct IOStdReqinexec/io.h
Current status
fatso is still alpha-quality software: the core FAT/exFAT handler, hybrid RDB automount path, and tools work on the current emulator/hardfile setup, but real-hardware coverage and full Amiga-native filesystem semantics are still pending.
Implemented and tested on the current emulator/hardfile setup:
- Handler process loop and
ACTION_STARTUP - FAT12/16/32 mounting through FatFs
- Small exFAT hardfile mounting through FatFs, tested with a 64 MiB raw exFAT image
- Long filename (LFN) support
- Amiga Latin-1-ish ↔ FatFs CP850 filename and volume label conversion
- Workbench volume integration:
- real
DLT_VOLUMEnode registration - disk icon appears as a normal volume icon
ACTIVATE=1startup behavior- Workbench
Rename...updates and persists the FAT volume label
- real
- File and directory operations:
ACTION_LOCATE_OBJECT,ACTION_FREE_LOCKACTION_COPY_DIR,ACTION_PARENTACTION_EXAMINE_OBJECT,ACTION_EXAMINE_NEXTACTION_FINDINPUT,ACTION_FINDOUTPUT,ACTION_FINDUPDATEACTION_READ,ACTION_WRITE,ACTION_SEEK,ACTION_ENDACTION_CREATE_DIR,ACTION_DELETE_OBJECT,ACTION_RENAME_OBJECTACTION_FLUSH,ACTION_DIE
- Metadata and compatibility packets:
ACTION_INFO/ACTION_DISK_INFOACTION_SET_DATEACTION_SET_PROTECTACTION_SET_FILE_SIZEACTION_SAME_LOCKACTION_FH_FROM_LOCKACTION_COPY_DIR_FHACTION_PARENT_FHACTION_EXAMINE_FH
- FatFs
disk_initialize,disk_status,disk_read,disk_write,disk_ioctl - Classic 32-bit
CMD_READ/CMD_WRITEblock-device path - Partition offset calculation from
DosEnvec MaxTransfersplitting- FatFs volume label get/set support
- Standalone raw-media formatter tool (
fatso-format) using FatFsf_mkfs() - Self-contained hybrid MBR/RDB formatting:
fatso-format ... hybrid YESembedsL:fatsointo an RDBFSHD/LSEGchain for boot-time import/automount - Hybrid/RDB converter tool (
fatso-disco) for adding PC MBR entries to compatible existing RDB FAT/exFAT disks - Experimental handler-side
ACTION_FORMATsupport for AmigaDOSFormat()/Format DRIVE ..., including whole-disk FAT32/exFAT hybrid promotion with embeddedL:fatsoin the RDBFSHD/LSEGchain - Standard AmigaDOS MS-DOS disk type (
ID_MSDOS_DISK,0x4d534400) for Workbench/CrossDOS compatibility - Basic write safety:
- write-protect latch/probe where supported
- dirty tracking
- sync fallback using
CMD_UPDATE/CMD_FLUSH - conservative mutation conflict checks
Known remaining gaps:
- Full validation on real Amiga block devices, removable media, and write-protected media
- Disk-change handling beyond the current basic status/probe behavior
- Bounce buffers for
Mask/memory constraints BufMemType-aware transfer allocation- Optional 64-bit block-device commands (
TD_READ64/TD_WRITE64, NSD/SCSI direct) - exFAT hardening beyond the current small-volume 32-bit-limited FatFs enablement; newly formatted exFAT volumes use the standard Windows/macOS upcase table for better host automount compatibility
- Broader character set/Unicode policy beyond the current Western Latin-1-ish ↔ CP850 mapping
- Full Amiga-native metadata semantics such as file comments, all protection bits, owner/group, links, and record locking
- Boot/install validation for using fatso as a SYS: volume; current hybrid RDB automount support makes this plausible, but it is not yet a supported/released workflow
Hardfile test images
The repository includes raw, non-RDB hardfile images for filesystem regression testing:
| Image | Filesystem | Size | Label | Sectors | HighCyl |
DOSDriver |
|---|---|---|---|---|---|---|
misc/fat12_1440K.hdf |
FAT12 | 1.44 MiB | FAT12TEST |
2880 |
2879 |
misc/DOSDrivers/FAT12 |
misc/fat16_16M.hdf |
FAT16 | 16 MiB | FAT16TEST |
32768 |
32767 |
misc/DOSDrivers/FAT16 |
misc/fat32_64M.hdf |
FAT32 | 64 MiB | FAT32TEST |
131072 |
131071 |
misc/DOSDrivers/FAT32 |
misc/exfat64M.hdf |
exFAT | 64 MiB | EXFAT95 |
131072 |
131071 |
misc/DOSDrivers/EXFAT |
The DOSDriver entries assume the images are attached to an emulator as raw hardfiles on uaehf.device units 0 through 3 respectively. Adjust Device and Unit if your emulator assigns different units. In FS-UAE, beware that uaehf.device unit numbers may be compacted across occupied hardfile slots: leaving an earlier hardfile slot empty can shift later images down to lower unit numbers. If fatso-probe fatfs reports err=218 (ERROR_DEVICE_NOT_MOUNTED), first verify the actual uaehf.device unit with fatso-probe io/fatso-probe fatfs and update the DOSDriver Unit field. The handler derives its initial fallback volume name from the DOSDriver node name, so these can be mounted as FAT12:, FAT16:, FAT32:, and EXFAT: without requiring a FAT0: device. Install them by copying the desired files to DEVS:DOSDrivers/, for example:
Copy misc/DOSDrivers/FAT12 DEVS:DOSDrivers/FAT12
Copy misc/DOSDrivers/FAT16 DEVS:DOSDrivers/FAT16
Copy misc/DOSDrivers/FAT32 DEVS:DOSDrivers/FAT32
Copy misc/DOSDrivers/EXFAT DEVS:DOSDrivers/EXFAT
Mount FAT12:
Mount FAT16:
Mount FAT32:
Mount EXFAT:
Then run targeted tests, for example:
fatso-probe fatfs uaehf.device 0 2880 0 encoding
fatso-probe dostest FAT12:FS_TEST
fatso-probe fatfs uaehf.device 1 32768 0 encoding
fatso-probe dostest FAT16:FS_TEST
fatso-probe fatfs uaehf.device 2 131072 0 encoding
fatso-probe dostest FAT32:FS_TEST
fatso-probe fatfs uaehf.device 3 131072 0 encoding
fatso-probe dostest EXFAT:FS_TEST
misc/fat10M.hdf is the older raw 10MB FAT16 image. On macOS, a raw .hdf needs the raw disk image class when attaching:
hdiutil attach -nomount -imagekey diskimage-class=CRawDiskImage misc/fat10M.hdf
If it needs to be recreated/formatted:
python3 -c 'open("misc/fat10M.hdf", "wb").truncate(10240000)'
hdiutil attach -nomount -imagekey diskimage-class=CRawDiskImage misc/fat10M.hdf
# Suppose it prints /dev/disk4:
diskutil eraseVolume "MS-DOS FAT16" FAT10M /dev/disk4
hdiutil detach /dev/disk4
For emulator testing with the older image, add misc/fat10M.hdf as a raw hardfile and use misc/DOSDrivers/Examples/fatso-hdf.mount.example as the DOSDrivers entry. Adjust Device/Unit to match your emulator, e.g. uaehf.device unit 0.
Probe the hardfile device directly on the Amiga before mounting:
fatso-probe io uaehf.device 0
A valid FAT16 image should show boot-sector bytes beginning with EB 3C 90 ... and contain FAT16 later in the first sector.
To inspect filename encoding behavior through FatFs, run the FatFs probe with the encoding mode. This creates a temporary ENC_TEST directory, writes representative Latin-1 byte names and CP850 byte names, lists the raw bytes FatFs returns, then removes the known probe files and directory:
fatso-probe fatfs uaehf.device 3 20000 0 encoding
Adjust device, unit, sector count, and flags to match the emulator/device under test.
Small exFAT hardfile test image
A 64 MiB raw exFAT hardfile has been tested successfully with fatso-probe fatfs, manual CLI create/read/delete, the manual Workbench checklist, and fatso-probe dostest EXFAT:FS_TEST.
Create and format the image on macOS:
cd /Users/kludge/dev/uhc/fatso
dd if=/dev/zero of=misc/exfat64M.hdf bs=1m count=64
hdiutil attach -nomount -imagekey diskimage-class=CRawDiskImage misc/exfat64M.hdf
# Suppose it prints /dev/disk7:
sudo newfs_exfat -v EXFATTEST /dev/disk7
hdiutil detach /dev/disk7
Add misc/exfat64M.hdf to the emulator as a raw, non-RDB hardfile. For a 512-byte-sector 64 MiB image, use:
sectors = 131072
LowCyl = 0
HighCyl = 131071
Example DOSDriver geometry:
Device = uaehf.device
Unit = 3
Flags = 0
Surfaces = 1
SectorsPerTrack = 1
SectorSize = 512
Reserved = 0
Interleave = 0
LowCyl = 0
HighCyl = 131071
Buffers = 30
BufMemType = 0
Probe before mounting through the handler:
fatso-probe fatfs uaehf.device 3 131072 0 encoding
A successful exFAT probe should report f_mount result=0 and FF_FS_EXFAT=1. Then mount and run a cautious CLI smoke test before Workbench testing:
Mount EXFAT:
List EXFAT:
MakeDir EXFAT:EXFAT_TEST
Echo "hello" >EXFAT:EXFAT_TEST/hello.txt
Type EXFAT:EXFAT_TEST/hello.txt
Delete EXFAT:EXFAT_TEST/hello.txt
Delete EXFAT:EXFAT_TEST
fatso-probe dostest EXFAT:FS_TEST
MBR partition scanning
fatso-probe mbrscan is a read-only helper for inspecting raw media. It opens a block device, reads sector 0, identifies raw FAT/exFAT superfloppy volumes or MBR partition entries, probes each in-bounds partition's first sector for FAT/exFAT, and prints suggested DOSDriver geometry for mounting a partition through the current LowCyl/HighCyl offset mechanism. Add dosdrivers [prefix] to emit MountList-style stanzas named with the selected prefix.
Syntax:
fatso-probe mbrscan <mountname:> [dosdrivers [prefix]]
fatso-probe mbrscan <device> <unit> <sectors> [flags] [dosdrivers [prefix]]
Example:
fatso-probe mbrscan FAT0:
fatso-probe mbrscan uaehf.device 0 8388608
fatso-probe mbrscan uaehf.device 0 8388608 0 dosdrivers FAT
For an MBR partition, it prints geometry like:
Surfaces = 1
SectorsPerTrack = 1
LowCyl = <partition start LBA>
HighCyl = <partition start LBA + partition sectors - 1>
The <mountname:> form resolves the existing DOSDriver/mount entry and scans exactly that configured geometry, including any LowCyl offset. Use the raw <device> <unit> <sectors> form when you want to inspect sector 0 of a whole disk for an MBR.
The handler also has conservative automatic single-partition MBR selection: if a DOSDriver points at a whole disk (LowCyl=0) and sector 0 contains exactly one supported FAT/exFAT MBR partition, fatso verifies that partition's first sector looks like a FAT/exFAT VBR and mounts it automatically. If HighCyl is omitted or left as zero with LowCyl=0, fatso asks the underlying block device for TD_GETGEOMETRY and uses the reported whole-device sector count.
For multi-partition MBR disks, there are two practical options:
- Generate static MountList-style stanzas with
fatso-probe mbrscan ... dosdrivers [prefix], then adapt the desired entries forDEVS:DOSDrivers/or an old-style MountList. - Use the boot-time helper to add live DeviceNodes for all detected FAT/exFAT MBR partitions:
fatso-mount scan uaehf.device [unit|ALL] [sectors] [flags] [prefix]
The scan mode defaults to unit=ALL, sectors=0 (use TD_GETGEOMETRY), flags=0, and prefix=FAT, so a typical startup command can scan all units exposed by the device:
fatso-mount scan uaehf.device
If you know the exact unit, you can still scan only that one:
fatso-mount scan uaehf.device 2 0 0 FAT
This registers L:fatso in FileSystem.resource, scans primary and logical MBR partitions, verifies each candidate VBR as FAT/exFAT, adds device names such as FAT0:, FAT1:, etc., and asks expansion.library to start each added device immediately. This is intentionally similar in spirit to fat95's documented partition-selection approach: fat95 uses DosType=0x46415401, 0x46415402, etc. with LowCyl=0/HighCyl=1 to select FAT partitions from PC partition tables rather than relying on native RDB FSHD import.
Mixed MBR test image
A disposable mixed-partition image can be generated from the existing formatted raw test images:
python3 tools/make_mbr_mixed.py --unit 2
This writes misc/mbr_mixed.hdf with this layout:
| Partition | MBR type | Role | Start LBA | Sectors | Source payload |
|---|---|---|---|---|---|
| 1 | 0x01 |
primary FAT12 | 2048 |
2880 |
misc/fat12_1440K.hdf |
| 2 | 0x06 |
primary FAT16 | 8192 |
32768 |
misc/fat16_16M.hdf |
| 3 | 0x0f |
extended container | 45056 |
264193 |
EBR chain |
| 5 | 0x0c |
logical FAT32 | 45057 |
131072 |
misc/fat32_64M.hdf |
| 6 | 0x07 |
logical exFAT | 178177 |
131072 |
misc/exfat64M.hdf |
It also writes DOSDriver examples under misc/DOSDrivers/MBR/:
MBR12
MBR16
MBR32
MBREXF
Attach misc/mbr_mixed.hdf as a raw hardfile, update the Unit fields if your emulator assigns a different uaehf.device unit, then scan the whole disk:
fatso-probe mbrscan uaehf.device <unit> 311296
The scanner should report both primary partitions and the logical partitions from the EBR chain. You can then use fatso-mount scan for dynamic devices, or adapt generated/static DOSDrivers, mount them, and run targeted tests such as:
Mount MBR12:
Mount MBR16:
Mount MBR32:
Mount MBREXF:
fatso-probe dostest MBR12:FS_TEST
fatso-probe dostest MBR16:FS_TEST
fatso-probe dostest MBR32:FS_TEST
fatso-probe dostest MBREXF:FS_TEST
RDB / hybrid MBR-RDB scanning
fatso-probe rdbscan is a read-only helper for inspecting Amiga RDB-family blocks before attempting hybrid MBR/RDB writes. It scans the first RDB location blocks for RDSK, PART, FSHD, LSEG, and BADB identifiers, verifies block checksums, and traverses the RDB partition list when present.
Syntax:
fatso-probe rdbscan <device> <unit> <sectors> [flags] [scan_blocks]
fatso-probe rdbscan plan-mixed
Examples:
fatso-probe rdbscan uaehf.device 2 311296
fatso-probe rdbscan uaehf.device 2 311296 0 64
fatso-probe rdbscan plan-mixed
For the current MBR-only mixed image, the scan is expected to report no RDB-family blocks. plan-mixed prints the proposed non-destructive hybrid layout plan:
- keep the MBR partition table/signature in sector 0 for PC/Mac detection
- also place
RDSKin the first 256 bytes of block 0 - place the first RDB
PARTat block 1,FSHDat block 2,LSEGchain from block 3, and remainingPARTblocks after theLSEGchain - keep FAT payload partitions at their existing LBA offsets
- use RDB geometry
Surfaces=1,SectorsPerTrack=1, so RDB cylinders map directly to LBAs
This is still planning only. fatso-probe rdbscan does not write any disk blocks.
A disposable hybrid image can be generated on the host:
python3 tools/make_hybrid_mbr_rdb.py
This copies misc/mbr_mixed.hdf to misc/hybrid_mbr_rdb.hdf, keeps the sector-0 MBR partition table/signature, and writes PFS3-style RDB metadata into the reserved area before the first FAT partition:
| Block | RDB block | Purpose |
|---|---|---|
| 0 | RDSK + MBR |
RigidDiskBlock in first 256 bytes; MBR partition table/signature preserved |
| 1 | PART |
first RDB partition, MBR12, FAT12 payload at 2048..4927 |
| 2 | FSHD |
filesystem header for embedded fatso handler |
| 3+ | LSEG |
LoadSeg chain containing build/fatso |
after LSEG |
PART |
remaining RDB partitions: MBR16, MBR32, MBREXF |
The generated RDB uses valid big-endian RDB checksums, embeds the current build/fatso handler binary as an RDB LSEG chain, and leaves all FAT/exFAT payload blocks untouched. The raw .hdf can be attached directly by emulators and by macOS with -imagekey diskimage-class=CRawDiskImage. Windows' built-in image mounter expects VHD/VHDX containers rather than arbitrary raw HDF files; for Windows smoke tests, wrap the raw image in a fixed VHD footer:
python3 tools/make_fixed_vhd.py misc/hybrid_mbr_rdb.hdf misc/hybrid_mbr_rdb.vhd
The .vhd contains the same sector data plus a 512-byte fixed-VHD footer. Build the canonical handler first:
make build/fatso
python3 tools/make_hybrid_mbr_rdb.py
To isolate hybrid-sector behavior from ordinary RDB behavior, generate a plain RDB control image without preserving the sector-0 MBR table/signature:
python3 tools/make_hybrid_mbr_rdb.py --pure-rdb --output misc/rdb_only.hdf
tools/make_hybrid_mbr_rdb.py embeds build/fatso by default. The normal distributed handler is deliberately linked as a single stripped Amiga hunk so the same file can be installed as L:fatso or embedded in an RDB LSEG chain. This matters because some AmigaOS/expansion.library RDB filesystem import paths reject or mishandle multi-hunk images, and may be less tolerant of optional hunk records such as HUNK_SYMBOL, even though LoadSeg() can load them normally. The generated LSEG chain uses full 512-byte, 128-long checksummed blocks with zero padding at the end of the executable, matching conservative RDB filesystem payload practice. The embedded FSHD leaves fhb_FileSysName empty, like the known-working PFS3AIO header, so the import path should treat it as a purely LSEG-backed filesystem. When started from an RDB-loaded DeviceNode with a nonzero dn_SegList, fatso also self-registers that seglist in FileSystem.resource, mirroring the PFS3AIO pattern so later matching RDB partitions can reuse the loaded filesystem. Test it with both scanners:
fatso-probe mbrscan uaehf.device <unit> 311296
fatso-probe rdbscan uaehf.device <unit> 311296
Caveat: the embedded filesystem header and RDB partitions use private DosType = 0x4654534f (FTSO) so AmigaOS should select the embedded fatso FSHD instead of an existing CrossDOS/FileSystem.resource entry for ID_MSDOS_DISK. The RDSK flags are set to the PFS3-style RDBFF_LAST | RDBFF_LASTLUN | RDBFF_LASTTID value, the FSHD uses a full 128-long checksum and PatchFlags = 0x1b0 (StackSize, Priority, SegList, and GlobalVec), and the RDB DosEnvec table size is kept to 16. Once running, the handler still reports ID_MSDOS_DISK for Workbench/CrossDOS-compatible disk identity. This layout is intended for disposable emulator images first; validate automount behavior carefully before using it on real media.
If the generated hybrid image still creates RDB PART DeviceNodes without importing the embedded FTSO filesystem, repeat the same boot test with misc/rdb_only.hdf. If the pure-RDB image imports FTSO but the hybrid one does not, the blocker is the sector-0 MBR/RDB coexistence rather than the handler or FSHD payload. Capture the boot state before running any helper:
fatso-probe fsrestrace
fatso-probe dntrace MBR32:
List MBR32:
Expected successful native RDB automount evidence is an FTSO entry in FileSystem.resource at boot and RDB-created DeviceNodes with the patched handler fields (dn_StackSize, dn_SegList, and dn_GlobalVec) before running fatso-mount. fatso-mount remains the manual workaround: it defaults to L:fatso, DosType=0x4654534f, and ALL, registers the handler in FileSystem.resource, and patches matching existing RDB-created DeviceNodes in one command.
Converting an existing RDB disk to hybrid MBR/RDB
fatso-disco is a small Amiga-side disk converter. It inspects an existing RDB partition chain and, when safe, adds a PC-style MBR primary partition table plus the 0x55aa boot signature to block 0. This can make an RDB-partitioned FAT/exFAT disk visible to PC-side tools without moving any partition payload data.
fatso-disco <device> <unit> <sectors> [flags] [plan]
fatso-disco <device> <unit> <sectors> [flags] write YES
The default mode is a dry-run plan. The write mode requires the final YES argument because it modifies block 0.
The first implementation is deliberately conservative:
- It only writes when the
RDSKblock is block 0. - It refuses layouts whose
RDSKchecksum area overlaps the MBR partition table at bytes446..511. - It refuses to overwrite existing non-matching MBR bytes.
- It supports at most four RDB partitions, because a plain PC MBR has only four primary slots.
- It infers each MBR type from the partition boot sector and currently accepts only FAT12 (
0x01), FAT16 (0x06), FAT32 LBA (0x0c), and exFAT/NTFS-style (0x07).
On a normal RDB disk, block 0 often has unused/reserved space after the checksummed RDB header. If rdb_SummedLongs is the common 64-long value, the checksum covers only bytes 0..255, so the MBR table/signature area can coexist without changing the RDB checksum. fatso-disco checks this before writing.
Formatting test media
fatso-format is a standalone Amiga-side formatter. It uses the same block I/O path as the handler and FatFs f_mkfs(). For initial destructive tests, prefer this tool over Workbench/AmigaDOS Format because it avoids formatting through a live mounted handler.
Layout is controlled independently from filesystem type. By default, whole-disk fat32 and exfat formats create one hybrid MBR/RDB partition and format inside that partition; fat and fat1216 default to raw/superfloppy layout. Add raw or hybrid before the final YES to override the default. In mount-name form, hybrid layout is only allowed when the resolved DOSDriver starts at LowCyl=0 (a raw whole-disk/superfloppy mount). If the mount name already points at a partition (LowCyl>0), formatting defaults to partition-local raw layout.
Syntax:
fatso-format <mountname:> <fat|fat1216|fat32|exfat> <label> [raw|hybrid] YES
fatso-format <device> <unit> <sectors> <fat|fat1216|fat32|exfat> <label> [flags] [raw|hybrid] YES
The final YES argument is required because formatting destroys existing data. In the mount-name form, fatso-format resolves the DOSDriver/mount entry and uses its Device, Unit, Flags, and geometry, so it can be used with names such as FAT0:, FAT1:, PC0:, or PC1: without manually counting emulator units. If a mount entry has LowCyl=0 and omitted/zero HighCyl, fatso-format also uses TD_GETGEOMETRY to discover the whole-device size. This makes the common raw exFAT/FAT32 removable-media case simple: mount the card as EXFAT: or FAT32:, then run fatso-format EXFAT: exfat LABEL YES or fatso-format FAT32: fat32 LABEL YES to convert a raw whole-disk FAT volume into a hybrid MBR/RDB single-partition disk. To keep a raw/superfloppy layout instead, add raw before YES.
Examples matching the checked-in test images:
fatso-format FAT0: fat NEWLABEL YES
fatso-format FAT32: fat32 FAT32TEST YES ; default hybrid on whole-disk FAT32
fatso-format EXFAT: exfat EXFATTEST YES ; default hybrid on whole-disk exFAT
fatso-format FAT32: fat32 FAT32TEST raw YES ; explicit raw/SFD FAT32
fatso-format uaehf.device 0 2880 fat FAT12TEST YES
fatso-format uaehf.device 1 32768 fat FAT16TEST hybrid YES ; hybrid FAT12/FAT16 auto
fatso-format uaehf.device 2 131072 fat32 FAT32TEST YES ; default hybrid MBR/RDB
fatso-format uaehf.device 3 131072 exfat EXFATTEST YES ; default hybrid MBR/RDB
fatso-format uaehf.device 2 131072 fat32 FAT32TEST raw YES ; explicit raw/SFD FAT32
fatso-format uaehf.device 3 131072 exfat EXFATTEST raw YES ; explicit raw/SFD exFAT
Mode behavior:
fat: FAT with automatic FAT12/FAT16/FAT32 selection by FatFs from volume geometry and cluster count. This allows FAT32 when the media is too large for FAT16.fat1216: FAT constrained to FAT12/FAT16 auto-selection.fat32: explicit FAT32.exfat: explicit exFAT.
Layout options:
- default/no option: raw for
fat/fat1216; hybrid for whole-diskfat32/exfat; partition-local raw when formatting an existing partition mount. raw: raw/superfloppy layout, with no MBR/RDB metadata.hybrid: create one MBR/RDB partition starting at LBA 2048, then format inside it. For auto FAT modes,fatso-formatrefreshes the MBR partition type and RDB partition name after formatting once it knows whether FatFs created FAT12, FAT16, or FAT32.
For hybrid formatting, the MBR partition type is 0x01 for FAT12, 0x06 for FAT16, 0x0c for FAT32, and 0x07 for exFAT. The RDB side writes an RDSK, one PART with DosType=0x4654534f (FTSO), and an embedded FSHD/LSEG chain containing L:fatso. This makes the disk self-contained for RDB boot-time import and automounting; it should not require fatso-mount after reboot. Because the handler is embedded from L:fatso, hybrid formatting fails if that file is missing or unreadable, and users should make sure L:fatso is the current canonical fatso binary before formatting. After formatting, the tool mounts the new filesystem through FatFs, sets the label, syncs, remounts, refreshes hybrid metadata if needed, and prints the detected filesystem type.
Validated formatter results on the checked-in test image sizes:
| Command mode / geometry | Detected result |
|---|---|
fat on 2880 sectors |
FAT12 |
fat on 32768 sectors |
FAT16 |
fat32 raw on 131072 sectors |
FAT32 raw/SFD |
exfat raw on 131072 sectors |
exFAT raw/SFD |
fat32 on 131072 sectors, device/unit form |
FAT32 inside hybrid MBR/RDB partition |
exfat on 131072 sectors, device/unit form |
exFAT inside hybrid MBR/RDB partition |
Freshly formatted FAT12/FAT16/FAT32/exFAT images have passed fatso-probe fatfs, List, and fatso-probe dostest. Both the raw device form and the mount-name form, such as fatso-format FAT0: fat TESTVOL YES, have been validated on disposable images.
AmigaDOS Format / handler-side ACTION_FORMAT
The handler also implements experimental ACTION_FORMAT, so AmigaDOS formatting tools can call Format() on a mounted fatso device. If the mounted handler covers a raw whole disk (LowCyl=0) and the selected/preserved format is FAT32 or exFAT, handler-side formatting promotes the media to a single hybrid MBR/RDB partition before formatting. Existing partition mounts remain partition-local. For whole-disk FAT32/exFAT promotion, the handler now reads L:fatso and embeds it into an RDB FSHD/LSEG chain, matching standalone fatso-format ... hybrid YES so the resulting disk is self-contained for RDB boot-time import/automount. Because the live handler reads L:fatso, make sure L:fatso is installed and current before using AmigaDOS Format to create hybrid media. The filesystem type selection is intentionally not based on the public device name (FAT0:, PC0:, etc.):
- If the target already contains a readable exFAT filesystem, handler-side format preserves exFAT.
- FAT targets use FatFs automatic FAT12/FAT16/FAT32 selection from geometry, so FAT32 is selected when the media is too large for FAT16.
- Blank/unreadable media also use FAT12/FAT16/FAT32 auto-selection unless a custom caller passes one of fatso's private format
dostypevalues.
Private dostype values for custom callers are:
FATSO_FORMAT_DOSTYPE_FAT /* 'FAT ' */
FATSO_FORMAT_DOSTYPE_FAT32 /* 'FA32' */
FATSO_FORMAT_DOSTYPE_EXFAT /* 'EXFA' */
The normal Amiga Format command may not expose arbitrary dostype selection for these private values, so fatso-format remains the explicit tool for choosing exFAT on blank media. FAT32 can be selected automatically for large FAT media or explicitly with fatso-format.
Example CLI usage should be through the normal AmigaDOS syntax, such as:
Format DRIVE FAT32: NAME FAT32TEST
Format DRIVE EXFAT: NAME EXFATTEST
Important limitations:
- FAT32/exFAT whole-disk targets are promoted to single-partition hybrid MBR/RDB media with an embedded
L:fatsohandler; existing partition mounts stay partition-local. - The target must not have open files/locks/Workbench windows; the handler returns
ERROR_OBJECT_IN_USEif it sees active user objects. - Start with disposable images and verify afterwards with
fatso-probe fatfs,fatso-probe mbrscan,fatso-probe rdbscan,List, andfatso-probe dostest.
CLI Format DRIVE ... NAME ... and QUICK formatting have been validated on disposable images, including a whole-disk FAT32 hybrid promotion whose RDB FSHD/LSEG chain was checksum-clean and mounted on both AmigaOS and Windows/macOS as an MBR disk.
Charset policy
FatFs is currently configured with:
#define FF_CODE_PAGE 850
#define FF_LFN_UNICODE 0
In this mode, FatFs exposes TCHAR = char API strings using CP850 bytes. Classic AmigaDOS/Workbench strings are treated by fatso as an 8-bit Latin-1-ish character set for the Western European characters commonly used on Amiga systems.
src/charset.c is the single conversion boundary:
- AmigaDOS/Workbench path components and volume labels are converted Latin-1 → CP850 before calling FatFs.
- FatFs directory names and volume labels are converted CP850 → Latin-1 before returning them to AmigaDOS/Workbench.
- ASCII bytes are unchanged.
- Bytes that cannot be mapped are currently preserved as a fallback so unusual existing names remain addressable, but their displayed character may not be semantically correct.
This is intentionally not full Unicode support. FAT LFN stores Unicode internally, but with FF_LFN_UNICODE = 0, FatFs converts through CP850 at the API boundary. Supporting arbitrary Unicode names would require switching FatFs to a Unicode API mode, such as UTF-8, and adding a broader Amiga-side conversion policy.
Mount example
misc/DOSDrivers/Examples/fatso.mount.example is a DOSDrivers-style single-device file. In this format, the device name comes from the filename, so install or rename it as the device name you want, for example:
Copy misc/DOSDrivers/Examples/fatso.mount.example DEVS:DOSDrivers/FAT0
Mount FAT0:
Do not include a leading FAT0: label in a DOSDrivers-style file. That label belongs only in an old multi-entry MountList used via Mount FAT0: FROM some-mountlist.
The examples use DosType = 0x4d534400 (ID_MSDOS_DISK, MSD\0). If you already installed a DOSDriver from an older example, update its DosType too before retesting Workbench icon behavior.
Documentation
docs/fatso.guide is an AmigaGuide manual covering installation, mounting, MBR scanning, formatting, diagnostics, DOSDriver fields, Workbench notes, and troubleshooting. In the release archive it is copied to the archive root as fatso.guide; on AmigaOS, open it with AmigaGuide or MultiView, for example:
MultiView fatso.guide
Workbench .info sidecar icons are included for docs/fatso.guide and the mount examples. The source tree keeps the fatso-mount.info Tool icon in icons/; the release archive installs it as C/fatso-mount.info. Edit its Tool Types with Workbench Information... to configure MODE, DEVICE, UNIT, SECTORS, FLAGS, PREFIX, or HANDLER for Workbench-launched scans.
Installing from a release archive
The Amiga release archive is dist/fatso-<version>.lha. It contains fatso.guide, Install-fatso, L/fatso, C/fatso-format, C/fatso-probe, C/fatso-mount, C/fatso-disco, Workbench icons, and example DOSDrivers/ entries. The archive also includes a drawer icon for the extracted fatso-<version> folder.
On AmigaOS, extract the archive and enter the drawer:
lha x fatso-0.1-alpha4.lha RAM:
CD RAM:fatso-0.1-alpha4
The included AmigaDOS script installs the core handler and tools:
Execute Install-fatso
By default it copies only L/fatso and the C: tools. DOSDrivers are site-specific and may auto-mount devices on the next boot, so they are optional. For most MBR disks you can skip static DOSDrivers and use fatso-mount scan instead:
Execute Install-fatso DOSDRIVERS ; also copy raw/superfloppy DOSDrivers
Execute Install-fatso DOSDRIVERS MBR ; also copy MBR DOSDrivers
Manual core install is simply:
Copy L/#? L:
Copy C/#? C:
Then copy only the DOSDrivers you actually want to DEVS:DOSDrivers/ or keep them in Storage/DOSDrivers/ and mount manually.
Versioning and release archive
The package version is kept in VERSION and is embedded into the handler/tools at build time. The command-line tools accept version or --version.
Maintainers can build an Amiga release archive with:
make release
Building from source
End users should normally install from a release archive. The source tree is useful for development, rebuilding tools, and generating test images.
The source repository is:
git clone https://git.uhc.fyi/UHC/fatso.git
cd fatso
The Makefile assumes vbcc is installed at /opt/vbcc and uses the +aos68k config. For a clean rebuild of the handler and Amiga-side tools:
make clean all
make debug performs a safe clean rebuild of the same handler/tools without enabling handler-side DOS file logging. Do not enable DOS-file logging for normal Workbench testing: writing SYS:fatso.log from inside packet handling can reenter DOS and make Workbench rename/delete paths crash.
There is an explicit unsafe diagnostic target for narrow CLI/emulator experiments only:
make unsafe-log
The Makefile honors VBCC, NDK32_INC, NDK32_ROOT, and NDK32_LIB if they are set. It also allows lower-level overrides such as VC, VLINK, VBCCLIB, NDKLIB, and CFLAGS. NDK32_ROOT is used by make release for the stock Workbench icons and defaults to the parent of NDK32_INC.
On a POSIX build host, for example:
export VBCC=/opt/vbcc
export NDK32_ROOT=/opt/vbcc/NDK/NDK3.2
export NDK32_INC=/opt/vbcc/NDK/NDK3.2/include_h
export NDK32_LIB=/opt/vbcc/NDK/NDK3.2/lib
On an Amiga/native build setup, the same variables can use Amiga paths, for example:
setenv VBCC Work:Dev/VBCC
setenv NDK32_ROOT Work:Dev/NDK/NDK3.2
setenv NDK32_INC Work:Dev/NDK/NDK3.2/include_h
setenv NDK32_LIB Work:Dev/NDK/NDK3.2/lib
The default build enables vbcc -warnings-as-errors, so compiler warnings are treated as build failures. It uses -O1 -size because that currently produces smaller handler/tool binaries than -O2 with vbcc while preserving the RDB-safe single stripped hunk shape for build/fatso. The Makefile intentionally does not use vbcc -ansi because the Amiga NDK inline prototype headers rely on vbcc-specific extensions such as __reg().
The FatFs configuration is also size/memory oriented while keeping write, exFAT, LFN, label, protection/date, and formatting support enabled: LFN work buffers are allocated on the handler stack (FF_USE_LFN=2), and file data uses the shared FatFs sector window (FF_FS_TINY=1) instead of a private 512-byte buffer per open file.
Amiga-side diagnostics and regression tests
fatso-probe contains the Amiga-side diagnostic and regression helpers:
fatso-probe io ; low-level OpenDevice/CMD_READ probe
fatso-probe fatfs ; FatFs mount/encoding probe
fatso-probe mbrscan ; raw/VBR/MBR scanner
fatso-probe rdbscan ; RDB/PART/FSHD/LSEG scanner
fatso-probe dntrace ; inspect a DOS DeviceNode
fatso-probe fsrestrace ; inspect FileSystem.resource
fatso-probe dostest ; AmigaDOS filesystem regression tests
fatso-probe wbtrace ; Workbench-style lock/rename trace
fatso-probe voltrace ; inspect DOS volume list
fatso-probe dostest is an AmigaDOS regression test subcommand built into build/fatso-probe.
Typical emulator workflow:
Copy build/fatso L:fatso
Copy build/fatso-format C:fatso-format
Copy build/fatso-mount C:fatso-mount
Copy build/fatso-probe C:fatso-probe
Mount FAT0:
fatso-probe dostest
The default test suite covers:
- create/read/delete with ASCII and accented filenames
- LFN display and lookup
- accented rename
- directory create/rename/delete, including nested files
- replace with shorter content
- seek overwrite and append
- large chunked binary write/read
MODE_READWRITEcreate/updateSetFileSize()truncate/extend behaviorSetFileDate()SetProtection()Flush()- compatibility helpers/packets:
SameLock()plus directACTION_SAME_LOCKExamineFH()DupLockFromFH()ParentOfFH()OpenFromLock()NameFromLock()NameFromFH()
- negative/error cases:
- missing file open/lock/delete
- protected file update/replace rejection
- directory-as-file rejection
- non-empty directory deletion rejection
- rename-over-existing rejection
- too-long path rejection
Persistence test mode:
fatso-probe dostest persist-create
; reboot or remount the volume
fatso-probe dostest persist-check
fatso replies to ACTION_SAME_LOCK using the compatibility values needed for public SameLock() to match the documented LOCK_SAME / LOCK_SAME_VOLUME behavior on the tested AmigaOS 2.x Workbench path.
Manual Workbench checklist
After installing the handler and DOSDriver:
- Boot with
ACTIVATE = 1and confirm the volume icon appears without first accessingFAT0:from Shell. - Open the disk icon from Workbench.
- Create, rename, and delete a drawer/file from Workbench if desired.
- Use Workbench
Rename...on the disk icon and confirm:- the icon label updates
- the new label persists after reboot/remount
- Confirm no placeholder
FAT0:MSD\0icon appears.
Known Workbench caveat: renaming the disk icon while its volume window is open changes and persists the FAT/exFAT label, but the open window may close when the new volume name takes effect. FFS keeps the window open and retitles it; this remains a known integration difference rather than a data-correctness failure.
exFAT status and plan
FatFs exFAT support is enabled for small-volume experiments. fatso's formatter uses the standard compressed exFAT upcase table (5836 bytes, checksum 0xe619d30d) because macOS and Windows are stricter about this during automount than FatFs' default generated table.
FatFs configuration:
#define FF_FS_EXFAT 1
#define FF_LBA64 0
Current validation covers a 64 MiB raw exFAT hardfile on uaehf.device with:
fatso-probe fatfs uaehf.device 3 131072 0 encoding- manual CLI create/read/delete
- the same manual Workbench create/rename/delete behavior observed on FAT12/16/32
fatso-probe dostest EXFAT:FS_TESTpassing withALL TESTS PASSED
This support is intentionally limited to exFAT images/devices that fit within the existing classic 32-bit Amiga block I/O path. Larger media will need a separate 64-bit I/O strategy, likely involving TD_READ64/TD_WRITE64, NSD, or SCSI-direct style commands depending on the device.
Classic AmigaDOS 2.x packet APIs still expose many file sizes, offsets, and disk block counts as 32-bit LONG. fatso now clamps public metadata where possible and rejects file offsets/sizes or classic CMD_READ/CMD_WRITE byte offsets that would overflow current 32-bit assumptions, but large exFAT files/volumes still need fuller policy, tests, and 64-bit I/O before large-media behavior should be considered supported.