[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)
[reactos.git] / modules / rostests / kmtests / ntos_cc / CcSetFileSizes_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 CcSetFileSizes 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 #define IOCTL_START_TEST 1
14 #define IOCTL_FINISH_TEST 2
15
16 typedef struct _TEST_FCB
17 {
18 FSRTL_ADVANCED_FCB_HEADER Header;
19 SECTION_OBJECT_POINTERS SectionObjectPointers;
20 FAST_MUTEX HeaderMutex;
21 } TEST_FCB, *PTEST_FCB;
22
23 static ULONG TestTestId = -1;
24 static PFILE_OBJECT TestFileObject;
25 static PDEVICE_OBJECT TestDeviceObject;
26 static KMT_IRP_HANDLER TestIrpHandler;
27 static KMT_MESSAGE_HANDLER TestMessageHandler;
28 static BOOLEAN TestUnpin = FALSE;
29 static BOOLEAN TestSizing = FALSE;
30 static BOOLEAN TestDirtying = FALSE;
31 static BOOLEAN TestUncaching = FALSE;
32 static BOOLEAN TestWritten = FALSE;
33
34 NTSTATUS
35 TestEntry(
36 _In_ PDRIVER_OBJECT DriverObject,
37 _In_ PCUNICODE_STRING RegistryPath,
38 _Out_ PCWSTR *DeviceName,
39 _Inout_ INT *Flags)
40 {
41 NTSTATUS Status = STATUS_SUCCESS;
42
43 PAGED_CODE();
44
45 UNREFERENCED_PARAMETER(RegistryPath);
46
47 *DeviceName = L"CcSetFileSizes";
48 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE |
49 TESTENTRY_BUFFERED_IO_DEVICE |
50 TESTENTRY_NO_READONLY_DEVICE;
51
52 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler);
53 KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler);
54 KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
55
56 return Status;
57 }
58
59 VOID
60 TestUnload(
61 _In_ PDRIVER_OBJECT DriverObject)
62 {
63 PAGED_CODE();
64 }
65
66 BOOLEAN
67 NTAPI
68 AcquireForLazyWrite(
69 _In_ PVOID Context,
70 _In_ BOOLEAN Wait)
71 {
72 return TRUE;
73 }
74
75 VOID
76 NTAPI
77 ReleaseFromLazyWrite(
78 _In_ PVOID Context)
79 {
80 return;
81 }
82
83 BOOLEAN
84 NTAPI
85 AcquireForReadAhead(
86 _In_ PVOID Context,
87 _In_ BOOLEAN Wait)
88 {
89 return TRUE;
90 }
91
92 VOID
93 NTAPI
94 ReleaseFromReadAhead(
95 _In_ PVOID Context)
96 {
97 return;
98 }
99
100 static CACHE_MANAGER_CALLBACKS Callbacks = {
101 AcquireForLazyWrite,
102 ReleaseFromLazyWrite,
103 AcquireForReadAhead,
104 ReleaseFromReadAhead,
105 };
106
107 static CC_FILE_SIZES NewFileSizes = {
108 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)VACB_MAPPING_GRANULARITY), // .AllocationSize
109 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)VACB_MAPPING_GRANULARITY), // .FileSize
110 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)VACB_MAPPING_GRANULARITY) // .ValidDataLength
111 };
112
113 static
114 PVOID
115 MapAndLockUserBuffer(
116 _In_ _Out_ PIRP Irp,
117 _In_ ULONG BufferLength)
118 {
119 PMDL Mdl;
120
121 if (Irp->MdlAddress == NULL)
122 {
123 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
124 if (Mdl == NULL)
125 {
126 return NULL;
127 }
128
129 _SEH2_TRY
130 {
131 MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoWriteAccess);
132 }
133 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
134 {
135 IoFreeMdl(Mdl);
136 Irp->MdlAddress = NULL;
137 _SEH2_YIELD(return NULL);
138 }
139 _SEH2_END;
140 }
141
142 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
143 }
144
145 static
146 VOID
147 PerformTest(
148 ULONG TestId,
149 PDEVICE_OBJECT DeviceObject)
150 {
151 PVOID Bcb;
152 BOOLEAN Ret;
153 PULONG Buffer;
154 PTEST_FCB Fcb;
155 LARGE_INTEGER Offset;
156 IO_STATUS_BLOCK IoStatus;
157
158 ok_eq_pointer(TestFileObject, NULL);
159 ok_eq_pointer(TestDeviceObject, NULL);
160 ok_eq_ulong(TestTestId, -1);
161
162 TestWritten = FALSE;
163 TestDeviceObject = DeviceObject;
164 TestTestId = TestId;
165 TestFileObject = IoCreateStreamFileObject(NULL, DeviceObject);
166 if (!skip(TestFileObject != NULL, "Failed to allocate FO\n"))
167 {
168 Fcb = ExAllocatePool(NonPagedPool, sizeof(TEST_FCB));
169 if (!skip(Fcb != NULL, "ExAllocatePool failed\n"))
170 {
171 RtlZeroMemory(Fcb, sizeof(TEST_FCB));
172 ExInitializeFastMutex(&Fcb->HeaderMutex);
173 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
174
175 TestFileObject->FsContext = Fcb;
176 TestFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
177 Fcb->Header.AllocationSize.QuadPart = VACB_MAPPING_GRANULARITY;
178 Fcb->Header.FileSize.QuadPart = VACB_MAPPING_GRANULARITY - PAGE_SIZE;
179 Fcb->Header.ValidDataLength.QuadPart = VACB_MAPPING_GRANULARITY - PAGE_SIZE;
180
181 if ((TestId > 1 && TestId < 4) || TestId >= 5)
182 {
183 Fcb->Header.AllocationSize.QuadPart = VACB_MAPPING_GRANULARITY - PAGE_SIZE;
184 }
185
186 KmtStartSeh();
187 CcInitializeCacheMap(TestFileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, TRUE, &Callbacks, NULL);
188 KmtEndSeh(STATUS_SUCCESS);
189
190 if (!skip(CcIsFileCached(TestFileObject) == TRUE, "CcInitializeCacheMap failed\n"))
191 {
192 trace("Starting test: %d\n", TestId);
193
194 if (TestId == 0 || TestId == 2)
195 {
196 Offset.QuadPart = 0;
197 KmtStartSeh();
198 Ret = CcMapData(TestFileObject, &Offset, VACB_MAPPING_GRANULARITY - PAGE_SIZE, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
199 KmtEndSeh(STATUS_SUCCESS);
200
201 if (!skip(Ret == TRUE, "CcMapData failed\n"))
202 {
203 ok_eq_ulong(Buffer[(VACB_MAPPING_GRANULARITY - PAGE_SIZE - sizeof(ULONG)) / sizeof(ULONG)], 0xBABABABA);
204 CcUnpinData(Bcb);
205 }
206
207 KmtStartSeh();
208 CcSetFileSizes(TestFileObject, &NewFileSizes);
209 KmtEndSeh(STATUS_SUCCESS);
210
211 Fcb->Header.AllocationSize.QuadPart = VACB_MAPPING_GRANULARITY;
212 Fcb->Header.FileSize.QuadPart = VACB_MAPPING_GRANULARITY;
213
214 Offset.QuadPart = 0;
215 KmtStartSeh();
216 Ret = CcMapData(TestFileObject, &Offset, VACB_MAPPING_GRANULARITY, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
217 KmtEndSeh(STATUS_SUCCESS);
218
219 if (!skip(Ret == TRUE, "CcMapData failed\n"))
220 {
221 ok_eq_ulong(Buffer[(VACB_MAPPING_GRANULARITY - sizeof(ULONG)) / sizeof(ULONG)], 0xBABABABA);
222
223 CcUnpinData(Bcb);
224 }
225 }
226 else if (TestId == 1 || TestId == 3)
227 {
228 Buffer = ExAllocatePool(NonPagedPool, PAGE_SIZE);
229 if (!skip(Buffer != NULL, "ExAllocatePool failed\n"))
230 {
231 Ret = FALSE;
232 Offset.QuadPart = VACB_MAPPING_GRANULARITY - 2 * PAGE_SIZE;
233
234 KmtStartSeh();
235 Ret = CcCopyRead(TestFileObject, &Offset, PAGE_SIZE, TRUE, Buffer, &IoStatus);
236 KmtEndSeh(STATUS_SUCCESS);
237
238 ok_eq_ulong(Buffer[(PAGE_SIZE - sizeof(ULONG)) / sizeof(ULONG)], 0xBABABABA);
239
240 KmtStartSeh();
241 CcSetFileSizes(TestFileObject, &NewFileSizes);
242 KmtEndSeh(STATUS_SUCCESS);
243
244 Fcb->Header.AllocationSize.QuadPart = VACB_MAPPING_GRANULARITY;
245 Fcb->Header.FileSize.QuadPart = VACB_MAPPING_GRANULARITY;
246 RtlZeroMemory(Buffer, PAGE_SIZE);
247
248 Offset.QuadPart = VACB_MAPPING_GRANULARITY - PAGE_SIZE;
249
250 KmtStartSeh();
251 Ret = CcCopyRead(TestFileObject, &Offset, PAGE_SIZE, TRUE, Buffer, &IoStatus);
252 KmtEndSeh(STATUS_SUCCESS);
253
254 ok_eq_ulong(Buffer[(PAGE_SIZE - sizeof(ULONG)) / sizeof(ULONG)], 0xBABABABA);
255
256 ExFreePool(Buffer);
257 }
258 }
259 else if (TestId == 4 || TestId == 5)
260 {
261 /* Kill lazy writer */
262 CcSetAdditionalCacheAttributes(TestFileObject, FALSE, TRUE);
263
264 Offset.QuadPart = 0;
265 KmtStartSeh();
266 Ret = CcPinRead(TestFileObject, &Offset, VACB_MAPPING_GRANULARITY - PAGE_SIZE, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
267 KmtEndSeh(STATUS_SUCCESS);
268
269 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
270 {
271 LARGE_INTEGER Flushed;
272
273 ok_eq_ulong(Buffer[(VACB_MAPPING_GRANULARITY - PAGE_SIZE - sizeof(ULONG)) / sizeof(ULONG)], 0xBABABABA);
274 Buffer[(VACB_MAPPING_GRANULARITY - PAGE_SIZE - sizeof(ULONG)) / sizeof(ULONG)] = 0xDADADADA;
275
276 TestDirtying = TRUE;
277 CcSetDirtyPinnedData(Bcb, NULL);
278 TestDirtying = FALSE;
279
280 ok_bool_false(TestWritten, "Dirty VACB has been unexpectedly written!\n");
281
282 TestSizing = TRUE;
283 KmtStartSeh();
284 CcSetFileSizes(TestFileObject, &NewFileSizes);
285 KmtEndSeh(STATUS_SUCCESS);
286 TestSizing = FALSE;
287
288 ok_bool_false(TestWritten, "Dirty VACB has been unexpectedly written!\n");
289
290 Fcb->Header.AllocationSize.QuadPart = VACB_MAPPING_GRANULARITY;
291 Fcb->Header.FileSize.QuadPart = VACB_MAPPING_GRANULARITY;
292
293 Flushed = CcGetFlushedValidData(TestFileObject->SectionObjectPointer, FALSE);
294 ok(Flushed.QuadPart == 0, "Flushed: %I64d\n", Flushed.QuadPart);
295
296 TestUnpin = TRUE;
297 CcUnpinData(Bcb);
298 TestUnpin = FALSE;
299
300 ok_bool_false(TestWritten, "Dirty VACB has been unexpectedly written!\n");
301
302 Offset.QuadPart = 0;
303 KmtStartSeh();
304 Ret = CcMapData(TestFileObject, &Offset, VACB_MAPPING_GRANULARITY, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
305 KmtEndSeh(STATUS_SUCCESS);
306
307 if (!skip(Ret == TRUE, "CcMapData failed\n"))
308 {
309 ok_eq_ulong(Buffer[(VACB_MAPPING_GRANULARITY - PAGE_SIZE - sizeof(ULONG)) / sizeof(ULONG)], 0xDADADADA);
310 ok_eq_ulong(Buffer[(VACB_MAPPING_GRANULARITY - sizeof(ULONG)) / sizeof(ULONG)], 0xBABABABA);
311
312 CcUnpinData(Bcb);
313
314 ok_bool_false(TestWritten, "Dirty VACB has been unexpectedly written!\n");
315 }
316 }
317 }
318 else if (TestId == 6)
319 {
320 Offset.QuadPart = 0;
321 KmtStartSeh();
322 Ret = CcMapData(TestFileObject, &Offset, VACB_MAPPING_GRANULARITY - PAGE_SIZE, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
323 KmtEndSeh(STATUS_SUCCESS);
324
325 if (!skip(Ret == TRUE, "CcMapData failed\n"))
326 {
327 ok_eq_ulong(Buffer[(VACB_MAPPING_GRANULARITY - PAGE_SIZE - sizeof(ULONG)) / sizeof(ULONG)], 0xBABABABA);
328 }
329
330 KmtStartSeh();
331 CcSetFileSizes(TestFileObject, &NewFileSizes);
332 KmtEndSeh(STATUS_SUCCESS);
333
334 if (Ret == TRUE)
335 CcUnpinData(Bcb);
336 }
337 }
338 }
339 }
340 }
341
342
343 static
344 VOID
345 CleanupTest(
346 ULONG TestId,
347 PDEVICE_OBJECT DeviceObject)
348 {
349 LARGE_INTEGER Zero = RTL_CONSTANT_LARGE_INTEGER(0LL);
350 CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
351
352 ok_eq_pointer(TestDeviceObject, DeviceObject);
353 ok_eq_ulong(TestTestId, TestId);
354
355 if (!skip(TestFileObject != NULL, "No test FO\n"))
356 {
357 if (CcIsFileCached(TestFileObject))
358 {
359 TestUncaching = TRUE;
360 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
361 CcUninitializeCacheMap(TestFileObject, &Zero, &CacheUninitEvent);
362 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
363 TestUncaching = FALSE;
364 }
365
366 if (TestFileObject->FsContext != NULL)
367 {
368 ExFreePool(TestFileObject->FsContext);
369 TestFileObject->FsContext = NULL;
370 TestFileObject->SectionObjectPointer = NULL;
371 }
372
373 ObDereferenceObject(TestFileObject);
374 }
375
376 TestFileObject = NULL;
377 TestDeviceObject = NULL;
378 TestTestId = -1;
379 }
380
381
382 static
383 NTSTATUS
384 TestMessageHandler(
385 _In_ PDEVICE_OBJECT DeviceObject,
386 _In_ ULONG ControlCode,
387 _In_opt_ PVOID Buffer,
388 _In_ SIZE_T InLength,
389 _Inout_ PSIZE_T OutLength)
390 {
391 NTSTATUS Status = STATUS_SUCCESS;
392
393 FsRtlEnterFileSystem();
394
395 switch (ControlCode)
396 {
397 case IOCTL_START_TEST:
398 ok_eq_ulong((ULONG)InLength, sizeof(ULONG));
399 PerformTest(*(PULONG)Buffer, DeviceObject);
400 break;
401
402 case IOCTL_FINISH_TEST:
403 ok_eq_ulong((ULONG)InLength, sizeof(ULONG));
404 CleanupTest(*(PULONG)Buffer, DeviceObject);
405 break;
406
407 default:
408 Status = STATUS_NOT_IMPLEMENTED;
409 break;
410 }
411
412 FsRtlExitFileSystem();
413
414 return Status;
415 }
416
417 static
418 NTSTATUS
419 TestIrpHandler(
420 _In_ PDEVICE_OBJECT DeviceObject,
421 _In_ PIRP Irp,
422 _In_ PIO_STACK_LOCATION IoStack)
423 {
424 NTSTATUS Status;
425
426 PAGED_CODE();
427
428 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction);
429 ASSERT(IoStack->MajorFunction == IRP_MJ_READ ||
430 IoStack->MajorFunction == IRP_MJ_WRITE);
431
432 FsRtlEnterFileSystem();
433
434 Status = STATUS_NOT_SUPPORTED;
435 Irp->IoStatus.Information = 0;
436
437 if (IoStack->MajorFunction == IRP_MJ_READ)
438 {
439 PMDL Mdl;
440 ULONG Length;
441 PTEST_FCB Fcb;
442 LARGE_INTEGER Offset;
443 PVOID Buffer, OrigBuffer;
444
445 Offset = IoStack->Parameters.Read.ByteOffset;
446 Length = IoStack->Parameters.Read.Length;
447 Fcb = IoStack->FileObject->FsContext;
448
449 ok_eq_pointer(DeviceObject, TestDeviceObject);
450 ok_eq_pointer(IoStack->FileObject, TestFileObject);
451 ok(Fcb != NULL, "Null FCB\n");
452
453 ok(FlagOn(Irp->Flags, IRP_NOCACHE), "Not coming from Cc\n");
454
455 ok_irql(APC_LEVEL);
456 ok((Offset.QuadPart % PAGE_SIZE == 0 || Offset.QuadPart == 0), "Offset is not aligned: %I64i\n", Offset.QuadPart);
457 ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length);
458
459 ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n");
460 OrigBuffer = Buffer = MapAndLockUserBuffer(Irp, Length);
461 ok(Buffer != NULL, "Null pointer!\n");
462 if (Buffer == NULL)
463 {
464 Status = STATUS_UNSUCCESSFUL;
465 goto Exit;
466 }
467
468 if (Offset.QuadPart < Fcb->Header.FileSize.QuadPart)
469 {
470 RtlFillMemory(Buffer, min(Length, Fcb->Header.FileSize.QuadPart - Offset.QuadPart), 0xBA);
471 Buffer = (PVOID)((ULONG_PTR)Buffer + (ULONG_PTR)min(Length, Fcb->Header.FileSize.QuadPart - Offset.QuadPart));
472
473 if (Length > (Fcb->Header.FileSize.QuadPart - Offset.QuadPart))
474 {
475 RtlFillMemory(Buffer, Length - (Fcb->Header.FileSize.QuadPart - Offset.QuadPart), 0xBD);
476 }
477 }
478 else
479 {
480 RtlFillMemory(Buffer, Length, 0xBD);
481 }
482
483 if ((TestTestId == 4 || TestTestId == 5) && TestWritten &&
484 Offset.QuadPart <= VACB_MAPPING_GRANULARITY - PAGE_SIZE - sizeof(ULONG) &&
485 Offset.QuadPart + Length >= VACB_MAPPING_GRANULARITY - PAGE_SIZE)
486 {
487 Buffer = (PVOID)((ULONG_PTR)OrigBuffer + (VACB_MAPPING_GRANULARITY - PAGE_SIZE - sizeof(ULONG)));
488 RtlFillMemory(Buffer, sizeof(ULONG), 0xDA);
489 }
490
491 Status = STATUS_SUCCESS;
492
493 Mdl = Irp->MdlAddress;
494 ok(Mdl != NULL, "Null pointer for MDL!\n");
495 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n");
496 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n");
497 ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0, "Non paging IO\n");
498 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n");
499
500 Irp->IoStatus.Information = Length;
501 }
502 else if (IoStack->MajorFunction == IRP_MJ_WRITE)
503 {
504 PMDL Mdl;
505 ULONG Length;
506 PVOID Buffer;
507 LARGE_INTEGER Offset;
508
509 Offset = IoStack->Parameters.Write.ByteOffset;
510 Length = IoStack->Parameters.Write.Length;
511
512 ok((TestTestId == 4 || TestTestId == 5), "Unexpected test id: %d\n", TestTestId);
513 ok_eq_pointer(DeviceObject, TestDeviceObject);
514 ok_eq_pointer(IoStack->FileObject, TestFileObject);
515
516 ok_bool_false(TestUnpin, "Write triggered while unpinning!\n");
517 ok_bool_false(TestSizing, "Write triggered while sizing!\n");
518 ok_bool_false(TestDirtying, "Write triggered while dirtying!\n");
519 ok_bool_true(TestUncaching, "Write not triggered while uncaching!\n");
520
521 ok(FlagOn(Irp->Flags, IRP_NOCACHE), "Not coming from Cc\n");
522
523 ok_irql(PASSIVE_LEVEL);
524 ok((Offset.QuadPart % PAGE_SIZE == 0 || Offset.QuadPart == 0), "Offset is not aligned: %I64i\n", Offset.QuadPart);
525 ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length);
526
527 Buffer = MapAndLockUserBuffer(Irp, Length);
528 ok(Buffer != NULL, "Null pointer!\n");
529
530 Mdl = Irp->MdlAddress;
531 ok(Mdl != NULL, "Null pointer for MDL!\n");
532 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n");
533 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n");
534 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n");
535
536 TestWritten = TRUE;
537 Status = STATUS_SUCCESS;
538 Irp->IoStatus.Information = Length;
539 }
540
541 if (Status == STATUS_PENDING)
542 {
543 IoMarkIrpPending(Irp);
544 IoCompleteRequest(Irp, IO_NO_INCREMENT);
545 Status = STATUS_PENDING;
546 }
547 else
548 {
549 Irp->IoStatus.Status = Status;
550 IoCompleteRequest(Irp, IO_NO_INCREMENT);
551 }
552
553 Exit:
554 FsRtlExitFileSystem();
555
556 return Status;
557 }