Refuse a directory whose last entries cannot be named as a parent
A parent is an entry index PLUS ONE in two bytes, so entry 65535 has no parent number: adding one wraps to zero, and zero is the root. Eight entries to a block, so 8192 directory blocks reaches it and SplitDisk formatted that happily. It does not fail by refusing, which is why it was worth chasing rather than reasoning about. Reproduced on a disk built for it: mkdir /deep/child, with /deep at entry 65535, printed 'Made "/deep/child" as entry 0' and put child in the ROOT. Listing /deep then showed nothing, because the search is for a parent of 65536 and the entry carries zero - so the same mkdir succeeded again, and again, and five entries called /child piled up in the root. Duplicate names in one directory are the one thing rename refuses outright, on the grounds that a search answers with whichever it meets first and the rest can never be reached; this manufactured them one per attempt. 8191 blocks is the most, giving 65528 entries. Refused when formatting and again when reading, in both implementations, because a disk claiming more was made by something that never checked. On the machine only the high byte of the count has to be looked at: anything from 0x20 up is too many. Three checks, all of which fail with their guard removed. The machine's disk claims the size rather than having it, so the test image is 64 blocks that lie rather than sixteen megabytes that do not - mounting is refused at the geometry, which is read out of block 0.
This commit is contained in:
@@ -155,6 +155,23 @@ before=$(blocksFree tree.img)
|
||||
"$TOOL" mkdir tree.img /Empty >/dev/null 2>&1
|
||||
check "a directory costs no blocks" [ "$before" = "$(blocksFree tree.img)" ]
|
||||
|
||||
# ---- A directory no bigger than the parent field can name ----
|
||||
#
|
||||
# Eight entries to a block and the parent is an index plus one in two bytes, so entry
|
||||
# 65535 has no parent number: adding one wraps to zero, and zero is the root. Such an
|
||||
# entry does not refuse what is put inside it. It writes the thing into the ROOT while
|
||||
# reporting the path that was asked for, and then cannot find it again - so the same
|
||||
# create succeeds over and over, piling up entries of one name in one directory, which is
|
||||
# the exact corruption rename exists to refuse.
|
||||
refuses "no directory past the wrap" "$TOOL" format huge.img 65535 8192
|
||||
check "the largest that fits" "$TOOL" format huge.img 65535 8191
|
||||
|
||||
# And a disk claiming one, which is what something that never checked would have written.
|
||||
# The claim is in the superblock, so it does not need a disk that size to be made.
|
||||
"$TOOL" format lying.img 64 2 >/dev/null
|
||||
printf '\x20\x00' | dd of=lying.img bs=1 seek=10 conv=notrunc status=none
|
||||
refuses "nor reading one that claims it" "$TOOL" list lying.img
|
||||
|
||||
echo
|
||||
if [ "$FAIL" -eq 0 ]; then
|
||||
echo "All $PASS disk tool checks passed."
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
CosmOS
|
||||
no filesystem on the disk
|
||||
> no filesystem on the disk
|
||||
> halted
|
||||
Execution halted.
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
dir
|
||||
exit
|
||||
@@ -342,3 +342,14 @@ for i in 1 2 3 4 5 6 7 8; do
|
||||
DEEPPATH="$DEEPPATH/abcdefghijklmnopqrst0$i"
|
||||
"$TOOL" mkdir "$DISKS/deep.img" "$DEEPPATH" >/dev/null
|
||||
done
|
||||
|
||||
# A disk whose superblock claims a directory bigger than the parent field can name. Entry
|
||||
# 65535 has no parent number - index plus one wraps to zero, which is the root - so
|
||||
# anything created inside it lands in the root instead while the tool reports success.
|
||||
#
|
||||
# THE CLAIM IS ALL THAT IS NEEDED, so this is a small disk that lies rather than a sixteen
|
||||
# megabyte one that tells the truth. Mounting reads block 0 and gets as far as the
|
||||
# geometry, which is where it is refused. SplitDisk will not make one of these any more,
|
||||
# so the superblock is written by hand.
|
||||
"$TOOL" format "$DISKS/bigdir.img" 64 2 >/dev/null
|
||||
printf '\x20\x00' | dd of="$DISKS/bigdir.img" bs=1 seek=10 conv=notrunc status=none
|
||||
|
||||
@@ -345,6 +345,14 @@ cosmosCopyCompare | CosmOS/Source/cosmos.asm | run | cosmosCop
|
||||
# help and cd and exit from down there rather than just looking at the prompt. A prompt
|
||||
# that is merely wrong is a cosmetic fault; this one was writing into other variables.
|
||||
cosmosDeep | CosmOS/Source/cosmos.asm | run | cosmosDeep.in | - | disks/deep.img
|
||||
|
||||
# A disk claiming a directory of 8192 blocks, which is 65536 entries. The last of those is
|
||||
# entry 65535, and the parent field is an index PLUS ONE in two bytes - so it wraps to
|
||||
# zero, which means the root. Anything created in such a directory goes into the root
|
||||
# while the caller is told it went where it asked, and looking there afterwards finds
|
||||
# nothing, so the same create works again and again and fills the root with entries of one
|
||||
# name. Refused at mount, which is the only place it can be refused once and for all.
|
||||
cosmosBigDir | CosmOS/Source/cosmos.asm | run | cosmosBigDir.in | - | disks/bigdir.img
|
||||
# Reading a disk that has directories on it. The machine can walk a path at this point but
|
||||
# cannot make a directory, so the disk is built by the host tool and read here - which is
|
||||
# the two implementations checking each other rather than either checking itself.
|
||||
|
||||
Reference in New Issue
Block a user