OS 3.2 File System and Handler Changes

AmigaOS 3.1.4 and 3.2 reworked almost every ROM handler: the FastFileSystem gained long file names and a new set of mount flags, the RAM-Handler learned "external links", the CON-Handler got a third input mode and lost its history packets, the CD file system picked up HFS/UDF and ACTION_SAME_LOCK, and dos.library changed how handler stacks are sized. This article collects the changes from the NDK 3.2 release notes that matter to programmers who write handlers, disk tools, installers or programs that talk to these handlers directly.

Version numbers below are the handler's own (FFS 45.x/46.x = 3.1.4 project, 47.x = 3.2 project), as given in the release notes.

FastFileSystem

Long file names: DOS\6 and DOS\7

FFS V45.19 added experimental long file name support ("up to 54 characters"). FFS V46.1 replaced it with two new DOS types that store long names "in OFS and FFS fashion with separate extension blocks in case the combined length of filename and comment grow too large":

Constant (dos/dos.h) Value ASCII Meaning
ID_LONG_DOS_DISK 3.2+ 0x444F5306 DOS\6 OFS-style data blocks, long file names
ID_LONG_FFS_DISK 3.2+ 0x444F5307 DOS\7 FFS-style data blocks, long file names
ID_COMPLONG_FFS_DISK 3.2+ 0x444F5308 DOS\8 defined in dos/dos.h; the earlier long-name variant that HDToolBox 46.1, Format 46.1 and FileSystem.resource 46.1 replaced by DOS\6/DOS\7

The 2024 RKM dates the long-name flavours differently: DOS\6/DOS\7 were "introduced in version 45 of AmigaDOS", and the 54-character DOS\8 variant "was already introduced in AmigaDOS 43" but "never officially announced" and is still experimental. DOS\8 keeps the classic block layout and stores the extra name characters in two spare header fields, so older FFS versions can still read such disks (without seeing the long names); DOS\6/DOS\7 use a new header layout. Both are documented in AmigaDOS Filesystem On-Disk Structures.

Note: the NDK 3.2 FastFileSystem release notes give FFS 45.19 for the experimental 54-character names and FFS 46.1 for DOS\6/DOS\7.

Rules and gotchas from the release notes:

  • Volume labels stay at 30 characters. FFS 46.6: "volume labels are still limited to 30 characters, not the full file name size as the administration is somewhat different in the root block." Relabel 47.2 enforces the same 30-character limit.
  • Long names imply international mode and no directory cache. Format 46.8: "Long file names always imply no directory cache and international mode."
  • Format only offers long names on FFS ≥ V46. Format checks the version of any file system that claims to be FFS (through FileSystem.resource since 46.12); if the version is ≥ 46 it assumes DOS\6/DOS\7 work, otherwise the option is greyed out or fails on the command line.
  • ACTION_FORMAT on long-name volumes no longer writes directory-cache information (FFS 46.15).
  • fib_FileName in struct FileInfoBlock is 108 bytes; programs that copy names into 30- or 32-byte buffers break on these volumes (List 45.4 was fixed for exactly this: "no longer crashes on file names longer than 32 characters").
  • icon.library V47 added BumpRevisionLength() with an output buffer size "to allow long file names" and no longer overwrites an existing file if the file system truncates an over-long name.

Detecting the volume type from a program is a plain Info() call. This works only for the FFS: id_DiskType is not meant to be the DOS type. That the FFS reports its flavour there is, in the words of the RKM, a "historical error"; other file systems should report ID_DOS_DISK, so the test below says nothing about non-FFS volumes.

#include <exec/memory.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <proto/dos.h>

/* Returns TRUE if the volume holding 'lock' uses long file names. */
BOOL IsLongNameVolume(BPTR lock)
{
    struct InfoData *id;
    BOOL result = FALSE;

    /* InfoData must be longword aligned: allocate it */
    if ((id = AllocVec(sizeof(struct InfoData), MEMF_PUBLIC)) != NULL)
    {
        if (Info(lock, id))
        {
            result = (id->id_DiskType == ID_LONG_DOS_DISK ||
                      id->id_DiskType == ID_LONG_FFS_DISK);
        }
        FreeVec(id);
    }
    return result;
}

Interleave flags: ENVF_SCSIDIRECT, ENVF_SUPERFLOPPY, ENVF_DISABLENSD

Since 3.1.4 the upper 16 bits of de_Interleave (DE_INTERLEAVE, index 8 of the environment vector) carry flags. They are defined in dos/filehandler.h:

/*
** Starting with release 3.1.4, the upper 16 bits of the
** DE_INTERLEAVE entry contain the following additional flags:
*/
#define ENVF_SCSIDIRECT  (1L << 16)   /* Use HD_SCSICMD instead of TD_READ/TD_READ64 */
#define ENVF_SUPERFLOPPY (1L << 17)   /* Request device geometry by TD_GETGEOMETRY or HD_SCSICMD, DE_LOWCYL must be 0 */
#define ENVF_DISABLENSD  (1L << 18)   /* Do not query for NSD */
Bit Name Mountlist Interleave Effect (FFS release notes)
16 ENVF_SCSIDIRECT 0x10000 Read/write sectors through HD_SCSICMD. Replaces the 3.9 method of setting bit 7 of the DOS type (e.g. 0x444F5383), which FFS 45.18 phased out. With SCSI direct the tens digit of the unit number addresses the LUN. SCSI mode-page geometry parsing is only used when this bit is set (46.12).
17 ENVF_SUPERFLOPPY 0x20000 Superfloppy: FFS queries the device geometry itself. LowCyl must be 0.
18 ENVF_DISABLENSD 0x40000 Skip the "potentially dangerous" NSDCMD_QUERY and go straight to TD64.

Bits can be combined (Interleave = 0x30000 = SCSI direct + superfloppy). The lower 16 bits keep their old meaning.

The older way of requesting automatic geometry — LowCyl = 0 together with Surfaces = 0 (FFS 45.2) — "still works but should probably remain undocumented" according to FFS 45.18. It needs a device that supports TD_GETGEOMETRY; until a disk is recognised FFS uses two surfaces internally.

Other device-level behaviour:

  • If a partition lies beyond 4 GB and NSD64 detection fails, FFS falls back to TD64 commands (45.2).
  • FFS 45.3 first tries HD_SCSICMD to identify removable media and read their capacity, then falls back to TD_GETGEOMETRY.
  • Device names treated as trackdisk-like (safe for TD_GETGEOMETRY) include trackfile.device since FFS 47.4. The RKM itself names only trackdisk.device and carddisk.device as the devices for which the FFS always reads the geometry; for any other device set SuperFloppy.

The CD file system follows the same 3.1.4 conventions: CDFS 45.1 "speaks now NSD, TD64 and DirectSCSI ... and accepts the mount list entries that switch between the various modes", and honours MaxTransfer, Mask and BufMemType.

Reading the flags of a mounted device

The environment vector is reachable from the device entry in the DOS list. dol_Startup is not always a FileSysStartupMsg: MountInfo 47.2 notes that it now "checks if it contains a small integer rather than what could be a valid BCPL pointer", because non-disk handlers store small values there. The example below rejects zero and anything that does not point into RAM (TypeOfMem()), copies what it needs while the list is locked, and prints only after UnLockDosList().

#include <exec/memory.h>
#include <dos/dosextens.h>
#include <dos/filehandler.h>
#include <proto/exec.h>
#include <proto/dos.h>

#define MAXDEV 32

struct DevInfo {
    char  name[32];
    ULONG dostype;
    ULONG interleave;
};

int main(void)
{
    struct DevInfo info[MAXDEV];
    struct DosList *dl;
    ULONG flags = LDF_DEVICES | LDF_READ;
    LONG n = 0, i;

    dl = LockDosList(flags);
    while (n < MAXDEV && (dl = NextDosEntry(dl, flags)) != NULL)
    {
        ULONG startup = dl->dol_misc.dol_handler.dol_Startup;
        struct FileSysStartupMsg *fssm;
        struct DosEnvec *de;
        UBYTE *bname;

        if (startup == 0 || TypeOfMem(BADDR(startup)) == 0)
            continue;                          /* not a FileSysStartupMsg */
        fssm = (struct FileSysStartupMsg *)BADDR(startup);
        if (fssm->fssm_Environ == 0 || TypeOfMem(BADDR(fssm->fssm_Environ)) == 0)
            continue;
        de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
        if (de->de_TableSize < DE_DOSTYPE)
            continue;                          /* too short to hold a DosType */

        bname = (UBYTE *)BADDR(dl->dol_Name);  /* BSTR: length byte + chars */
        i = bname[0] < 31 ? bname[0] : 31;
        CopyMem(bname + 1, info[n].name, i);
        info[n].name[i] = '\0';
        info[n].dostype    = de->de_DosType;
        info[n].interleave = de->de_Interleave;
        n++;
    }
    UnLockDosList(flags);

    for (i = 0; i < n; i++)
    {
        Printf("%s: DosType 0x%08lx%s%s%s\n", info[i].name, info[i].dostype,
               (info[i].interleave & ENVF_SCSIDIRECT)  ? " SCSIDIRECT"  : "",
               (info[i].interleave & ENVF_SUPERFLOPPY) ? " SUPERFLOPPY" : "",
               (info[i].interleave & ENVF_DISABLENSD)  ? " DISABLENSD"  : "");
    }
    return 0;
}

ACTION_DIE

ACTION_DIE (5, dos/dosextens.h) is implemented by FFS 47.2 "to safely shut down a file system", which also fixes a leak when file system creation failed. The release note adds a warning: this "requires a new workbench as the current one will deadlock in case a device is removed that was present at its creation." CDFS supports ACTION_DIE since 45.1.

Self-installation and GlobVec

  • FFS 46.3 installs itself into FileSystem.resource if the hard disk controller has not done so, "so once loaded, it becomes immediately available to all other devices." Modifying the resource is Forbid()-protected (46.5).
  • FFS 46.3 runs with both GlobVec = 0 (BCPL) and GlobVec = -1 (C); 46.4 made the seglist in FileSystem.resource independent of BCPL vs C startup.
  • FFS 46.20 changed its patch flags "to also include a larger stack size, and to signal a C type mount."
  • system-startup 47.3: "In case a later version of the FastFileSystem is found on disk, it also replaces the root file system."

Behaviour changes that affect programs

Version Change
45.20 ACTION_READ_LINK reworked: honours the target buffer size, inserts the volume name for a leading :, no double slash for trailing /, errors instead of crashing on paths > 256 characters.
45.21 ExAll/Examine/ExNext no longer return garbage in fib_Comment for the root. ACTION_SET_COMMENT on a hard link now sets the link's own comment.
46.2 ACTION_SET_DATE works on the root directory.
46.16 The startup packet is replied only after the volume has been restarted, delaying other file systems on the same drive.
47.3 ExNext()/ExAll() on the zero lock (lock = 0) now fail instead of causing hits.

Further version notes from the 2024 RKM:

  • Soft links did not work correctly in the FFS before version 45.
  • FIBB_HOLD (the h protection bit) was introduced in V36, removed from the sources in V40 for ROM space, and reintroduced in V45.
  • ReadLink() buffer overflow: the FFS returns 0 in versions 46 and below and −1 in version 47, instead of the documented −2; FFS 46 and below also return 0 for other errors. Treat 0 and all negative results as failure.
  • ACTION_SET_OWNER is supported by the FFS since version 43.
  • ACTION_FLUSH was replied immediately (a write barrier only) up to FFS 40 and waits for the data to reach the medium since version 43.
  • The FFS never checks the length of a soft-link target and corrupts the volume if it is too long for the link block.

RAM-Handler

RAM-Handler 47.1 supports external links — links from RAM: to objects on other file systems. When such a link is resolved, RAM: "either creates a directory within RAM: if such a directory exists on the link target, or pulls the target file into the RAM-Disk transparently." The motivating use is lazy mirroring of ENVARC::

MakeLink RAM:ENV to ENVARC: Force
Assign ENV: RAM:ENV

Only files that the system actually asks for are copied into RAM:, not the whole of ENVARC:.

To keep a deleted variable from being re-fetched from ENVARC:, dos.library 47.20 leaves "an unreadable dummy file in ENV:" when a variable is deleted; $?var and $var handle this correctly.

RAM-Handler limitations (RKM)

  • No ACTION_SET_OWNER, and no console packets.
  • It is not a file and not registered in FileSystem.resource, so it cannot be mounted from a mountlist; it ignores its startup value (0).
  • RAD: is not the RAM-Handler: it is the FFS running on ramdrive.device, which presents part of RAM as a pre-formatted FFS block device.
  • Before version 45, id_NumBlocks was 0 and id_NumBlocksUsed meaningless — guard percentage calculations against division by zero.
  • ChangeMode(CHANGE_FH, ...) does not interpret the new mode correctly.
  • It accepts C1 control characters (0x80–0x9F) in names (probably by mistake); the FFS accepts no control characters.
  • Soft links whose first (directory) component is itself a soft link do not resolve correctly, even in the latest version.
  • ACTION_READ_LINK on a path without a soft link fails with ERROR_OBJECT_WRONG_TYPE instead of ERROR_OBJECT_NOT_FOUND.

Other RAM: changes

Version Change
45.2 / 45.5 ACTION_DISK_INFO reports total available RAM (with a 32K safety margin) and includes structure overhead.
45.4 Hard links can carry their own file note; delete-protected links can no longer be deleted; ACTION_EXAMINE_ALL follows links for protection, date and size.
47.3 Lock() silently treats any mode other than EXCLUSIVE_LOCK as SHARED_LOCK.
47.3 Truncation of partially used blocks extended from the first block to the last block of a file.
47.3 ACTION_SET_FILESIZE fails on write-protected files.
47.6 ExNext()/ExAll() on the zero lock no longer cause hits.
47.7 SetFileSize() that extends a file leaves the file position untouched.

CON-Handler

Medium mode: SetMode(fh, 2)

Besides raw (1) and cooked (0), con-handler 47.1 supports medium mode, activated with SetMode(fh, 2). The dos.library autodoc describes it as "the medium mode within which TAB and history functions create immediate CSI sequences, but lines are buffered." The release note: "the console sends CSI sequences upon the current user input on TAB, Shift+TAB and the up and down arrows. The V47 shell uses these sequences to handle the history and the tab expansion itself."

Shell 47.1 receives TAB as a CSI cmd;len;pos U sequence. The RKM calls it the TAB Report:

CSI <m>;<s>;<c>U<line>

CSI is 0x9B; <s> is the length of the line being edited and <c> the 1-based cursor position in it (both ASCII decimal), and <line> is a copy of that line. <m> names the key and the requested function:

Key <m> Shell function
Cursor up 2 Previous history line
Cursor down 3 Next history line
Shift+Cursor up 4 Search history upwards
Shift+Cursor down 5 Search history downwards
Ctrl+R 6 Search history upwards using only the text left of the cursor
Ctrl+B 10 Rewind history
TAB 12 Next expansion
Shift+TAB 13 Previous expansion

Other values are reserved. The Shell answers by typing the result back into the console with ACTION_FORCE. Before it runs a command it switches the console back to cooked mode, and re-enables medium mode afterwards — so the V47 Shell also works in a RAW: window. See Interactive Files and Handler Detection for SetMode() usage and ROM Handlers: CON, Port, Queue and RAM for the full key tables.

Removed packets

con-handler 47.1 removed packets that were never usable:

Packet Reason given in release note
ACTION_GET_VARS Returned pointers into the BCPL global vector / BSS of the console, which "is changing and will continue to change".
ACTION_REPLACE, ACTION_PEEK "were not compiled in and their purpose was unclear."
ACTION_SIZE_HIST, ACTION_SET_HIST, ACTION_GET_HIST Never compiled in. All history functions removed: "Managing the history is now the job of the shell."

ACTION_UNDISK_INFO and ACTION_DISK_INFO

Before 47.1, an ACTION_DISK_INFO sent to a console disabled its AUTO behaviour for good. con-handler 47.1 adds ACTION_UNDISK_INFO (513, dos/dosextens.h) "to restore the auto-feature of the console." Since 47.3 ACTION_DISK_INFO forces the window open and can therefore always return the IO pointer; since 47.13 it clears id_VolumeNode if there is no window or the console is an AUX: console.

ACTION_WAIT_CHAR fixes

ACTION_WAIT_CHAR (20; called ACTION_WAIT_FOR_CHAR in the notes) was fixed in 47.1: several pending packets no longer confuse the console; the secondary result is the number of buffered lines (now counting paste and STACK/QUEUE buffers); EOF returns 0 instead of 1; the packet returns early with 1 when lines are waiting in the paste or stack buffer.

Other CON: changes

  • The CSI/ESC parser was rewritten; ESC [ is accepted as a CSI replacement in input (needed when the input is not console.device). Vertical cursor moves by more than one unit are still unsupported.
  • Errors from the output device are forwarded to the requester of the packet.
  • ACTION_FORCE, ACTION_QUEUE and ACTION_STACK now open the AUTO window.
  • Switching from RAW to cooked mode re-enables the close-gadget event.
  • On non-console output devices, \n → \r\n conversion no longer modifies the caller's buffer (which may be in ROM).
  • \/ and \\ escape / and \ in the window title (47.6).
  • ICONIFY in the path adds an iconify gadget; needs ConClip V47 (47.8). AppWindow drops need ConClip 47.3 (47.16).
  • A window without coordinates opens under the mouse pointer (47.15).
  • con-handler can replace aux-handler (47.2). aux-handler 47.1 is now a stub that forwards to the con-handler segment from the DOS resident list (47.2). The RKM documents the resulting AUX: path options (AUX:baud/control/RAW/UNIT n/AUTO/WAIT) and mountlist keys in ROM Handlers: CON, Port, Queue and RAM.
  • ACTION_FORCE existed since V36 but put the characters into the wrong (output) buffer; it works as intended only since V47.

Port-Handler and Queue-Handler

The RKM documents two more handler upgrades from the 3.1.4/3.2 projects:

  • Port-Handler V45 (SER:, PAR:, PRT:): accepts options in the path — BAUD, CONTROL, NOWAIT and UNIT for SER:, UNIT for PAR:, TRANSPARENT, RAW and UNIT for PRT: — can be mounted with EHandler on third-party devices (with Baud and Control defaults; the Baud keyword since V43), uses NSCMD_DEVICEQUERY to tell serial-, parallel- and printer-like devices apart, and supports WaitForChar(). It still needs GlobVec = 0.
  • Queue-Handler (PIPE:): the path PIPE:name/quantum/buffers sets the block size (default 1024 bytes) and the number of blocks before the writer blocks (default 8; 0 = fill memory up to a 64K safety margin). The empty name PIPE: is the anonymous pipe (V45), which attaches to the pipe already on the process's standard input or output. Since V47 the ROM mounts PIPE: at startup.

Details and mountlist examples: ROM Handlers: CON, Port, Queue and RAM.

CD File System

CDFS was reset to version 45 in 3.1.4 and continued as 47.x in 3.2.

Version Change
45.1 ACTION_DIE supported. Accepts GlobVec = 0. NSD, TD64 and DirectSCSI. Honours MaxTransfer, Mask, BufMemType. Exclusive locks work. 2K stack sufficient. Seeking in files > 2 GB.
45.8 UDF support (mostly DVD-ROM) re-enabled with asynchronous I/O and prefetch.
45.16 / 47.25 DOS type changed to CD0\1 (45.16) "to avoid conflicts with other implementations"; 47.25 changed the signature "consistently back to CD01" and identifies its own locks by a magic number instead.
47.1 HFS support re-enabled; HFS+ still missing.
47.2 ExNext() on the zero lock no longer causes hits.
47.7 ACTION_SAME_LOCK (40) supported. Lock modes other than SHARED_LOCK/EXCLUSIVE_LOCK produce a shared lock. ACTION_INFO with a zero lock still needs a medium, unlike ACTION_DISK_INFO.
47.8 ACTION_EXAMINE zeroes the FileInfoBlock provided, so reserved fields no longer contain random data. HFS/HFS+/UDF ExNext on the zero lock returns ERROR_NO_MORE_ENTRIES.
47.9 HFS names mapped through Mac Roman → ISO 8859-1 (unmappable → _); HFS dates come from "last modified".
47.13 HFS+ enabled; names longer than 107 characters on HFS+/UDF/Joliet noted as truncated on ExNext().
47.20 HFS+ disabled again after crashes on test discs.
47.24 The coroutine stack size is inherited from the mount file settings.

With ACTION_SAME_LOCK in place, SameLock() works on CD volumes:

LONG r = SameLock(lock1, lock2);  /* LOCK_SAME, LOCK_SAME_VOLUME or LOCK_DIFFERENT */

CDFS maintains its own FileSystem.resource entry named CDFileSystem; version information is in fse_Version (47.16), and the entry reuses the segment list, stack size and priority from the device node (47.11, 47.21).

dos.library and handler stacks

FRead()/FWrite() bursts

dos 47.2: the BCPL-inherited FRead() and FWrite() "were terribly slow as they went through the low-level I/O byte per byte." They now read whole blocks and try to burst, going directly to the DOS virtual file system. 47.11 inlined more of the buffered put/get code, and the *Printf family is buffered since 47.23.

Stack size units

The dn_StackSize / mountlist StackSize value has different units depending on the handler type:

Handler type GlobVec Stack unit
BCPL-style 0 or −3 (DOS builds a global vector), > 0 (custom vector) LONGs
C-style −1 or −2 BYTEs

The RKM's table 8.2 adds that −1 and 0 keep the device list locked exclusively while the handler starts, −2 and −3 only shared; see IFF Format and Mountlist Reference.

The NDK's DAControl/mount_floppy_file.c shows the consequence when building a DeviceNode by hand for the ROM file system segment (rn_FileHandlerSegment): it uses dn_GlobalVec = 0 with dn_StackSize = 600 ("Number of 32 bit words"), and warns that dn_GlobVec = -1 with dn_StackSize = 2400 "will crash it because this will force the 'C' interface for the file system to be used (which isn't there)."

dos 47.6 (and system-startup 47.5) fixed the default stack patch, which used "512" regardless of unit and left C-style handlers with very tight stacks. SetPatch 45.19 fixed the same mistake in its handler stack check for the Port-Handler. dos 47.1 increased the default stack for CON:, RAW:, PRT:, SER:, PAR:, RAM: and the FFS. HDToolBox 46.23 fills in a larger default stack for new file systems, as "the default stack size of 600 bytes is probably a bit too low."

dos 47.7: "When mounting handlers, the handler segment is now scanned for the magic $STACK cookie, and the stack size is adjusted accordingly." The same scanner is exported as ScanStackToken() (V47, LVO −1158), which returns the maximum of the passed default and all $STACK: tokens in the segment list:

/* In the handler source */
static const char stackcookie[] = "$STACK: 8192\n";

/* In a program that loads and starts a handler or command itself */
LONG stack = ScanStackToken(seglist, 4096);   /* bytes */

See Hunk Version and Stack Cookies for the cookie format.

Other dos changes relevant to handler writers

  • ExAll() passes the file system task in A2 (47.1).
  • dos 47.9 no longer mounts boot nodes itself; system-startup does. dos requesters open intuition.library instead of using the GlobVec copy, so Intuition can be replaced.
  • dos 47.14 fixed a 20-byte leak when a BCPL-style handler exits.
  • VolumeRequestHook() (47.4) lets an external program answer "Please insert volume" requests — see OS 3.2 Shell Commands.

See Also


Sources: NDK 3.2 R4 ReleaseNotes/FastFileSystem-RelNotes, ram-handler-RelNotes, con-handler-RelNotes, aux-handler-RelNotes, CDFS-RelNotes, DOS-RelNotes, system-startup-RelNotes, SetPatch-RelNotes, Format-RelNotes, HDToolBox-RelNotes, filesysres-RelNotes, MountInfo-RelNotes, Relabel-RelNotes, List-RelNotes, icon-RelNotes, shell-RelNotes; Include_H/dos/dos.h, dos/dosextens.h, dos/filehandler.h; Autodocs/dos.doc (SetMode, ScanStackToken); SFD/dos_lib.sfd; Include_I/lvo/dos_lib.i; DAControl+trackfile/DAControl/mount_floppy_file.c Thomas Richter, Amiga ROM Kernel Reference Manual: AmigaDOS (2024, v1.27), §6.1.6 (p. 60), §6.3 (pp. 63–66), §7.1 (p. 71), §7.4 (pp. 84–88), §8.1.3 (pp. 104–107), §13.2–13.6 (pp. 220–253), §14.9.4 (p. 307) Updated: 2026-11-13