[KMTESTS:MM]
[reactos.git] / rostests / kmtests / ntos_mm / NtCreateSection_drv.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test driver for NtCreateSection function
5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
6 */
7
8 #include <kmt_test.h>
9
10 #define NDEBUG
11 #include <debug.h>
12
13 typedef struct _TEST_FCB
14 {
15 FSRTL_ADVANCED_FCB_HEADER Header;
16 SECTION_OBJECT_POINTERS SectionObjectPointers;
17 FAST_MUTEX HeaderMutex;
18 } TEST_FCB, *PTEST_FCB;
19
20 static PFILE_OBJECT TestFileObject;
21 static PDEVICE_OBJECT TestDeviceObject;
22 static KMT_IRP_HANDLER TestIrpHandler;
23 static FAST_IO_DISPATCH TestFastIoDispatch;
24
25 static UNICODE_STRING InitOnCreate = RTL_CONSTANT_STRING(L"\\InitOnCreate");
26 static UNICODE_STRING InitOnRW = RTL_CONSTANT_STRING(L"\\InitOnRW");
27 static UNICODE_STRING InvalidInit = RTL_CONSTANT_STRING(L"\\InvalidInit");
28
29 static
30 BOOLEAN
31 NTAPI
32 FastIoRead(
33 _In_ PFILE_OBJECT FileObject,
34 _In_ PLARGE_INTEGER FileOffset,
35 _In_ ULONG Length,
36 _In_ BOOLEAN Wait,
37 _In_ ULONG LockKey,
38 _Out_ PVOID Buffer,
39 _Out_ PIO_STATUS_BLOCK IoStatus,
40 _In_ PDEVICE_OBJECT DeviceObject)
41 {
42 IoStatus->Status = STATUS_NOT_SUPPORTED;
43 return FALSE;
44 }
45
46 static
47 BOOLEAN
48 NTAPI
49 FastIoWrite(
50 _In_ PFILE_OBJECT FileObject,
51 _In_ PLARGE_INTEGER FileOffset,
52 _In_ ULONG Length,
53 _In_ BOOLEAN Wait,
54 _In_ ULONG LockKey,
55 _Out_ PVOID Buffer,
56 _Out_ PIO_STATUS_BLOCK IoStatus,
57 _In_ PDEVICE_OBJECT DeviceObject)
58 {
59 IoStatus->Status = STATUS_NOT_SUPPORTED;
60 return FALSE;
61 }
62
63 static
64 BOOLEAN
65 NTAPI
66 FastIoQueryStandardInfo(
67 _In_ PFILE_OBJECT FileObject,
68 _In_ BOOLEAN Wait,
69 _Out_ PFILE_STANDARD_INFORMATION Buffer,
70 _Out_ PIO_STATUS_BLOCK IoStatus,
71 _In_ PDEVICE_OBJECT DeviceObject)
72 {
73 IoStatus->Status = STATUS_NOT_SUPPORTED;
74 return FALSE;
75 }
76
77 NTSTATUS
78 TestEntry(
79 _In_ PDRIVER_OBJECT DriverObject,
80 _In_ PCUNICODE_STRING RegistryPath,
81 _Out_ PCWSTR *DeviceName,
82 _Inout_ INT *Flags)
83 {
84 NTSTATUS Status = STATUS_SUCCESS;
85
86 PAGED_CODE();
87
88 UNREFERENCED_PARAMETER(RegistryPath);
89
90 *DeviceName = L"NtCreateSection";
91 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE |
92 TESTENTRY_BUFFERED_IO_DEVICE |
93 TESTENTRY_NO_READONLY_DEVICE;
94
95 KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler);
96 KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler);
97 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler);
98 KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler);
99 KmtRegisterIrpHandler(IRP_MJ_QUERY_INFORMATION, NULL, TestIrpHandler);
100 KmtRegisterIrpHandler(IRP_MJ_SET_INFORMATION, NULL, TestIrpHandler);
101
102 TestFastIoDispatch.FastIoRead = FastIoRead;
103 TestFastIoDispatch.FastIoWrite = FastIoWrite;
104 TestFastIoDispatch.FastIoQueryStandardInfo = FastIoQueryStandardInfo;
105 DriverObject->FastIoDispatch = &TestFastIoDispatch;
106
107
108 return Status;
109 }
110
111 VOID
112 TestUnload(
113 _In_ PDRIVER_OBJECT DriverObject)
114 {
115 PAGED_CODE();
116 }
117
118 BOOLEAN
119 NTAPI
120 AcquireForLazyWrite(
121 _In_ PVOID Context,
122 _In_ BOOLEAN Wait)
123 {
124 return TRUE;
125 }
126
127 VOID
128 NTAPI
129 ReleaseFromLazyWrite(
130 _In_ PVOID Context)
131 {
132 return;
133 }
134
135 BOOLEAN
136 NTAPI
137 AcquireForReadAhead(
138 _In_ PVOID Context,
139 _In_ BOOLEAN Wait)
140 {
141 return TRUE;
142 }
143
144 VOID
145 NTAPI
146 ReleaseFromReadAhead(
147 _In_ PVOID Context)
148 {
149 return;
150 }
151
152 static CACHE_MANAGER_CALLBACKS Callbacks = {
153 AcquireForLazyWrite,
154 ReleaseFromLazyWrite,
155 AcquireForReadAhead,
156 ReleaseFromReadAhead,
157 };
158
159 static
160 PVOID
161 MapAndLockUserBuffer(
162 _In_ _Out_ PIRP Irp,
163 _In_ ULONG BufferLength)
164 {
165 PMDL Mdl;
166
167 if (Irp->MdlAddress == NULL)
168 {
169 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
170 if (Mdl == NULL)
171 {
172 return NULL;
173 }
174
175 _SEH2_TRY
176 {
177 MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoWriteAccess);
178 }
179 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
180 {
181 IoFreeMdl(Mdl);
182 Irp->MdlAddress = NULL;
183 _SEH2_YIELD(return NULL);
184 }
185 _SEH2_END;
186 }
187
188 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
189 }
190
191
192 static
193 NTSTATUS
194 TestIrpHandler(
195 _In_ PDEVICE_OBJECT DeviceObject,
196 _In_ PIRP Irp,
197 _In_ PIO_STACK_LOCATION IoStack)
198 {
199 NTSTATUS Status;
200 PTEST_FCB Fcb;
201 CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
202
203 PAGED_CODE();
204
205 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction);
206 ASSERT(IoStack->MajorFunction == IRP_MJ_CLEANUP ||
207 IoStack->MajorFunction == IRP_MJ_CREATE ||
208 IoStack->MajorFunction == IRP_MJ_READ ||
209 IoStack->MajorFunction == IRP_MJ_WRITE ||
210 IoStack->MajorFunction == IRP_MJ_QUERY_INFORMATION ||
211 IoStack->MajorFunction == IRP_MJ_SET_INFORMATION);
212
213 Status = STATUS_NOT_SUPPORTED;
214 Irp->IoStatus.Information = 0;
215
216 if (IoStack->MajorFunction == IRP_MJ_CREATE)
217 {
218 ULONG RequestedDisposition = ((IoStack->Parameters.Create.Options >> 24) & 0xff);
219 ok(RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OPEN, "Invalid disposition: %lu\n", RequestedDisposition);
220
221 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR))
222 {
223 TestDeviceObject = DeviceObject;
224 TestFileObject = IoStack->FileObject;
225 }
226 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI');
227 RtlZeroMemory(Fcb, sizeof(*Fcb));
228 ExInitializeFastMutex(&Fcb->HeaderMutex);
229 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
230
231 /* Consider file/dir doesn't exist */
232 if (RequestedDisposition == FILE_CREATE)
233 {
234 Fcb->Header.AllocationSize.QuadPart = 0;
235 Fcb->Header.FileSize.QuadPart = 0;
236 Fcb->Header.ValidDataLength.QuadPart = 0;
237 }
238 else
239 {
240 Fcb->Header.AllocationSize.QuadPart = 512;
241 Fcb->Header.FileSize.QuadPart = 512;
242 Fcb->Header.ValidDataLength.QuadPart = 512;
243 }
244 Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
245
246 DPRINT1("File: %wZ\n", &IoStack->FileObject->FileName);
247
248 IoStack->FileObject->FsContext = Fcb;
249 if (RtlCompareUnicodeString(&IoStack->FileObject->FileName, &InvalidInit, FALSE) != 0)
250 {
251 IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
252 }
253
254 if (IoStack->FileObject->FileName.Length == 0 ||
255 RtlCompareUnicodeString(&IoStack->FileObject->FileName, &InitOnCreate, FALSE) == 0)
256 {
257 DPRINT1("Init\n");
258
259 CcInitializeCacheMap(IoStack->FileObject,
260 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
261 FALSE, &Callbacks, NULL);
262 }
263
264 Irp->IoStatus.Information = (RequestedDisposition == FILE_CREATE) ? FILE_CREATED : FILE_OPENED;
265 Status = STATUS_SUCCESS;
266 }
267 else if (IoStack->MajorFunction == IRP_MJ_READ)
268 {
269 BOOLEAN Ret;
270 ULONG Length;
271 PVOID Buffer;
272 LARGE_INTEGER Offset;
273
274 Offset = IoStack->Parameters.Read.ByteOffset;
275 Length = IoStack->Parameters.Read.Length;
276 Fcb = IoStack->FileObject->FsContext;
277
278 ok_eq_pointer(DeviceObject, TestDeviceObject);
279 ok_eq_pointer(IoStack->FileObject, TestFileObject);
280
281 if (Offset.QuadPart + Length > Fcb->Header.FileSize.QuadPart)
282 {
283 Status = STATUS_END_OF_FILE;
284 }
285 else if (Length == 0)
286 {
287 Status = STATUS_SUCCESS;
288 }
289 else
290 {
291 if (!FlagOn(Irp->Flags, IRP_NOCACHE))
292 {
293 Buffer = Irp->AssociatedIrp.SystemBuffer;
294 ok(Buffer != NULL, "Null pointer!\n");
295
296 _SEH2_TRY
297 {
298 if (IoStack->FileObject->PrivateCacheMap == NULL)
299 {
300 DPRINT1("Init\n");
301 ok_eq_ulong(RtlCompareUnicodeString(&IoStack->FileObject->FileName, &InitOnRW, FALSE), 0);
302 CcInitializeCacheMap(IoStack->FileObject,
303 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
304 FALSE, &Callbacks, Fcb);
305 }
306
307 Ret = CcCopyRead(IoStack->FileObject, &Offset, Length, TRUE, Buffer,
308 &Irp->IoStatus);
309 ok_bool_true(Ret, "CcCopyRead");
310 }
311 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
312 {
313 Irp->IoStatus.Status = _SEH2_GetExceptionCode();
314 }
315 _SEH2_END;
316
317 Status = Irp->IoStatus.Status;
318 }
319 else
320 {
321 ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n");
322 Buffer = MapAndLockUserBuffer(Irp, Length);
323 ok(Buffer != NULL, "Null pointer!\n");
324 RtlFillMemory(Buffer, Length, 0xBA);
325
326 Status = STATUS_SUCCESS;
327 }
328 }
329
330 if (NT_SUCCESS(Status))
331 {
332 Irp->IoStatus.Information = Length;
333 IoStack->FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
334 }
335 }
336 else if (IoStack->MajorFunction == IRP_MJ_WRITE)
337 {
338 BOOLEAN Ret;
339 ULONG Length;
340 PVOID Buffer;
341 LARGE_INTEGER Offset;
342
343 Offset = IoStack->Parameters.Write.ByteOffset;
344 Length = IoStack->Parameters.Write.Length;
345 Fcb = IoStack->FileObject->FsContext;
346
347 ok_eq_pointer(DeviceObject, TestDeviceObject);
348 ok_eq_pointer(IoStack->FileObject, TestFileObject);
349
350 if (Length == 0)
351 {
352 Status = STATUS_SUCCESS;
353 }
354 else
355 {
356 if (!FlagOn(Irp->Flags, IRP_NOCACHE))
357 {
358 Buffer = Irp->AssociatedIrp.SystemBuffer;
359 ok(Buffer != NULL, "Null pointer!\n");
360
361 _SEH2_TRY
362 {
363 if (IoStack->FileObject->PrivateCacheMap == NULL)
364 {
365 ok_eq_ulong(RtlCompareUnicodeString(&IoStack->FileObject->FileName, &InitOnRW, FALSE), 0);
366 CcInitializeCacheMap(IoStack->FileObject,
367 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
368 FALSE, &Callbacks, Fcb);
369 }
370
371 Ret = CcCopyWrite(IoStack->FileObject, &Offset, Length, TRUE, Buffer);
372 ok_bool_true(Ret, "CcCopyWrite");
373 }
374 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
375 {
376 Irp->IoStatus.Status = _SEH2_GetExceptionCode();
377 }
378 _SEH2_END;
379
380 Status = Irp->IoStatus.Status;
381 }
382 else
383 {
384 Status = STATUS_SUCCESS;
385 }
386
387 if (NT_SUCCESS(Status))
388 {
389 if (Length + Offset.QuadPart > Fcb->Header.FileSize.QuadPart)
390 {
391 Fcb->Header.AllocationSize.QuadPart = Length + Offset.QuadPart;
392 Fcb->Header.FileSize.QuadPart = Length + Offset.QuadPart;
393 Fcb->Header.ValidDataLength.QuadPart = Length + Offset.QuadPart;
394
395 if (CcIsFileCached(IoStack->FileObject))
396 {
397 CcSetFileSizes(IoStack->FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
398 }
399 }
400 }
401 }
402 }
403 else if (IoStack->MajorFunction == IRP_MJ_CLEANUP)
404 {
405 Fcb = IoStack->FileObject->FsContext;
406 ok(Fcb != NULL, "Null pointer!\n");
407 if (IoStack->FileObject->PrivateCacheMap != NULL)
408 {
409 CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);
410 CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE);
411 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
412 CcUninitializeCacheMap(IoStack->FileObject, NULL, &CacheUninitEvent);
413 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
414 }
415 ExFreePoolWithTag(Fcb, 'FwrI');
416 IoStack->FileObject->FsContext = NULL;
417 Status = STATUS_SUCCESS;
418 }
419 else if (IoStack->MajorFunction == IRP_MJ_QUERY_INFORMATION)
420 {
421 Fcb = IoStack->FileObject->FsContext;
422
423 ok_eq_pointer(DeviceObject, TestDeviceObject);
424 ok_eq_pointer(IoStack->FileObject, TestFileObject);
425 ok_eq_ulong(IoStack->Parameters.QueryFile.FileInformationClass, FileStandardInformation);
426
427 if (IoStack->Parameters.QueryFile.FileInformationClass == FileStandardInformation)
428 {
429 PFILE_STANDARD_INFORMATION StandardInfo = Irp->AssociatedIrp.SystemBuffer;
430 ULONG BufferLength = IoStack->Parameters.QueryFile.Length;
431
432 if (BufferLength < sizeof(FILE_STANDARD_INFORMATION))
433 {
434 Status = STATUS_BUFFER_OVERFLOW;
435 }
436 else
437 {
438 ok(StandardInfo != NULL, "Null pointer!\n");
439 ok(Fcb != NULL, "Null pointer!\n");
440
441 StandardInfo->AllocationSize = Fcb->Header.AllocationSize;
442 StandardInfo->EndOfFile = Fcb->Header.FileSize;
443 StandardInfo->Directory = FALSE;
444 StandardInfo->NumberOfLinks = 1;
445 StandardInfo->DeletePending = FALSE;
446
447 Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
448 Status = STATUS_SUCCESS;
449 }
450 }
451 else
452 {
453 Status = STATUS_NOT_IMPLEMENTED;
454 }
455 }
456 else if (IoStack->MajorFunction == IRP_MJ_SET_INFORMATION)
457 {
458 Fcb = IoStack->FileObject->FsContext;
459
460 ok_eq_pointer(DeviceObject, TestDeviceObject);
461 ok_eq_pointer(IoStack->FileObject, TestFileObject);
462 ok_eq_ulong(IoStack->Parameters.SetFile.FileInformationClass, FileEndOfFileInformation);
463
464 if (IoStack->Parameters.SetFile.FileInformationClass == FileEndOfFileInformation)
465 {
466 PFILE_END_OF_FILE_INFORMATION EOFInfo = Irp->AssociatedIrp.SystemBuffer;
467 ULONG BufferLength = IoStack->Parameters.SetFile.Length;
468
469 if (BufferLength < sizeof(FILE_END_OF_FILE_INFORMATION))
470 {
471 Status = STATUS_BUFFER_OVERFLOW;
472 }
473 else
474 {
475 ok(EOFInfo != NULL, "Null pointer!\n");
476 ok(Fcb != NULL, "Null pointer!\n");
477 ok_bool_false(IoStack->Parameters.SetFile.AdvanceOnly, "AdvanceOnly set!\n");
478 ok(EOFInfo->EndOfFile.QuadPart > Fcb->Header.AllocationSize.QuadPart, "New size smaller\n");
479
480 if (CcIsFileCached(IoStack->FileObject))
481 {
482 CcSetFileSizes(IoStack->FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
483 }
484
485 Status = STATUS_SUCCESS;
486 }
487 }
488 else
489 {
490 Status = STATUS_NOT_IMPLEMENTED;
491 }
492 }
493
494 if (Status == STATUS_PENDING)
495 {
496 IoMarkIrpPending(Irp);
497 IoCompleteRequest(Irp, IO_NO_INCREMENT);
498 Status = STATUS_PENDING;
499 }
500 else
501 {
502 Irp->IoStatus.Status = Status;
503 IoCompleteRequest(Irp, IO_NO_INCREMENT);
504 }
505
506 return Status;
507 }