AmigaDOS Assigns

An assign is a logical name (without a colon) that binds to one or more directories on a volume. After creation, paths starting with name: are resolved against the bound directories. AmigaDOS supports four assign kinds, each created or updated by a dedicated dos.library function:

Assign kind Created by Binds to
Regular (single directory) AssignLock(name, lock) One directory, on a specific volume
Multi AssignLock() + repeated AssignAdd() An ordered list of directories across volumes
Non-binding AssignPath(name, path) A path; re-resolved against whatever volume currently matches, on each access
Late binding AssignLate(name, path) A path that, on first access, becomes a regular assign to whatever directory the path currently points to; that binding then persists across media ejection/reinsertion

Assign names are limited to 30 characters (the legacy L: BCPL limit). All four creation functions accept the name without the trailing colon.

Race condition. All AssignLock, AssignPath, AssignLate, AssignAdd, and RemAssignList calls have a known race condition in current AmigaDOS: the lock used to identify the target directory is released during the operation, but that lock may already have been handed out to other applications (for example via GetDeviceProc()) and may still be in use by them. There is no reference count, so passing locks around via DeviceProc() while reassigning is unsafe.

AssignLock — regular assign (create / update / remove)

BOOL AssignLock(STRPTR name, BPTR lock);   /* V36 */

lock is either ZERO (cancel the assign) or a shared lock to a directory. Behaviour:

Pre-state lock Result
No assign of name non-ZERO New regular assign to lock
Existing assign (any kind) non-ZERO Convert to regular assign to lock; multi/late/non-binding resources released
Existing assign (any kind) ZERO Cancel — release all locks and resources, remove from device list

On success the function returns non-zero and absorbs lock (the caller must not use it after). On error it returns 0 and IoErr() is set. Possible error codes:

  • ERROR_NO_FREE_STORE — out of memory.
  • ERROR_INVALID_COMPONENT_NAME — name longer than 30 characters.
  • ERROR_OBJECT_EXISTS — a volume, handler, or filesystem of the same name already exists.

IoErr() is unreliable on success. Do not check IoErr() for a "good" return; check the boolean only.

AssignPath — non-binding assign

BOOL AssignPath(STRPTR name, STRPTR path);   /* V36 */

Binds name: to path without fixing a volume. On each access, name: is resolved against whatever volume or assign currently matches path. Useful for portable paths (THEME:, USER:) that should follow the user across media. path is copied internally; the caller's string remains valid.

Use absolute paths. Relative paths will be resolved against the current directory of whichever process happens to be using the assign, which is rarely what you want.

Errors and return-value semantics are the same as AssignLock. IoErr() on success is again unreliable.

AssignLate — late binding assign

BOOL AssignLate(STRPTR name, STRPTR path);   /* V36 */

On creation, only path is stored. On first resolution, dos.library resolves path to a directory and converts the assign into a regular one bound to that specific directory (and volume). The binding survives ejection and reinsertion into the same drive — even into a different drive — and survives Inhibit/UnInhibit cycles. If the path does not exist on first access, the assign resolves to nothing; subsequent volumes of the same name may re-bind it.

Use for paths that need not be valid at boot time but must stay bound once found (legacy: C:, LIBS:, FONTS:, LOCALE:, S:, ENV:, DEVS:, L:).

Same error/return semantics as AssignLock.

AssignAdd — append a directory to a multi-assign

BOOL AssignAdd(STRPTR name, BPTR lock);   /* V36 */

Adds lock to the directory list of an existing regular or multi-assign. The lock is a shared lock to a directory. The new directory is scanned last during resolution (lowest priority). A regular assign is automatically promoted to a multi-assign on the first successful AssignAdd.

name must already exist as a regular or multi-assign. Adding to a handler, volume, late-binding, or non-binding assign fails.

On success, lock is absorbed into the assign. On failure, lock remains valid, but IoErr() is not consistently populated — the autodoc is silent on which failure mode produced the 0.

RemAssignList — remove a directory from a multi-assign

BOOL RemAssignList(STRPTR name, BPTR lock);   /* V36 */

Removes lock from the multi-assign. The provided lock is used as an identifier; it need not be the same lock object stored in the assign, but must compare equal via SameLock() to one of them. After successful removal, that lock is released with UnLock() — which can race with applications still using a lock they obtained from GetDeviceProc().

If the multi-assign drops to a single directory, it is converted back to a regular assign. If it drops to zero, the assign is removed entirely.

The caller's lock remains valid regardless of outcome (it is used only as a key). IoErr() is again unreliable on failure.

Multi-assign resolution semantics

When a multi-assign contains several directories, dos.library checks them in order: first directory first. The first that yields a match (existence or open success) wins. Directories later in the list are not consulted for that name. This is what enables overlay patterns like:

AssignAdd("C", lock_a);
AssignAdd("C", lock_b);  /* tried only if lock_a did not have the requested file */

The order of AssignAdd calls determines priority.

Worked example: building a multi-assign at startup

#include <dos/dos.h>

BOOL MakeMultiAssign(STRPTR name,
                     STRPTR first_path,
                     STRPTR second_path)
{
    BPTR l1 = Lock(first_path, ACCESS_READ);
    BPTR l2 = Lock(second_path, ACCESS_READ);

    if (!l1 || !l2) {
        UnLock(l1); UnLock(l2);
        return FALSE;
    }

    /* Start with a regular assign, then promote to multi. */
    if (!AssignLock(name, l1)) {           /* l1 absorbed on success */
        UnLock(l2);
        return FALSE;
    }
    if (!AssignAdd(name, l2)) {            /* l2 absorbed on success */
        UnLock(l2);
        return FALSE;
    }
    return TRUE;
}

Comparison: when to use each kind

Need Use
Bind name: to a fixed directory (e.g., user data on Work:) AssignLock() (regular)
Search name: across multiple volumes in priority order AssignLock() + AssignAdd() (multi)
name: should always mean "whatever is mounted as WORK: right now" AssignPath() (non-binding)
name: must be valid later (e.g., C:, S:) and stay bound once found AssignLate() (late binding)

See Also


Sources: Thomas Richter, "ROM Kernel Reference Manual: AmigaDOS" (First Edition, 2024), Chapter 8.6 — Creating and Updating Assigns. Raw: raw/rkm/rkm-dos-book.md Updated: 2026-10-02