// Native file metadata smoke test. // Verifies path stat, handle stat, directory metadata, missing paths, and invalid handles. #include #include #include #include #define TEST_FILE_SIZE 1537u static uint8_t gPattern[TEST_FILE_SIZE]; // 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) { for (;;) SysExitProcess(code); } // Fails the test with one plain message. static void fail(const char* msg) { print("file_stat_smoke: "); print(msg); print("\n"); exit_now(1); } // Fails the test with one status value. static void fail_status(const char* what, uint32_t status) { print("file_stat_smoke: "); print(what); print(" failed status="); print_u64(status); print("\n"); exit_now(1); } // Removes a file path if it already exists. static void delete_file_path(const char* path) { SYS_PATH_REQUEST req = { SysSvFromCstr(path) }; (void)SysDeleteFile(&req); } // Removes a directory path if it already exists. static void remove_dir_path(const char* path) { SYS_PATH_REQUEST req = { SysSvFromCstr(path) }; (void)SysRemoveDir(&req); } // Opens a new 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_stat_smoke.tmp", "/file_stat_smoke.tmp", "1:/file_stat_smoke.tmp", "0:/file_stat_smoke.tmp", }; for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i) { uint32_t h = 0; delete_file_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_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; } // Creates a temporary directory on the first writable path that works. static uint32_t create_temp_dir(const char** pathOut) { static const char* paths[] = { "file_stat_smoke.dir", "/file_stat_smoke.dir", "1:/file_stat_smoke.dir", "0:/file_stat_smoke.dir", }; for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i) { remove_dir_path(paths[i]); SYS_PATH_REQUEST req = { SysSvFromCstr(paths[i]) }; uint32_t s = SysCreateDir(&req); if (s == NTLSTATUS_SUCCESS) { *pathOut = paths[i]; return NTLSTATUS_SUCCESS; } } return NTLSTATUS_NOT_FOUND; } // Fills the write pattern used by the test file. static void fill_pattern(void) { for (size_t i = 0; i < sizeof(gPattern); ++i) gPattern[i] = (uint8_t)(0x31u + (uint8_t)(i * 17u + (i >> 3))); } // Writes the test file contents and flushes them to the filesystem. static void write_test_file(uint32_t file) { size_t done = 0; SYS_FILE_IO_REQUEST writeReq = SysMakeFileIoRequest(file, gPattern, sizeof(gPattern), &done); uint32_t s = SysWriteFile(&writeReq); if (s != NTLSTATUS_SUCCESS) fail_status("write test file", s); if (done != sizeof(gPattern)) fail("short write"); s = SysFlushFile(file); if (s != NTLSTATUS_SUCCESS) fail_status("flush test file", s); } // Checks one regular-file metadata result. static void check_regular_stat(const SYS_FILE_STAT* stat, uint64_t expectedSize, const char* what) { if (stat->Size != sizeof(*stat)) fail("stat abi size mismatch"); if (stat->Type != SYS_FILE_TYPE_REGULAR) { print("file_stat_smoke: "); print(what); print(" type="); print_u64(stat->Type); print("\n"); exit_now(1); } if ((stat->Attributes & SYS_FILE_ATTR_DIRECTORY) != 0) fail("regular file has directory attribute"); if (stat->LinkCount == 0) fail("regular file has zero links"); if (stat->FileSize != expectedSize) { print("file_stat_smoke: "); print(what); print(" size="); print_u64(stat->FileSize); print(" expected="); print_u64(expectedSize); print("\n"); exit_now(1); } } // Checks one directory metadata result. static void check_directory_stat(const SYS_FILE_STAT* stat) { if (stat->Size != sizeof(*stat)) fail("directory stat abi size mismatch"); if (stat->Type != SYS_FILE_TYPE_DIRECTORY) fail("directory stat type mismatch"); if ((stat->Attributes & SYS_FILE_ATTR_DIRECTORY) == 0) fail("directory attribute missing"); if (stat->LinkCount == 0) fail("directory has zero links"); } // Exercises handle and path stat for one regular file. static void test_file_stat(uint32_t file, const char* path) { SYS_FILE_STAT byHandle; memset(&byHandle, 0xA5, sizeof(byHandle)); uint32_t s = SysGetFileStat(file, &byHandle); if (s != NTLSTATUS_SUCCESS) fail_status("get file stat", s); check_regular_stat(&byHandle, sizeof(gPattern), "handle stat"); uint64_t size = 0; s = SysGetFileSize(file, &size); if (s != NTLSTATUS_SUCCESS) fail_status("get file size", s); if (size != byHandle.FileSize) fail("file size and file stat disagree"); SYS_FILE_STAT byPath; memset(&byPath, 0x5A, sizeof(byPath)); SYS_STAT_FILE_REQUEST statReq = { SysSvFromCstr(path), &byPath }; s = SysStatFile(&statReq); if (s != NTLSTATUS_SUCCESS) fail_status("path stat", s); check_regular_stat(&byPath, sizeof(gPattern), "path stat"); if (byHandle.VolumeId != 0 && byPath.VolumeId != 0 && byHandle.VolumeId != byPath.VolumeId) fail("handle and path volume ids differ"); if (byHandle.FileId != 0 && byPath.FileId != 0 && byHandle.FileId != byPath.FileId) fail("handle and path file ids differ"); } // Exercises path stat for one directory. static void test_directory_stat(const char* path) { SYS_FILE_STAT stat; memset(&stat, 0xCC, sizeof(stat)); SYS_STAT_FILE_REQUEST statReq = { SysSvFromCstr(path), &stat }; uint32_t s = SysStatFile(&statReq); if (s != NTLSTATUS_SUCCESS) fail_status("directory stat", s); check_directory_stat(&stat); } // Checks failure status paths that stat callers depend on. static void test_failure_paths(void) { SYS_FILE_STAT stat; SYS_STAT_FILE_REQUEST missingReq = { SysSvFromCstr("file_stat_smoke_missing.nope"), &stat }; uint32_t s = SysStatFile(&missingReq); if (s != NTLSTATUS_NOT_FOUND) fail_status("missing path status", s); s = SysGetFileStat(0xFFFFFFFFu, &stat); if (s != NTLSTATUS_INVALID_HANDLE) fail_status("invalid handle status", s); SYS_STAT_FILE_REQUEST badReq = { SysSvFromCstr("file_stat_smoke_missing.nope"), 0 }; s = SysStatFile(&badReq); if (s != NTLSTATUS_INVALID_PARAMETER) fail_status("null stat output status", s); } // Runs the native file metadata smoke test. int main(void) { print("file_stat_smoke: start\n"); fill_pattern(); uint32_t file = 0; const char* filePath = 0; uint32_t s = create_temp_file(&file, &filePath); if (s != NTLSTATUS_SUCCESS) fail_status("create temp file", s); write_test_file(file); test_file_stat(file, filePath); SysCloseHandle(file); delete_file_path(filePath); const char* dirPath = 0; s = create_temp_dir(&dirPath); if (s != NTLSTATUS_SUCCESS) fail_status("create temp dir", s); test_directory_stat(dirPath); remove_dir_path(dirPath); SYS_PATH_REQUEST dirReq = { SysSvFromCstr(dirPath) }; s = SysCreateDir(&dirReq); if (s != NTLSTATUS_SUCCESS) fail_status("recreate temp dir", s); test_directory_stat(dirPath); remove_dir_path(dirPath); test_failure_paths(); print("file_stat_smoke: PASS\n"); exit_now(0); return 0; }