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.
48 lines
2.3 KiB
Markdown
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.
|