[KMTESTS:IO]
[reactos.git] / rostests / kmtests / ntos_io / IoCreateFile.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Io Regressions KM-Test (IoCreateFile)
5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
6 */
7
8 #include <kmt_test.h>
9
10 static UNICODE_STRING SystemRoot = RTL_CONSTANT_STRING(L"\\SystemRoot\\");
11 static UNICODE_STRING Regedit = RTL_CONSTANT_STRING(L"regedit.exe");
12 static UNICODE_STRING Foobar = RTL_CONSTANT_STRING(L"foobar.exe");
13 static UNICODE_STRING SystemRootRegedit = RTL_CONSTANT_STRING(L"\\SystemRoot\\regedit.exe");
14 static UNICODE_STRING SystemRootFoobar = RTL_CONSTANT_STRING(L"\\SystemRoot\\foobar.exe");
15 static UNICODE_STRING SystemRootFoobarFoobar = RTL_CONSTANT_STRING(L"\\SystemRoot\\foobar\\foobar.exe");
16 static UNICODE_STRING FoobarFoobar = RTL_CONSTANT_STRING(L"foobar\\foobar.exe");
17
18 static
19 VOID
20 NTAPI
21 KernelModeTest(IN PVOID Context)
22 {
23 NTSTATUS Status;
24 IO_STATUS_BLOCK IoStatusBlock;
25 OBJECT_ATTRIBUTES ObjectAttributes;
26 PFILE_OBJECT ParentFileObject, TargetFileObject;
27 HANDLE ParentHandle, SystemRootHandle, TargetHandle;
28
29 UNREFERENCED_PARAMETER(Context);
30
31 /* Kernelmode mandatory for IoCreateFile */
32 ok(ExGetPreviousMode() == KernelMode, "UserMode returned!\n");
33
34 /* First of all, open \\SystemRoot
35 * We're interested in 3 pieces of information about it:
36 * -> Its target (it's a symlink): \Windows or \ReactOS
37 * -> Its associated File Object
38 * -> Its associated FCB
39 */
40 TargetFileObject = NULL;
41 IoStatusBlock.Status = 0xFFFFFFFF;
42 TargetHandle = INVALID_HANDLE_VALUE;
43 IoStatusBlock.Information = 0xFFFFFFFF;
44 InitializeObjectAttributes(&ObjectAttributes,
45 &SystemRoot,
46 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
47 NULL, NULL);
48 Status = ZwOpenFile(&TargetHandle,
49 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
50 &ObjectAttributes,
51 &IoStatusBlock,
52 FILE_SHARE_READ | FILE_SHARE_WRITE,
53 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
54 ok_eq_hex(Status, STATUS_SUCCESS);
55 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
56 if (Status == STATUS_SUCCESS)
57 {
58 Status = ObReferenceObjectByHandle(TargetHandle,
59 FILE_READ_DATA,
60 IoFileObjectType,
61 KernelMode,
62 (PVOID *)&TargetFileObject,
63 NULL);
64 ok_eq_hex(Status, STATUS_SUCCESS);
65 }
66
67 ok(TargetFileObject != NULL, "Not target to continue!\n");
68 if (TargetFileObject == NULL)
69 {
70 if (TargetHandle != INVALID_HANDLE_VALUE)
71 {
72 ObCloseHandle(TargetHandle, KernelMode);
73 }
74 return;
75 }
76
77 /* Open target directory of \SystemRoot\Regedit.exe
78 * This must lead to \SystemRoot opening
79 */
80 IoStatusBlock.Status = 0xFFFFFFFF;
81 IoStatusBlock.Information = 0xFFFFFFFF;
82 InitializeObjectAttributes(&ObjectAttributes,
83 &SystemRootRegedit,
84 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
85 NULL, NULL);
86 Status = IoCreateFile(&ParentHandle,
87 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
88 &ObjectAttributes,
89 &IoStatusBlock,
90 NULL,
91 0,
92 FILE_SHARE_READ | FILE_SHARE_WRITE,
93 FILE_OPEN,
94 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
95 NULL,
96 0,
97 CreateFileTypeNone,
98 NULL,
99 IO_OPEN_TARGET_DIRECTORY);
100 ok_eq_hex(Status, STATUS_SUCCESS);
101 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
102 if (Status == STATUS_SUCCESS)
103 {
104 Status = ObReferenceObjectByHandle(ParentHandle,
105 FILE_READ_DATA,
106 IoFileObjectType,
107 KernelMode,
108 (PVOID *)&ParentFileObject,
109 NULL);
110 ok_eq_hex(Status, STATUS_SUCCESS);
111 if (Status == STATUS_SUCCESS)
112 {
113 /* At that point, file object must point to \SystemRoot
114 * But must not be the same FO than target (diverted file object)
115 * This means FCB & FileName are equal
116 * But CCB & FO are different
117 * CCB must be != NULL, otherwise it means open failed
118 */
119 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n");
120 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext);
121 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n");
122 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n");
123 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0);
124 ObDereferenceObject(ParentFileObject);
125 }
126 /* Because target exists FSD must signal it */
127 ok_eq_long(IoStatusBlock.Information, FILE_EXISTS);
128 ObCloseHandle(ParentHandle, KernelMode);
129 }
130
131 /* Do the same with relative open */
132 IoStatusBlock.Status = 0xFFFFFFFF;
133 IoStatusBlock.Information = 0xFFFFFFFF;
134 InitializeObjectAttributes(&ObjectAttributes,
135 &SystemRoot,
136 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
137 NULL, NULL);
138 Status = ZwOpenFile(&SystemRootHandle,
139 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
140 &ObjectAttributes,
141 &IoStatusBlock,
142 FILE_SHARE_READ | FILE_SHARE_WRITE,
143 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
144 ok_eq_hex(Status, STATUS_SUCCESS);
145 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
146 if (Status == STATUS_SUCCESS)
147 {
148 IoStatusBlock.Status = 0xFFFFFFFF;
149 IoStatusBlock.Information = 0xFFFFFFFF;
150 InitializeObjectAttributes(&ObjectAttributes,
151 &Regedit,
152 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
153 SystemRootHandle,
154 NULL);
155 Status = IoCreateFile(&ParentHandle,
156 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
157 &ObjectAttributes,
158 &IoStatusBlock,
159 NULL,
160 0,
161 FILE_SHARE_READ | FILE_SHARE_WRITE,
162 FILE_OPEN,
163 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
164 NULL,
165 0,
166 CreateFileTypeNone,
167 NULL,
168 IO_OPEN_TARGET_DIRECTORY);
169 ok_eq_hex(Status, STATUS_SUCCESS);
170 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
171 if (Status == STATUS_SUCCESS)
172 {
173 Status = ObReferenceObjectByHandle(ParentHandle,
174 FILE_READ_DATA,
175 IoFileObjectType,
176 KernelMode,
177 (PVOID *)&ParentFileObject,
178 NULL);
179 ok_eq_hex(Status, STATUS_SUCCESS);
180 if (Status == STATUS_SUCCESS)
181 {
182 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n");
183 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext);
184 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n");
185 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n");
186 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0);
187 ObDereferenceObject(ParentFileObject);
188 }
189 ok_eq_long(IoStatusBlock.Information, FILE_EXISTS);
190 ObCloseHandle(ParentHandle, KernelMode);
191 }
192 ObCloseHandle(SystemRootHandle, KernelMode);
193 }
194
195 /* *** */
196
197 /* Now redo the same scheme, but using a target that doesn't exist
198 * The difference will be in IoStatusBlock.Information, the FSD will
199 * inform that the target doesn't exist.
200 * Clear for rename :-)
201 */
202 IoStatusBlock.Status = 0xFFFFFFFF;
203 IoStatusBlock.Information = 0xFFFFFFFF;
204 InitializeObjectAttributes(&ObjectAttributes,
205 &SystemRootFoobar,
206 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
207 NULL, NULL);
208 Status = IoCreateFile(&ParentHandle,
209 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
210 &ObjectAttributes,
211 &IoStatusBlock,
212 NULL,
213 0,
214 FILE_SHARE_READ | FILE_SHARE_WRITE,
215 FILE_OPEN,
216 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
217 NULL,
218 0,
219 CreateFileTypeNone,
220 NULL,
221 IO_OPEN_TARGET_DIRECTORY);
222 ok_eq_hex(Status, STATUS_SUCCESS);
223 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
224 if (Status == STATUS_SUCCESS)
225 {
226 Status = ObReferenceObjectByHandle(ParentHandle,
227 FILE_READ_DATA,
228 IoFileObjectType,
229 KernelMode,
230 (PVOID *)&ParentFileObject,
231 NULL);
232 ok_eq_hex(Status, STATUS_SUCCESS);
233 if (Status == STATUS_SUCCESS)
234 {
235 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n");
236 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext);
237 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n");
238 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n");
239 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0);
240 ObDereferenceObject(ParentFileObject);
241 }
242 ok_eq_long(IoStatusBlock.Information, FILE_DOES_NOT_EXIST);
243 ObCloseHandle(ParentHandle, KernelMode);
244 }
245
246 IoStatusBlock.Status = 0xFFFFFFFF;
247 IoStatusBlock.Information = 0xFFFFFFFF;
248 InitializeObjectAttributes(&ObjectAttributes,
249 &SystemRoot,
250 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
251 NULL, NULL);
252 Status = ZwOpenFile(&SystemRootHandle,
253 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
254 &ObjectAttributes,
255 &IoStatusBlock,
256 FILE_SHARE_READ | FILE_SHARE_WRITE,
257 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
258 ok_eq_hex(Status, STATUS_SUCCESS);
259 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
260 if (Status == STATUS_SUCCESS)
261 {
262 IoStatusBlock.Status = 0xFFFFFFFF;
263 IoStatusBlock.Information = 0xFFFFFFFF;
264 InitializeObjectAttributes(&ObjectAttributes,
265 &Foobar,
266 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
267 SystemRootHandle,
268 NULL);
269 Status = IoCreateFile(&ParentHandle,
270 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
271 &ObjectAttributes,
272 &IoStatusBlock,
273 NULL,
274 0,
275 FILE_SHARE_READ | FILE_SHARE_WRITE,
276 FILE_OPEN,
277 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
278 NULL,
279 0,
280 CreateFileTypeNone,
281 NULL,
282 IO_OPEN_TARGET_DIRECTORY);
283 ok_eq_hex(Status, STATUS_SUCCESS);
284 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
285 if (Status == STATUS_SUCCESS)
286 {
287 Status = ObReferenceObjectByHandle(ParentHandle,
288 FILE_READ_DATA,
289 IoFileObjectType,
290 KernelMode,
291 (PVOID *)&ParentFileObject,
292 NULL);
293 ok_eq_hex(Status, STATUS_SUCCESS);
294 if (Status == STATUS_SUCCESS)
295 {
296 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n");
297 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext);
298 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n");
299 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n");
300 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0);
301 ObDereferenceObject(ParentFileObject);
302 }
303 ok_eq_long(IoStatusBlock.Information, FILE_DOES_NOT_EXIST);
304 ObCloseHandle(ParentHandle, KernelMode);
305 }
306 ObCloseHandle(SystemRootHandle, KernelMode);
307 }
308
309 ObDereferenceObject(TargetFileObject);
310 ObCloseHandle(TargetHandle, KernelMode);
311
312 /* *** */
313
314 /* Direct target open of something that doesn't exist */
315 IoStatusBlock.Status = 0xFFFFFFFF;
316 IoStatusBlock.Information = 0xFFFFFFFF;
317 InitializeObjectAttributes(&ObjectAttributes,
318 &SystemRootFoobarFoobar,
319 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
320 NULL, NULL);
321 Status = IoCreateFile(&ParentHandle,
322 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
323 &ObjectAttributes,
324 &IoStatusBlock,
325 NULL,
326 0,
327 FILE_SHARE_READ | FILE_SHARE_WRITE,
328 FILE_OPEN,
329 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
330 NULL,
331 0,
332 CreateFileTypeNone,
333 NULL,
334 IO_OPEN_TARGET_DIRECTORY);
335 ok_eq_hex(Status, STATUS_OBJECT_PATH_NOT_FOUND);
336 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF);
337 if (Status == STATUS_SUCCESS)
338 {
339 ObCloseHandle(ParentHandle, KernelMode);
340 }
341
342 /* Relative target open of something that doesn't exist */
343 IoStatusBlock.Status = 0xFFFFFFFF;
344 IoStatusBlock.Information = 0xFFFFFFFF;
345 InitializeObjectAttributes(&ObjectAttributes,
346 &SystemRoot,
347 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
348 NULL, NULL);
349 Status = ZwOpenFile(&SystemRootHandle,
350 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
351 &ObjectAttributes,
352 &IoStatusBlock,
353 FILE_SHARE_READ | FILE_SHARE_WRITE,
354 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
355 ok_eq_hex(Status, STATUS_SUCCESS);
356 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
357 if (Status == STATUS_SUCCESS)
358 {
359 IoStatusBlock.Status = 0xFFFFFFFF;
360 IoStatusBlock.Information = 0xFFFFFFFF;
361 InitializeObjectAttributes(&ObjectAttributes,
362 &FoobarFoobar,
363 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
364 SystemRootHandle,
365 NULL);
366 Status = IoCreateFile(&ParentHandle,
367 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
368 &ObjectAttributes,
369 &IoStatusBlock,
370 NULL,
371 0,
372 FILE_SHARE_READ | FILE_SHARE_WRITE,
373 FILE_OPEN,
374 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
375 NULL,
376 0,
377 CreateFileTypeNone,
378 NULL,
379 IO_OPEN_TARGET_DIRECTORY);
380 ok_eq_hex(Status, STATUS_OBJECT_PATH_NOT_FOUND);
381 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF);
382 if (Status == STATUS_SUCCESS)
383 {
384 ObCloseHandle(ParentHandle, KernelMode);
385 }
386 ObCloseHandle(SystemRootHandle, KernelMode);
387 }
388 }
389
390 static
391 VOID
392 NTAPI
393 UserModeTest(VOID)
394 {
395 NTSTATUS Status;
396 IO_STATUS_BLOCK IoStatusBlock;
397 OBJECT_ATTRIBUTES ObjectAttributes;
398 HANDLE ParentHandle, SystemRootHandle;
399
400 ok(ExGetPreviousMode() == UserMode, "KernelMode returned!\n");
401
402 /* Attempt direct target open */
403 IoStatusBlock.Status = 0xFFFFFFFF;
404 IoStatusBlock.Information = 0xFFFFFFFF;
405 InitializeObjectAttributes(&ObjectAttributes,
406 &SystemRootRegedit,
407 OBJ_CASE_INSENSITIVE,
408 NULL, NULL);
409 Status = IoCreateFile(&ParentHandle,
410 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
411 &ObjectAttributes,
412 &IoStatusBlock,
413 NULL,
414 0,
415 FILE_SHARE_READ | FILE_SHARE_WRITE,
416 FILE_OPEN,
417 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
418 NULL,
419 0,
420 CreateFileTypeNone,
421 NULL,
422 IO_OPEN_TARGET_DIRECTORY);
423 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
424 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF);
425 if (Status == STATUS_SUCCESS)
426 {
427 ObCloseHandle(ParentHandle, KernelMode);
428 }
429
430 /* Attempt relative target open */
431 IoStatusBlock.Status = 0xFFFFFFFF;
432 IoStatusBlock.Information = 0xFFFFFFFF;
433 InitializeObjectAttributes(&ObjectAttributes,
434 &SystemRoot,
435 OBJ_CASE_INSENSITIVE,
436 NULL, NULL);
437 Status = ZwOpenFile(&SystemRootHandle,
438 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
439 &ObjectAttributes,
440 &IoStatusBlock,
441 FILE_SHARE_READ | FILE_SHARE_WRITE,
442 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
443 ok_eq_hex(Status, STATUS_SUCCESS);
444 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
445 if (Status == STATUS_SUCCESS)
446 {
447 IoStatusBlock.Status = 0xFFFFFFFF;
448 IoStatusBlock.Information = 0xFFFFFFFF;
449 InitializeObjectAttributes(&ObjectAttributes,
450 &Regedit,
451 OBJ_CASE_INSENSITIVE,
452 SystemRootHandle,
453 NULL);
454 Status = IoCreateFile(&ParentHandle,
455 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
456 &ObjectAttributes,
457 &IoStatusBlock,
458 NULL,
459 0,
460 FILE_SHARE_READ | FILE_SHARE_WRITE,
461 FILE_OPEN,
462 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
463 NULL,
464 0,
465 CreateFileTypeNone,
466 NULL,
467 IO_OPEN_TARGET_DIRECTORY);
468 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
469 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF);
470 if (Status == STATUS_SUCCESS)
471 {
472 ObCloseHandle(ParentHandle, KernelMode);
473 }
474 ObCloseHandle(SystemRootHandle, KernelMode);
475 }
476 }
477
478 START_TEST(IoCreateFile)
479 {
480 NTSTATUS Status;
481 OBJECT_ATTRIBUTES ObjectAttributes;
482 HANDLE ThreadHandle;
483 PVOID ThreadObject = NULL;
484
485 /* Justify the next comment/statement */
486 UserModeTest();
487
488 /* We've to be in kernel mode, so spawn a thread */
489 InitializeObjectAttributes(&ObjectAttributes,
490 NULL,
491 OBJ_KERNEL_HANDLE,
492 NULL,
493 NULL);
494 Status = PsCreateSystemThread(&ThreadHandle,
495 SYNCHRONIZE,
496 &ObjectAttributes,
497 NULL,
498 NULL,
499 KernelModeTest,
500 NULL);
501 ok_eq_hex(Status, STATUS_SUCCESS);
502 if (Status == STATUS_SUCCESS)
503 {
504 /* Then, just wait on our thread to finish */
505 Status = ObReferenceObjectByHandle(ThreadHandle,
506 SYNCHRONIZE,
507 PsThreadType,
508 KernelMode,
509 &ThreadObject,
510 NULL);
511 ObCloseHandle(ThreadHandle, KernelMode);
512
513 Status = KeWaitForSingleObject(ThreadObject,
514 Executive,
515 KernelMode,
516 FALSE,
517 NULL);
518 ok_eq_hex(Status, STATUS_SUCCESS);
519 ObDereferenceObject(ThreadObject);
520 }
521 }