D1: teach SplitDisk directories, without moving a byte

SBFS version two adds directories out of space each entry had already set
aside: two of the four reserved bytes become a parent, and one of the seven
spare flag bits says an entry is a directory. The entry is still thirty two
bytes, so it still divides two hundred and fifty six and still never straddles
a block, and nothing in the block layer knows anything happened.

A directory is an entry with no blocks. That is what keeps the flat array of
entries the whole allocation map, which is the property the format is built
on: with files laid down contiguously, every block is inside some entry's
range or it is not, and an entry with no range is in nobody's way. There is
still no allocation table to consult and none to keep right.

THE PARENT IS AN INDEX PLUS ONE, so zero means the root. A version one disk has
zeroes in those bytes, and "in the root" is exactly where every file on a flat
disk is - so a version one image is already a valid version two image, with
nothing to convert and no tool to convert it with.

A disk is at the lowest version that describes what is on it. format makes a
version one disk and mkdir is what raises it, so everything built here stays
readable by a reader that has never heard of a directory right up until it
really does have one. That is what lets this land before the machine knows
anything: the whole existing suite passes untouched.

The tool gains mkdir and rmdir, and list, put, get and delete take paths. list
also now reports entries used against entries available, because a disk has two
ceilings and the entry one is the one nobody notices until it bites.

rmdir refuses a directory with anything in it, and that is not politeness:
parents are entry indices, a freed index gets handed out again, and the
children of a removed directory would reappear inside whatever took its place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-08-24 18:41:11 -04:00
co-authored by Claude Opus 5
parent f4fb56606e
commit 78e9eef472
4 changed files with 623 additions and 54 deletions
+22 -5
View File
@@ -117,16 +117,33 @@ Without `-o` the output takes the source file's name, in the directory you calle
| Command | What it does |
| --- | --- |
| `format <image> [blocks] [dirblocks]` | Lay down a fresh filesystem. 512 blocks and 8 of directory by default, which is 128K and room for 64 files. |
| `list <image>` | Show what is on the disk. |
| `put <image> <file> [name]` | Put a host file onto it. Without a name it uses the file's own, which is often longer than the 22 characters a name may be. |
| `get <image> <name> [file]` | Take one off it. |
| `delete <image> <name>` | Remove one. |
| `format <image> [blocks] [dirblocks]` | Lay down a fresh filesystem. 512 blocks and 8 of directory by default, which is 128K and room for 64 entries. |
| `list <image> [path]` | Show the whole disk, or one directory of it. |
| `put <image> <file> [path]` | Put a host file onto it. Without a path it uses the file's own name, which is often longer than the 22 characters a name may be. |
| `get <image> <path> [file]` | Take one off it. |
| `delete <image> <path>` | Remove a file. |
| `mkdir <image> <path>` | Make a directory. |
| `rmdir <image> <path>` | Remove an empty one. |
SplitDisk speaks the same on disk format SplitBit does, so an image it makes is one the machine can read, and one the machine writes is one it can read back. It is a convenience rather than a necessity: SplitBit writes its own filesystem, and now assembles its own programs, so a disk can be filled without leaving the machine.
Files are laid down contiguously, so a disk can have free blocks without having them in one piece. When that happens `put` says so rather than putting part of a file on.
A path is names with `/` between them, always from the root, since a command line tool has nowhere to keep a working directory between one run and the next. `.` and `..` mean what they usually do, and `..` from the root is the root.
A disk has two ceilings and it is usually the less obvious one that bites: blocks, and **entries**. Every file and every directory costs one entry, and `list` says how many of them are gone as well as how many blocks are. On a disk of small files the entries run out long before the space does, which is a matter of how the disk was formatted rather than a limit of the format - `dirblocks` is carried per disk, and each one is 256 bytes and holds eight entries.
### Two Versions:
| Version | What it means |
| --- | --- |
| 1 | Flat. Every file is in the root, because there is nowhere else. |
| 2 | Directories. Each entry says which directory it is in. |
**A version one disk is already a valid version two disk.** The parent is stored as an entry index *plus one*, so the zeroes a version one disk has in those bytes read as "in the root" - which is exactly where all of its files are. There is nothing to convert.
A disk is at the lowest version that describes what is on it, so `format` makes a version one disk and `mkdir` is what raises it. That is deliberate: a disk stays readable by anything that has never heard of a directory right up until it actually has one. Compatibility runs one way, which is the ordinary shape of it - version one code reading a version two disk would list directories as strange empty files.
## Building Programs With Make:
The assembler is built to work with make. `-o` puts the output where the build system wants it, and `-M` writes out which libraries went into it, so that editing a library reassembles everything that includes it.