148 lines
4.0 KiB
C
148 lines
4.0 KiB
C
// Current-directory PEB cache smoke test.
|
|
// Verifies that SysSetCwd updates the user-visible PEB cache without a getter syscall.
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <ntlite/syscall.h>
|
|
|
|
// Prints one NUL-terminated string to the kernel console.
|
|
static void print(const char* s) {
|
|
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
|
SysWriteConsole(&req);
|
|
}
|
|
|
|
// Prints one unsigned integer to the kernel console.
|
|
static void print_u64(uint64_t v) {
|
|
char buf[32];
|
|
int i = 0;
|
|
if (v == 0) {
|
|
print("0");
|
|
return;
|
|
}
|
|
while (v && i < (int)sizeof(buf)) {
|
|
buf[i++] = (char)('0' + (v % 10));
|
|
v /= 10;
|
|
}
|
|
while (i--) {
|
|
char c = buf[i];
|
|
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
|
SysWriteConsole(&req);
|
|
}
|
|
}
|
|
|
|
// Terminates the current test process.
|
|
static void exit_now(int code) {
|
|
while (true) SysExitProcess(code);
|
|
}
|
|
|
|
// Fails the test with one status value.
|
|
static void fail_status(const char* what, uint32_t status) {
|
|
print("cwd_peb_smoke: ");
|
|
print(what);
|
|
print(" status=");
|
|
print_u64(status);
|
|
print("\n");
|
|
exit_now(1);
|
|
}
|
|
|
|
// Fails the test with a simple message.
|
|
static void fail(const char* what) {
|
|
print("cwd_peb_smoke: ");
|
|
print(what);
|
|
print("\n");
|
|
exit_now(1);
|
|
}
|
|
|
|
// Copies a string view into a NUL-terminated buffer.
|
|
static int copy_view(char* dst, size_t cap, SYS_STRING_VIEW view) {
|
|
if (!dst || cap == 0 || !view.Data || view.Length + 1 > cap)
|
|
return 0;
|
|
memcpy(dst, view.Data, view.Length);
|
|
dst[view.Length] = '\0';
|
|
return 1;
|
|
}
|
|
|
|
// Computes the parent of one canonical native current-directory string.
|
|
static int parent_of_cwd(const char* cwd, char* out, size_t cap) {
|
|
if (!cwd || !out || cap == 0)
|
|
return 0;
|
|
|
|
size_t len = strlen(cwd);
|
|
if (len < 3 || cwd[1] != ':' || (cwd[2] != '/' && cwd[2] != '\\'))
|
|
return 0;
|
|
if (len + 1 > cap)
|
|
return 0;
|
|
|
|
memcpy(out, cwd, len + 1);
|
|
while (len > 3 && (out[len - 1] == '/' || out[len - 1] == '\\'))
|
|
out[--len] = '\0';
|
|
if (len <= 3) {
|
|
out[0] = cwd[0];
|
|
out[1] = ':';
|
|
out[2] = '/';
|
|
out[3] = '\0';
|
|
return 1;
|
|
}
|
|
|
|
size_t pos = len;
|
|
while (pos > 3 && out[pos - 1] != '/' && out[pos - 1] != '\\')
|
|
pos--;
|
|
if (pos <= 3) {
|
|
out[0] = cwd[0];
|
|
out[1] = ':';
|
|
out[2] = '/';
|
|
out[3] = '\0';
|
|
} else {
|
|
out[pos - 1] = '\0';
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// Sets the current directory to one native path.
|
|
static void set_cwd_or_fail(const char* path, const char* what) {
|
|
SYS_PATH_REQUEST req = { SysSvFromCstr(path) };
|
|
uint32_t status = SysSetCwd(&req);
|
|
if (status != NTLSTATUS_SUCCESS) fail_status(what, status);
|
|
}
|
|
|
|
// Verifies the current-directory PEB view against one native path.
|
|
static void expect_cwd(const char* expected) {
|
|
SYS_STRING_VIEW cwd = SysGetCurrentDirectoryView();
|
|
size_t expectedLen = strlen(expected);
|
|
if (cwd.Length != expectedLen) fail("cwd length mismatch");
|
|
if (cwd.Length && !cwd.Data) fail("cwd data missing");
|
|
if (cwd.Length && memcmp(cwd.Data, expected, cwd.Length) != 0) fail("cwd value mismatch");
|
|
}
|
|
|
|
// Program entry point.
|
|
int main(void) {
|
|
char original[SYS_CWD_MAX];
|
|
char parent[SYS_CWD_MAX];
|
|
|
|
print("cwd_peb_smoke: start\n");
|
|
|
|
SYS_PEB* peb = SysGetPeb();
|
|
if (!peb) fail("peb missing");
|
|
if (peb->Magic != SYS_PEB_MAGIC) fail("peb magic mismatch");
|
|
if (peb->Version != SYS_ENV_VERSION) fail("peb version mismatch");
|
|
|
|
if (!copy_view(original, sizeof(original), SysGetCurrentDirectoryView()))
|
|
fail("initial cwd missing");
|
|
if (!parent_of_cwd(original, parent, sizeof(parent)))
|
|
fail("initial cwd malformed");
|
|
|
|
set_cwd_or_fail(".", "set dot cwd");
|
|
expect_cwd(original);
|
|
|
|
set_cwd_or_fail("..", "set parent cwd");
|
|
expect_cwd(parent);
|
|
|
|
set_cwd_or_fail(original, "restore original cwd");
|
|
expect_cwd(original);
|
|
|
|
print("cwd_peb_smoke: PASS\n");
|
|
exit_now(0);
|
|
return 0;
|
|
}
|