1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Kernel-Mode Test Suite File System test 5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org> 6 */ 7 8 #include <kmt_test.h> 9 10 /* FIXME: Test this stuff on non-FAT volumes */ 11 12 static 13 NTSTATUS 14 QueryFileInfo( 15 _In_ HANDLE FileHandle, 16 _Out_ PVOID *Info, 17 _Inout_ PSIZE_T Length, 18 _In_ FILE_INFORMATION_CLASS FileInformationClass) 19 { 20 NTSTATUS Status; 21 IO_STATUS_BLOCK IoStatus; 22 PVOID Buffer; 23 24 *Info = NULL; 25 if (*Length) 26 { 27 Buffer = KmtAllocateGuarded(*Length); 28 if (skip(Buffer != NULL, "Failed to allocate %Iu bytes\n", *Length)) 29 return STATUS_INSUFFICIENT_RESOURCES; 30 31 RtlFillMemory(Buffer, *Length, 0xdd); 32 } 33 else 34 { 35 Buffer = NULL; 36 } 37 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); 38 _SEH2_TRY 39 { 40 Status = ZwQueryInformationFile(FileHandle, 41 &IoStatus, 42 Buffer, 43 *Length, 44 FileInformationClass); 45 } 46 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 47 { 48 Status = _SEH2_GetExceptionCode(); 49 ok(0, "Exception %lx querying class %d with length %Iu\n", 50 Status, FileInformationClass, *Length); 51 } 52 _SEH2_END; 53 if (Status == STATUS_PENDING) 54 { 55 Status = ZwWaitForSingleObject(FileHandle, FALSE, NULL); 56 ok_eq_hex(Status, STATUS_SUCCESS); 57 Status = IoStatus.Status; 58 } 59 60 *Length = IoStatus.Information; 61 if (NT_SUCCESS(Status)) 62 { 63 *Info = Buffer; 64 } 65 else if (Buffer) 66 { 67 KmtFreeGuarded(Buffer); 68 } 69 return Status; 70 } 71 72 static 73 VOID 74 TestAllInformation(VOID) 75 { 76 NTSTATUS Status; 77 UNICODE_STRING FileName = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\ntoskrnl.exe"); 78 UNICODE_STRING Ntoskrnl = RTL_CONSTANT_STRING(L"ntoskrnl.exe"); 79 OBJECT_ATTRIBUTES ObjectAttributes; 80 HANDLE FileHandle; 81 IO_STATUS_BLOCK IoStatus; 82 PFILE_ALL_INFORMATION FileAllInfo; 83 SIZE_T Length; 84 ULONG NameLength; 85 PWCHAR Name; 86 UNICODE_STRING NamePart; 87 88 InitializeObjectAttributes(&ObjectAttributes, 89 &FileName, 90 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 91 NULL, 92 NULL); 93 Status = ZwOpenFile(&FileHandle, 94 SYNCHRONIZE | FILE_READ_ATTRIBUTES, 95 &ObjectAttributes, 96 &IoStatus, 97 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 98 FILE_NON_DIRECTORY_FILE); 99 if (Status == STATUS_PENDING) 100 { 101 Status = ZwWaitForSingleObject(FileHandle, FALSE, NULL); 102 ok_eq_hex(Status, STATUS_SUCCESS); 103 Status = IoStatus.Status; 104 } 105 ok_eq_hex(Status, STATUS_SUCCESS); 106 if (skip(NT_SUCCESS(Status), "No file handle, %lx\n", Status)) 107 return; 108 109 /* NtQueryInformationFile doesn't do length checks for kernel callers in a free build */ 110 if (KmtIsCheckedBuild) 111 { 112 /* Zero length */ 113 Length = 0; 114 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 115 ok_eq_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 116 ok_eq_size(Length, (ULONG_PTR)0x5555555555555555); 117 if (FileAllInfo) 118 KmtFreeGuarded(FileAllInfo); 119 120 /* One less than the minimum */ 121 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) - 1; 122 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 123 ok_eq_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 124 ok_eq_size(Length, (ULONG_PTR)0x5555555555555555); 125 if (FileAllInfo) 126 KmtFreeGuarded(FileAllInfo); 127 128 /* No space for the name -- fastfat handles this gracefully, ntfs doesn't. 129 * But the Io manager makes it fail on checked builds, so it's 130 * technically illegal 131 */ 132 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName); 133 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 134 ok_eq_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 135 ok_eq_size(Length, (ULONG_PTR)0x5555555555555555); 136 if (FileAllInfo) 137 KmtFreeGuarded(FileAllInfo); 138 } 139 140 /* The minimum allowed */ 141 Length = sizeof(FILE_ALL_INFORMATION); 142 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 143 ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW); 144 ok_eq_size(Length, sizeof(FILE_ALL_INFORMATION)); 145 if (FileAllInfo) 146 KmtFreeGuarded(FileAllInfo); 147 148 /* Plenty of space -- determine NameLength and copy the name */ 149 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + MAX_PATH * sizeof(WCHAR); 150 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 151 ok_eq_hex(Status, STATUS_SUCCESS); 152 if (skip(NT_SUCCESS(Status) && FileAllInfo != NULL, "No info\n")) 153 { 154 goto NoInfo; 155 } 156 157 NameLength = FileAllInfo->NameInformation.FileNameLength; 158 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength); 159 Name = ExAllocatePoolWithTag(PagedPool, NameLength + sizeof(UNICODE_NULL), 'sFmK'); 160 if (!skip(Name != NULL, "Could not allocate %lu bytes\n", NameLength + (ULONG)sizeof(UNICODE_NULL))) 161 { 162 RtlCopyMemory(Name, 163 FileAllInfo->NameInformation.FileName, 164 NameLength); 165 Name[NameLength / sizeof(WCHAR)] = UNICODE_NULL; 166 ok(Name[0] == L'\\', "Name is %ls, expected first char to be \\\n", Name); 167 ok(NameLength >= Ntoskrnl.Length + sizeof(WCHAR), "NameLength %lu too short\n", NameLength); 168 if (NameLength >= Ntoskrnl.Length) 169 { 170 NamePart.Buffer = Name + (NameLength - Ntoskrnl.Length) / sizeof(WCHAR); 171 NamePart.Length = Ntoskrnl.Length; 172 NamePart.MaximumLength = NamePart.Length; 173 ok(RtlEqualUnicodeString(&NamePart, &Ntoskrnl, TRUE), 174 "Name ends in '%wZ', expected %wZ\n", &NamePart, &Ntoskrnl); 175 } 176 ExFreePoolWithTag(Name, 'sFmK'); 177 } 178 ok(FileAllInfo->NameInformation.FileName[NameLength / sizeof(WCHAR)] == 0xdddd, 179 "Char past FileName is %x\n", 180 FileAllInfo->NameInformation.FileName[NameLength / sizeof(WCHAR)]); 181 if (FileAllInfo) 182 KmtFreeGuarded(FileAllInfo); 183 184 /* One char less than needed */ 185 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength - sizeof(WCHAR); 186 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 187 ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW); 188 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength - sizeof(WCHAR)); 189 if (FileAllInfo) 190 KmtFreeGuarded(FileAllInfo); 191 192 /* One byte less than needed */ 193 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength - 1; 194 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 195 ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW); 196 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength - 1); 197 if (FileAllInfo) 198 KmtFreeGuarded(FileAllInfo); 199 200 /* Exactly the required size */ 201 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength; 202 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 203 ok_eq_hex(Status, STATUS_SUCCESS); 204 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength); 205 if (FileAllInfo) 206 KmtFreeGuarded(FileAllInfo); 207 208 /* One byte more than needed */ 209 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength + 1; 210 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 211 ok_eq_hex(Status, STATUS_SUCCESS); 212 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength); 213 if (FileAllInfo) 214 KmtFreeGuarded(FileAllInfo); 215 216 /* One char more than needed */ 217 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength + sizeof(WCHAR); 218 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 219 ok_eq_hex(Status, STATUS_SUCCESS); 220 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength); 221 if (FileAllInfo) 222 KmtFreeGuarded(FileAllInfo); 223 224 NoInfo: 225 Status = ObCloseHandle(FileHandle, KernelMode); 226 ok_eq_hex(Status, STATUS_SUCCESS); 227 } 228 229 static 230 VOID 231 Substitute( 232 _Out_writes_bytes_(BufferSize) PWCHAR Buffer, 233 _In_ ULONG BufferSize, 234 _In_ PCWSTR Template, 235 _In_ PCWSTR SystemDriveName, 236 _In_ PCWSTR SystemRootName) 237 { 238 UNICODE_STRING SystemDriveTemplate = RTL_CONSTANT_STRING(L"C:"); 239 UNICODE_STRING SystemRootTemplate = RTL_CONSTANT_STRING(L"ReactOS"); 240 ULONG SystemDriveLength; 241 ULONG SystemRootLength; 242 PWCHAR Dest = Buffer; 243 UNICODE_STRING String; 244 245 SystemDriveLength = wcslen(SystemDriveName) * sizeof(WCHAR); 246 SystemRootLength = wcslen(SystemRootName) * sizeof(WCHAR); 247 248 RtlInitUnicodeString(&String, Template); 249 ASSERT(String.Length % sizeof(WCHAR) == 0); 250 while (String.Length) 251 { 252 if (RtlPrefixUnicodeString(&SystemDriveTemplate, &String, TRUE)) 253 { 254 ASSERT((Dest - Buffer) * sizeof(WCHAR) + SystemDriveLength < BufferSize); 255 RtlCopyMemory(Dest, 256 SystemDriveName, 257 SystemDriveLength); 258 Dest += SystemDriveLength / sizeof(WCHAR); 259 260 String.Buffer += SystemDriveTemplate.Length / sizeof(WCHAR); 261 String.Length -= SystemDriveTemplate.Length; 262 String.MaximumLength -= SystemDriveTemplate.Length; 263 continue; 264 } 265 266 if (RtlPrefixUnicodeString(&SystemRootTemplate, &String, TRUE)) 267 { 268 ASSERT((Dest - Buffer) * sizeof(WCHAR) + SystemRootLength < BufferSize); 269 RtlCopyMemory(Dest, 270 SystemRootName, 271 SystemRootLength); 272 Dest += SystemRootLength / sizeof(WCHAR); 273 274 String.Buffer += SystemRootTemplate.Length / sizeof(WCHAR); 275 String.Length -= SystemRootTemplate.Length; 276 String.MaximumLength -= SystemRootTemplate.Length; 277 continue; 278 } 279 280 ASSERT(Dest - Buffer < BufferSize / sizeof(WCHAR)); 281 *Dest++ = String.Buffer[0]; 282 283 String.Buffer++; 284 String.Length -= sizeof(WCHAR); 285 String.MaximumLength -= sizeof(WCHAR); 286 } 287 ASSERT(Dest - Buffer < BufferSize / sizeof(WCHAR)); 288 *Dest = UNICODE_NULL; 289 } 290 291 static 292 VOID 293 TestRelativeNames(VOID) 294 { 295 NTSTATUS Status; 296 struct 297 { 298 PCWSTR ParentPathTemplate; 299 PCWSTR RelativePathTemplate; 300 BOOLEAN IsDirectory; 301 NTSTATUS Status; 302 BOOLEAN IsDrive; 303 } Tests[] = 304 { 305 { NULL, L"C:\\", TRUE, STATUS_SUCCESS, TRUE }, 306 { NULL, L"C:\\\\", TRUE, STATUS_SUCCESS, TRUE }, 307 { NULL, L"C:\\\\\\", TRUE, STATUS_OBJECT_NAME_INVALID, TRUE }, 308 { NULL, L"C:\\ReactOS", TRUE, STATUS_SUCCESS }, 309 { NULL, L"C:\\ReactOS\\", TRUE, STATUS_SUCCESS }, 310 { NULL, L"C:\\ReactOS\\\\", TRUE, STATUS_SUCCESS }, 311 { NULL, L"C:\\ReactOS\\\\\\", TRUE, STATUS_OBJECT_NAME_INVALID }, 312 { NULL, L"C:\\\\ReactOS", TRUE, STATUS_SUCCESS }, 313 { NULL, L"C:\\\\ReactOS\\", TRUE, STATUS_SUCCESS }, 314 { NULL, L"C:\\ReactOS\\explorer.exe", FALSE, STATUS_SUCCESS }, 315 { NULL, L"C:\\ReactOS\\\\explorer.exe", FALSE, STATUS_OBJECT_NAME_INVALID }, 316 { NULL, L"C:\\ReactOS\\explorer.exe\\", FALSE, STATUS_OBJECT_NAME_INVALID }, 317 { NULL, L"C:\\ReactOS\\explorer.exe\\file", FALSE, STATUS_OBJECT_PATH_NOT_FOUND }, 318 { NULL, L"C:\\ReactOS\\explorer.exe\\\\", FALSE, STATUS_OBJECT_NAME_INVALID }, 319 /* This will never return STATUS_NOT_A_DIRECTORY. IsDirectory=TRUE is a little hacky but achieves that without special handling */ 320 { NULL, L"C:\\ReactOS\\explorer.exe\\\\\\", TRUE, STATUS_OBJECT_NAME_INVALID }, 321 { L"C:\\", L"", TRUE, STATUS_SUCCESS }, 322 { L"C:\\", L"\\", TRUE, STATUS_OBJECT_NAME_INVALID }, 323 { L"C:\\", L"ReactOS", TRUE, STATUS_SUCCESS }, 324 { L"C:\\", L"\\ReactOS", TRUE, STATUS_OBJECT_NAME_INVALID }, 325 { L"C:\\", L"ReactOS\\", TRUE, STATUS_SUCCESS }, 326 { L"C:\\", L"\\ReactOS\\", TRUE, STATUS_OBJECT_NAME_INVALID }, 327 { L"C:\\ReactOS", L"", TRUE, STATUS_SUCCESS }, 328 { L"C:\\ReactOS", L"explorer.exe", FALSE, STATUS_SUCCESS }, 329 { L"C:\\ReactOS\\explorer.exe", L"", FALSE, STATUS_SUCCESS }, 330 { L"C:\\ReactOS\\explorer.exe", L"file", FALSE, STATUS_OBJECT_PATH_NOT_FOUND }, 331 /* Let's try some nonexistent things */ 332 { NULL, L"C:\\ReactOS\\IDoNotExist", FALSE, STATUS_OBJECT_NAME_NOT_FOUND }, 333 { NULL, L"C:\\ReactOS\\IDoNotExist\\file", FALSE, STATUS_OBJECT_PATH_NOT_FOUND }, 334 { NULL, L"C:\\ReactOS\\IDoNotExist\\file?", FALSE, STATUS_OBJECT_PATH_NOT_FOUND }, 335 { NULL, L"C:\\ReactOS\\IDoNotExist\\file\\\\",TRUE,STATUS_OBJECT_PATH_NOT_FOUND }, 336 { NULL, L"C:\\ReactOS\\IDoNotExist\\file\\\\\\",TRUE,STATUS_OBJECT_PATH_NOT_FOUND }, 337 { NULL, L"C:\\ReactOS\\AmIInvalid?", FALSE, STATUS_OBJECT_NAME_INVALID }, 338 { NULL, L"C:\\ReactOS\\.", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 339 { NULL, L"C:\\ReactOS\\..", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 340 { NULL, L"C:\\ReactOS\\...", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 341 { NULL, L"C:\\ReactOS\\.\\system32", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 342 { NULL, L"C:\\ReactOS\\..\\ReactOS", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 343 { L"C:\\", L".", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 344 { L"C:\\", L"..", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 345 { L"C:\\", L"...", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 346 { L"C:\\", L".\\ReactOS", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 347 { L"C:\\", L"..\\ReactOS", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 348 { L"C:\\ReactOS", L".", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 349 { L"C:\\ReactOS", L"..", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 350 { L"C:\\ReactOS", L"...", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 351 { L"C:\\ReactOS", L".\\system32", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 352 { L"C:\\ReactOS", L"..\\ReactOS", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 353 /* Volume open */ 354 { NULL, L"C:", FALSE, STATUS_SUCCESS, TRUE }, 355 { L"C:", L"", FALSE, STATUS_SUCCESS, TRUE }, 356 { L"C:", L"\\", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 357 { L"C:", L"file", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 358 }; 359 ULONG i; 360 OBJECT_ATTRIBUTES ObjectAttributes; 361 IO_STATUS_BLOCK IoStatus; 362 UNICODE_STRING ParentPath; 363 UNICODE_STRING RelativePath; 364 HANDLE ParentHandle; 365 HANDLE FileHandle; 366 UNICODE_STRING SystemRoot = RTL_CONSTANT_STRING(L"\\SystemRoot"); 367 HANDLE SymbolicLinkHandle = NULL; 368 WCHAR LinkNameBuffer[128]; 369 UNICODE_STRING SymbolicLinkName; 370 PWSTR SystemDriveName; 371 PWSTR SystemRootName; 372 PWCHAR Buffer = NULL; 373 BOOLEAN TrailingBackslash; 374 LARGE_INTEGER AllocationSize; 375 FILE_DISPOSITION_INFORMATION DispositionInfo; 376 377 /* Query \SystemRoot */ 378 InitializeObjectAttributes(&ObjectAttributes, 379 &SystemRoot, 380 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 381 NULL, 382 NULL); 383 Status = ZwOpenSymbolicLinkObject(&SymbolicLinkHandle, 384 GENERIC_READ, 385 &ObjectAttributes); 386 if (skip(NT_SUCCESS(Status), "Failed to open SystemRoot, %lx\n", Status)) 387 return; 388 389 RtlInitEmptyUnicodeString(&SymbolicLinkName, 390 LinkNameBuffer, 391 sizeof(LinkNameBuffer)); 392 Status = ZwQuerySymbolicLinkObject(SymbolicLinkHandle, 393 &SymbolicLinkName, 394 NULL); 395 ObCloseHandle(SymbolicLinkHandle, KernelMode); 396 if (skip(NT_SUCCESS(Status), "Failed to query SystemRoot, %lx\n", Status)) 397 return; 398 399 /* Split SymbolicLinkName into drive and path */ 400 SystemDriveName = SymbolicLinkName.Buffer; 401 SystemRootName = SymbolicLinkName.Buffer + SymbolicLinkName.Length / sizeof(WCHAR); 402 *SystemRootName-- = UNICODE_NULL; 403 while (*SystemRootName != L'\\') 404 { 405 ASSERT(SystemRootName > SymbolicLinkName.Buffer); 406 SystemRootName--; 407 } 408 *SystemRootName++ = UNICODE_NULL; 409 trace("System Drive: '%ls'\n", SystemDriveName); 410 trace("System Root: '%ls'\n", SystemRootName); 411 412 /* Allocate path buffer */ 413 Buffer = ExAllocatePoolWithTag(PagedPool, MAXUSHORT, 'sFmK'); 414 if (skip(Buffer != NULL, "No buffer\n")) 415 return; 416 417 /* Finally run some tests! */ 418 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 419 { 420 /* Open parent directory first */ 421 ParentHandle = NULL; 422 if (Tests[i].ParentPathTemplate) 423 { 424 Substitute(Buffer, 425 MAXUSHORT, 426 Tests[i].ParentPathTemplate, 427 SystemDriveName, 428 SystemRootName); 429 RtlInitUnicodeString(&ParentPath, Buffer); 430 InitializeObjectAttributes(&ObjectAttributes, 431 &ParentPath, 432 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 433 NULL, 434 NULL); 435 Status = ZwOpenFile(&ParentHandle, 436 GENERIC_READ, 437 &ObjectAttributes, 438 &IoStatus, 439 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 440 0); 441 ok(Status == STATUS_SUCCESS, 442 "[%lu] Status = %lx, expected STATUS_SUCCESS\n", i, Status); 443 if (skip(NT_SUCCESS(Status), "No parent handle %lu\n", i)) 444 continue; 445 } 446 447 /* Now open the relative file: */ 448 Substitute(Buffer, 449 MAXUSHORT, 450 Tests[i].RelativePathTemplate, 451 SystemDriveName, 452 SystemRootName); 453 RtlInitUnicodeString(&RelativePath, Buffer); 454 InitializeObjectAttributes(&ObjectAttributes, 455 &RelativePath, 456 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 457 ParentHandle, 458 NULL); 459 TrailingBackslash = FALSE; 460 if (wcslen(Buffer) && Buffer[wcslen(Buffer) - 1] == L'\\') 461 TrailingBackslash = TRUE; 462 463 /* (1) No flags */ 464 Status = ZwOpenFile(&FileHandle, 465 GENERIC_READ, 466 &ObjectAttributes, 467 &IoStatus, 468 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 469 0); 470 ok(Status == Tests[i].Status, 471 "[%lu] Status = %lx, expected %lx\n", i, Status, Tests[i].Status); 472 if (NT_SUCCESS(Status)) 473 ObCloseHandle(FileHandle, KernelMode); 474 475 /* (2) Directory File */ 476 Status = ZwOpenFile(&FileHandle, 477 GENERIC_READ, 478 &ObjectAttributes, 479 &IoStatus, 480 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 481 FILE_DIRECTORY_FILE); 482 if (Tests[i].IsDirectory || (!TrailingBackslash && !NT_SUCCESS(Tests[i].Status))) 483 ok(Status == Tests[i].Status, 484 "[%lu] Status = %lx, expected %lx\n", i, Status, Tests[i].Status); 485 else 486 ok(Status == STATUS_NOT_A_DIRECTORY, 487 "[%lu] Status = %lx, expected STATUS_NOT_A_DIRECTORY\n", i, Status); 488 if (NT_SUCCESS(Status)) 489 ObCloseHandle(FileHandle, KernelMode); 490 491 /* (3) Non-Directory File */ 492 Status = ZwOpenFile(&FileHandle, 493 GENERIC_READ, 494 &ObjectAttributes, 495 &IoStatus, 496 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 497 FILE_NON_DIRECTORY_FILE); 498 if (Tests[i].IsDirectory && NT_SUCCESS(Tests[i].Status)) 499 ok(Status == STATUS_FILE_IS_A_DIRECTORY, 500 "[%lu] Status = %lx, expected STATUS_FILE_IS_A_DIRECTORY\n", i, Status); 501 else 502 ok(Status == Tests[i].Status, 503 "[%lu] Status = %lx, expected %lx\n", i, Status, Tests[i].Status); 504 if (NT_SUCCESS(Status)) 505 ObCloseHandle(FileHandle, KernelMode); 506 507 /* (4) Directory + Non-Directory */ 508 Status = ZwOpenFile(&FileHandle, 509 GENERIC_READ, 510 &ObjectAttributes, 511 &IoStatus, 512 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 513 FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE); 514 if (Tests[i].Status == STATUS_OBJECT_NAME_INVALID && Tests[i].IsDrive) 515 ok(Status == STATUS_OBJECT_NAME_INVALID, 516 "[%lu] Status = %lx, expected STATUS_OBJECT_NAME_INVALID\n", i, Status); 517 else 518 ok(Status == STATUS_INVALID_PARAMETER, 519 "[%lu] Status = %lx, expected STATUS_INVALID_PARAMETER\n", i, Status); 520 if (NT_SUCCESS(Status)) 521 ObCloseHandle(FileHandle, KernelMode); 522 523 /* (5) Try to create it */ 524 AllocationSize.QuadPart = 0; 525 Status = ZwCreateFile(&FileHandle, 526 GENERIC_READ | DELETE, 527 &ObjectAttributes, 528 &IoStatus, 529 &AllocationSize, 530 FILE_ATTRIBUTE_NORMAL, 531 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 532 FILE_CREATE, 533 0, 534 NULL, 535 0); 536 if (Tests[i].Status == STATUS_OBJECT_NAME_NOT_FOUND) 537 ok(Status == STATUS_SUCCESS, 538 "[%lu] Status = %lx, expected STATUS_SUCCESS\n", i, Status); 539 else if (Tests[i].Status == STATUS_OBJECT_NAME_INVALID && Tests[i].IsDrive) 540 ok(Status == STATUS_OBJECT_NAME_INVALID, 541 "[%lu] Status = %lx, expected STATUS_OBJECT_NAME_INVALID\n", i, Status); 542 else if (Tests[i].IsDrive) 543 ok(Status == STATUS_ACCESS_DENIED, 544 "[%lu] Status = %lx, expected STATUS_ACCESS_DENIED\n", i, Status); 545 else if (Tests[i].Status == STATUS_SUCCESS) 546 ok(Status == STATUS_OBJECT_NAME_COLLISION, 547 "[%lu] Status = %lx, expected STATUS_OBJECT_NAME_COLLISION\n", i, Status); 548 else 549 ok(Status == Tests[i].Status, 550 "[%lu] Status = %lx, expected %lx; %ls -- %ls\n", i, Status, Tests[i].Status, Tests[i].ParentPathTemplate, Tests[i].RelativePathTemplate); 551 if (NT_SUCCESS(Status)) 552 { 553 if (IoStatus.Information == FILE_CREATED) 554 { 555 DispositionInfo.DeleteFile = TRUE; 556 Status = ZwSetInformationFile(FileHandle, 557 &IoStatus, 558 &DispositionInfo, 559 sizeof(DispositionInfo), 560 FileDispositionInformation); 561 ok(Status == STATUS_SUCCESS, 562 "[%lu] Status = %lx, expected STATUS_SUCCESS\n", i, Status); 563 } 564 ObCloseHandle(FileHandle, KernelMode); 565 } 566 567 /* And close */ 568 ObCloseHandle(ParentHandle, KernelMode); 569 } 570 571 ExFreePoolWithTag(Buffer, 'sFmK'); 572 } 573 574 static 575 VOID 576 TestSharedCacheMap(VOID) 577 { 578 NTSTATUS Status; 579 struct 580 { 581 PCWSTR ParentPath; 582 PCWSTR RelativePath; 583 } Tests[] = 584 { 585 { 0, L"\\SystemRoot\\system32\\drivers\\etc\\hosts" }, 586 { L"\\SystemRoot", L"system32\\drivers\\etc\\hosts" }, 587 { L"\\SystemRoot\\system32", L"drivers\\etc\\hosts" }, 588 { L"\\SystemRoot\\system32\\drivers", L"etc\\hosts" }, 589 { L"\\SystemRoot\\system32\\drivers\\etc", L"hosts" }, 590 }; 591 OBJECT_ATTRIBUTES ObjectAttributes; 592 IO_STATUS_BLOCK IoStatus; 593 UNICODE_STRING ParentPath; 594 UNICODE_STRING RelativePath; 595 HANDLE ParentHandle[RTL_NUMBER_OF(Tests)] = { NULL }; 596 HANDLE FileHandle[RTL_NUMBER_OF(Tests)] = { NULL }; 597 PFILE_OBJECT FileObject[RTL_NUMBER_OF(Tests)] = { NULL }; 598 PFILE_OBJECT SystemRootObject = NULL; 599 UCHAR Buffer[32]; 600 HANDLE EventHandle; 601 LARGE_INTEGER FileOffset; 602 ULONG i; 603 604 /* We need an event for ZwReadFile */ 605 InitializeObjectAttributes(&ObjectAttributes, 606 NULL, 607 OBJ_KERNEL_HANDLE, 608 NULL, 609 NULL); 610 Status = ZwCreateEvent(&EventHandle, 611 SYNCHRONIZE, 612 &ObjectAttributes, 613 NotificationEvent, 614 FALSE); 615 if (skip(NT_SUCCESS(Status), "No event\n")) 616 goto Cleanup; 617 618 /* Open all test files and get their FILE_OBJECT pointers */ 619 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 620 { 621 if (Tests[i].ParentPath) 622 { 623 RtlInitUnicodeString(&ParentPath, Tests[i].ParentPath); 624 InitializeObjectAttributes(&ObjectAttributes, 625 &ParentPath, 626 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 627 NULL, 628 NULL); 629 Status = ZwOpenFile(&ParentHandle[i], 630 GENERIC_READ, 631 &ObjectAttributes, 632 &IoStatus, 633 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 634 0); 635 ok_eq_hex(Status, STATUS_SUCCESS); 636 if (skip(NT_SUCCESS(Status), "No parent handle %lu\n", i)) 637 goto Cleanup; 638 } 639 640 RtlInitUnicodeString(&RelativePath, Tests[i].RelativePath); 641 InitializeObjectAttributes(&ObjectAttributes, 642 &RelativePath, 643 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 644 ParentHandle[i], 645 NULL); 646 Status = ZwOpenFile(&FileHandle[i], 647 FILE_ALL_ACCESS, 648 &ObjectAttributes, 649 &IoStatus, 650 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 651 0); 652 ok_eq_hex(Status, STATUS_SUCCESS); 653 if (skip(NT_SUCCESS(Status), "No file handle %lu\n", i)) 654 goto Cleanup; 655 656 Status = ObReferenceObjectByHandle(FileHandle[i], 657 FILE_ALL_ACCESS, 658 *IoFileObjectType, 659 KernelMode, 660 (PVOID*)&FileObject[i], 661 NULL); 662 ok_eq_hex(Status, STATUS_SUCCESS); 663 if (skip(NT_SUCCESS(Status), "No file object %lu\n", i)) 664 goto Cleanup; 665 } 666 667 /* Also get a file object for the SystemRoot directory */ 668 Status = ObReferenceObjectByHandle(ParentHandle[1], 669 GENERIC_READ, 670 *IoFileObjectType, 671 KernelMode, 672 (PVOID*)&SystemRootObject, 673 NULL); 674 ok_eq_hex(Status, STATUS_SUCCESS); 675 if (skip(NT_SUCCESS(Status), "No SystemRoot object\n")) 676 goto Cleanup; 677 678 /* Before read, caching is not initialized */ 679 ok_eq_pointer(SystemRootObject->SectionObjectPointer, NULL); 680 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 681 { 682 ok(FileObject[i]->SectionObjectPointer != NULL, "FileObject[%lu]->SectionObjectPointer = NULL\n", i); 683 ok(FileObject[i]->SectionObjectPointer == FileObject[0]->SectionObjectPointer, 684 "FileObject[%lu]->SectionObjectPointer = %p, expected %p\n", 685 i, FileObject[i]->SectionObjectPointer, FileObject[0]->SectionObjectPointer); 686 } 687 if (!skip(FileObject[0]->SectionObjectPointer != NULL, "No section object pointers\n")) 688 ok_eq_pointer(FileObject[0]->SectionObjectPointer->SharedCacheMap, NULL); 689 690 /* Perform a read on one handle to initialize caching */ 691 FileOffset.QuadPart = 0; 692 Status = ZwReadFile(FileHandle[0], 693 EventHandle, 694 NULL, 695 NULL, 696 &IoStatus, 697 Buffer, 698 sizeof(Buffer), 699 &FileOffset, 700 NULL); 701 if (Status == STATUS_PENDING) 702 { 703 Status = ZwWaitForSingleObject(EventHandle, FALSE, NULL); 704 ok_eq_hex(Status, STATUS_SUCCESS); 705 Status = IoStatus.Status; 706 } 707 ok_eq_hex(Status, STATUS_SUCCESS); 708 709 /* Now we see a SharedCacheMap for the file */ 710 ok_eq_pointer(SystemRootObject->SectionObjectPointer, NULL); 711 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 712 { 713 ok(FileObject[i]->SectionObjectPointer != NULL, "FileObject[%lu]->SectionObjectPointer = NULL\n", i); 714 ok(FileObject[i]->SectionObjectPointer == FileObject[0]->SectionObjectPointer, 715 "FileObject[%lu]->SectionObjectPointer = %p, expected %p\n", 716 i, FileObject[i]->SectionObjectPointer, FileObject[0]->SectionObjectPointer); 717 } 718 if (!skip(FileObject[0]->SectionObjectPointer != NULL, "No section object pointers\n")) 719 ok(FileObject[0]->SectionObjectPointer->SharedCacheMap != NULL, "SharedCacheMap is NULL\n"); 720 721 Cleanup: 722 if (SystemRootObject) 723 ObDereferenceObject(SystemRootObject); 724 if (EventHandle) 725 ObCloseHandle(EventHandle, KernelMode); 726 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 727 { 728 if (FileObject[i]) 729 ObDereferenceObject(FileObject[i]); 730 if (FileHandle[i]) 731 ObCloseHandle(FileHandle[i], KernelMode); 732 if (ParentHandle[i]) 733 ObCloseHandle(ParentHandle[i], KernelMode); 734 } 735 } 736 737 START_TEST(IoFilesystem) 738 { 739 TestAllInformation(); 740 TestRelativeNames(); 741 TestSharedCacheMap(); 742 } 743