oaknut-dfs
A Python library for reading, writing, and creating Acorn DFS floppy disc images, as used by the BBC Micro.
With oaknut-dfs you can open DFS floppy images (SSD/DSD) to browse the catalogue, read and write files, inspect metadata, and create new formatted discs — all from Python, with a pathlib-inspired API.
Looking for ADFS? The hierarchical Advanced Disc Filing System lives in the sibling
oaknut-adfspackage (from oaknut.adfs import ADFS). DFS and ADFS are independent filing systems and independent packages. For a unified command-line tool across DFS, ADFS, AFS, ROMFS and ZIP, seeoaknut-disc.
Part of the oaknut monorepo.
Supported formats
- Acorn DFS — 40-track and 80-track, single-sided (SSD) and double-sided (DSD)
- Watford DFS — extended catalogue supporting up to 62 files
- DSD interleaving — both interleaved and sequential double-sided layouts
Acorn load/exec addresses, the lock bit, and the BBC Micro character set
(the acorn text codec, £, ¦) are handled through the shared
oaknut-file
metadata layer.
Installation
uv add oaknut-dfs # or: pip install oaknut-dfs
oaknut-dfs is a standard Python package installable with any package
manager; the examples use uv.
Usage
Opening and reading files
The disc format is auto-detected from the file extension and size; pass a format explicitly only to override detection.
from oaknut.dfs import DFS
with DFS.from_file("Zalaga.ssd") as dfs:
print(dfs.title) # 'ZALAG-L'
# Navigate with a pathlib-inspired API.
for entry in dfs.root / "$":
s = entry.stat()
print(f"{entry.name:10s} {s.length:6d} load={s.load_address:08X}")
# Read file data.
data = (dfs.root / "$" / "ZALAGA").read_bytes()
Creating a new disc
from oaknut.dfs import DFS, ACORN_DFS_80T_SINGLE_SIDED
with DFS.create_file("demo.ssd", ACORN_DFS_80T_SINGLE_SIDED, title="DEMO") as dfs:
(dfs.root / "$.HELLO").write_bytes(b"Hello, World!", load_address=0x1900)
(dfs.root / "$.README").write_bytes(b"oaknut-dfs demo disc")
Double-sided discs (DSD)
A DSD image holds two independent sides, each with its own catalogue —
mirroring the BBC Micro, where the sides were accessed as separate drives
(*DRIVE 0 and *DRIVE 2). Select a side with the side= argument.
from oaknut.dfs import DFS
with DFS.from_file("game.dsd") as side0:
print(side0.title)
with DFS.from_file("game.dsd", side=1) as side2:
print(side2.title)
Walking the disc
DFS directories ($, A–Z) appear as children of a virtual root:
with DFS.from_file("disc.ssd") as dfs:
for dirpath, dirnames, filenames in dfs.root.walk():
for name in filenames:
print(dirpath / name)
Development
The package is developed in the oaknut workspace. From the repository root:
uv sync # install all workspace members editable
uv run pytest packages/oaknut-dfs/tests # this package's tests
uv run ruff check # lint
Architecture
A layered design, dependencies flowing strictly downward (every module imports only from the layer below):
DFS (dfs.py) user-facing DFS / DFSPath / DFSStat
↓
CataloguedSurface (catalogued_surface.py)
↓
Catalogue ABC (catalogue.py) ← AcornDFSCatalogue / WatfordDFSCatalogue
↓
Surface / SectorsView (from oaknut-discimage)
dfs.py— user-facingDFS,DFSPath,DFSStat; methods mirror the DFS star commands (load,save,delete,rename,lock, …).catalogue.py— the catalogue ABC (Catalogue,FileEntry,DiscInfo): 31-file cap, single-character directories, 7-char names.acorn_dfs_catalogue.py/watford_dfs_catalogue.py— the Acorn (sectors 0–1, 31 files) and Watford (sectors 0–3, 62 files) catalogues.catalogued_surface.py— pairs aSurfacewith aCatalogue.formats.py— DFS and Watford disc-format constants.
Sector-level access (Surface, SectorsView, UnifiedDisc) lives in
oaknut-discimage;
metadata and the acorn codec in oaknut-file; BBC BASIC
(de)tokenisation (for DFSPath.read_basic / write_basic) in
oaknut-basic.
References
- Acorn DFS disc format — BeebWiki specification for the catalogue layout.
- Disc Filing System — Wikipedia overview of DFS and its variants.
- DiscImageManager — Gerald Holdsworth's reference for DFS and other Acorn formats.
- INF file format —
the
.infsidecar metadata format. - Stardot INF format specification —
Tom Seddon's formal grammar for
.inffiles, which oaknut follows. - Storing Acorn/BBC metadata on other systems — J.G. Harston's INF and ZIP metadata rules, used where the Stardot specification leaves room.
License
MIT — see LICENSE.
Metadata
Release files for oaknut-dfs 13.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| oaknut_dfs-13.2.0.tar.gz | 112.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| oaknut_dfs-13.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 169.2 kB
Release files / oaknut_dfs-13.2.0.tar.gz
| Download URL | oaknut_dfs-13.2.0.tar.gz |
|---|---|
| Size | 112.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4869f5bbb1a46435a07b409469475bf074e2d2ff78aa948d551849e4fb767691
|
|
BLAKE2b-256 checksum How to use checksums |
dc47f59ae5d00b35137e8215d63c5df30a8957b0364f2aeb5b71b86c27c5c5af
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / oaknut_dfs-13.2.0-py3-none-any.whl
| Download URL | oaknut_dfs-13.2.0-py3-none-any.whl |
|---|---|
| Size | 56.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4da74d192e58df0cb3a3948e58fb69fd4474e3dec3cc349366ed20c250f1acd9
|
|
BLAKE2b-256 checksum How to use checksums |
27162fa4a6281d4d49ee90ac298e16e5c7768a26db5086b62d226a52daffc4d5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|