D4: the machine makes directories too
mkdir and rmdir are the machine's own now, and a file goes where its path says rather than always in the root. A disk can be organised without the host tool touching it. Everything below the surface works in terms of a directory and a name rather than a path. sbfsWalkParent splits the last name off, walks the rest, and hands back the two - and the separator stays on the end of the head, which is what makes one rule cover every kind of path: "/x" leaves "/", which is the root; "x" leaves nothing, which is where the machine already is; and "A/x" leaves "A/", which is neither and needs no special case to say so. Saving works in those two as well, and had to. The careful order a save uses - make a temporary, write it, delete the original, rename the temporary - only works if the temporary is made in the SAME directory as the file, because the rename at the end changes a name and does not move anything. Renaming to a path naming a different directory is refused for that reason, rather than quietly being a lie the disk goes along with. Three things this cost, all found by running it: mkdir Apps/Deep made /Apps/Apps. The leaf was worked out into SbfsWanted and then the head was walked - and walking goes through sbfsPathNext, which puts every name it meets into SbfsWanted on the way past. The head's last name landed exactly where the leaf was. It has somewhere of its own now. rmdir took a directory with something still in it, which is the one failure the whole design is arranged to prevent. Looking for children clobbered DP2 and rebuilt it from the buffer and the entry count with the subtraction the wrong way round, so the pointer walked off the end of the block and found nothing. The comparison goes through a CALL now, like the two beside it, and DP2 comes back on the entry because a RET puts it there. SplitDisk's "in use but not reachable from the root" line is what caught it. Refusing a name longer than twenty two used to read the twenty third character of a shorter one, which is somebody else's string. It is measured now. Tests/agree.sh is new and is the gate this rung was for: the same disk built twice, once with SplitDisk and once with CosmOS, compared byte for byte. The two share no code and only a written specification, and every field one writes and the other only reads is checked there and nowhere else - which entry a thing lands in, which block, what a directory's unused fields hold, the version, the free count. It caught a wrong parent immediately when that was broken on purpose. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
36ce9f6ccf
commit
da91a36d92
@@ -23,6 +23,8 @@ for itself.
|
||||
- Working Directory: `cd` moves the machine, `dir` lists where it is, and the prompt says
|
||||
where that is once it is not the root. A program may move too, and the shell puts the
|
||||
working directory back when the program stops.
|
||||
- Making Directories: `mkdir` and `rmdir` on the machine, and files written where their
|
||||
path says, so a disk can be organised without the host tool.
|
||||
- Loadable Applications: Validate SBEX files, copy their Program and Data segments into
|
||||
the addresses for which they were assembled, and start them at their declared entry
|
||||
point.
|
||||
@@ -92,6 +94,8 @@ CosmOS currently provides these built-in commands:
|
||||
| `load <path>` | Read and validate an SBEX application, then place its code and data where its header requests. |
|
||||
| `run [words]` | Start the loaded application and make the rest of the line available to it as an argument. |
|
||||
| `cd [path]` | Go to a directory, or to the root with nothing after it. |
|
||||
| `mkdir <path>` | Make a directory. |
|
||||
| `rmdir <path>` | Remove one, if it is empty. |
|
||||
| `<name> [words]` | Any word the shell does not recognise is looked for on the disk as `<name>.sbx`, and loaded and started if it is there. |
|
||||
| `delete <file>` | Remove a file from the filesystem and release its blocks. |
|
||||
| `rename <file> <to>` | Give a file a different name without moving its contents. |
|
||||
@@ -194,10 +198,44 @@ path as it was typed, so `notes.txt` is the same key in two directories and noth
|
||||
the entry it holds would look wrong. It is the kind of stale that gets believed rather
|
||||
than noticed.
|
||||
|
||||
At this stage CosmOS **reads** directories and does not make them: there is no `mkdir`, and
|
||||
files a program writes go in the directory you are in. Deleting or renaming a directory is
|
||||
refused - deleting one would free its entry index, and since a parent is written as an
|
||||
index, the next file created would take that index and inherit its children.
|
||||
### Making And Removing Directories:
|
||||
|
||||
`mkdir` and `rmdir` are the machine's own, so a disk can be organised without the host
|
||||
tool. A file a program writes goes where its path says, and a bare name means the
|
||||
directory you are in.
|
||||
|
||||
**A directory costs one entry and no blocks at all.** Its start, block count and tail are
|
||||
all zero, which is what keeps the flat array of entries the whole allocation map - 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.
|
||||
|
||||
Making the first directory on a disk is what raises it from version one to version two,
|
||||
because it is the only thing that makes the difference between them real. A disk stays
|
||||
readable by anything that has never heard of a directory right up until it actually has
|
||||
one.
|
||||
|
||||
Four things are refused, and each refusal is the reason a separate command exists:
|
||||
|
||||
**`rmdir` will not take a file and `delete` will not take a directory.** Neither can be
|
||||
the one that removed more than was asked for.
|
||||
|
||||
**A directory with anything in it is refused.** This is not politeness. A parent is an
|
||||
entry *index*, and a freed index is handed to the next thing created - so the children of
|
||||
a directory removed from under them would turn up inside whatever took its place. Nothing
|
||||
points downward, so there would be no way to find them afterwards and no way to notice.
|
||||
|
||||
**A name already used in that directory is refused.** Two entries with one name in one
|
||||
place is a directory that cannot be searched sensibly: a search answers with whichever it
|
||||
meets first, and the other becomes unreachable without ever having been deleted. The same
|
||||
name in a *different* directory is fine, and is the point of the exercise.
|
||||
|
||||
**`rename` will not move anything.** Only the twenty two bytes of the name change and the
|
||||
parent is not among them, so `rename a/x b/y` would be a lie the disk went along with.
|
||||
|
||||
`Tests/agree.sh` builds the same disk twice, once with SplitDisk and once with CosmOS, and
|
||||
compares the images byte for byte. Every field one writes and the other only reads is
|
||||
checked there and nowhere else: which entry a thing lands in, which block, what a
|
||||
directory's unused fields hold, the version, the free count.
|
||||
|
||||
### Starting An Application By Name:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user