Volume Administration

A handful of dos.library functions act on a file system or volume as a whole rather than on single files: Info() reports the state and capacity of a volume, and the V36 functions AddBuffers(), Relabel(), Format() and Inhibit() change the buffer count, rename the volume, write an empty file system structure and block the file system from touching its medium. A few further volume operations exist only as packets: ACTION_DISK_INFO, ACTION_SERIALIZE_DISK and ACTION_WRITE_PROTECT.

All of these are thin wrappers around packets, and each has its own traps: InfoData fields that lie, return values that differ from the autodoc, and the ambiguity of volume names. This page collects them.

Info() and the InfoData structure

BOOL Info(BPTR lock, struct InfoData *parameterBlock);

lock is a lock on any object of the volume; it only identifies the volume. The InfoData must be longword-aligned (allocate it with AllocVec() or use the D_S() alignment macro; there is no AllocDosObject() type for it). Info() returns non-zero on success; IoErr() is then undefined. On failure it returns 0 with an error code in IoErr().

struct InfoData {               /* dos/dos.h */
    LONG id_NumSoftErrors;
    LONG id_UnitNumber;
    LONG id_DiskState;
    LONG id_NumBlocks;
    LONG id_NumBlocksUsed;
    LONG id_BytesPerBlock;
    LONG id_DiskType;
    BPTR id_VolumeNode;
    LONG id_InUse;
};
Field Meaning and caveats
id_NumSoftErrors Read/write errors seen by the file system during its lifetime, not tied to the current medium
id_UnitNumber Unit number of the underlying exec device
id_DiskState See disk states
id_NumBlocks Total blocks (free + used). Not constant: the RAM-Handler adjusts it to available memory, and RAM-Handler versions before 45 report 0. Guard against division by zero
id_NumBlocksUsed Blocks in use. Includes file system overhead, so it cannot tell you whether a file will fit. Garbage on pre-45 RAM-Handlers and while the volume is validating
id_BytesPerBlock Payload bytes per block, not necessarily the physical sector size (OFS blocks carry headers, for example)
id_DiskType See disk types. Not the DOSTYPE of the mountlist
id_VolumeNode BPTR to the volume's DosList entry (for ACTION_DISK_INFO: the currently inserted volume, or ZERO if none is claimed)
id_InUse Number of locks and open files on the volume

Disk states

id_DiskState Value Meaning
ID_WRITE_PROTECTED 1.3+ 80 Consistent but read-only: physically write-protected, or software-protected (ACTION_WRITE_PROTECT, used by the Lock command)
ID_VALIDATING 1.3+ 81 The file system found inconsistencies. The FFS rebuilds its bitmap during validation and refuses writes meanwhile. If validation cannot fix the volume (the FFS shows a requester for severe errors), the state stays ID_VALIDATING
ID_VALIDATED 1.3+ 82 Consistent and writable

Disk types

id_DiskType Value Meaning From Info()?
ID_DOS_DISK and FFS flavours 'DOS\0'…'DOS\8' The file system recognises the medium Yes
ID_NO_DISK_PRESENT 1.3+ −1 Drive is empty No: Info() fails with ERROR_NO_DISK
ID_UNREADABLE_DISK 1.3+ 'BAD\0' The exec device cannot read the medium No: ERROR_NOT_A_DOS_DISK
ID_NOT_REALLY_DOS 1.3+ 'NDOS' Readable, but the structure is invalid; the FFS also uses it when the boot block starts with four zero bytes No: ERROR_NOT_A_DOS_DISK
ID_KICKSTART_DISK 1.3+ 'KICK' An A1000 Kickstart floppy (a side effect of its first four bytes) No: ERROR_NOT_A_DOS_DISK
'BUSY' 0x42555359 File system is inhibited. Not defined in dos/dos.h Only via ACTION_DISK_INFO
'CON\0', 'RAW\0' 0x434F4E00, 0x52415700 Returned by the CON-Handler, which reuses InfoData for console information No: consoles hand out no locks
anything else — First longword of the boot block of an unrecognised medium (FFS) No

id_DiskType is not a file system identifier. File systems are supposed to return the generic ID_DOS_DISK when they accept a medium; that the FFS returns its own DOSTYPE (DOS\1, DOS\3…) is a historical error that new file systems should not copy, and some third-party file systems return yet other values. To test "is this a usable volume", check the first three bytes for DOS:

#define IS_DOS_TYPE(t)  (((ULONG)(t) & 0xFFFFFF00UL) == 0x444F5300UL)   /* 'DOS' */

A recognised volume can still be inconsistent (ID_VALIDATING), so check id_DiskState as well.

Example: free space of the volume holding a path

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

/* Returns free payload bytes, or -1 if unknown or on error.
 * Clamps on overflow. */
LONG FreeBytes(STRPTR path)
{
    struct InfoData *id;
    BPTR lock;
    LONG result = -1;

    if ((id = AllocVec(sizeof(*id), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
        return -1;

    if ((lock = Lock(path, SHARED_LOCK)) != 0) {
        if (Info(lock, id) && id->id_DiskState != ID_VALIDATING) {
            ULONG freeblocks = (ULONG)(id->id_NumBlocks - id->id_NumBlocksUsed);
            ULONG bpb        = (ULONG)id->id_BytesPerBlock;

            if (id->id_NumBlocks == 0)           /* pre-45 RAM-Handler: unknown */
                result = -1;
            else if (bpb && freeblocks > 0x7FFFFFFFUL / bpb)
                result = 0x7FFFFFFF;
            else
                result = (LONG)(freeblocks * bpb);
        }
        UnLock(lock);
    }
    FreeVec(id);
    return result;
}

The same zero check protects any percentage computation (id_NumBlocksUsed * 100 / id_NumBlocks).

Info() versus ACTION_INFO and ACTION_DISK_INFO

Info() sends ACTION_INFO. A second packet, ACTION_DISK_INFO, fills the same structure but takes no lock; it describes whatever medium is currently in the drive and is not exposed by any dos.library function.

ACTION_INFO (26) / Info() ACTION_DISK_INFO (25)
Arguments Arg1 lock (ZERO = inserted volume), Arg2 BPTR InfoData Arg1 BPTR InfoData
Volume described The one holding the locked object Whatever is in the drive right now
Empty drive Fails, ERROR_NO_DISK Succeeds, ID_NO_DISK_PRESENT
Unreadable / non-DOS / KICK medium Fails, ERROR_NOT_A_DOS_DISK Succeeds with that disk type
Volume of the lock not inserted Fails, ERROR_DEVICE_NOT_MOUNTED —
Inhibited file system — Works, reports 'BUSY'
Used by Applications Workbench (to decide which icon to show), consoles

ACTION_DISK_INFO is a snapshot: the user can swap the medium at any moment. When you need information on one specific volume, use Info() with a lock on it.

#include <dos/dos.h>
#include <dos/dosextens.h>
#include <proto/dos.h>

/* Query the medium in a drive without locking anything. 'id' must be
 * longword aligned. Returns FALSE if the device cannot be reached. */
BOOL DriveState(STRPTR device, struct InfoData *id)   /* device e.g. "DF0:" */
{
    struct DevProc *dp;
    BOOL ok = FALSE;

    if ((dp = GetDeviceProc(device, NULL)) != NULL) {
        ok = DoPkt1(dp->dvp_Port, ACTION_DISK_INFO, MKBADDR(id)) != DOSFALSE;
        FreeDeviceProc(dp);
    }
    return ok;
}

Remember that GetDeviceProc() starts the handler if it is not running (see The AmigaDOS Device List).

Naming the target: devices beat volume names

AddBuffers(), Relabel(), Format() and Inhibit() take a path that is resolved with GetDeviceProc(); only the file system responsible for it matters, and the object need not exist. Consequences:

  • Include the colon. "DF0" is a relative path and affects the file system of your current directory. Use "DF0:".
  • Relative paths and assigns are accepted too, and act on the file system behind them.
  • AmigaDOS may know several volumes of the same name (distinguished only by creation date). A volume name resolves to the first matching entry on the device list. When in doubt, use the device name ("DF0:") rather than the volume name.
  • Device, volume and assign names are limited to 30 characters, because GetDeviceProc() copies the name into a 30-character buffer and truncates.

AddBuffers()

LONG AddBuffers(STRPTR filesystem, LONG number);   /* V36 */

Adds number buffers to the file system (negative values remove buffers). What a buffer is depends on the file system. The FFS uses them to cache metadata (directory blocks and the blocks describing where file data lives, which speeds up Seek() in large files) and as bounce buffers when the caller's memory is unaligned or unreachable for the device (see MASK/BUFMEMTYPE in The AmigaDOS Device List). More buffers help up to a point, after which the management overhead dominates; for the FFS, larger blocks help more than more buffers.

Return value: on success the FFS returns the new total number of buffers as the function result; the AddBuffers command depends on this. On failure the result is 0 and IoErr() holds the error. The manual recommends accepting this as the specification. The packet ACTION_MORE_CACHE (18) returns the total in Res1, so sending it with an increment of 0 queries the current buffer count.

LONG total = AddBuffers("DH0:", 20);

if (total == 0)
    PrintFault(IoErr(), "AddBuffers");
else if (total == DOSTRUE)                  /* file system following the autodoc */
    Printf("DH0: now has %ld buffers\n", IoErr());
else
    Printf("DH0: now has %ld buffers\n", total);

FFS versions 34 and below could not reduce the buffer count and did not accept an increment of 0; fixed in V36. The packet exists in all AmigaDOS versions, but the function only from V36.

Note: the NDK 3.2 autodoc states that on success the buffer count is returned in IoErr(), that the V36 ROM file system reports the wrong count unless preceded by AddBuffers(fs, -1) (fixed in V37), and that the V37 and older ROM file system returns the buffer count instead of success. It suggests treating 0 as failure, DOSTRUE (−1) as "count in IoErr()", and any other value as the count.

Relabel()

BOOL Relabel(STRPTR volumename, STRPTR name);   /* V36 */

Renames the volume in the file system behind the path volumename (with colon, see above) to name. name is not a path: no colon, no slash. Not every file system supports volume names; those that do not make it fail. IoErr() holds the error on failure and is undefined on success. The packet (ACTION_RENAME_DISK, 9) existed before V36 but had no library function.

The packet carries only the new name and always relabels the medium currently in the drive. If the user swaps disks between your call and the handler receiving it, the wrong disk is renamed. The handler also updates dol_Name of the volume's DosList entry. Volume names follow the 30-character device-list limit; see OS 3.2 File System and Handler Changes for the FFS 46.6 and Relabel 47.2 notes on this limit.

Format()

BOOL Format(STRPTR filesystem, STRPTR volumename, ULONG dostype);   /* V36 */

Writes an empty file system structure (a "quick format") onto the medium or partition of filesystem. Old data blocks are not overwritten, only the administration information is lost. volumename follows the same rules as Relabel()'s name, and is ignored by file systems without volume names. dostype selects the flavour for file systems that support several (for the FFS one of the DOS\0…DOS\8 types, see IFF Format and Mountlist Reference); it corresponds to DOSTYPE in the mountlist, and single-flavour file systems may ignore it. There is no API to ask a file system which flavours it supports: the Format command offers the FFS flavours when the mount entry says FFS, and otherwise just uses de_DosType.

Format() does not low-level format the medium. A complete format sequence is:

  1. Inhibit("DF0:", DOSTRUE): stop the file system from touching the medium.
  2. Optionally low-level format through the exec device (for example TD_FORMAT on trackdisk.device).
  3. Format("DF0:", "Empty", ID_INTER_FFS_DISK).
  4. Inhibit("DF0:", DOSFALSE): the file system re-reads the medium as if it had been inserted.
  5. Expect a short validation phase in which writes are refused; the FFS builds the bitmap only after the volume becomes available.
#include <dos/dos.h>
#include <proto/dos.h>

/* Quick-format an already low-level formatted medium. Requires V37. */
LONG QuickFormat(STRPTR device, STRPTR label, ULONG dostype)   /* device with ':' */
{
    LONG error = 0;

    if (!Inhibit(device, DOSTRUE))
        return IoErr();

    if (!Format(device, label, dostype))
        error = IoErr();

    if (!Inhibit(device, DOSFALSE) && error == 0)
        error = IoErr();

    return error;
}

Before V36 neither the function nor its packet existed, and the Format command wrote the OFS/FFS root block itself.

Note: the NDK 3.2 autodoc states that Format() was non-functional in V36 because the volume name was not converted to a BSTR (workaround: require V37, or pass a BPTR to a BSTR under V36), and that several printed packet docs give wrong arguments for ACTION_FORMAT. In the packet, Arg1 is the BSTR volume name and Arg2 the DOS type.

Inhibit()

BOOL Inhibit(STRPTR filesystem, LONG flag);   /* V36 */

With flag = DOSTRUE the file system stops all access to its medium. Programs such as disk editors, salvage tools and formatters can then use the exec device directly. With DOSFALSE access is allowed again and the file system revalidates the medium exactly as after a disk change: it checks the structure and flavour, and may create a new volume entry, since the medium may have been rewritten completely. The DiskChange command works this way. Revalidation takes a few seconds, during which writes are not possible.

While inhibited:

  • ACTION_DISK_INFO still works and reports id_DiskType = 'BUSY'.
  • ACTION_FORMAT and ACTION_SERIALIZE_DISK still work; they even require the inhibited state.
  • All other requests are suspended.

Inhibiting can fail, for example while files are open for writing (the bitmap is then inconsistent and inhibiting could damage the volume). IoErr() holds the error on failure and is undefined on success. The packet (ACTION_INHIBIT, 31) predates the V36 function.

Packet-only volume operations

Packet No. Arguments Purpose
ACTION_DISK_INFO 1.3+ 25 Arg1 BPTR InfoData State of the medium in the drive, see above
ACTION_SERIALIZE_DISK 2.04+ 4200 — Make the inserted volume unique after a disk copy; the FFS sets the volume creation date to the current date. Used by DiskCopy. Requires the file system to be inhibited
ACTION_WRITE_PROTECT 1.3+ 1023 Arg1 flag (non-zero = protect), Arg2 password hash Software write protection, used by the Lock command. Writes then fail with ERROR_DISK_WRITE_PROTECTED. A hash of 0 lets any password unprotect; a wrong hash fails with ERROR_INVALID_COMPONENT_NAME. Protecting an already protected volume fails
ACTION_CURRENT_VOLUME 1.3+ 7 Arg1 fh_Arg1 or ZERO BPTR to the volume DosList of a file, or of the inserted volume. Used by ErrorReport(). With ZERO, lock the device list while reading the result, because the volume can vanish

The V47 Lock command computes the password hash like this (the file system only compares hashes):

ULONG ComputeHash(const UBYTE *password)
{
    ULONG hash = 0;

    while (*password)
        hash = 10 * hash + *password++;
    return hash;
}

See Also


Sources: Thomas Richter, Amiga ROM Kernel Reference Manual: AmigaDOS (2024, v1.27), §4.3 (p. 23), §6.3 (pp. 64–66), §8.1.3 (pp. 101–105), §8.2.1 (p. 112), §8.7 (pp. 126–129), §14.7 (pp. 290–294), §14.9.1–14.9.2 (pp. 305–306); NDK 3.2 R4 dos/dos.h, dos/dosextens.h, clib/dos_protos.h, dos.doc (AddBuffers, Format, Info, Inhibit, Relabel) Updated: 2026-11-13