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                 PMDL Mdl;
385 
386                 Mdl = Irp->MdlAddress;
387                 ok(Mdl != NULL, "Null pointer for MDL!\n");
388                 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n");
389                 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n");
390                 ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) == 0, "Paging IO for reading\n");
391                 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n");
392 
393                 Status = STATUS_SUCCESS;
394             }
395 
396             if (NT_SUCCESS(Status))
397             {
398                 if (Length + Offset.QuadPart > Fcb->Header.FileSize.QuadPart)
399                 {
400                     Fcb->Header.AllocationSize.QuadPart = Length + Offset.QuadPart;
401                     Fcb->Header.FileSize.QuadPart = Length + Offset.QuadPart;
402                     Fcb->Header.ValidDataLength.QuadPart = Length + Offset.QuadPart;
403 
404                     if (CcIsFileCached(IoStack->FileObject))
405                     {
406                         CcSetFileSizes(IoStack->FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
407                     }
408                 }
409             }
410         }
411     }
412     else if (IoStack->MajorFunction == IRP_MJ_CLEANUP)
413     {
414         Fcb = IoStack->FileObject->FsContext;
415         ok(Fcb != NULL, "Null pointer!\n");
416         if (IoStack->FileObject->SectionObjectPointer != NULL)
417         {
418             LARGE_INTEGER Zero = RTL_CONSTANT_LARGE_INTEGER(0LL);
419 
420             if (CcIsFileCached(IoStack->FileObject))
421             {
422                 CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);
423                 CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE);
424             }
425 
426             KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
427             CcUninitializeCacheMap(IoStack->FileObject, &Zero, &CacheUninitEvent);
428             KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
429         }
430         ExFreePoolWithTag(Fcb, 'FwrI');
431         IoStack->FileObject->FsContext = NULL;
432         Status = STATUS_SUCCESS;
433     }
434     else if (IoStack->MajorFunction == IRP_MJ_QUERY_INFORMATION)
435     {
436         Fcb = IoStack->FileObject->FsContext;
437 
438         ok_eq_pointer(DeviceObject, TestDeviceObject);
439         ok_eq_pointer(IoStack->FileObject, TestFileObject);
440         ok_eq_ulong(IoStack->Parameters.QueryFile.FileInformationClass, FileStandardInformation);
441 
442         if (IoStack->Parameters.QueryFile.FileInformationClass == FileStandardInformation)
443         {
444             PFILE_STANDARD_INFORMATION StandardInfo = Irp->AssociatedIrp.SystemBuffer;
445             ULONG BufferLength = IoStack->Parameters.QueryFile.Length;
446 
447             if (BufferLength < sizeof(FILE_STANDARD_INFORMATION))
448             {
449                 Status = STATUS_BUFFER_OVERFLOW;
450             }
451             else
452             {
453                 ok(StandardInfo != NULL, "Null pointer!\n");
454                 ok(Fcb != NULL, "Null pointer!\n");
455 
456                 StandardInfo->AllocationSize = Fcb->Header.AllocationSize;
457                 StandardInfo->EndOfFile = Fcb->Header.FileSize;
458                 StandardInfo->Directory = FALSE;
459                 StandardInfo->NumberOfLinks = 1;
460                 StandardInfo->DeletePending = FALSE;
461 
462                 Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
463                 Status = STATUS_SUCCESS;
464             }
465         }
466         else
467         {
468             Status = STATUS_NOT_IMPLEMENTED;
469         }
470     }
471     else if (IoStack->MajorFunction == IRP_MJ_SET_INFORMATION)
472     {
473         Fcb = IoStack->FileObject->FsContext;
474 
475         ok_eq_pointer(DeviceObject, TestDeviceObject);
476         ok_eq_pointer(IoStack->FileObject, TestFileObject);
477         ok_eq_ulong(IoStack->Parameters.SetFile.FileInformationClass, FileEndOfFileInformation);
478 
479         if (IoStack->Parameters.SetFile.FileInformationClass == FileEndOfFileInformation)
480         {
481             PFILE_END_OF_FILE_INFORMATION EOFInfo = Irp->AssociatedIrp.SystemBuffer;
482             ULONG BufferLength = IoStack->Parameters.SetFile.Length;
483 
484             if (BufferLength < sizeof(FILE_END_OF_FILE_INFORMATION))
485             {
486                 Status = STATUS_BUFFER_OVERFLOW;
487             }
488             else
489             {
490                 ULONG TestSize = 0;
491 
492                 ok(EOFInfo != NULL, "Null pointer!\n");
493                 ok(Fcb != NULL, "Null pointer!\n");
494                 ok_bool_false(IoStack->Parameters.SetFile.AdvanceOnly, "AdvanceOnly set!\n");
495                 ok(EOFInfo->EndOfFile.QuadPart > Fcb->Header.AllocationSize.QuadPart, "New size smaller\n");
496 
497                 if (Fcb->Header.AllocationSize.QuadPart != 0)
498                 {
499                     TestSize = 512;
500                 }
501 
502                 Fcb->Header.AllocationSize.QuadPart = EOFInfo->EndOfFile.QuadPart;
503                 ok_eq_ulong(Fcb->Header.FileSize.QuadPart, TestSize);
504                 ok_eq_ulong(Fcb->Header.ValidDataLength.QuadPart, TestSize);
505 
506                 if (CcIsFileCached(IoStack->FileObject))
507                 {
508                     CcSetFileSizes(IoStack->FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
509                 }
510 
511                 ok_eq_ulong(Fcb->Header.FileSize.QuadPart, TestSize);
512                 ok_eq_ulong(Fcb->Header.ValidDataLength.QuadPart, TestSize);
513 
514                 Status = STATUS_SUCCESS;
515             }
516         }
517         else
518         {
519             Status = STATUS_NOT_IMPLEMENTED;
520         }
521     }
522 
523     if (Status == STATUS_PENDING)
524     {
525         IoMarkIrpPending(Irp);
526         IoCompleteRequest(Irp, IO_NO_INCREMENT);
527         Status = STATUS_PENDING;
528     }
529     else
530     {
531         Irp->IoStatus.Status = Status;
532         IoCompleteRequest(Irp, IO_NO_INCREMENT);
533     }
534 
535     return Status;
536 }
537