A listing says what is left of the disk, and what will fit
dir said what was there and nothing about what was left. SplitDisk has printed the free figure since it was written, so the machine's own listing was the poorer of the two implementations at describing the same disk. 43 files, 3 directories 46 of 64 entries, 1893 blocks free Entries first, because they are the ceiling nobody notices until they hit it: a disk of small files runs out of directory slots long before it runs out of blocks. COUNTED RATHER THAN ASKED. The superblock keeps a free count and this file calls it "a note rather than the truth" in three places. sbfsSpace reads the whole directory table instead, which costs a read per directory block and is the answer rather than a guess. SplitDisk goes on reading the note and saying when it is stale, which is the right place for that check - the host tool is what you audit a disk with. ---- And it is a fact about the disk, not about where you are ---- The first version added the blocks up as the LISTING walked past them, which cost no extra read and was wrong: that walk stops only on entries in the working directory, so the same disk came out as 1,996 blocks free from the root and 2,025 from /Apps. Comparing against SplitDisk is what said so, which is what having two implementations is for. ---- The longest run, which is what decides whether a file fits ---- 4 of 16 entries, 37 blocks free the longest run is 25 Files are laid down contiguously, so the free total does not say whether a file will fit. Both implementations learn it, from one specification. Said only when it differs from the free total. Deleting is what fragments a contiguous store, and a disk that has only been appended to has one gap at the end - so on a healthy disk this is silent, and a line that appears only when something is wrong is a line somebody reads. There is no sort on this machine and the entries are in no order, so a candidate walks the disk: each pass finds the used extent nearest at or after it, and anything the candidate stands inside pushes it to the far end and starts the pass again. The same trick allocating uses. So it costs a pass per gap rather than per file - nearly nothing on a disk with one gap, more the more fragmented the disk is, which is the right way round. holes.img is six files with the second and fourth deleted, because no other disk here can show any of this: none of them has ever had anything deleted from it. 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
2ad8edf9bc
commit
323d7a0330
@@ -15,6 +15,7 @@ made
|
||||
> cd Notes
|
||||
/Notes> dir
|
||||
0 files
|
||||
8 of 32 entries, 308 blocks free
|
||||
/Notes> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -29,6 +29,7 @@ across.txt 700
|
||||
empty.txt 0
|
||||
aName22CharactersLong! 22
|
||||
12 files
|
||||
12 of 16 entries, 48 blocks free
|
||||
>
|
||||
> frobnicate
|
||||
I do not know: frobnicate
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
CosmOS
|
||||
> dir
|
||||
0 files
|
||||
0 of 16 entries, 125 blocks free
|
||||
> mkdir Apps
|
||||
made
|
||||
> mkdir Apps/Deep
|
||||
@@ -11,10 +12,12 @@ made
|
||||
Apps <dir>
|
||||
Notes <dir>
|
||||
0 files, 2 directories
|
||||
3 of 16 entries, 125 blocks free
|
||||
> cd Apps
|
||||
/Apps> dir
|
||||
Deep <dir>
|
||||
0 files, 1 directory
|
||||
3 of 16 entries, 125 blocks free
|
||||
/Apps> mkdir Deep
|
||||
cannot make that: check the path, the name, and whether it is taken
|
||||
/Apps> mkdir /Notes/Deep
|
||||
@@ -23,6 +26,7 @@ made
|
||||
/Notes> dir
|
||||
Deep <dir>
|
||||
0 files, 1 directory
|
||||
4 of 16 entries, 125 blocks free
|
||||
/Notes> rmdir /Apps
|
||||
cannot remove that: it must be a directory, and empty
|
||||
/Notes> rmdir /Apps/Deep
|
||||
@@ -44,6 +48,7 @@ removed
|
||||
removed
|
||||
> dir
|
||||
0 files
|
||||
0 of 16 entries, 125 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -7,6 +7,7 @@ finished
|
||||
Claim.sbx 580
|
||||
claim.dat 266
|
||||
2 files
|
||||
2 of 16 entries, 56 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -51,6 +51,7 @@ pass.script 20
|
||||
holds.script 87
|
||||
crossed.txt 560
|
||||
36 files, 2 directories
|
||||
47 of 64 entries, 1890 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -4,11 +4,13 @@ Apps <dir>
|
||||
A <dir>
|
||||
B <dir>
|
||||
0 files, 3 directories
|
||||
9 of 32 entries, 240 blocks free
|
||||
> cd /A
|
||||
/A> dir
|
||||
Say.sbx 53
|
||||
notes.txt 25
|
||||
2 files
|
||||
9 of 32 entries, 240 blocks free
|
||||
/A> Type notes.txt
|
||||
these are the notes in A
|
||||
finished
|
||||
@@ -29,6 +31,7 @@ Apps <dir>
|
||||
A <dir>
|
||||
B <dir>
|
||||
0 files, 3 directories
|
||||
9 of 32 entries, 240 blocks free
|
||||
> cd /B
|
||||
/B> Type ../A/notes.txt
|
||||
these are the notes in A
|
||||
@@ -50,6 +53,7 @@ Apps <dir>
|
||||
A <dir>
|
||||
B <dir>
|
||||
0 files, 3 directories
|
||||
9 of 32 entries, 240 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -40,6 +40,7 @@ args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> drive 1
|
||||
> dir
|
||||
other.txt 28
|
||||
@@ -47,6 +48,7 @@ notes <dir>
|
||||
2things <dir>
|
||||
twoblocks.txt 560
|
||||
2 files, 2 directories
|
||||
4 of 32 entries, 503 blocks free
|
||||
> cd /notes
|
||||
/notes> drive 0
|
||||
> drive 1
|
||||
|
||||
@@ -57,6 +57,7 @@ args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -3,17 +3,21 @@ CosmOS
|
||||
one.txt 13
|
||||
two.txt 14
|
||||
2 files
|
||||
2 of 8 entries, 28 blocks free
|
||||
> rename one.txt first.txt
|
||||
renamed
|
||||
> dir
|
||||
first.txt 13
|
||||
two.txt 14
|
||||
2 files
|
||||
2 of 8 entries, 28 blocks free
|
||||
> delete first.txt
|
||||
gone
|
||||
> dir
|
||||
two.txt 14
|
||||
1 file
|
||||
1 of 8 entries, 29 blocks free
|
||||
the longest run is 28
|
||||
> delete first.txt
|
||||
no such file
|
||||
> rename two.txt
|
||||
|
||||
@@ -47,6 +47,7 @@ args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -47,6 +47,7 @@ args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -17,6 +17,7 @@ notes.sbx 21
|
||||
hello.sh 38
|
||||
Apps <dir>
|
||||
6 files, 1 directory
|
||||
8 of 16 entries, 54 blocks free
|
||||
> Greet a program with no extension
|
||||
it says: a program with no extension
|
||||
finished
|
||||
|
||||
@@ -133,6 +133,7 @@ args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -52,6 +52,7 @@ args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -2,12 +2,14 @@ CosmOS
|
||||
> drive 1
|
||||
> dir
|
||||
0 files
|
||||
0 of 128 entries, 2031 blocks free
|
||||
> Copy 0:/Say.sbx 1:/Say.sbx
|
||||
copied
|
||||
finished
|
||||
> dir
|
||||
Say.sbx 156
|
||||
1 file
|
||||
1 of 128 entries, 2030 blocks free
|
||||
> drive
|
||||
1
|
||||
> exit
|
||||
|
||||
@@ -40,6 +40,7 @@ args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> load
|
||||
load what?
|
||||
> load nosuch.sbx
|
||||
|
||||
@@ -38,6 +38,7 @@ args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> load Say.sbx
|
||||
loaded, starting at 5000
|
||||
> run the disk took its time
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
CosmOS
|
||||
> dir
|
||||
greet.sbx 211
|
||||
hello.sbx 53
|
||||
Life.sbx 1396
|
||||
Snake.sbx 2164
|
||||
Keys.sbx 664
|
||||
Say.sbx 156
|
||||
Where.sbx 827
|
||||
Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Sprite.sbx 442
|
||||
Depth.sbx 672
|
||||
Packages <dir>
|
||||
Pad.sbx 264
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 318
|
||||
Play.sbx 2526
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
bad.script 45
|
||||
plain.script 24
|
||||
cross.script 280
|
||||
nonl.script 38
|
||||
outer.script 376
|
||||
inner.script 44
|
||||
loop.script 35
|
||||
hush.script 42
|
||||
aloud.script 59
|
||||
args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> drive 1
|
||||
> dir
|
||||
f1.txt 1500
|
||||
f3.txt 1500
|
||||
f5.txt 1500
|
||||
f6.txt 1500
|
||||
4 files
|
||||
4 of 16 entries, 37 blocks free
|
||||
the longest run is 25
|
||||
> drive 0
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
[exit 0]
|
||||
@@ -47,6 +47,7 @@ args.script 64
|
||||
pass.script 20
|
||||
holds.script 87
|
||||
35 files, 2 directories
|
||||
46 of 64 entries, 1893 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -3,6 +3,7 @@ CosmOS
|
||||
Apps <dir>
|
||||
rooted.txt 21
|
||||
1 file, 1 directory
|
||||
5 of 32 entries, 248 blocks free
|
||||
> load /Apps/Say.sbx
|
||||
loaded, starting at 5000
|
||||
> run the shallow one
|
||||
@@ -43,6 +44,8 @@ gone
|
||||
Apps <dir>
|
||||
rooted.txt 21
|
||||
1 file, 1 directory
|
||||
4 of 32 entries, 249 blocks free
|
||||
the longest run is 248
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -3,6 +3,7 @@ CosmOS
|
||||
Folder <dir>
|
||||
Edit.sbx 2243
|
||||
1 file, 1 directory
|
||||
3 of 16 entries, 244 blocks free
|
||||
> load Edit.sbx
|
||||
loaded, starting at 5000
|
||||
> run note.txt
|
||||
@@ -20,6 +21,7 @@ Folder <dir>
|
||||
Edit.sbx 2243
|
||||
note.txt 67
|
||||
2 files, 1 directory
|
||||
4 of 16 entries, 243 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -6,6 +6,7 @@ finished
|
||||
System <dir>
|
||||
Apps <dir>
|
||||
0 files, 2 directories
|
||||
8 of 32 entries, 305 blocks free
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -13,6 +13,7 @@ made
|
||||
> cd Notes
|
||||
/Notes> dir
|
||||
0 files
|
||||
7 of 32 entries, 309 blocks free
|
||||
/Notes> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -13,6 +13,7 @@ made
|
||||
> cd Notes
|
||||
/Notes> dir
|
||||
0 files
|
||||
7 of 32 entries, 309 blocks free
|
||||
/Notes> exit
|
||||
halted
|
||||
Execution halted.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
dir
|
||||
drive 1
|
||||
dir
|
||||
drive 0
|
||||
exit
|
||||
@@ -230,6 +230,26 @@ printf '#! script\nfor a in 1 2\n for b in x y\n echo $a$b\n end\nend\nset
|
||||
printf 'this is not a program' > notes.txt
|
||||
"$TOOL" put "$DISKS/cosmos.img" notes.txt >/dev/null
|
||||
|
||||
# ---- A disk with holes in it ----
|
||||
#
|
||||
# Six files laid down one after another, then the second and the fourth taken away. Files are
|
||||
# laid down CONTIGUOUSLY on this format, so what is left is thirty seven free blocks in three
|
||||
# pieces - two of six between the survivors and twenty five at the end - and the largest file
|
||||
# that will fit is twenty five blocks, not thirty seven.
|
||||
#
|
||||
# That gap between "how much is free" and "how much will fit" is the whole reason a listing
|
||||
# says the longest run, and it is invisible on every other disk here: a disk that has only
|
||||
# been appended to has one gap, at the end, and the two numbers are the same. Deleting is what
|
||||
# fragments a contiguous store, so a disk that has never had anything deleted from it cannot
|
||||
# demonstrate any of this.
|
||||
"$TOOL" format "$DISKS/holes.img" 64 2 >/dev/null
|
||||
python3 -c "open('holey.txt','w').write('x' * 1500)"
|
||||
for i in 1 2 3 4 5 6; do
|
||||
"$TOOL" put "$DISKS/holes.img" holey.txt "f$i.txt" >/dev/null
|
||||
done
|
||||
"$TOOL" delete "$DISKS/holes.img" f2.txt >/dev/null
|
||||
"$TOOL" delete "$DISKS/holes.img" f4.txt >/dev/null
|
||||
|
||||
# ---- A second disk, for the second drive ----
|
||||
#
|
||||
# Deliberately nothing like the first: its own file and its own directory, so that a test
|
||||
|
||||
@@ -1033,6 +1033,24 @@ cosmosWhere | CosmOS/Source/cosmos.asm | run | cosmosWhe
|
||||
# a name twice. Then the same walk in /Apps, because a walk that only ever ran at the root
|
||||
# would not have proved it walks where you are.
|
||||
cosmosWalk | CosmOS/Source/cosmos.asm | run | cosmosWalk.in | 200000000 | disks/cosmos.img
|
||||
# ---- What a listing says about the disk it is listing ----
|
||||
#
|
||||
# dir said what was there and nothing about what was left. SplitDisk has printed the free
|
||||
# figure since it was written, so the machine's own listing was the poorer of the two
|
||||
# implementations at describing the same disk.
|
||||
#
|
||||
# COUNTED RATHER THAN ASKED. The superblock keeps a free count and sbfs.asm calls it "a note
|
||||
# rather than the truth" in three places; this reads the whole directory table instead. The
|
||||
# first version added the blocks up as the LISTING walked past them, which cost nothing extra
|
||||
# and was wrong - that walk stops only on entries in the working directory, so the same disk
|
||||
# came out as 1,996 blocks free from the root and 2,025 from /Apps. Listing both directories
|
||||
# here is what would say so again.
|
||||
#
|
||||
# And then a disk with holes in it, which is the case the longest run exists for: thirty seven
|
||||
# blocks free in three pieces, so the largest file that will fit is twenty five. Said only
|
||||
# when it differs from the free total, so the first listing is silent about it and the second
|
||||
# is not - a line that appears only when something is wrong is a line somebody reads.
|
||||
cosmosSpace | CosmOS/Source/cosmos.asm | run | cosmosSpace.in | 200000000 | disks/cosmos.img+disks/holes.img
|
||||
# ---- Starting itself ----
|
||||
#
|
||||
# /System/Boot/startup.sh runs before anybody can type. This one is also the check on #quiet
|
||||
|
||||
Reference in New Issue
Block a user