lib/os+selfhost: *u8→str path migration (#23)
Path-shaped entrypoints now take str: open, tryopen, access, remove, mkdir, rmdir, mkdirs, stat, lstat, exists, execve (path arg only). Each cites its Hare source (ref/hare/os/*.ha, ref/hare/sys/+linux/ *.ha). New internal kpath(str) *u8 copies into module-level pathbuf: [4096]u8 and NUL-terminates; mirrors ref/hare/sys/+linux/syscalls.ha:25,53. Non-reentrant — graduates with thread story. mkdirs flattens to one kpath at entry then walks pathbuf invoking raw SYS_mkdir to avoid nested kpath clobber. One Hare divergence at kpath: ships *u8 with nil ENAMETOOLONG sentinel instead of (*const u8 | errno). Reason: wwstage over-allocates 1-word-payload tagged returns to 24B (cstage emits 16B); filed as follow-up. Repro at .ai/probe_tagged_return_pointer_payload.ww; graduates when fix lands. Each selfhost cmd grew a private pathstr(*u8) str (cstrlen + bs) for remaining *u8 path sites; w6l shares via obj.ww. Probe 7 in smoke updated. Tests 975/976/981 cover migrated entrypoints; 976 extended with two ENAMETOOLONG rows (-36 for stat, false for exists).
This commit is contained in:
@@ -186,7 +186,9 @@ export fn named(outfd: *i32, outpath: *str,
|
||||
};
|
||||
for (true) {
|
||||
pathlen = makenamed(dir);
|
||||
let fd: i32 = os.open(&pathbuf[0], flags, perm);
|
||||
let bs: str;
|
||||
bs.ptr = &pathbuf[0]; bs.len = pathlen;
|
||||
let fd: i32 = os.open(bs, flags, perm);
|
||||
if (fd >= 0) {
|
||||
*outfd = fd;
|
||||
let p: str;
|
||||
@@ -227,7 +229,9 @@ export fn file(iomode: mode, perm: i32) (i32 | os.oserror) = {
|
||||
export fn dir() str = {
|
||||
for (true) {
|
||||
pathlen = makedir();
|
||||
let r: i32 = os.mkdir(&pathbuf[0], 448i32); // 0o700
|
||||
let bs: str;
|
||||
bs.ptr = &pathbuf[0]; bs.len = pathlen;
|
||||
let r: i32 = os.mkdir(bs, 448i32); // 0o700
|
||||
if (r >= 0) {
|
||||
let p: str;
|
||||
p.ptr = &pathbuf[0];
|
||||
|
||||
@@ -94,13 +94,13 @@ fn streq(a: str, b: str) bool = {
|
||||
};
|
||||
|
||||
// File exists pre-cleanup.
|
||||
if (os.access(p.ptr, 0i32) != 0) { fail(); };
|
||||
if (os.access(p, 0i32) != 0) { fail(); };
|
||||
|
||||
if (os.close(fd) != 0) { fail(); };
|
||||
if (os.remove(p.ptr) != 0) { fail(); };
|
||||
if (os.remove(p) != 0) { fail(); };
|
||||
|
||||
// Cleanup landed.
|
||||
if (os.access(p.ptr, 0i32) == 0) { fail(); };
|
||||
if (os.access(p, 0i32) == 0) { fail(); };
|
||||
|
||||
i += 1;
|
||||
};
|
||||
@@ -156,10 +156,10 @@ fn strslice(p: str, lo: i32, hi: i32) str = {
|
||||
if (fd1 == fd2) { fail(); };
|
||||
|
||||
if (os.close(fd2) != 0) { fail(); };
|
||||
if (os.remove(p2.ptr) != 0) { fail(); };
|
||||
if (os.remove(p2) != 0) { fail(); };
|
||||
|
||||
if (os.close(fd1) != 0) { fail(); };
|
||||
if (os.remove(&snap[0]) != 0) { fail(); };
|
||||
if (os.remove(psnap) != 0) { fail(); };
|
||||
};
|
||||
|
||||
// NOTE: temp.file() has no test of its own. The function is a thin
|
||||
@@ -187,17 +187,20 @@ fn strslice(p: str, lo: i32, hi: i32) str = {
|
||||
if (d.ptr[d.len] != 0u8) { fail(); };
|
||||
|
||||
// Dir exists.
|
||||
if (os.access(d.ptr, 0i32) != 0) { fail(); };
|
||||
if (os.access(d, 0i32) != 0) { fail(); };
|
||||
|
||||
// Snapshot the dir path into a local NUL-terminated buffer:
|
||||
// we'll need it after os.open() (the child create) leaves
|
||||
// the buffer alone, but it's good hygiene given future
|
||||
// helpers might share pathbuf.
|
||||
// the os.* path entrypoints now copy through lib/os.pathbuf
|
||||
// (kpath), so d's view into temp.pathbuf is safe; the
|
||||
// snapshot still buys robustness against future helpers
|
||||
// that might share temp's buffer.
|
||||
let dsnap: [128]u8;
|
||||
let dlen: i32 = d.len;
|
||||
let s: i32 = 0;
|
||||
for (s < d.len) { dsnap[s] = d[s]; s += 1; };
|
||||
dsnap[d.len] = 0u8;
|
||||
let dview: str;
|
||||
dview.ptr = &dsnap[0]; dview.len = dlen;
|
||||
|
||||
if (childn[i] > 0) {
|
||||
// Build "<d>/x\0" in a local buffer.
|
||||
@@ -208,23 +211,25 @@ fn strslice(p: str, lo: i32, hi: i32) str = {
|
||||
cbuf[off] = 47u8; off += 1; // '/'
|
||||
cbuf[off] = 120u8; off += 1; // 'x'
|
||||
cbuf[off] = 0u8;
|
||||
let cview: str;
|
||||
cview.ptr = &cbuf[0]; cview.len = off;
|
||||
let cflags: os.flag = os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL;
|
||||
let fd: i32 = os.open(&cbuf[0], cflags, 384i32);
|
||||
let fd: i32 = os.open(cview, cflags, 384i32);
|
||||
if (fd < 0) { fail(); };
|
||||
let payload: [3]u8;
|
||||
payload[0] = 88u8; payload[1] = 89u8; payload[2] = 90u8; // "XYZ"
|
||||
let wr: i64 = os.write(fd, &payload[0], 3u64);
|
||||
if (wr != 3i64) { fail(); };
|
||||
if (os.close(fd) != 0) { fail(); };
|
||||
if (os.remove(&cbuf[0]) != 0) { fail(); };
|
||||
if (os.remove(cview) != 0) { fail(); };
|
||||
};
|
||||
|
||||
// Rmdir uses dsnap (more robust if the static buffer were
|
||||
// Rmdir uses dview (more robust if the static buffer were
|
||||
// touched between dir() and here).
|
||||
if (os.rmdir(&dsnap[0]) != 0) { fail(); };
|
||||
if (os.rmdir(dview) != 0) { fail(); };
|
||||
|
||||
// Cleanup landed.
|
||||
if (os.access(&dsnap[0], 0i32) == 0) { fail(); };
|
||||
if (os.access(dview, 0i32) == 0) { fail(); };
|
||||
|
||||
i += 1;
|
||||
};
|
||||
@@ -249,8 +254,8 @@ fn strslice(p: str, lo: i32, hi: i32) str = {
|
||||
if (streq(strslice(d2, 0, d2.len), dsnap)) { fail(); };
|
||||
|
||||
// Cleanup both, using snap for d1's old contents.
|
||||
if (os.rmdir(d2.ptr) != 0) { fail(); };
|
||||
if (os.rmdir(&snap[0]) != 0) { fail(); };
|
||||
if (os.rmdir(d2) != 0) { fail(); };
|
||||
if (os.rmdir(dsnap) != 0) { fail(); };
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
|
||||
Reference in New Issue
Block a user