oaknut.file

The shared metadata layer every other oaknut-* package builds on. It knows nothing of disc images or catalogues; it deals only in the side-channel metadata an Acorn file carries — load and execution addresses, the access byte, RISC OS filetypes — and the several host-side representations that metadata can travel in: INF sidecars, extended attributes, encoded filenames, and the acorn text codec.

Every name documented here is importable directly from oaknut.file.

Core types

The central metadata types and the host round-trip helpers are introduced, with worked examples, in the API patterns rather than repeated here:

Errors

The filesystem exception hierarchy. Each inherits from DataError; the broader error model and the handled_errors boundary are covered in Error handling.

exception oaknut.file.FSError(*args, exit_code=None)

Base exception for every oaknut filesystem error.

Format-specific subclasses live inside each filesystem package (e.g. oaknut.dfs.exceptions.DFSError, oaknut.adfs.exceptions.ADFSError, oaknut.afs.exceptions.AFSError). The default ExitCode is ExitCode.DATA_ERR inherited from DataError; specific subclasses override _exit_code to a more precise code.

Parameters:
  • args (object)

  • exit_code (Optional[ExitCode])

Return type:

None

exception oaknut.file.FilesystemClosedError(*args, exit_code=None)

An I/O operation was attempted on a closed filesystem handle.

Raised when a path object outlives the with block that opened its filesystem and a method is called that would have needed to touch the underlying disc image. Pure path manipulation (slash-join, parent, name, parts, path, equality) does not raise this.

Parameters:
  • args (object)

  • exit_code (Optional[ExitCode])

Return type:

None

exception oaknut.file.TitleNotSupportedError(*args, exit_code=None)

The target entity cannot carry a title.

A title is a human-readable label distinct from a name. Only some Acorn entities have a slot for one: the disc (every filesystem) and — on ADFS only — every directory. DFS and AFS directories have no title field, and files never do. Attempting to read or set a title on such an entity raises this.

Parameters:
  • args (object)

  • exit_code (Optional[ExitCode])

Return type:

None

exception oaknut.file.InvalidAddressError(*args, exit_code=None)

A load or execution address could not be parsed.

Addresses are written as integer literals whose base comes from the prefix — 0x hex, 0o octal, 0b binary, or none for decimal. Input that is not a valid literal (non-numeric text, or the Acorn & hex sigil) raises this. As an FSError it carries the data-error exit code and is rendered by the CLI boundary without a traceback.

Parameters:
  • args (object)

  • exit_code (Optional[ExitCode])

Return type:

None

Load and execution addresses

oaknut.file.parse_address(text)

Parse a load/exec address literal, honouring its base prefix.

0x1900 is hex, 0o14400 octal, 0b1 binary, and a bare 6400 decimal. Raises InvalidAddressError if text is not a valid integer literal.

Parameters:

text (str)

Return type:

int

Access flags

The Access enum (see File metadata) is the in-memory form; these helpers convert to and from the textual and hexadecimal representations used in INF sidecars and CLI output.

oaknut.file.parse_access(text)

Parse an access string back to an Access value.

Accepts three forms:

  • Symbolic: "LWR/R", "WR/WR", "R/" — letters before the slash are owner flags (L, W, R, E), letters after are public flags (W, R). Case-insensitive. A missing slash treats the entire string as owner flags.

  • Hex with prefix: "0x0B", "0x33" — parsed as an integer.

  • Bare hex: "0B", "33" — two hex digits without prefix.

Raises ValueError on unrecognised input.

Parameters:

text (str)

Return type:

Access

oaknut.file.format_access_text(attr)

Format attributes as a human-readable access string.

Returns "owner/public" form, e.g. "LWR/R".

Parameters:

attr (int | None)

Return type:

str

oaknut.file.format_access_hex(attr)

Format an attribute byte as a two-digit uppercase hex string.

Returns empty string for None.

Parameters:

attr (int | None)

Return type:

str

INF sidecars

Reading and writing the .inf sidecar lines that carry metadata alongside a plain data file, in both the traditional and PiEconetBridge flavours.

oaknut.file.parse_inf_line(line)

Parse an INF sidecar line, auto-detecting the format.

Returns (source_label, metadata) or None if the line cannot be parsed.

The source_label is "inf-trad" or "inf-pieb".

Parameters:

line (str)

Return type:

tuple[str, AcornMeta] | None

oaknut.file.format_trad_inf_line(filename, load_address, exec_address, length, attr=None)

Format a traditional INF line.

Returns a string like "HELLO    00001900 00008023 00000100 03".

Parameters:
Return type:

str

oaknut.file.format_pieb_inf_line(load_address, exec_address, attr=None, owner=0)

Format a PiEconetBridge INF line.

Returns a string like "0 ffffdd00 ffffdd00 17".

Parameters:
Return type:

str

oaknut.file.read_inf_file(filepath)

Read and parse an INF sidecar file.

Returns (source_label, metadata) or None if the file does not exist or cannot be parsed.

Parameters:

filepath (Path)

Return type:

tuple[str, AcornMeta] | None

oaknut.file.write_inf_file(filepath, content)

Write an INF sidecar file.

Parameters:
Return type:

None

Filename encoding

Metadata encoded into the filename itself — the name,xxx filetype suffix and the name,llllllll,eeeeeeee load/exec forms.

oaknut.file.parse_encoded_filename(filename)

Strip metadata suffix from a filename.

Tries each encoding scheme in order: RISC OS load/exec, MOS load/exec, filetype. Returns (clean_filename, metadata) where metadata is None if no encoding was found.

Parameters:

filename (str)

Return type:

tuple[str, AcornMeta | None]

oaknut.file.build_filename_suffix(meta)

Build a RISC OS filename encoding suffix.

Returns ,xxx for filetype-stamped files, or ,llllllll,eeeeeeee for literal load/exec addresses.

Parameters:

meta (AcornMeta)

Return type:

str

oaknut.file.build_mos_filename_suffix(meta)

Build a MOS filename encoding suffix.

Returns ,load-exec with variable-width lowercase hex.

Parameters:

meta (AcornMeta)

Return type:

str

Extended attributes

Reading and writing metadata in host filesystem extended attributes, under both the user.acorn.* namespace and the PiEconetBridge user.econet_* convention.

oaknut.file.read_acorn_xattrs(filepath)

Read Acorn file metadata from extended attributes.

Tries the user.acorn.* namespace first; falls back to user.econet_* if the preferred namespace is absent. Returns None if neither namespace is present.

Parameters:

filepath (str | Path)

Return type:

AcornMeta | None

oaknut.file.write_acorn_xattrs(filepath, load_address, exec_address, attr=None)

Write Acorn file metadata as extended attributes.

Writes user.acorn.load, user.acorn.exec, and optionally user.acorn.attr as uppercase hex strings.

Parameters:
Return type:

None

oaknut.file.read_econet_xattrs(filepath)

Read PiEconetBridge extended attributes.

Returns None if no Econet attributes are present.

Parameters:

filepath (str | Path)

Return type:

AcornMeta | None

oaknut.file.write_econet_xattrs(filepath, load_address, exec_address, attr=None, owner=0)

Write PiEconetBridge-compatible extended attributes.

Writes the four user.econet_* attributes used by PiEconetBridge. When attr is None, the conventional default of 0x17 (LR/R) is written.

Parameters:
Return type:

None

The acorn text codec

Importing oaknut.file registers an acorn text codec, so data.decode("acorn") works anywhere; these are the direct entry points for the same conversion.

oaknut.file.decode_text(data, *, encoding='acorn', newline=None)

Decode data as text, optionally normalising line endings.

Parameters:
  • data (bytes) – Raw bytes to decode.

  • encoding (str) – Text encoding. Defaults to "acorn" — the BBC character set, registered as a Python codec by oaknut.file.acorn_encoding.

  • newline (str | None) –

    Line-ending translation policy.

    • None (the default): universal newlines — "\r\n", "\r" and "\n" all become "\n" in the returned string.

    • "": pass the decoded text through unchanged.

Return type:

str

oaknut.file.encode_text(text, *, encoding='acorn', newline='\r')

Encode text as bytes, optionally translating line endings.

Parameters:
  • text (str) – String to encode.

  • encoding (str) – Text encoding. Defaults to "acorn" — the BBC character set, registered as a Python codec by oaknut.file.acorn_encoding.

  • newline (str | None) –

    Line-ending translation policy.

    • "\r" (the default): every "\n" in text is replaced with "\r" before encoding. A natural Python multiline string lands on the disc with the Acorn-native line terminator.

    • "" or None: pass text through unchanged.

    • Any other string: replace each "\n" with the given sequence before encoding.

Return type:

bytes

Metadata source labels

String labels naming where a piece of metadata was resolved from. The parsing helpers return one of these, and the CLI reports it.

oaknut.file.SOURCE_DIR = 'dir'

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.

oaknut.file.SOURCE_FILENAME = 'filename'

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.

oaknut.file.SOURCE_INF_TRAD = 'inf-trad'

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.

oaknut.file.SOURCE_INF_PIEB = 'inf-pieb'

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.

oaknut.file.SOURCE_SPARKFS = 'sparkfs'

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.

oaknut.file.SOURCE_XATTR_ACORN = 'xattr-acorn'

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.

oaknut.file.SOURCE_XATTR_PIEB = 'xattr-pieb'

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.

Default metadata formats

The formats the host-bridge helpers fall back to; the import cascade is discussed under File metadata.

oaknut.file.DEFAULT_EXPORT_META_FORMAT = MetaFormat.INF_TRAD

Supported metadata output formats.

oaknut.file.DEFAULT_IMPORT_META_FORMATS = (MetaFormat.INF_TRAD, MetaFormat.XATTR_ACORN, MetaFormat.FILENAME_RISCOS)

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple. If iterable is specified the tuple is initialized from iterable’s items.

If the argument is a tuple, the return value is the same object.

Host filesystem helpers

oaknut.file.copy_file(src, dst, **write_kwargs)

Copy a single file from src to dst.

Reads data and metadata (load address, exec address, access attributes) from src and writes them to dst. Both arguments must be path-like objects supporting read_bytes(), stat(), exists(), is_dir(), and write_bytes(data, ...).

Additional keyword arguments override source metadata.

Raises:
Parameters:
Return type:

None

class oaknut.file.Stat(*args, **kwargs)

Uniform metadata shape returned by every oaknut path’s stat().

Six fields, all required:

  • length — byte length of the file’s contents (0 for directories).

  • load_address — Acorn load address (32-bit unsigned).

  • exec_address — Acorn exec address (32-bit unsigned).

  • access — canonical Access flags synthesised from whatever the source filesystem stores natively.

  • is_directoryTrue if this entry is a directory.

  • date — entry date stamp, or None where the format does not store one. Type is the source filesystem’s date type (AFS uses oaknut.afs.AfsDate); callers that need to compare across filesystems should check is None first.

Stat is decorated with typing.runtime_checkable() so isinstance(st, Stat) works for ducktype tests, but the cheapest check in cross-filesystem code is still attribute access.

oaknut.file.resolving_io(method)

Decorator: resolve ^ components before calling an I/O method.

Wraps a path-class I/O method so any literal carets stored in the path are collapsed via AcornPath.resolve() before the underlying body runs. If the path has no carets, the call goes straight through.

Apply to every method on a concrete path class whose answer depends on the disc — read_bytes(), exists(), stat(), iterdir(), and the rest. Pure path ops (__str__, parts, parent) stay un-decorated because they should preserve the literal form.

Parameters:

method (_F)

Return type:

_F