docs
This commit is contained in:
+57
-2
@@ -1012,6 +1012,56 @@ private:
|
||||
return(stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode));
|
||||
}
|
||||
|
||||
// Keep cwd host behavior local to this process but guard it with the same
|
||||
// write-root policy we use for file writes (plus a single parity fallback).
|
||||
String resolve_guest_cwd_set(const String& raw)
|
||||
{
|
||||
if(raw == "" || raw.find('\0') != String::npos)
|
||||
return("");
|
||||
|
||||
String raw_target = raw;
|
||||
if(raw.rfind("/", 0) != 0)
|
||||
{
|
||||
String cwd = ::cwd_get();
|
||||
if(cwd == "")
|
||||
return("");
|
||||
raw_target = cwd + "/" + raw;
|
||||
}
|
||||
|
||||
char resolved[PATH_MAX];
|
||||
if(!realpath(raw_target.c_str(), resolved))
|
||||
return("");
|
||||
String resolved_target(resolved);
|
||||
if(!dir_exists_host(resolved_target))
|
||||
return("");
|
||||
|
||||
// Policy: allow only roots we already expose for writable filesystem access.
|
||||
std::vector<String> roots;
|
||||
roots.push_back(worker.cfg.site_root);
|
||||
for(auto& root : worker.cfg.write_roots)
|
||||
roots.push_back(root);
|
||||
for(auto& root : roots)
|
||||
{
|
||||
if(root == "")
|
||||
continue;
|
||||
char root_real[PATH_MAX];
|
||||
if(!realpath(root.c_str(), root_real))
|
||||
continue;
|
||||
String canonical_root(root_real);
|
||||
if(resolved_target == canonical_root)
|
||||
return(resolved_target);
|
||||
if(canonical_root != "/" && resolved_target.rfind(canonical_root + "/", 0) == 0)
|
||||
return(resolved_target);
|
||||
}
|
||||
|
||||
// Parity/fallback: allow returning to the process start directory so
|
||||
// legacy behavior is not silently broken for existing native/cached flows.
|
||||
String start_directory = ::process_start_directory();
|
||||
if(start_directory != "" && resolved_target == start_directory)
|
||||
return(resolved_target);
|
||||
return("");
|
||||
}
|
||||
|
||||
String resolve_source_path(const String& file_name, const String& current_unit)
|
||||
{
|
||||
std::vector<String> bases;
|
||||
@@ -1378,7 +1428,8 @@ private:
|
||||
return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> {
|
||||
String path;
|
||||
self->hostcall_read(args[0].i32(), args[1].i32(), path);
|
||||
results[0] = Val(::chdir(path.c_str()) == 0 ? (int32_t)1 : (int32_t)0);
|
||||
String resolved = self->resolve_guest_cwd_set(path);
|
||||
results[0] = Val(::chdir(resolved.c_str()) == 0 ? (int32_t)1 : (int32_t)0);
|
||||
return(std::monostate());
|
||||
}));
|
||||
if(mod == "env" && name == "uce_host_process_start_directory")
|
||||
@@ -1991,6 +2042,10 @@ private:
|
||||
f64 interval = args[3].f64();
|
||||
u64 timeout = (u64)args[4].i64();
|
||||
bool repeat = args[5].i32() != 0;
|
||||
// task()/task_repeat() fork and invoke this lambda only in the child
|
||||
// before the hostcall stack unwinds, so `self` points to the child's
|
||||
// copy of this per-request workspace. The parent request can return and
|
||||
// destroy its workspace without invalidating the child copy.
|
||||
auto run_callback = [self, callback_id]() {
|
||||
String error = self->run_task_callback(callback_id);
|
||||
if(error != "")
|
||||
@@ -2049,7 +2104,7 @@ private:
|
||||
}));
|
||||
if(mod == "env" && name == "uce_host_regex")
|
||||
return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> {
|
||||
// {op,pattern,subject,flags,replacement} in (UCEB1) → result out.
|
||||
// {op,pattern,subject,flags,replacement} in (UCEB2) → result out.
|
||||
// PCRE2 lives host-side; this runs the native regex_*.
|
||||
String encoded;
|
||||
self->hostcall_read(args[0].i32(), args[1].i32(), encoded);
|
||||
|
||||
Reference in New Issue
Block a user