[NTOSKRNL]
[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);
520 else if (Tests[i].IsDrive)
521 ok(Status == STATUS_ACCESS_DENIED,
522 "[%lu] Status = %lx, expected STATUS_ACCESS_DENIED\n", i, Status);
523 else if (Tests[i].Status == STATUS_SUCCESS)
524 ok(Status == STATUS_OBJECT_NAME_COLLISION,
525 "[%lu] Status = %lx, expected STATUS_OBJECT_NAME_COLLISION\n", i, Status);
526 else
527 ok(Status == Tests[i].Status,
528 "[%lu] Status = %lx, expected %lx; %ls -- %ls\n", i, Status, Tests[i].Status, Tests[i].ParentPathTemplate, Tests[i].RelativePathTemplate);
529 if (NT_SUCCESS(Status))
530 {
531 if (IoStatus.Information == FILE_CREATED)
532 {
533 DispositionInfo.DeleteFile = TRUE;
534 Status = ZwSetInformationFile(FileHandle,
535 &IoStatus,
536 &DispositionInfo,
537 sizeof(DispositionInfo),
538 FileDispositionInformation);
539 ok(Status == STATUS_SUCCESS,
540 "[%lu] Status = %lx, expected STATUS_SUCCESS\n", i, Status);
541 }
542 ObCloseHandle(FileHandle, KernelMode);
543 }
544
545 /* And close */
546 ObCloseHandle(ParentHandle, KernelMode);
547 }
548
549 ExFreePoolWithTag(Buffer, 'sFmK');
550 }
551
552 static
553 VOID
554 TestSharedCacheMap(VOID)
555 {
556 NTSTATUS Status;
557 struct
558 {
559 PCWSTR ParentPath;
560 PCWSTR RelativePath;
561 } Tests[] =
562 {
563 { 0, L"\\SystemRoot\\system32\\drivers\\etc\\hosts" },
564 { L"\\SystemRoot", L"system32\\drivers\\etc\\hosts" },
565 { L"\\SystemRoot\\system32", L"drivers\\etc\\hosts" },
566 { L"\\SystemRoot\\system32\\drivers", L"etc\\hosts" },
567 { L"\\SystemRoot\\system32\\drivers\\etc", L"hosts" },
568 };
569 OBJECT_ATTRIBUTES ObjectAttributes;
570 IO_STATUS_BLOCK IoStatus;
571 UNICODE_STRING ParentPath;
572 UNICODE_STRING RelativePath;
573 HANDLE ParentHandle[RTL_NUMBER_OF(Tests)] = { NULL };
574 HANDLE FileHandle[RTL_NUMBER_OF(Tests)] = { NULL };
575 PFILE_OBJECT FileObject[RTL_NUMBER_OF(Tests)] = { NULL };
576 PFILE_OBJECT SystemRootObject = NULL;
577 UCHAR Buffer[32];
578 HANDLE EventHandle;
579 LARGE_INTEGER FileOffset;
580 ULONG i;
581
582 /* We need an event for ZwReadFile */
583 InitializeObjectAttributes(&ObjectAttributes,
584 NULL,
585 OBJ_KERNEL_HANDLE,
586 NULL,
587 NULL);
588 Status = ZwCreateEvent(&EventHandle,
589 SYNCHRONIZE,
590 &ObjectAttributes,
591 NotificationEvent,
592 FALSE);
593 if (skip(NT_SUCCESS(Status), "No event\n"))
594 goto Cleanup;
595
596 /* Open all test files and get their FILE_OBJECT pointers */
597 for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
598 {
599 if (Tests[i].ParentPath)
600 {
601 RtlInitUnicodeString(&ParentPath, Tests[i].ParentPath);
602 InitializeObjectAttributes(&ObjectAttributes,
603 &ParentPath,
604 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
605 NULL,
606 NULL);
607 Status = ZwOpenFile(&ParentHandle[i],
608 GENERIC_READ,
609 &ObjectAttributes,
610 &IoStatus,
611 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
612 0);
613 ok_eq_hex(Status, STATUS_SUCCESS);
614 if (skip(NT_SUCCESS(Status), "No parent handle %lu\n", i))
615 goto Cleanup;
616 }
617
618 RtlInitUnicodeString(&RelativePath, Tests[i].RelativePath);
619 InitializeObjectAttributes(&ObjectAttributes,
620 &RelativePath,
621 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
622 ParentHandle[i],
623 NULL);
624 Status = ZwOpenFile(&FileHandle[i],
625 FILE_ALL_ACCESS,
626 &ObjectAttributes,
627 &IoStatus,
628 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
629 0);
630 ok_eq_hex(Status, STATUS_SUCCESS);
631 if (skip(NT_SUCCESS(Status), "No file handle %lu\n", i))
632 goto Cleanup;
633
634 Status = ObReferenceObjectByHandle(FileHandle[i],
635 FILE_ALL_ACCESS,
636 *IoFileObjectType,
637 KernelMode,
638 (PVOID*)&FileObject[i],
639 NULL);
640 ok_eq_hex(Status, STATUS_SUCCESS);
641 if (skip(NT_SUCCESS(Status), "No file object %lu\n", i))
642 goto Cleanup;
643 }
644
645 /* Also get a file object for the SystemRoot directory */
646 Status = ObReferenceObjectByHandle(ParentHandle[1],
647 GENERIC_READ,
648 *IoFileObjectType,
649 KernelMode,
650 (PVOID*)&SystemRootObject,
651 NULL);
652 ok_eq_hex(Status, STATUS_SUCCESS);
653 if (skip(NT_SUCCESS(Status), "No SystemRoot object\n"))
654 goto Cleanup;
655
656 /* Before read, caching is not initialized */
657 ok_eq_pointer(SystemRootObject->SectionObjectPointer, NULL);
658 for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
659 {
660 ok(FileObject[i]->SectionObjectPointer != NULL, "FileObject[%lu]->SectionObjectPointer = NULL\n", i);
661 ok(FileObject[i]->SectionObjectPointer == FileObject[0]->SectionObjectPointer,
662 "FileObject[%lu]->SectionObjectPointer = %p, expected %p\n",
663 i, FileObject[i]->SectionObjectPointer, FileObject[0]->SectionObjectPointer);
664 }
665 if (!skip(FileObject[0]->SectionObjectPointer != NULL, "No section object pointers\n"))
666 ok_eq_pointer(FileObject[0]->SectionObjectPointer->SharedCacheMap, NULL);
667
668 /* Perform a read on one handle to initialize caching */
669 FileOffset.QuadPart = 0;
670 Status = ZwReadFile(FileHandle[0],
671 EventHandle,
672 NULL,
673 NULL,
674 &IoStatus,
675 Buffer,
676 sizeof(Buffer),
677 &FileOffset,
678 NULL);
679 if (Status == STATUS_PENDING)
680 {
681 Status = ZwWaitForSingleObject(EventHandle, FALSE, NULL);
682 ok_eq_hex(Status, STATUS_SUCCESS);
683 Status = IoStatus.Status;
684 }
685 ok_eq_hex(Status, STATUS_SUCCESS);
686
687 /* Now we see a SharedCacheMap for the file */
688 ok_eq_pointer(SystemRootObject->SectionObjectPointer, NULL);
689 for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
690 {
691 ok(FileObject[i]->SectionObjectPointer != NULL, "FileObject[%lu]->SectionObjectPointer = NULL\n", i);
692 ok(FileObject[i]->SectionObjectPointer == FileObject[0]->SectionObjectPointer,
693 "FileObject[%lu]->SectionObjectPointer = %p, expected %p\n",
694 i, FileObject[i]->SectionObjectPointer, FileObject[0]->SectionObjectPointer);
695 }
696 if (!skip(FileObject[0]->SectionObjectPointer != NULL, "No section object pointers\n"))
697 ok(FileObject[0]->SectionObjectPointer->SharedCacheMap != NULL, "SharedCacheMap is NULL\n");
698
699 Cleanup:
700 if (SystemRootObject)
701 ObDereferenceObject(SystemRootObject);
702 if (EventHandle)
703 ObCloseHandle(EventHandle, KernelMode);
704 for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
705 {
706 if (FileObject[i])
707 ObDereferenceObject(FileObject[i]);
708 if (FileHandle[i])
709 ObCloseHandle(FileHandle[i], KernelMode);
710 if (ParentHandle[i])
711 ObCloseHandle(ParentHandle[i], KernelMode);
712 }
713 }
714
715 START_TEST(IoFilesystem)
716 {
717 TestAllInformation();
718 TestRelativeNames();
719 TestSharedCacheMap();
720 }