Index: CMakeLists.txt =================================================================== --- modules/rostests/apitests/ntdll/CMakeLists.txt (revision 72853) +++ modules/rostests/apitests/ntdll/CMakeLists.txt (working copy) @@ -19,6 +19,7 @@ NtQueryVolumeInformationFile.c NtSaveKey.c NtSetValueKey.c + NtWriteFile.c RtlAllocateHeap.c RtlBitmap.c RtlCopyMappedMemory.c Index: NtWriteFile.c =================================================================== --- modules/rostests/apitests/ntdll/NtWriteFile.c (nonexistent) +++ modules/rostests/apitests/ntdll/NtWriteFile.c (working copy) @@ -0,0 +1,261 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory + * PURPOSE: Test for NtWriteFile + * PROGRAMMER: Thomas Faber + */ + +#include + +#define WIN32_NO_STATUS +#include +#include +#include +#include +#include +#include +#include + +static +BOOL +Is64BitSystem(VOID) +{ +#ifdef _WIN64 + return TRUE; +#else + NTSTATUS Status; + ULONG_PTR IsWow64; + + Status = NtQueryInformationProcess(NtCurrentProcess(), + ProcessWow64Information, + &IsWow64, + sizeof(IsWow64), + NULL); + if (NT_SUCCESS(Status)) + { + return IsWow64 != 0; + } + + return FALSE; +#endif +} + +static +BOOL +IsPaeEnabled(VOID) +{ + NTSTATUS Status; + DWORD Value; + RTL_QUERY_REGISTRY_TABLE QueryTable[2] = + { + { NULL, RTL_QUERY_REGISTRY_DIRECT, L"PhysicalAddressExtension", &Value, REG_DWORD, 0, sizeof(DWORD) } + }; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"Session Manager\\Memory Management", + QueryTable, + NULL, + NULL); + if (NT_SUCCESS(Status)) + { + return Value != 0; + } + + return FALSE; +} + +static +ULONG +SizeOfMdl(VOID) +{ + return Is64BitSystem() ? 48 : 28; +} + +static +ULONG +SizeOfPfnNumber(VOID) +{ + if (Is64BitSystem()) + return sizeof(ULONGLONG); + if (IsPaeEnabled()) + return sizeof(ULONGLONG); + return sizeof(ULONG); +} + +START_TEST(NtWriteFile) +{ + NTSTATUS Status; + HANDLE FileHandle; + UNICODE_STRING FileName = RTL_CONSTANT_STRING(L"\\SystemRoot\\ntdll-apitest-NtWriteFile-test.bin"); + PVOID Buffer; + SIZE_T BufferSize; + LARGE_INTEGER ByteOffset; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatus; + FILE_DISPOSITION_INFORMATION DispositionInfo; + ULONG TooLargeDataSize = (MAXUSHORT + 1 - SizeOfMdl()) / SizeOfPfnNumber() * PAGE_SIZE; // 0x3FF9000 on x86 non-PAE + ULONG LargeMdlMaxDataSize = TooLargeDataSize - PAGE_SIZE; + + trace("System is %d bits, PAE %s\n", Is64BitSystem() ? 64 : 32, IsPaeEnabled() ? "enabled" : "disabled"); + trace("Size of MDL: %lu, size of PFN_NUMBER: %lu\n", SizeOfMdl(), SizeOfPfnNumber()); + trace("Max MDL data size: 0x%lx bytes\n", LargeMdlMaxDataSize); + + ByteOffset.QuadPart = 0; + + Buffer = NULL; + BufferSize = TooLargeDataSize; + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + &Buffer, + 0, + &BufferSize, + MEM_RESERVE | MEM_COMMIT, + PAGE_READONLY); + if (!NT_SUCCESS(Status)) + { + skip("Failed to allocate memory, status %lx\n", Status); + return; + } + + InitializeObjectAttributes(&ObjectAttributes, + &FileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtCreateFile(&FileHandle, + FILE_WRITE_DATA | DELETE | SYNCHRONIZE, + &ObjectAttributes, + &IoStatus, + NULL, + 0, + 0, + FILE_SUPERSEDE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | + FILE_NO_INTERMEDIATE_BUFFERING, + NULL, + 0); + ok_hex(Status, STATUS_SUCCESS); + + /* non-cached, max size -- succeeds */ + ok(ByteOffset.QuadPart == 0, "%I64x\n", ByteOffset.QuadPart); + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatus, + Buffer, + LargeMdlMaxDataSize - PAGE_SIZE, + &ByteOffset, + NULL); + ok_hex(Status, STATUS_SUCCESS); + + /* non-cached, max size -- succeeds */ + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatus, + Buffer, + LargeMdlMaxDataSize, + &ByteOffset, + NULL); + ok_hex(Status, STATUS_SUCCESS); + + /* non-cached, too large -- fails to allocate MDL + * Note: this returns STATUS_SUCCESS on Win7 -- higher MDL size limit */ + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatus, + Buffer, + LargeMdlMaxDataSize + PAGE_SIZE, + &ByteOffset, + NULL); + ok_hex(Status, STATUS_INSUFFICIENT_RESOURCES); + + /* non-cached, unaligned -- fails with invalid parameter */ + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatus, + Buffer, + LargeMdlMaxDataSize + 1, + &ByteOffset, + NULL); + ok_hex(Status, STATUS_INVALID_PARAMETER); + + DispositionInfo.DeleteFile = TRUE; + Status = NtSetInformationFile(FileHandle, + &IoStatus, + &DispositionInfo, + sizeof(DispositionInfo), + FileDispositionInformation); + ok_hex(Status, STATUS_SUCCESS); + Status = NtClose(FileHandle); + ok_hex(Status, STATUS_SUCCESS); + + /****/ + Status = NtCreateFile(&FileHandle, + FILE_WRITE_DATA | DELETE | SYNCHRONIZE, + &ObjectAttributes, + &IoStatus, + NULL, + 0, + 0, + FILE_SUPERSEDE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); + ok_hex(Status, STATUS_SUCCESS); + + /* cached: succeeds with arbitrary length */ + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatus, + Buffer, + LargeMdlMaxDataSize, + &ByteOffset, + NULL); + ok_hex(Status, STATUS_SUCCESS); + + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatus, + Buffer, + LargeMdlMaxDataSize + 1, + &ByteOffset, + NULL); + ok_hex(Status, STATUS_SUCCESS); + + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatus, + Buffer, + TooLargeDataSize, + &ByteOffset, + NULL); + ok_hex(Status, STATUS_SUCCESS); + + DispositionInfo.DeleteFile = TRUE; + Status = NtSetInformationFile(FileHandle, + &IoStatus, + &DispositionInfo, + sizeof(DispositionInfo), + FileDispositionInformation); + ok_hex(Status, STATUS_SUCCESS); + Status = NtClose(FileHandle); + ok_hex(Status, STATUS_SUCCESS); + + Status = NtFreeVirtualMemory(NtCurrentProcess(), + &Buffer, + &BufferSize, + MEM_RELEASE); + ok_hex(Status, STATUS_SUCCESS); +} Index: testlist.c =================================================================== --- modules/rostests/apitests/ntdll/testlist.c (revision 72853) +++ modules/rostests/apitests/ntdll/testlist.c (working copy) @@ -23,6 +23,7 @@ extern void func_NtSaveKey(void); extern void func_NtSetValueKey(void); extern void func_NtSystemInformation(void); +extern void func_NtWriteFile(void); extern void func_RtlAllocateHeap(void); extern void func_RtlBitmap(void); extern void func_RtlCopyMappedMemory(void); @@ -68,6 +69,7 @@ { "NtSaveKey", func_NtSaveKey}, { "NtSetValueKey", func_NtSetValueKey}, { "NtSystemInformation", func_NtSystemInformation }, + { "NtWriteFile", func_NtWriteFile }, { "RtlAllocateHeap", func_RtlAllocateHeap }, { "RtlBitmapApi", func_RtlBitmap }, { "RtlCopyMappedMemory", func_RtlCopyMappedMemory }, Index: IoMdl.c =================================================================== --- modules/rostests/kmtests/ntos_io/IoMdl.c (revision 72853) +++ modules/rostests/kmtests/ntos_io/IoMdl.c (working copy) @@ -10,6 +10,11 @@ #define NDEBUG #include +#ifdef _MSC_VER +#undef __readcr4 +#pragma intrinsic(__readcr4) +#endif + START_TEST(IoMdl) { PMDL Mdl; @@ -16,12 +21,18 @@ PIRP Irp; PVOID VirtualAddress; ULONG MdlSize = 2*4096+184; // 2 pages and some random value +#ifdef __i386__ + ULONG SizeOfPfnNumber = (__readcr4() & CR4_PAE) ? sizeof(ULONGLONG) : sizeof(PVOID); +#else + ULONG SizeOfPfnNumber = sizeof(PVOID); +#endif + ULONG TooLargeMdlSize = (0x10000 - sizeof(MDL)) / SizeOfPfnNumber * PAGE_SIZE; // Try to alloc 2Gb MDL Mdl = IoAllocateMdl(NULL, 2048UL*0x100000, FALSE, FALSE, NULL); ok(Mdl == NULL, - "IoAllocateMdl should fail allocation of 2Gb or more, but got Mdl=0x%X", + "IoAllocateMdl should fail allocation of 2Gb or more, but got Mdl=0x%X\n", (UINT_PTR)Mdl); if (Mdl) @@ -30,22 +41,40 @@ // Now create a valid MDL VirtualAddress = ExAllocatePool(NonPagedPool, MdlSize); Mdl = IoAllocateMdl(VirtualAddress, MdlSize, FALSE, FALSE, NULL); - ok(Mdl != NULL, "Mdl allocation failed"); + ok(Mdl != NULL, "Mdl allocation failed\n"); // Check fields of the allocated struct - ok(Mdl->Next == NULL, "Mdl->Next should be NULL, but is 0x%X", + ok(Mdl->Next == NULL, "Mdl->Next should be NULL, but is 0x%X\n", (UINT_PTR)Mdl->Next); ok(Mdl->ByteCount == MdlSize, - "Mdl->ByteCount should be equal to MdlSize, but is 0x%X", + "Mdl->ByteCount should be equal to MdlSize, but is 0x%X\n", (UINT_PTR)Mdl->ByteCount); // TODO: Check other fields of MDL struct IoFreeMdl(Mdl); + + // Test maximum size for an MDL + Mdl = IoAllocateMdl(NULL, TooLargeMdlSize, FALSE, FALSE, NULL); + ok(Mdl == NULL, "Mdl allocation for %lu bytes succeeded\n", TooLargeMdlSize); + if (Mdl) IoFreeMdl(Mdl); + + Mdl = IoAllocateMdl(NULL, TooLargeMdlSize - PAGE_SIZE + 1, FALSE, FALSE, NULL); + ok(Mdl == NULL, "Mdl allocation for %lu bytes succeeded\n", TooLargeMdlSize - PAGE_SIZE + 1); + if (Mdl) IoFreeMdl(Mdl); + + Mdl = IoAllocateMdl(NULL, TooLargeMdlSize - PAGE_SIZE, FALSE, FALSE, NULL); + ok(Mdl != NULL, "Mdl allocation for %lu bytes failed\n", TooLargeMdlSize - PAGE_SIZE); + if (Mdl) IoFreeMdl(Mdl); + + Mdl = IoAllocateMdl(NULL, TooLargeMdlSize / 2, FALSE, FALSE, NULL); + ok(Mdl != NULL, "Mdl allocation for %lu bytes failed\n", TooLargeMdlSize / 2); + if (Mdl) IoFreeMdl(Mdl); + // Allocate now with pointer to an Irp Irp = IoAllocateIrp(1, FALSE); - ok(Irp != NULL, "IRP allocation failed"); + ok(Irp != NULL, "IRP allocation failed\n"); Mdl = IoAllocateMdl(VirtualAddress, MdlSize, FALSE, FALSE, Irp); - ok(Mdl != NULL, "Mdl allocation failed"); - ok(Irp->MdlAddress == Mdl, "Irp->MdlAddress should be 0x%X, but is 0x%X", + ok(Mdl != NULL, "Mdl allocation failed\n"); + ok(Irp->MdlAddress == Mdl, "Irp->MdlAddress should be 0x%X, but is 0x%X\n", (UINT_PTR)Mdl, (UINT_PTR)Irp->MdlAddress); IoFreeMdl(Mdl);