SchOS/.claude/memory/schunix-dirsiz-14.md
Nexoniarz 3182da3965 Carry project memory in the repo, with tools/memory-sync.sh
Claude Code keeps per-project memory at <home>/.claude/projects/<key>/,
where <key> is the project's absolute path with every separator and the
drive colon turned into a dash. That makes it both rename-fragile and
machine-specific, and this project has hit each of those once:

  - D:\DEV\Schunix -> D:\DEV\SchOS changed the key, and 43 memories were
    invisible until moved across by hand.
  - Development happens from Windows and from Linux, and each looks in a
    different place for the same checkout.

Committing .claude/memory/ fixes both -- git carries it across renames
and between hosts -- and `import` puts it wherever the local machine
expects. .claude/settings.local.json stays ignored: those are per-machine
permissions.

The colon maps to a dash rather than being dropped. Deleting it gives
D-DEV-SchOS, which matches nothing and silently finds zero memories; that
was the first attempt. On Git Bash the key comes from `cygpath -w`,
because Claude Code is a Windows program and sees D:\DEV\SchOS, not
/d/DEV/SchOS.
2026-08-09 14:27:22 +02:00

48 lines
2.3 KiB
Markdown

---
name: schunix-dirsiz-14
description: DIRSIZ was 14 and truncated silently; raised to 30 on 2026-08-09 by holding the HTree bucket at 256 bytes.
metadata:
type: project
---
Found 2026-08-09 while staging fonts. `DIRSIZ` in `include/fs.h` is **14**, an
xv6 inheritance, and the v1 filesystem truncates to it **silently**.
`JetBrainsMono-Regular.ttf` was stored as `JetBrainsMono-`. Two consequences,
the second much worse than the first:
- The file cannot be opened by its real name, and `stat` fails on it — `ls -l`
showed `?` for every field, which is what tipped this off.
- **`JetBrainsMono-Regular.ttf` and `JetBrainsMono-Bold.ttf` both truncate to
`JetBrainsMono-`.** Any set of files sharing a 14-character prefix collides.
That is silent data loss, not a display limitation.
## Fixed the same day: DIRSIZ is 30
**The trick that made it safe: hold the HTree bucket at 256 bytes.**
The directory hash tree is laid out in *bytes*, not entries. A bucket was 16
slots x 16 bytes = 256, and `HASHRANGE`, `OVERFLOW_DIR_START` (113 * BSIZE),
`OVERFLOW_DIR_END` and `MAXFSIZE` are all derived from that. Raising DIRSIZ
naively to 62 would have made buckets 1024 bytes and pushed the primary area
from 117 KB to 470 KB, straight through the overflow region -- silent corruption
of every directory.
DIRSIZ 30 makes `struct dirent` exactly **32 bytes**, so a 256-byte bucket holds
**8** slots instead of 16 and **every byte offset in the layout is unchanged**.
`DIRENT_BUCKET_BYTES` in `include/fs.h` is now the constant the maths is written
against; `kernel/fs/fs.c` and `tools/mkfs.c` both use it instead of
`16 * sizeof(struct dirent)`. Cost: more overflow use in heavily collided
directories.
**Verified in the running system**: `/usr/share/fonts` lists
`JetBrainsMono-Regular.ttf` in full, and `/tmp/JetBrainsMono-Regular.txt` and
`/tmp/JetBrainsMono-Bold.txt` coexist with distinct contents -- the exact case
that used to collapse into one entry. All four bootcheck modes pass.
**Still not POSIX's 255.** Getting there means reshaping the directory format,
which wants the on-disk version policy SchFS is getting first. 30 covers real
filenames; it is not a general solution.
`sysroot/bin`'s 244 toybox links were checked for collisions at the old limit:
there were none, so nothing was silently broken before this.