1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Test for NtWriteFile 5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org> 6 */ 7 8 #include "precomp.h" 9 10 static 11 BOOL 12 Is64BitSystem(VOID) 13 { 14 #ifdef _WIN64 15 return TRUE; 16 #else 17 NTSTATUS Status; 18 ULONG_PTR IsWow64; 19 20 Status = NtQueryInformationProcess(NtCurrentProcess(), 21 ProcessWow64Information, 22 &IsWow64, 23 sizeof(IsWow64), 24 NULL); 25 if (NT_SUCCESS(Status)) 26 { 27 return IsWow64 != 0; 28 } 29 30 return FALSE; 31 #endif 32 } 33 34 static 35 ULONG 36 SizeOfMdl(VOID) 37 { 38 return Is64BitSystem() ? 48 : 28; 39 } 40 41 static 42 ULONG 43 SizeOfSector(VOID) 44 { 45 BOOL Ret; 46 ULONG SectorSize; 47 48 /* FIXME: Would be better to actually open systemroot */ 49 Ret = GetDiskFreeSpaceW(NULL, NULL, &SectorSize, NULL, NULL); 50 ok(Ret != FALSE, "GetDiskFreeSpaceW failed: %lx\n", GetLastError()); 51 if (!Ret) 52 { 53 SectorSize = 4096; /* On failure, assume max size */ 54 } 55 56 return SectorSize; 57 } 58 59 START_TEST(NtWriteFile) 60 { 61 NTSTATUS Status; 62 HANDLE FileHandle; 63 UNICODE_STRING FileName = RTL_CONSTANT_STRING(L"\\SystemRoot\\ntdll-apitest-NtWriteFile-test.bin"); 64 PVOID Buffer; 65 SIZE_T BufferSize; 66 LARGE_INTEGER ByteOffset; 67 OBJECT_ATTRIBUTES ObjectAttributes; 68 IO_STATUS_BLOCK IoStatus; 69 FILE_DISPOSITION_INFORMATION DispositionInfo; 70 ULONG TooLargeDataSize = (MAXUSHORT + 1 - SizeOfMdl()) / sizeof(ULONG_PTR) * PAGE_SIZE; // 0x3FF9000 on x86 71 ULONG LargeMdlMaxDataSize = TooLargeDataSize - PAGE_SIZE; 72 73 trace("System is %d bits, Size of MDL: %lu\n", Is64BitSystem() ? 64 : 32, SizeOfMdl()); 74 trace("Max MDL data size: 0x%lx bytes\n", LargeMdlMaxDataSize); 75 76 ByteOffset.QuadPart = 0; 77 78 Buffer = NULL; 79 BufferSize = TooLargeDataSize; 80 Status = NtAllocateVirtualMemory(NtCurrentProcess(), 81 &Buffer, 82 0, 83 &BufferSize, 84 MEM_RESERVE | MEM_COMMIT, 85 PAGE_READONLY); 86 if (!NT_SUCCESS(Status)) 87 { 88 skip("Failed to allocate memory, status %lx\n", Status); 89 return; 90 } 91 92 InitializeObjectAttributes(&ObjectAttributes, 93 &FileName, 94 OBJ_CASE_INSENSITIVE, 95 NULL, 96 NULL); 97 Status = NtCreateFile(&FileHandle, 98 FILE_WRITE_DATA | DELETE | SYNCHRONIZE, 99 &ObjectAttributes, 100 &IoStatus, 101 NULL, 102 0, 103 0, 104 FILE_SUPERSEDE, 105 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 106 FILE_NO_INTERMEDIATE_BUFFERING, 107 NULL, 108 0); 109 ok_hex(Status, STATUS_SUCCESS); 110 111 /* non-cached, max size -- succeeds */ 112 Status = NtWriteFile(FileHandle, 113 NULL, 114 NULL, 115 NULL, 116 &IoStatus, 117 Buffer, 118 LargeMdlMaxDataSize - PAGE_SIZE, 119 &ByteOffset, 120 NULL); 121 ok_hex(Status, STATUS_SUCCESS); 122 123 /* non-cached, max size -- succeeds */ 124 Status = NtWriteFile(FileHandle, 125 NULL, 126 NULL, 127 NULL, 128 &IoStatus, 129 Buffer, 130 LargeMdlMaxDataSize, 131 &ByteOffset, 132 NULL); 133 ok_hex(Status, STATUS_SUCCESS); 134 135 /* non-cached, too large -- fails to allocate MDL 136 * Note: this returns STATUS_SUCCESS on Win7 -- higher MDL size limit */ 137 Status = NtWriteFile(FileHandle, 138 NULL, 139 NULL, 140 NULL, 141 &IoStatus, 142 Buffer, 143 LargeMdlMaxDataSize + PAGE_SIZE, 144 &ByteOffset, 145 NULL); 146 ok_hex(Status, STATUS_INSUFFICIENT_RESOURCES); 147 148 /* non-cached, unaligned -- fails with invalid parameter */ 149 Status = NtWriteFile(FileHandle, 150 NULL, 151 NULL, 152 NULL, 153 &IoStatus, 154 Buffer, 155 LargeMdlMaxDataSize + 1, 156 &ByteOffset, 157 NULL); 158 ok_hex(Status, STATUS_INVALID_PARAMETER); 159 160 DispositionInfo.DeleteFile = TRUE; 161 Status = NtSetInformationFile(FileHandle, 162 &IoStatus, 163 &DispositionInfo, 164 sizeof(DispositionInfo), 165 FileDispositionInformation); 166 ok_hex(Status, STATUS_SUCCESS); 167 Status = NtClose(FileHandle); 168 ok_hex(Status, STATUS_SUCCESS); 169 170 Status = NtCreateFile(&FileHandle, 171 FILE_WRITE_DATA | DELETE | SYNCHRONIZE, 172 &ObjectAttributes, 173 &IoStatus, 174 NULL, 175 0, 176 0, 177 FILE_SUPERSEDE, 178 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 179 NULL, 180 0); 181 ok_hex(Status, STATUS_SUCCESS); 182 183 /* cached: succeeds with arbitrary length */ 184 Status = NtWriteFile(FileHandle, 185 NULL, 186 NULL, 187 NULL, 188 &IoStatus, 189 Buffer, 190 LargeMdlMaxDataSize, 191 &ByteOffset, 192 NULL); 193 ok_hex(Status, STATUS_SUCCESS); 194 195 Status = NtWriteFile(FileHandle, 196 NULL, 197 NULL, 198 NULL, 199 &IoStatus, 200 Buffer, 201 LargeMdlMaxDataSize + 1, 202 &ByteOffset, 203 NULL); 204 ok_hex(Status, STATUS_SUCCESS); 205 206 Status = NtWriteFile(FileHandle, 207 NULL, 208 NULL, 209 NULL, 210 &IoStatus, 211 Buffer, 212 TooLargeDataSize, 213 &ByteOffset, 214 NULL); 215 ok_hex(Status, STATUS_SUCCESS); 216 217 DispositionInfo.DeleteFile = TRUE; 218 Status = NtSetInformationFile(FileHandle, 219 &IoStatus, 220 &DispositionInfo, 221 sizeof(DispositionInfo), 222 FileDispositionInformation); 223 ok_hex(Status, STATUS_SUCCESS); 224 Status = NtClose(FileHandle); 225 ok_hex(Status, STATUS_SUCCESS); 226 227 Status = NtFreeVirtualMemory(NtCurrentProcess(), 228 &Buffer, 229 &BufferSize, 230 MEM_RELEASE); 231 ok_hex(Status, STATUS_SUCCESS); 232 233 /* Now, testing aligned/non aligned writes */ 234 235 BufferSize = SizeOfSector(); 236 trace("Sector is %ld bytes\n", BufferSize); 237 238 Status = NtAllocateVirtualMemory(NtCurrentProcess(), 239 &Buffer, 240 0, 241 &BufferSize, 242 MEM_RESERVE | MEM_COMMIT, 243 PAGE_READONLY); 244 if (!NT_SUCCESS(Status)) 245 { 246 skip("Failed to allocate memory, status %lx\n", Status); 247 return; 248 } 249 250 Status = NtCreateFile(&FileHandle, 251 FILE_WRITE_DATA | DELETE | SYNCHRONIZE, 252 &ObjectAttributes, 253 &IoStatus, 254 NULL, 255 0, 256 0, 257 FILE_SUPERSEDE, 258 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 259 FILE_NO_INTERMEDIATE_BUFFERING | 260 FILE_WRITE_THROUGH, 261 NULL, 262 0); 263 ok_hex(Status, STATUS_SUCCESS); 264 265 /* non-cached, broken length -- fails with invalid parameter */ 266 ByteOffset.QuadPart = 0; 267 Status = NtWriteFile(FileHandle, 268 NULL, 269 NULL, 270 NULL, 271 &IoStatus, 272 Buffer, 273 4, 274 &ByteOffset, 275 NULL); 276 ok_hex(Status, STATUS_INVALID_PARAMETER); 277 278 /* non-cached, broken offset -- fails with invalid parameter */ 279 ByteOffset.QuadPart = 4; 280 Status = NtWriteFile(FileHandle, 281 NULL, 282 NULL, 283 NULL, 284 &IoStatus, 285 Buffer, 286 BufferSize, 287 &ByteOffset, 288 NULL); 289 ok_hex(Status, STATUS_INVALID_PARAMETER); 290 291 /* non-cached, good length and offset -- succeeds */ 292 ByteOffset.QuadPart = 0; 293 Status = NtWriteFile(FileHandle, 294 NULL, 295 NULL, 296 NULL, 297 &IoStatus, 298 Buffer, 299 BufferSize, 300 &ByteOffset, 301 NULL); 302 ok_hex(Status, STATUS_SUCCESS); 303 304 DispositionInfo.DeleteFile = TRUE; 305 Status = NtSetInformationFile(FileHandle, 306 &IoStatus, 307 &DispositionInfo, 308 sizeof(DispositionInfo), 309 FileDispositionInformation); 310 ok_hex(Status, STATUS_SUCCESS); 311 Status = NtClose(FileHandle); 312 ok_hex(Status, STATUS_SUCCESS); 313 314 Status = NtFreeVirtualMemory(NtCurrentProcess(), 315 &Buffer, 316 &BufferSize, 317 MEM_RELEASE); 318 ok_hex(Status, STATUS_SUCCESS); 319 } 320