ww: enforce internal package visibility
This commit is contained in:
15
lib/os/os.ww
15
lib/os/os.ww
@@ -46,6 +46,7 @@ type nr = enum i64 {
|
||||
RMDIR = 84,
|
||||
UNLINK = 87,
|
||||
SYMLINK = 88,
|
||||
READLINK = 89,
|
||||
SETPGID = 109,
|
||||
GETDENTS64 = 217,
|
||||
NEWFSTATAT = 262,
|
||||
@@ -132,7 +133,7 @@ export def SFD_NONBLOCK: i32 = O_NONBLOCK;
|
||||
export def SFD_CLOEXEC: i32 = O_CLOEXEC;
|
||||
|
||||
fn kpath(p: str) *u8 = {
|
||||
if (p.len + 1 >= PATH_MAX) { return nil: *u8; }; // ENAMETOOLONG
|
||||
if (p.len + 1 > PATH_MAX) { return nil: *u8; }; // ENAMETOOLONG
|
||||
let i: i32 = 0;
|
||||
for (i < p.len) { pathbuf[i] = p[i]; i += 1; };
|
||||
pathbuf[p.len] = 0u8;
|
||||
@@ -347,7 +348,7 @@ export fn rmdir(path: str) i32 = {
|
||||
export fn rename(oldpath: str, newpath: str) i32 = {
|
||||
let p: *u8 = kpath(oldpath);
|
||||
if (p == nil: *u8) { return -36i32; };
|
||||
if (newpath.len + 1 >= PATH_MAX) { return -36i32; };
|
||||
if (newpath.len + 1 > PATH_MAX) { return -36i32; };
|
||||
let i: i32 = 0;
|
||||
for (i < newpath.len) { pathbuf2[i] = newpath[i]; i += 1; };
|
||||
pathbuf2[newpath.len] = 0u8;
|
||||
@@ -364,13 +365,21 @@ export fn rename(oldpath: str, newpath: str) i32 = {
|
||||
export fn symlink(target: str, path: str) i32 = {
|
||||
let p: *u8 = kpath(target);
|
||||
if (p == nil: *u8) { return -36i32; };
|
||||
if (path.len + 1 >= PATH_MAX) { return -36i32; };
|
||||
if (path.len + 1 > PATH_MAX) { return -36i32; };
|
||||
let i: i32 = 0;
|
||||
for (i < path.len) { pathbuf2[i] = path[i]; i += 1; };
|
||||
pathbuf2[path.len] = 0u8;
|
||||
return syscall2(nr.SYMLINK, p: i64, (&pathbuf2[0]): i64): i32;
|
||||
};
|
||||
|
||||
// readlink — read a symlink target without appending NUL. The caller owns the
|
||||
// buffer and uses the returned byte count, matching readlink(2).
|
||||
export fn readlink(path: str, buf: *u8, n: u64) i64 = {
|
||||
let p: *u8 = kpath(path);
|
||||
if (p == nil: *u8) { return -36i64; };
|
||||
return syscall3(nr.READLINK, p: i64, buf: i64, n: i64);
|
||||
};
|
||||
|
||||
// mkdirs — recursive mkdir. Creates `path` and any non-existent
|
||||
// parent directories with the given mode. EEXIST is silently
|
||||
// accepted (matches Hare's `errors::exists` skip in os::mkdirs);
|
||||
|
||||
@@ -157,6 +157,25 @@ fn istype(m: os.mode, t: os.mode) bool = {
|
||||
rmtree(&t);
|
||||
};
|
||||
|
||||
@test fn test_readlink_verbatim() void = {
|
||||
let t: tree;
|
||||
mktree(&t);
|
||||
let buf: [16]u8;
|
||||
let i: i32 = 0;
|
||||
for (i < 16) { buf[i] = 90u8; i += 1; }; // 'Z'
|
||||
let n: i64 = os.readlink(t.symlink, &buf[0], 16u64);
|
||||
assert(!(n != 9i64));
|
||||
let want: str = "./regfile";
|
||||
i = 0;
|
||||
for (i < want.len) {
|
||||
assert(!(buf[i] != want[i]));
|
||||
i += 1;
|
||||
};
|
||||
let ni: i32 = n: i32;
|
||||
assert(!(buf[ni] != 90u8));
|
||||
rmtree(&t);
|
||||
};
|
||||
|
||||
@test fn test_fstat_regfile() void = {
|
||||
let t: tree;
|
||||
mktree(&t);
|
||||
@@ -196,7 +215,7 @@ fn istype(m: os.mode, t: os.mode) bool = {
|
||||
};
|
||||
|
||||
// kpath copies into a single [PATH_MAX]u8 buffer and reserves one byte
|
||||
// for the NUL terminator (`p.len + 1 >= PATH_MAX` → reject). The
|
||||
// for the NUL terminator (`p.len + 1 > PATH_MAX` → reject). The
|
||||
// rejection surfaces as `oserror = -36` (ENAMETOOLONG) on (... |
|
||||
// oserror)-returning wrappers, and as `false` on [[os.exists]]
|
||||
// (Hare's os::exists doc: "true if a node exists at the given path,
|
||||
|
||||
Reference in New Issue
Block a user