Files
nt-lite/code/user/tests/cwd_userspace_smoke/cwd_userspace_smoke.c
T

118 lines
4.0 KiB
C

// Userspace current-directory smoke test.
// Verifies CWD inheritance and parent traversal clamped at the owning RSSRV resource binding.
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <ntlite/syscall.h>
#include <ntlite/path.h>
#include <ntlite/resource.h>
static void print(const char* s) {
SYS_WRITE_CONSOLE_REQUEST req = { sizeof(req), SysSvFromCstr(s) };
SysWriteConsole(&req);
}
static void exit_now(int code) {
while (true) SysExitProcess(code);
}
static void fail_status(const char* what, KSTATUS status) {
(void)status;
print("cwd_userspace_smoke: "); print(what); print("\n");
exit_now(1);
}
static void fail(const char* what) {
print("cwd_userspace_smoke: "); print(what); print("\n");
exit_now(1);
}
static void get_cwd_or_fail(char out[SYS_PATH_MAX + 1u]) {
size_t required = 0;
KSTATUS status = NtlGetCurrentDirectory(out, SYS_PATH_MAX + 1u, &required);
if (status != NTLSTATUS_SUCCESS || required == 0 || required > SYS_PATH_MAX + 1u)
fail_status("get cwd", status);
}
static void set_cwd_or_fail(const char* path, const char* what) {
KSTATUS status = NtlSetCurrentDirectory(SysSvFromCstr(path));
if (status != NTLSTATUS_SUCCESS) fail_status(what, status);
}
static void expect_cwd(const char* expected) {
char current[SYS_PATH_MAX + 1u];
get_cwd_or_fail(current);
if (strcmp(current, expected) != 0) fail("cwd value mismatch");
}
// Resolves the current absolute resource path and returns the owning namespace-prefix length.
static size_t resource_root_length_or_fail(const char* cwd) {
SYS_HANDLE session = SYS_HANDLE_INVALID;
KSTATUS status = NtlResourceConnect(&session);
if (status != NTLSTATUS_SUCCESS) fail_status("resource connect", status);
SYS_HANDLE root = SYS_HANDLE_INVALID;
uint32_t kind = NTL_RESOURCE_KIND_INVALID;
uint32_t resolvedLength = 0;
status = NtlResourceResolve(session, SysSvFromCstr(cwd), NTL_RESOURCE_FLAG_NONE,
&root, &kind, &resolvedLength);
(void)NtlResourceClose(session);
if (root != SYS_HANDLE_INVALID) (void)SysCloseHandle(root);
if (status != NTLSTATUS_SUCCESS) fail_status("resolve cwd root", status);
size_t length = strlen(cwd);
if (kind == NTL_RESOURCE_KIND_INVALID || resolvedLength < 2u || resolvedLength > length ||
(resolvedLength != length && cwd[resolvedLength] != '/'))
fail("initial cwd malformed");
return resolvedLength;
}
static void parent_of_cwd(const char* cwd, size_t rootLength, char* out, size_t cap) {
size_t length = strlen(cwd);
if (rootLength < 2u || rootLength > length || length + 1u > cap ||
(rootLength != length && cwd[rootLength] != '/'))
fail("initial cwd malformed");
memcpy(out, cwd, length + 1u);
if (length == rootLength) return;
while (length > rootLength && out[length - 1u] == '/') out[--length] = '\0';
while (length > rootLength && out[length - 1u] != '/') length--;
if (length <= rootLength + 1u) length = rootLength;
else length--;
out[length] = '\0';
}
int main(void) {
char original[SYS_PATH_MAX + 1u];
char parent[SYS_PATH_MAX + 1u];
char root[SYS_PATH_MAX + 1u];
print("cwd_userspace_smoke: start\n");
get_cwd_or_fail(original);
size_t rootLength = resource_root_length_or_fail(original);
parent_of_cwd(original, rootLength, parent, sizeof(parent));
memcpy(root, original, rootLength);
root[rootLength] = '\0';
// Refresh the cached binding boundary without changing the path.
set_cwd_or_fail(".", "set dot cwd");
expect_cwd(original);
set_cwd_or_fail("..", "set parent cwd");
expect_cwd(parent);
// Relative traversal stops at the actual bound resource, including multi-component roots.
set_cwd_or_fail(root, "set resource root cwd");
expect_cwd(root);
set_cwd_or_fail("..", "clamp parent at resource root");
expect_cwd(root);
set_cwd_or_fail(original, "restore original cwd");
expect_cwd(original);
print("cwd_userspace_smoke: PASS\n");
exit_now(0);
return 0;
}