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