// Advisory file-lock smoke test. // Verifies process-owned byte-range conflicts, timeout behavior, and exit cleanup. #include #include #include #include #define LOCK_OFFSET 0u #define LOCK_LENGTH 128u #define NONOVERLAP_OFFSET 512u #define CHILD_PREFIX_MAX 32u #define CHILD_PATH_MAX 256u // 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(int32_t code) { while (true) SysExitProcess(code); } // Fails the test with one status value. static void fail_status(const char* what, uint32_t status) { print("file_lock_smoke: "); print(what); print(" status="); print_u64(status); print("\n"); exit_now(1); } // Fails the test with one plain message. static void fail(const char* what) { print("file_lock_smoke: "); print(what); print("\n"); exit_now(1); } // Deletes one path if it already exists. static void delete_path(const char* path) { SYS_PATH_REQUEST req = { SysSvFromCstr(path) }; (void)SysDeleteFile(&req); } // Opens one path with lock rights. static uint32_t open_existing_lockable(const char* path, uint32_t* fileOut) { uint32_t h = 0; SYS_OPEN_FILE_REQUEST req = SysMakeOpenFileRequest(SysSvFromCstr(path), SYS_FILE_ACCESS_QUERY | SYS_FILE_ACCESS_LOCK, SYS_FILE_OPEN_EXISTING, SYS_FILE_FLAG_NONE, &h); uint32_t s = SysOpenFile(&req); if (s == NTLSTATUS_SUCCESS) *fileOut = h; return s; } // Creates a temporary file on the first writable path that works. static uint32_t create_temp_file(uint32_t* fileOut, const char** pathOut) { static const char* paths[] = { "file_lock_smoke.tmp", "/file_lock_smoke.tmp", "1:/file_lock_smoke.tmp", "0:/file_lock_smoke.tmp", }; for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { uint32_t h = 0; delete_path(paths[i]); SYS_OPEN_FILE_REQUEST req = SysMakeOpenFileRequest(SysSvFromCstr(paths[i]), SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_WRITE | SYS_FILE_ACCESS_QUERY | SYS_FILE_ACCESS_LOCK, SYS_FILE_CREATE_NEW, SYS_FILE_FLAG_NONE, &h); uint32_t s = SysOpenFile(&req); if (s == NTLSTATUS_SUCCESS) { *fileOut = h; *pathOut = paths[i]; return NTLSTATUS_SUCCESS; } } return NTLSTATUS_NOT_FOUND; } // Locks a range through the public request ABI. static uint32_t lock_range(uint32_t file, uint32_t mode, uint64_t offset, uint64_t length, uint64_t timeoutMs) { SYS_LOCK_FILE_REQUEST req = { sizeof(req), file, mode, SYS_FILE_LOCK_FLAG_NONE, offset, length, timeoutMs, }; return SysLockFile(&req); } // Unlocks a range through the public request ABI. static uint32_t unlock_range(uint32_t file, uint64_t offset, uint64_t length) { SYS_UNLOCK_FILE_REQUEST req = { sizeof(req), file, SYS_FILE_LOCK_FLAG_NONE, offset, length, }; return SysUnlockFile(&req); } // Splits the child command line into mode and path. static int parse_child_command(SYS_STRING_VIEW view, char* mode, size_t modeCap, char* path, size_t pathCap) { if (!view.Data || view.Length == 0) return 0; size_t sep = 0; while (sep < view.Length && view.Data[sep] != ':') sep++; if (sep == view.Length || sep + 1 >= view.Length) return 0; if (sep + 1 > modeCap || view.Length - sep > pathCap) return 0; memcpy(mode, view.Data, sep); mode[sep] = '\0'; memcpy(path, view.Data + sep + 1, view.Length - sep - 1); path[view.Length - sep - 1] = '\0'; return 1; } // Returns whether two NUL-terminated strings are equal. static int str_eq(const char* a, const char* b) { return strcmp(a, b) == 0; } // Returns whether one mode name belongs to the child command protocol. static int is_child_mode(const char* mode) { return str_eq(mode, "excl-blocked") || str_eq(mode, "excl-timeout") || str_eq(mode, "excl-wait") || str_eq(mode, "shared-ok") || str_eq(mode, "excl-nonoverlap") || str_eq(mode, "hold-exit"); } // Child process entry for cross-process lock checks. static void run_child(SYS_STRING_VIEW commandLine) { char mode[CHILD_PREFIX_MAX]; char path[CHILD_PATH_MAX]; if (!parse_child_command(commandLine, mode, sizeof(mode), path, sizeof(path))) exit_now(2); uint32_t file = 0; uint32_t s = open_existing_lockable(path, &file); if (s != NTLSTATUS_SUCCESS) exit_now(3); if (str_eq(mode, "excl-blocked")) { s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0); SysCloseHandle(file); exit_now(s == NTLSTATUS_WOULD_BLOCK ? 0 : 4); } if (str_eq(mode, "excl-timeout")) { s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 20); SysCloseHandle(file); exit_now(s == NTLSTATUS_TIMEOUT ? 0 : 5); } if (str_eq(mode, "excl-wait")) { s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, SYS_WAIT_TIMEOUT_INFINITE); if (s == NTLSTATUS_SUCCESS) (void)unlock_range(file, LOCK_OFFSET, LOCK_LENGTH); SysCloseHandle(file); exit_now(s == NTLSTATUS_SUCCESS ? 0 : 6); } if (str_eq(mode, "shared-ok")) { s = lock_range(file, SYS_FILE_LOCK_SHARED, LOCK_OFFSET, LOCK_LENGTH, 0); if (s == NTLSTATUS_SUCCESS) (void)unlock_range(file, LOCK_OFFSET, LOCK_LENGTH); SysCloseHandle(file); exit_now(s == NTLSTATUS_SUCCESS ? 0 : 7); } if (str_eq(mode, "excl-nonoverlap")) { s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, NONOVERLAP_OFFSET, LOCK_LENGTH, 0); if (s == NTLSTATUS_SUCCESS) (void)unlock_range(file, NONOVERLAP_OFFSET, LOCK_LENGTH); SysCloseHandle(file); exit_now(s == NTLSTATUS_SUCCESS ? 0 : 8); } if (str_eq(mode, "hold-exit")) { s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0); SysCloseHandle(file); exit_now(s == NTLSTATUS_SUCCESS ? 0 : 9); } SysCloseHandle(file); exit_now(10); } // Builds a child command line of the form mode:path. static void build_child_command(char* out, size_t outCap, const char* mode, const char* path) { size_t modeLen = strlen(mode); size_t pathLen = strlen(path); if (modeLen + 1 + pathLen + 1 > outCap) fail("child command too long"); memcpy(out, mode, modeLen); out[modeLen] = ':'; memcpy(out + modeLen + 1, path, pathLen + 1); } // Runs this image as a child and requires a zero exit code. static void run_child_expect_success(const char* mode, const char* path) { SYS_PEB* peb = SysGetPeb(); if (!peb || !peb->ImagePath.Data || peb->ImagePath.Length == 0) fail("missing image path"); char command[CHILD_PREFIX_MAX + CHILD_PATH_MAX]; build_child_command(command, sizeof(command), mode, path); uint32_t child = 0; SYS_CREATE_PROCESS_REQUEST req = { peb->ImagePath, SysSvFromCstr(command), &child, }; uint32_t s = SysCreateProcess(&req); if (s != NTLSTATUS_SUCCESS) fail_status("create child", s); s = SysWait(child, SYS_WAIT_FLAG_NONE); if (s != NTLSTATUS_SUCCESS) fail_status("wait child", s); int32_t exitCode = 0; s = SysGetProcessExitCode(child, &exitCode); if (s != NTLSTATUS_SUCCESS) fail_status("query child", s); SysCloseHandle(child); if (exitCode != 0) { print("file_lock_smoke: child "); print(mode); print(" exited "); print_u64((uint32_t)exitCode); print("\n"); exit_now(1); } } // Verifies validation paths that should not depend on filesystem state. static void test_validation(uint32_t file) { SYS_LOCK_FILE_REQUEST lockReq = { 0, file, SYS_FILE_LOCK_EXCLUSIVE, SYS_FILE_LOCK_FLAG_NONE, LOCK_OFFSET, LOCK_LENGTH, 0, }; uint32_t s = SysLockFile(&lockReq); if (s != NTLSTATUS_INVALID_PARAMETER) fail_status("bad lock size", s); lockReq.Size = sizeof(lockReq); lockReq.Length = 0; s = SysLockFile(&lockReq); if (s != NTLSTATUS_INVALID_PARAMETER) fail_status("zero lock length", s); SYS_UNLOCK_FILE_REQUEST unlockReq = { sizeof(unlockReq), file, SYS_FILE_LOCK_FLAG_NONE, LOCK_OFFSET, LOCK_LENGTH, }; s = SysUnlockFile(&unlockReq); if (s != NTLSTATUS_NOT_FOUND) fail_status("unlock missing range", s); lockReq.Length = LOCK_LENGTH; lockReq.FileHandle = 0xeeeeeeeeu; s = SysLockFile(&lockReq); if (s != NTLSTATUS_INVALID_HANDLE) fail_status("bad lock handle", s); } // Program entry point. int main(void) { SYS_PEB* peb = SysGetPeb(); if (peb && peb->CommandLine.Data && peb->CommandLine.Length != 0) { char mode[CHILD_PREFIX_MAX]; char path[CHILD_PATH_MAX]; if (parse_child_command(peb->CommandLine, mode, sizeof(mode), path, sizeof(path)) && is_child_mode(mode)) { run_child(peb->CommandLine); } } print("file_lock_smoke: start\n"); uint32_t file = 0; const char* path = 0; uint32_t s = create_temp_file(&file, &path); if (s != NTLSTATUS_SUCCESS) fail_status("create temp", s); test_validation(file); s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0); if (s != NTLSTATUS_SUCCESS) fail_status("exclusive parent lock", s); run_child_expect_success("excl-blocked", path); run_child_expect_success("excl-timeout", path); run_child_expect_success("excl-nonoverlap", path); s = unlock_range(file, LOCK_OFFSET, LOCK_LENGTH); if (s != NTLSTATUS_SUCCESS) fail_status("exclusive parent unlock", s); s = lock_range(file, SYS_FILE_LOCK_SHARED, LOCK_OFFSET, LOCK_LENGTH, 0); if (s != NTLSTATUS_SUCCESS) fail_status("shared parent lock", s); run_child_expect_success("shared-ok", path); run_child_expect_success("excl-blocked", path); s = unlock_range(file, LOCK_OFFSET, LOCK_LENGTH); if (s != NTLSTATUS_SUCCESS) fail_status("shared parent unlock", s); s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0); if (s != NTLSTATUS_SUCCESS) fail_status("blocking setup lock", s); SYS_PEB* selfPeb = SysGetPeb(); if (!selfPeb || !selfPeb->ImagePath.Data || selfPeb->ImagePath.Length == 0) fail("missing self image"); char command[CHILD_PREFIX_MAX + CHILD_PATH_MAX]; build_child_command(command, sizeof(command), "excl-wait", path); uint32_t child = 0; SYS_CREATE_PROCESS_REQUEST createReq = { selfPeb->ImagePath, SysSvFromCstr(command), &child }; s = SysCreateProcess(&createReq); if (s != NTLSTATUS_SUCCESS) fail_status("create blocking child", s); SysSleep(30); s = unlock_range(file, LOCK_OFFSET, LOCK_LENGTH); if (s != NTLSTATUS_SUCCESS) fail_status("wake unlock", s); s = SysWait(child, SYS_WAIT_FLAG_NONE); if (s != NTLSTATUS_SUCCESS) fail_status("wait blocking child", s); int32_t exitCode = 0; s = SysGetProcessExitCode(child, &exitCode); if (s != NTLSTATUS_SUCCESS) fail_status("query blocking child", s); SysCloseHandle(child); if (exitCode != 0) fail("blocking child failed"); run_child_expect_success("hold-exit", path); s = lock_range(file, SYS_FILE_LOCK_EXCLUSIVE, LOCK_OFFSET, LOCK_LENGTH, 0); if (s != NTLSTATUS_SUCCESS) fail_status("exit released lock", s); s = unlock_range(file, LOCK_OFFSET, LOCK_LENGTH); if (s != NTLSTATUS_SUCCESS) fail_status("exit release cleanup unlock", s); SysCloseHandle(file); delete_path(path); print("file_lock_smoke: PASS\n"); exit_now(0); return 0; }