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>
10 /* FIXME: Test this stuff on non-FAT volumes */
15 _Out_writes_bytes_(BufferSize
) PWCHAR Buffer
,
16 _In_ ULONG BufferSize
,
18 _In_ PCWSTR SystemDriveName
,
19 _In_ PCWSTR SystemRootName
)
21 UNICODE_STRING SystemDriveTemplate
= RTL_CONSTANT_STRING(L
"C:");
22 UNICODE_STRING SystemRootTemplate
= RTL_CONSTANT_STRING(L
"ReactOS");
23 ULONG SystemDriveLength
;
24 ULONG SystemRootLength
;
26 UNICODE_STRING String
;
28 SystemDriveLength
= wcslen(SystemDriveName
) * sizeof(WCHAR
);
29 SystemRootLength
= wcslen(SystemRootName
) * sizeof(WCHAR
);
31 RtlInitUnicodeString(&String
, Template
);
32 ASSERT(String
.Length
% sizeof(WCHAR
) == 0);
35 if (RtlPrefixUnicodeString(&SystemDriveTemplate
, &String
, TRUE
))
37 ASSERT((Dest
- Buffer
) * sizeof(WCHAR
) + SystemDriveLength
< BufferSize
);
41 Dest
+= SystemDriveLength
/ sizeof(WCHAR
);
43 String
.Buffer
+= SystemDriveTemplate
.Length
/ sizeof(WCHAR
);
44 String
.Length
-= SystemDriveTemplate
.Length
;
45 String
.MaximumLength
-= SystemDriveTemplate
.Length
;
49 if (RtlPrefixUnicodeString(&SystemRootTemplate
, &String
, TRUE
))
51 ASSERT((Dest
- Buffer
) * sizeof(WCHAR
) + SystemRootLength
< BufferSize
);
55 Dest
+= SystemRootLength
/ sizeof(WCHAR
);
57 String
.Buffer
+= SystemRootTemplate
.Length
/ sizeof(WCHAR
);
58 String
.Length
-= SystemRootTemplate
.Length
;
59 String
.MaximumLength
-= SystemRootTemplate
.Length
;
63 ASSERT(Dest
- Buffer
< BufferSize
/ sizeof(WCHAR
));
64 *Dest
++ = String
.Buffer
[0];
67 String
.Length
-= sizeof(WCHAR
);
68 String
.MaximumLength
-= sizeof(WCHAR
);
70 ASSERT(Dest
- Buffer
< BufferSize
/ sizeof(WCHAR
));
76 TestRelativeNames(VOID
)
81 PCWSTR ParentPathTemplate
;
82 PCWSTR RelativePathTemplate
;
87 { NULL
, L
"C:\\", TRUE
, STATUS_SUCCESS
},
88 { NULL
, L
"C:\\\\", TRUE
, STATUS_SUCCESS
},
89 { NULL
, L
"C:\\\\\\", TRUE
, STATUS_OBJECT_NAME_INVALID
},
90 { NULL
, L
"C:\\ReactOS", TRUE
, STATUS_SUCCESS
},
91 { NULL
, L
"C:\\ReactOS\\", TRUE
, STATUS_SUCCESS
},
92 { NULL
, L
"C:\\ReactOS\\\\", TRUE
, STATUS_SUCCESS
},
93 { NULL
, L
"C:\\ReactOS\\\\\\", TRUE
, STATUS_OBJECT_NAME_INVALID
},
94 { NULL
, L
"C:\\\\ReactOS", TRUE
, STATUS_SUCCESS
},
95 { NULL
, L
"C:\\\\ReactOS\\", TRUE
, STATUS_SUCCESS
},
96 { NULL
, L
"C:\\ReactOS\\explorer.exe", FALSE
, STATUS_SUCCESS
},
97 { NULL
, L
"C:\\ReactOS\\\\explorer.exe", FALSE
, STATUS_OBJECT_NAME_INVALID
},
98 { NULL
, L
"C:\\ReactOS\\explorer.exe\\", FALSE
, STATUS_OBJECT_NAME_INVALID
},
99 { NULL
, L
"C:\\ReactOS\\explorer.exe\\\\", FALSE
, STATUS_OBJECT_NAME_INVALID
},
100 /* This will never return STATUS_NOT_A_DIRECTORY. IsDirectory=TRUE is a little hacky but achieves that without special handling */
101 { NULL
, L
"C:\\ReactOS\\explorer.exe\\\\\\", TRUE
, STATUS_OBJECT_NAME_INVALID
},
102 { L
"C:\\", L
"", TRUE
, STATUS_SUCCESS
},
103 { L
"C:\\", L
"\\", TRUE
, STATUS_OBJECT_NAME_INVALID
},
104 { L
"C:\\", L
"ReactOS", TRUE
, STATUS_SUCCESS
},
105 { L
"C:\\", L
"\\ReactOS", TRUE
, STATUS_OBJECT_NAME_INVALID
},
106 { L
"C:\\", L
"ReactOS\\", TRUE
, STATUS_SUCCESS
},
107 { L
"C:\\", L
"\\ReactOS\\", TRUE
, STATUS_OBJECT_NAME_INVALID
},
108 { L
"C:\\ReactOS", L
"", TRUE
, STATUS_SUCCESS
},
109 { L
"C:\\ReactOS", L
"explorer.exe", FALSE
, STATUS_SUCCESS
},
110 { L
"C:\\ReactOS\\explorer.exe", L
"", FALSE
, STATUS_SUCCESS
},
111 /* Let's try some nonexistent things */
112 { NULL
, L
"C:\\ReactOS\\IDoNotExist", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
113 { NULL
, L
"C:\\ReactOS\\IDoNotExist\\file", FALSE
, STATUS_OBJECT_PATH_NOT_FOUND
},
114 { NULL
, L
"C:\\ReactOS\\IDoNotExist\\file?", FALSE
, STATUS_OBJECT_PATH_NOT_FOUND
},
115 { NULL
, L
"C:\\ReactOS\\IDoNotExist\\file\\\\",TRUE
,STATUS_OBJECT_PATH_NOT_FOUND
},
116 { NULL
, L
"C:\\ReactOS\\IDoNotExist\\file\\\\\\",TRUE
,STATUS_OBJECT_PATH_NOT_FOUND
},
117 { NULL
, L
"C:\\ReactOS\\AmIInvalid?", FALSE
, STATUS_OBJECT_NAME_INVALID
},
118 { NULL
, L
"C:\\ReactOS\\.", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
119 { NULL
, L
"C:\\ReactOS\\..", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
120 { NULL
, L
"C:\\ReactOS\\...", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
121 { L
"C:\\", L
".", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
122 { L
"C:\\", L
"..", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
123 { L
"C:\\", L
"...", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
124 { L
"C:\\ReactOS", L
".", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
125 { L
"C:\\ReactOS", L
"..", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
126 { L
"C:\\ReactOS", L
"...", FALSE
, STATUS_OBJECT_NAME_NOT_FOUND
},
129 OBJECT_ATTRIBUTES ObjectAttributes
;
130 IO_STATUS_BLOCK IoStatus
;
131 UNICODE_STRING ParentPath
;
132 UNICODE_STRING RelativePath
;
135 UNICODE_STRING SystemRoot
= RTL_CONSTANT_STRING(L
"\\SystemRoot");
136 HANDLE SymbolicLinkHandle
= NULL
;
137 WCHAR LinkNameBuffer
[128];
138 UNICODE_STRING SymbolicLinkName
;
139 PWSTR SystemDriveName
;
140 PWSTR SystemRootName
;
141 PWCHAR Buffer
= NULL
;
142 BOOLEAN TrailingBackslash
;
144 /* Query \SystemRoot */
145 InitializeObjectAttributes(&ObjectAttributes
,
147 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
150 Status
= ZwOpenSymbolicLinkObject(&SymbolicLinkHandle
,
153 if (skip(NT_SUCCESS(Status
), "Failed to open SystemRoot, %lx\n", Status
))
156 RtlInitEmptyUnicodeString(&SymbolicLinkName
,
158 sizeof(LinkNameBuffer
));
159 Status
= ZwQuerySymbolicLinkObject(SymbolicLinkHandle
,
162 ObCloseHandle(SymbolicLinkHandle
, KernelMode
);
163 if (skip(NT_SUCCESS(Status
), "Failed to query SystemRoot, %lx\n", Status
))
166 /* Split SymbolicLinkName into drive and path */
167 SystemDriveName
= SymbolicLinkName
.Buffer
;
168 SystemRootName
= SymbolicLinkName
.Buffer
+ SymbolicLinkName
.Length
/ sizeof(WCHAR
);
169 *SystemRootName
-- = UNICODE_NULL
;
170 while (*SystemRootName
!= L
'\\')
172 ASSERT(SystemRootName
> SymbolicLinkName
.Buffer
);
175 *SystemRootName
++ = UNICODE_NULL
;
176 trace("System Drive: '%ls'\n", SystemDriveName
);
177 trace("System Root: '%ls'\n", SystemRootName
);
179 /* Allocate path buffer */
180 Buffer
= ExAllocatePoolWithTag(PagedPool
, MAXUSHORT
, 'sFmK');
181 if (skip(Buffer
!= NULL
, "No buffer\n"))
184 /* Finally run some tests! */
185 for (i
= 0; i
< RTL_NUMBER_OF(Tests
); i
++)
187 /* Open parent directory first */
189 if (Tests
[i
].ParentPathTemplate
)
193 Tests
[i
].ParentPathTemplate
,
196 RtlInitUnicodeString(&ParentPath
, Buffer
);
197 InitializeObjectAttributes(&ObjectAttributes
,
199 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
202 Status
= ZwOpenFile(&ParentHandle
,
206 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
208 ok(Status
== STATUS_SUCCESS
,
209 "[%lu] Status = %lx, expected STATUS_SUCCESS\n", i
, Status
);
210 if (skip(NT_SUCCESS(Status
), "No parent handle %lu\n", i
))
214 /* Now open the relative file: */
217 Tests
[i
].RelativePathTemplate
,
220 RtlInitUnicodeString(&RelativePath
, Buffer
);
221 InitializeObjectAttributes(&ObjectAttributes
,
223 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
226 TrailingBackslash
= FALSE
;
227 if (wcslen(Buffer
) && Buffer
[wcslen(Buffer
) - 1] == L
'\\')
228 TrailingBackslash
= TRUE
;
231 Status
= ZwOpenFile(&FileHandle
,
235 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
237 ok(Status
== Tests
[i
].Status
,
238 "[%lu] Status = %lx, expected %lx\n", i
, Status
, Tests
[i
].Status
);
239 if (NT_SUCCESS(Status
))
240 ObCloseHandle(FileHandle
, KernelMode
);
242 /* (2) Directory File */
243 Status
= ZwOpenFile(&FileHandle
,
247 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
248 FILE_DIRECTORY_FILE
);
249 if (Tests
[i
].IsDirectory
|| (!TrailingBackslash
&& !NT_SUCCESS(Tests
[i
].Status
)))
250 ok(Status
== Tests
[i
].Status
,
251 "[%lu] Status = %lx, expected %lx\n", i
, Status
, Tests
[i
].Status
);
253 ok(Status
== STATUS_NOT_A_DIRECTORY
,
254 "[%lu] Status = %lx, expected STATUS_NOT_A_DIRECTORY\n", i
, Status
);
255 if (NT_SUCCESS(Status
))
256 ObCloseHandle(FileHandle
, KernelMode
);
258 /* (3) Non-Directory File */
259 Status
= ZwOpenFile(&FileHandle
,
263 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
264 FILE_NON_DIRECTORY_FILE
);
265 if (Tests
[i
].IsDirectory
&& NT_SUCCESS(Tests
[i
].Status
))
266 ok(Status
== STATUS_FILE_IS_A_DIRECTORY
,
267 "[%lu] Status = %lx, expected STATUS_FILE_IS_A_DIRECTORY\n", i
, Status
);
269 ok(Status
== Tests
[i
].Status
,
270 "[%lu] Status = %lx, expected %lx\n", i
, Status
, Tests
[i
].Status
);
271 if (NT_SUCCESS(Status
))
272 ObCloseHandle(FileHandle
, KernelMode
);
275 ObCloseHandle(ParentHandle
, KernelMode
);
278 ExFreePoolWithTag(Buffer
, 'sFmK');
283 TestSharedCacheMap(VOID
)
292 { 0, L
"\\SystemRoot\\system32\\drivers\\etc\\hosts" },
293 { L
"\\SystemRoot", L
"system32\\drivers\\etc\\hosts" },
294 { L
"\\SystemRoot\\system32", L
"drivers\\etc\\hosts" },
295 { L
"\\SystemRoot\\system32\\drivers", L
"etc\\hosts" },
296 { L
"\\SystemRoot\\system32\\drivers\\etc", L
"hosts" },
298 OBJECT_ATTRIBUTES ObjectAttributes
;
299 IO_STATUS_BLOCK IoStatus
;
300 UNICODE_STRING ParentPath
;
301 UNICODE_STRING RelativePath
;
302 HANDLE ParentHandle
[RTL_NUMBER_OF(Tests
)] = { NULL
};
303 HANDLE FileHandle
[RTL_NUMBER_OF(Tests
)] = { NULL
};
304 PFILE_OBJECT FileObject
[RTL_NUMBER_OF(Tests
)] = { NULL
};
305 PFILE_OBJECT SystemRootObject
= NULL
;
308 LARGE_INTEGER FileOffset
;
311 /* We need an event for ZwReadFile */
312 InitializeObjectAttributes(&ObjectAttributes
,
317 Status
= ZwCreateEvent(&EventHandle
,
322 if (skip(NT_SUCCESS(Status
), "No event\n"))
325 /* Open all test files and get their FILE_OBJECT pointers */
326 for (i
= 0; i
< RTL_NUMBER_OF(Tests
); i
++)
328 if (Tests
[i
].ParentPath
)
330 RtlInitUnicodeString(&ParentPath
, Tests
[i
].ParentPath
);
331 InitializeObjectAttributes(&ObjectAttributes
,
333 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
336 Status
= ZwOpenFile(&ParentHandle
[i
],
340 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
342 ok_eq_hex(Status
, STATUS_SUCCESS
);
343 if (skip(NT_SUCCESS(Status
), "No parent handle %lu\n", i
))
347 RtlInitUnicodeString(&RelativePath
, Tests
[i
].RelativePath
);
348 InitializeObjectAttributes(&ObjectAttributes
,
350 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
353 Status
= ZwOpenFile(&FileHandle
[i
],
357 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
359 ok_eq_hex(Status
, STATUS_SUCCESS
);
360 if (skip(NT_SUCCESS(Status
), "No file handle %lu\n", i
))
363 Status
= ObReferenceObjectByHandle(FileHandle
[i
],
367 (PVOID
*)&FileObject
[i
],
369 ok_eq_hex(Status
, STATUS_SUCCESS
);
370 if (skip(NT_SUCCESS(Status
), "No file object %lu\n", i
))
374 /* Also get a file object for the SystemRoot directory */
375 Status
= ObReferenceObjectByHandle(ParentHandle
[1],
379 (PVOID
*)&SystemRootObject
,
381 ok_eq_hex(Status
, STATUS_SUCCESS
);
382 if (skip(NT_SUCCESS(Status
), "No SystemRoot object\n"))
385 /* Before read, caching is not initialized */
386 ok_eq_pointer(SystemRootObject
->SectionObjectPointer
, NULL
);
387 for (i
= 0; i
< RTL_NUMBER_OF(Tests
); i
++)
389 ok(FileObject
[i
]->SectionObjectPointer
!= NULL
, "FileObject[%lu]->SectionObjectPointer = NULL\n", i
);
390 ok(FileObject
[i
]->SectionObjectPointer
== FileObject
[0]->SectionObjectPointer
,
391 "FileObject[%lu]->SectionObjectPointer = %p, expected %p\n",
392 i
, FileObject
[i
]->SectionObjectPointer
, FileObject
[0]->SectionObjectPointer
);
394 if (!skip(FileObject
[0]->SectionObjectPointer
!= NULL
, "No section object pointers\n"))
395 ok_eq_pointer(FileObject
[0]->SectionObjectPointer
->SharedCacheMap
, NULL
);
397 /* Perform a read on one handle to initialize caching */
398 FileOffset
.QuadPart
= 0;
399 Status
= ZwReadFile(FileHandle
[0],
408 if (Status
== STATUS_PENDING
)
410 Status
= ZwWaitForSingleObject(EventHandle
, FALSE
, NULL
);
411 ok_eq_hex(Status
, STATUS_SUCCESS
);
412 Status
= IoStatus
.Status
;
414 ok_eq_hex(Status
, STATUS_SUCCESS
);
416 /* Now we see a SharedCacheMap for the file */
417 ok_eq_pointer(SystemRootObject
->SectionObjectPointer
, NULL
);
418 for (i
= 0; i
< RTL_NUMBER_OF(Tests
); i
++)
420 ok(FileObject
[i
]->SectionObjectPointer
!= NULL
, "FileObject[%lu]->SectionObjectPointer = NULL\n", i
);
421 ok(FileObject
[i
]->SectionObjectPointer
== FileObject
[0]->SectionObjectPointer
,
422 "FileObject[%lu]->SectionObjectPointer = %p, expected %p\n",
423 i
, FileObject
[i
]->SectionObjectPointer
, FileObject
[0]->SectionObjectPointer
);
425 if (!skip(FileObject
[0]->SectionObjectPointer
!= NULL
, "No section object pointers\n"))
426 ok(FileObject
[0]->SectionObjectPointer
->SharedCacheMap
!= NULL
, "SharedCacheMap is NULL\n");
429 if (SystemRootObject
)
430 ObDereferenceObject(SystemRootObject
);
432 ObCloseHandle(EventHandle
, KernelMode
);
433 for (i
= 0; i
< RTL_NUMBER_OF(Tests
); i
++)
436 ObDereferenceObject(FileObject
[i
]);
438 ObCloseHandle(FileHandle
[i
], KernelMode
);
440 ObCloseHandle(ParentHandle
[i
], KernelMode
);
444 START_TEST(IoFilesystem
)
447 TestSharedCacheMap();