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 byAddBuffers(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 inIoErr()", 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:
Inhibit("DF0:", DOSTRUE): stop the file system from touching the medium.- Optionally low-level format through the exec device (for example
TD_FORMATontrackdisk.device). Format("DF0:", "Empty", ID_INTER_FFS_DISK).Inhibit("DF0:", DOSFALSE): the file system re-reads the medium as if it had been inserted.- 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 forACTION_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_INFOstill works and reportsid_DiskType = 'BUSY'.ACTION_FORMATandACTION_SERIALIZE_DISKstill 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¶
- Locks, FileInfoBlock and Examine
- The AmigaDOS Device List — volume entries,
GetDeviceProc(), mount parameters - IFF Format and Mountlist Reference —
DOSTYPE,BUFFERS,MASK - AmigaDOS Filesystem On-Disk Structures
- OS 3.2 File System and Handler Changes
- DOS Packet Reference
- dos.library Reference
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