File metadata

Acorn files carry side-channel metadata — a 32-bit load address, a 32-bit exec address, an access byte (the L/W/R/E/PR/PW flag set), and (under RISC OS) a 12-bit filetype. None of this travels through a plain host cp, so oaknut.file provides:

  • A canonical AcornMeta dataclass to hold the metadata for one file.

  • A small enum of MetaFormat values naming the side-channels the metadata can live in on a host filesystem.

  • A pair of helpers — export_with_metadata() and import_with_metadata() — that move bytes plus metadata across the host boundary using one of those formats.

The Acorn-side filing systems (DFS, ADFS, AFS) store the same fields natively in their on-disc directory entries. The cross-host formats exist to keep the fields alive when files leave the disc image.

AcornMeta

class oaknut.file.AcornMeta(load_address=None, exec_address=None, access=None, filetype=None)

Acorn file metadata.

Parameters:
load_address

32-bit load address, or None if unknown.

Type:

int | None

exec_address

32-bit execution address, or None if unknown.

Type:

int | None

access

Access byte (OSFILE convention), or None if unknown.

Type:

int | None

filetype

RISC OS filetype (0x000–0xFFF), or None if unknown.

Type:

int | None

property has_metadata: bool

True if any metadata is present.

property is_filetype_stamped: bool

True if the load address encodes a RISC OS filetype.

When the top 12 bits of the load address are 0xFFF, bits 8–19 encode a filetype and bits 0–7 encode a date component.

infer_filetype()

Extract filetype from load address, or fall back to the filetype field.

Return type:

int | None

Two derived properties are worth flagging. RISC OS encodes a filetype inside the top bits of the load address when bits 20–31 equal 0xFFF; AcornMeta.is_filetype_stamped says whether this convention applies and AcornMeta.infer_filetype() extracts the 12-bit filetype value when it does.

Access

class oaknut.file.Access(*values)

Acorn file access attributes.

Composable with |:

Access.R | Access.W | Access.L
Access.R | Access.W | Access.PR  # with public read

The integer value of a combination is the standard Acorn attribute byte, suitable for storage in xattrs or INF files:

int(Access.R | Access.W)  # 0x03

Two convenience composites cover the cases that come up in every write_bytes call site:

  • Access.WR — owner read+write (the filesystem default for a newly-created file).

  • Access.LWR — locked owner read+write (a file that should not be deleted, overwritten, or renamed). Pass this as access=Access.LWR for the locked-default case.

The integer value of an Access combination is the standard Acorn attribute byte (int(Access.LWR) == 0x0B), so it can be stored directly in xattrs, INF lines, or any other byte-sized slot. The parse_access() and matching format_access_text() / format_access_hex() helpers convert to and from the textual forms ("LWR/R", "0B", etc.) that show up in INF sidecars and CLI output.

BootOption

class oaknut.file.BootOption(*values)

Disk boot option (*OPT 4,n).

Controls what happens when the disk is booted.

The disc-level boot option (*OPT 4,n) sits next to file metadata because it is read and written through the same per-disc catalogues — OFF, LOAD, RUN, and EXEC match the four values the BBC’s OPT command accepts. Both DFS.boot_option and ADFS.boot_option return a BootOption and accept either a BootOption or a plain int on assignment.

MetaFormat — host-side metadata side-channels

class oaknut.file.MetaFormat(*values)

Supported metadata output formats.

The values are:

Value

Format

INF_TRAD

Traditional .inf sidecar — a single text line carrying filename load_address exec_address length [attr]. Default for export; widely supported by Acorn-era tooling.

INF_PIEB

PiEconetBridge .inf flavour — load_address exec_address attr owner, no filename field. Used when interoperating with PiEconetBridge file servers.

XATTR_ACORN

Filesystem extended attributes under the user.acorn.* namespace: user.acorn.load, user.acorn.exec, and user.acorn.attr (uppercase hex strings).

XATTR_PIEB

Filesystem extended attributes under the user.econet_* namespace (the PiEconetBridge convention): user.econet_load, user.econet_exec, user.econet_perm, and user.econet_owner.

FILENAME_RISCOS

Metadata in the filename itself, RISC OS style. Either name,xxx (a 3-digit hex filetype) or name,llllllll,eeeeeeee (8-hex load + 8-hex exec) when the file is not filetype-stamped.

FILENAME_MOS

Metadata in the filename, BBC MOS style: name,load-exec with variable-width lowercase hex separated by a hyphen.

Two host-side helpers compose the formats with file I/O:

oaknut.file.export_with_metadata(data, target_filepath, meta, *, meta_format=MetaFormat.INF_TRAD, owner=0, filename=None)

Write data to target_filepath and emit metadata.

Parameters:
  • data (bytes) – Raw file contents.

  • target_filepath (Path) – Destination on the host. Parent directories are created if missing.

  • meta (AcornMeta) – Metadata for the file.

  • meta_format (MetaFormat | None) – How to emit metadata. None writes only the data, no sidecar, no xattr, no filename rewriting.

  • owner (int) – Econet owner ID, used only by PiEconetBridge formats (INF_PIEB and XATTR_PIEB); ignored otherwise.

  • filename (str | None) – Acorn-native filename to record in traditional INF sidecars (e.g. "$.HELLO" or "Games.Elite"). Used only by MetaFormat.INF_TRAD, which is the only format with a filename field. When omitted, the host filename is used.

Returns:

The path that was actually written. For filename-encoded formats this differs from target_filepath because a suffix has been appended.

Return type:

Path

oaknut.file.import_with_metadata(source_filepath, *, meta_formats=(MetaFormat.INF_TRAD, MetaFormat.XATTR_ACORN, MetaFormat.FILENAME_RISCOS))

Resolve metadata for a host file by trying readers in order.

Parameters:
  • source_filepath (Path) – The host data file.

  • meta_formats (Sequence[MetaFormat]) – Ordered cascade of metadata schemes to try. First hit wins.

Returns:

(clean_source_path, source_label, meta).

  • clean_source_path equals source_filepath unless the filename-encoded reader matched, in which case the encoded suffix has been stripped.

  • source_label is one of oaknut.file’s SOURCE_* constants, "xattr-acorn" / "xattr-pieb", or None if no reader matched.

  • meta is the resolved AcornMeta, or an empty AcornMeta() when no reader matched.

Return type:

tuple[Path, str | None, AcornMeta]

The dialect-equivalent pairs (INF_TRAD/INF_PIEB and FILENAME_RISCOS/FILENAME_MOS) dispatch to the same reader; oaknut.file’s parsers auto-detect the dialect, so listing both is harmless but redundant.

Path objects on every filesystem wrap these helpers so the common case is one method call: export_file() writes bytes plus metadata in the chosen format; import_file() reads bytes plus metadata by trying the import cascade. See the API cookbook “Round-tripping a file through the host filesystem” recipe for a worked example.

Default cascades

Exports default to MetaFormat.INF_TRAD — the most widely recognised format. Override with the meta_format= keyword on export_file() or export_with_metadata().

Imports try a cascade in the order oaknut.file.DEFAULT_IMPORT_META_FORMATS:

  1. INF_TRAD — the traditional sidecar form.

  2. XATTR_ACORN — the preferred xattr namespace. The reader automatically falls back to user.econet_* when the user.acorn.* keys are absent on a file, so a separate XATTR_PIEB step in the cascade would be unreachable.

  3. FILENAME_RISCOS — the RISC OS filename suffix.

Callers can pass a different meta_formats= sequence to override the cascade — for example, listing XATTR_PIEB ahead of XATTR_ACORN when the source-of-truth on the host is known to be the PiEconetBridge namespace.