/* * PROJECT: ReactOS API Tests * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: Test for NtOpenFile * COPYRIGHT: Copyright 2021 Your name here * Copyright 2021 Mark Jansen */ #include "precomp.h" #include #include static BOOL create_temp_file(WCHAR* DosName, PUNICODE_STRING NtName) { WCHAR path[MAX_PATH]; HANDLE hFile; GetTempPathW(RTL_NUMBER_OF(path), path); /* wprintf(L"create_temp_file path: %S\n", path); */ GetTempFileNameW(path, L"NtO", 0, DosName); /* wprintf(L"create_temp_file DosName: %S\n", DosName); */ hFile = CreateFileW(DosName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); ok(hFile != INVALID_HANDLE_VALUE, "failed to create temp file\n"); if (hFile != INVALID_HANDLE_VALUE) { char Buf[0xff]; int n; for (n = 0; n < 10; ++n) { DWORD dwWritten; memset(Buf, n + '0', sizeof(Buf)); WriteFile(hFile, Buf, sizeof(Buf), &dwWritten, NULL); ok_int(dwWritten, sizeof(Buf)); } CloseHandle(hFile); RtlDosPathNameToNtPathName_U(DosName, NtName, NULL, NULL); /* wprintf(L"create_temp_file NtName: %wZ\n", NtName); */ return TRUE; } return FALSE; } static void run_test(UNICODE_STRING* FileName) { OBJECT_ATTRIBUTES ObjectAttributes1, ObjectAttributes2; FILE_STANDARD_INFORMATION FileStandardInfo1, FileStandardInfo2; IO_STATUS_BLOCK IoStatusBlock1, IoStatusBlock2; LARGE_INTEGER ByteOffset, File1Size, File2Size; UNICODE_STRING EmptyName = RTL_CONSTANT_STRING(L""); NTSTATUS Status; HANDLE hFile1, hFile2; char bufr[5] = { 0 }; wprintf(L"Calling NtOpenFile to open temporary file: %wZ\n", FileName ); InitializeObjectAttributes(&ObjectAttributes1, FileName, OBJ_CASE_INSENSITIVE, 0, NULL); Status = NtOpenFile(&hFile1, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, &ObjectAttributes1, &IoStatusBlock1, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT); ok_hex(Status, STATUS_SUCCESS); if (!NT_SUCCESS(Status)) { printf("NtOpenFile call failed, exiting test.\n"); return; } wprintf(L"Calling NtQueryInformationFile for temporary file 1: %wZ\n", FileName ); Status = NtQueryInformationFile(hFile1, &IoStatusBlock1, &FileStandardInfo1, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); ok_hex(Status, STATUS_SUCCESS); if (!NT_SUCCESS(Status)) { printf("NtQueryInformationFile call failed, closing first file handle.\n"); NtClose(hFile1); return; } File1Size = FileStandardInfo1.EndOfFile; wprintf(L"Filesize returned for temporary file: %lld\n", File1Size ); wprintf(L"Calling NtReadFile twice on handle for temporary file: %wZ\n", FileName ); Status = NtReadFile(hFile1, 0, NULL, NULL, &IoStatusBlock1, bufr, 4, NULL, NULL); /* aligned read */ ok_hex(Status, STATUS_SUCCESS); if (!NT_SUCCESS(Status)) { printf("NtReadFile call failed, closing first file handle.\n"); NtClose(hFile1); return; } ByteOffset.QuadPart = 44; Status = NtReadFile(hFile1, 0, NULL, NULL, &IoStatusBlock1, &bufr[0], 4, &ByteOffset, NULL); /* non-aligned read */ ok_hex(Status, STATUS_SUCCESS); if (!NT_SUCCESS(Status)) { printf("NtReadFile call failed, closing first file handle.\n"); NtClose(hFile1); return; } wprintf(L"Re-Opening temporary file Cygwin style using first handle in place of path for file: %wZ\n", FileName ); /* attributes do not include a path, only existing open handle */ InitializeObjectAttributes(&ObjectAttributes2, &EmptyName, OBJ_CASE_INSENSITIVE, hFile1, NULL); /* InitializeObjectAttributes(&ObjectAttributes2, NULL, OBJ_CASE_INSENSITIVE, hFile1, NULL); */ Status = NtOpenFile(&hFile2, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, &ObjectAttributes2, &IoStatusBlock2, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT); ok_hex(Status, STATUS_SUCCESS); if (!NT_SUCCESS(Status)) { printf("NtOpenFile testing failed to re-open file, closing first file handle.\n"); NtClose(hFile1); return; } wprintf(L"Calling NtQueryInformationFile on re-opened handle for temporary file: %wZ\n", FileName); Status = NtQueryInformationFile(hFile2, &IoStatusBlock2, &FileStandardInfo2, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); ok_hex(Status, STATUS_SUCCESS); if (!NT_SUCCESS(Status)) { printf("NtOpenFile testing failed, closing both file handles.\n"); NtClose(hFile1); NtClose(hFile2); return; } File2Size = FileStandardInfo2.EndOfFile; wprintf(L"Filesize returned for temporary file 2: %lld\n", File2Size ); ok_int(FileStandardInfo2.EndOfFile.LowPart, File1Size.LowPart); ok_int(FileStandardInfo2.EndOfFile.HighPart, File1Size.HighPart); if (File1Size.LowPart != File2Size.LowPart || File1Size.HighPart != File2Size.HighPart) printf("The File sizes do not match, NtOpenFile() did NOT open the same file !\n"); wprintf(L"Calling NtReadFile for aligned read on re-opened handle for temporary file: %wZ\n", FileName ); Status = NtReadFile(hFile2, 0, NULL, NULL, &IoStatusBlock2, bufr, 4, NULL, NULL); /* aligned read */ ok_hex(Status, STATUS_SUCCESS); if (!NT_SUCCESS(Status)) { printf("NtOpenFile testing failed, closing both file handles.\n"); NtClose(hFile1); NtClose(hFile2); return; } wprintf(L"Calling NtReadFile for non-aligned read on re-opened handle for temporary file: %wZ\n", FileName ); ByteOffset.QuadPart = 44; Status = NtReadFile(hFile2, 0, NULL, NULL, &IoStatusBlock2, &bufr[0], 4, &ByteOffset, NULL); /* non-aligned read */ ok_hex(Status, STATUS_SUCCESS); printf("NtOpenFile testing completed, closing both file handles.\n"); NtClose(hFile1); NtClose(hFile2); } START_TEST(NtOpenFile) { WCHAR DosName[MAX_PATH + 1] = { 0 }; UNICODE_STRING FileName; if (!create_temp_file(DosName, &FileName)) { wprintf(L"Failed to create temporary file: %wZ\n", &FileName); return; } wprintf(L"Created temporary file: %wZ\n", &FileName); printf("Executing NtOpenFile tests.\n"); run_test(&FileName); wprintf(L"NtOpenFile tests completed, Deleting temporary file: %wZ\n", &FileName); DeleteFileW(DosName); RtlFreeUnicodeString(&FileName); }