File metadata¶
Acorn files carry side-channel metadata — a 32-bit load address, a
32-bit exec address, an access byte (owner and public read, write, execute and lock),
and (under RISC OS) a 12-bit filetype. None of this travels through
a plain host cp, so oaknut.file provides:
A canonical
AcornMetadataclass to hold the metadata for one file.A small enum of
MetaFormatvalues naming the side-channels the metadata can live in on a host filesystem.A pair of helpers —
export_with_metadata()andimport_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, name=None)¶
Acorn file metadata.
- Parameters:
- name¶
The Acorn name a host metadata source carried (a traditional INF’s filename field, or a filename-encoded name), or None when the source has no name. Populated by the import readers so an importer can recover a name the host filename may have transliterated; filesystem writes ignore it.
- property is_filetype_stamped: bool¶
True if the load address carries the RISC OS filetype marker.
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. This is the pure structural marker used by the archival filename/INF/ SparkFS conventions, which record a filetype from the marker even for a
load == execpair. The display of a live filesystem additionally applies the FileSwitchload != execrule (seeis_datestamped()) to decide whether the pair is really a datestamp or a plain address.
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 asaccess=Access.LWRfor the locked-default case.
- property is_run_only: bool¶
Whether the owner may
*RUNthe file but not load or read it.Run-only is owner
EwithoutR(BeebWiki, File access:runonly%=(access% AND 5)=4). It is how the cassette and ROM filing systems’ copy protection is represented, and is a distinct axis from the disc filing systems’ delete-lockL.
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. Bits 8–10 (SYSTEM, HIDDEN, ARCHIVE) extend it with
the DOS attributes, as RISC OS DOSFS holds them; Acorn filing systems
ignore them, and INF lines and xattrs carry only the low byte. 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.
Each filing system stores access its own way, and its access convention
(see AccessConvention) maps it to and from this
word:
DFS records only a lock bit, which also means read-only: an unlocked file reads as
WR(&03) and a locked one asLR(&09). Writing keeps only the lock bit.ADFS stores owner read, write, execute and locked, public read, write and execute, and a private bit (
PL, bit 7), each as its own bit. New and Big directories store neither execute bit nor private.AFS stores owner and public read and write and the lock bit in its own byte layout (
AFSAccess); it has no execute bit.ROMFS records only whether a file is
*RUN-only: an ordinary file reads asR, a run-only one asEwithoutR(is_run_only).
Copying a file from one filing system to another keeps as much of its access as the destination can store.
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 |
|---|---|
|
Traditional |
|
PiEconetBridge |
|
Filesystem extended attributes under the |
|
Filesystem extended attributes under the |
|
Metadata in the filename itself, RISC OS style. Either
|
|
Metadata in the filename, BBC MOS style:
|
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, name_encoding='latin-1')¶
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.
Nonewrites only the data, no sidecar, no xattr, no filename rewriting.owner (int) – Econet owner ID, used only by PiEconetBridge formats (
INF_PIEBandXATTR_PIEB); ignored otherwise.filename (str | None) – Acorn-native filename to record in traditional INF sidecars (e.g.
"$.HELLO"or"Games.Elite"). Used only byMetaFormat.INF_TRAD, which is the only format with a filename field. When omitted, the host filename is used.name_encoding (str) – The name codec of the filing system filename comes from, so a traditional INF records the name’s own bytes on that medium (see
format_trad_inf_line()).
- Returns:
The path that was actually written. For filename-encoded formats this differs from target_filepath because a suffix has been appended.
- Return type:
- oaknut.file.import_with_metadata(source_filepath, *, meta_formats=(MetaFormat.INF_TRAD, MetaFormat.XATTR_ACORN, MetaFormat.FILENAME_RISCOS), name_encoding='latin-1')¶
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.
name_encoding (str) – The name codec of the filing system the file is bound for, used to decode a traditional INF’s name field (see
parse_inf_line()).
- Returns:
(clean_source_path, source_label, meta).clean_source_pathequals source_filepath unless the filename-encoded reader matched, in which case the encoded suffix has been stripped.source_labelis one of oaknut.file’sSOURCE_*constants,"xattr-acorn"/"xattr-pieb", orNoneif no reader matched.metais the resolvedAcornMeta, or an emptyAcornMeta()when no reader matched.
- Return type:
The dialect-equivalent pairs (
INF_TRAD/INF_PIEBandFILENAME_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:
INF_TRAD— the traditional sidecar form.XATTR_ACORN— the preferred xattr namespace. The reader automatically falls back touser.econet_*when theuser.acorn.*keys are absent on a file, so a separateXATTR_PIEBstep in the cascade would be unreachable.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.