Python library for handling Acorn DFS disc images (SSD/DSD format)
Project description
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.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file oaknut_dfs-12.8.0.tar.gz.
File metadata
- Download URL: oaknut_dfs-12.8.0.tar.gz
- Upload date:
- Size: 99.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d9f10a214b8b801c699de5b4198196bc0167388c76dc701734c3021cd68add3
|
|
| MD5 |
a08d871b8c26b68ed77149b817e66bd0
|
|
| BLAKE2b-256 |
4b9cd87f3d8a28c04274b4957f49a2c30a5cdaa2c1b72c5a96ab3240ead329e4
|
File details
Details for the file oaknut_dfs-12.8.0-py3-none-any.whl.
File metadata
- Download URL: oaknut_dfs-12.8.0-py3-none-any.whl
- Upload date:
- Size: 50.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3bdb9b747ec528d3eae39c1e2da8a100b2617233160d9988f35adf48966ab639
|
|
| MD5 |
5f5d4b5779dfb11fda038ec48c8d3867
|
|
| BLAKE2b-256 |
56b6522c9b98ff65027bb55e0b315e19a2710fff00fd45316508d3fae2ae3221
|