build: separate package identity from storage paths

This commit is contained in:
2026-08-13 05:37:56 +09:00
parent 5f0f544157
commit c3df0afeb0
11 changed files with 1167 additions and 505 deletions

View File

@@ -1,5 +1,7 @@
package wwpackage;
import crypto.sha256;
import hash;
import os;
import os.exec;
import strconv;
@@ -269,9 +271,9 @@ fn pkgkeepfile(name: str) bool = {
// One explicit package directory; with recurse (the DIR/... form) every
// subdirectory whose name does not begin with '.' or '_' is descended as
// well, Go's ./... convention. lstat is used for the root and each
// candidate so a symlink cannot be used to cross the boundary (including
// DT_UNKNOWN files); a symlinked subdirectory is skipped, not followed.
// well, Go's ./... convention. An explicitly selected root may be a symlink;
// canonical planning coalesces it with the target directory. Recursive child
// symlinks remain skipped and symlink source files remain rejected.
fn pkgdiscoverdir(path: str, st: *pkgdiscover, recurse: bool) void = {
let rootstat: os.filestat;
match (os.lstat(&rootstat, path)) {
@@ -283,9 +285,14 @@ fn pkgdiscoverdir(path: str, st: *pkgdiscover, recurse: bool) void = {
};
};
if (pkgmodeis(rootstat.mode, os.mode.LINK)) {
pkgfailpath(path, "symlink traversal is not allowed");
st.errors += 1;
return;
match (os.stat(&rootstat, path)) {
case void => void;
case let e: os.oserror => {
pkgfailpath(path, "cannot stat package directory");
st.errors += 1;
return;
};
};
};
if (!pkgmodeis(rootstat.mode, os.mode.DIR)) {
pkgfailpath(path, "expected one package directory");
@@ -540,7 +547,25 @@ fn pkgworkescape(s: str) str = {
};
fn pkgworkkey(dir: str) str = {
return strings.concat("d_", pkgworkescape(dir));
let escaped: str = strings.concat("d_", pkgworkescape(dir));
if (escaped.len <= 255) { return escaped; };
let state: sha256.state = sha256.sha256();
let h: *hash.hash = (&state): *hash.hash;
hash.write(h, strings.toutf8("ww-request-workdir-v1:"));
hash.write(h, strings.toutf8(dir));
let digest: [32]u8;
hash.sum(h, digest[0:32]);
let out: []u8 = alloc([], 65u64)!;
let digits: str = "0123456789abcdef";
let i: i32 = 0;
for (i < 32) {
let high: i32 = (digest[i] / 16u8): i32;
let low: i32 = (digest[i] % 16u8): i32;
append(out, digits[high]);
append(out, digits[low]);
i += 1;
};
return strings.concat("d_", strings.frombytes(out));
};
fn pkgsetplanpaths(p: *pkgplan, groups: []pkggroup, root: str, index: i32,