lib/dirs: abort loudly on over-long path, not silent truncation (#69)

dirs build() capped the composed path at the 256B pathbuf with a silent
break, so a HOME (or XDG_*) near/over ~240 bytes produced a truncated
path that lookup() then mkdir'd and returned rc=0 — a silently-wrong,
freshly-created directory. ref/hare/dirs/xdg.ha routes through
path::set/push whose too_long error the `!` aborts loudly. Precompute
the composition length in build() and rt_abort when it won't fit; drop
the now-dead silent caps. (Shape (a); routing dirs through lib/path is
the filed fidelity follow-up.)

975_dirs_toolong_run pins the abort + no-stray-dir on both driver twins.
This commit is contained in:
2026-06-13 10:38:51 +09:00
parent bccd111a16
commit 427b67f656
3 changed files with 163 additions and 3 deletions

View File

@@ -90,15 +90,24 @@ fn puts(off: i32, s: str) i32 = {
// Embedded '/' in `sub` (e.g. ".local/share") is fine — [[os.mkdirs]]
// handles intermediate dirs.
fn build(base: str, sub: str, prog: str) void = {
// ref/hare/dirs/xdg.ha routes through path::set/push, whose too_long
// error the `!` turns into a loud abort. ww's fixed 256B pathbuf
// (dirs.ww:58) is a documented simplification, but the overflow must
// be LOUD, not a silently-wrong directory that then gets mkdir'd:
// reject up front when the composition (+ trailing NUL) won't fit.
// Shape (a); routing dirs through lib/path is the fidelity follow-up.
let need: i32 = base.len + 1 + prog.len;
if (sub.len > 0) { need += 1 + sub.len; };
if (need >= 256) { rtabort("dirs: path too long"); };
let off: i32 = 0;
off = puts(off, base);
if (sub.len > 0) {
if (off < 255) { pathbuf[off] = SEP; off += 1; };
pathbuf[off] = SEP; off += 1;
off = puts(off, sub);
};
if (off < 255) { pathbuf[off] = SEP; off += 1; };
pathbuf[off] = SEP; off += 1;
off = puts(off, prog);
if (off > 255) { off = 255; };
pathbuf[off] = 0u8;
pathlen = off;
};