ca39f7cc180aab1066c02b73db0e4069ee40fac1
[reactos.git] / ntoskrnl / cc / copy.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cc/copy.c
5 * PURPOSE: Implements cache managers copy interface
6 *
7 * PROGRAMMERS: Some people?
8 * Pierre Schweitzer (pierre@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 static PFN_NUMBER CcZeroPage = 0;
20
21 #define MAX_ZERO_LENGTH (256 * 1024)
22
23 typedef enum _CC_COPY_OPERATION
24 {
25 CcOperationRead,
26 CcOperationWrite,
27 CcOperationZero
28 } CC_COPY_OPERATION;
29
30 ULONG CcRosTraceLevel = 0;
31 ULONG CcFastMdlReadWait;
32 ULONG CcFastMdlReadNotPossible;
33 ULONG CcFastReadNotPossible;
34 ULONG CcFastReadWait;
35 ULONG CcFastReadNoWait;
36 ULONG CcFastReadResourceMiss;
37
38 /* FUNCTIONS *****************************************************************/
39
40 VOID
41 NTAPI
42 MiZeroPhysicalPage (
43 IN PFN_NUMBER PageFrameIndex
44 );
45
46 VOID
47 NTAPI
48 CcInitCacheZeroPage (
49 VOID)
50 {
51 NTSTATUS Status;
52
53 MI_SET_USAGE(MI_USAGE_CACHE);
54 //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
55 Status = MmRequestPageMemoryConsumer(MC_SYSTEM, TRUE, &CcZeroPage);
56 if (!NT_SUCCESS(Status))
57 {
58 DbgPrint("Can't allocate CcZeroPage.\n");
59 KeBugCheck(CACHE_MANAGER);
60 }
61 MiZeroPhysicalPage(CcZeroPage);
62 }
63
64 NTSTATUS
65 NTAPI
66 CcReadVirtualAddress (
67 PROS_VACB Vacb)
68 {
69 ULONG Size, Pages;
70 PMDL Mdl;
71 NTSTATUS Status;
72 IO_STATUS_BLOCK IoStatus;
73 KEVENT Event;
74
75 Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
76 if (Size > VACB_MAPPING_GRANULARITY)
77 {
78 Size = VACB_MAPPING_GRANULARITY;
79 }
80
81 Pages = BYTES_TO_PAGES(Size);
82 ASSERT(Pages * PAGE_SIZE <= VACB_MAPPING_GRANULARITY);
83
84 Mdl = IoAllocateMdl(Vacb->BaseAddress, Pages * PAGE_SIZE, FALSE, FALSE, NULL);
85 if (!Mdl)
86 {
87 return STATUS_INSUFFICIENT_RESOURCES;
88 }
89
90 Status = STATUS_SUCCESS;
91 _SEH2_TRY
92 {
93 MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess);
94 }
95 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
96 {
97 Status = _SEH2_GetExceptionCode();
98 KeBugCheck(CACHE_MANAGER);
99 } _SEH2_END;
100
101 if (NT_SUCCESS(Status))
102 {
103 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
104 KeInitializeEvent(&Event, NotificationEvent, FALSE);
105 Status = IoPageRead(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
106 if (Status == STATUS_PENDING)
107 {
108 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
109 Status = IoStatus.Status;
110 }
111
112 MmUnlockPages(Mdl);
113 }
114
115 IoFreeMdl(Mdl);
116
117 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
118 {
119 DPRINT1("IoPageRead failed, Status %x\n", Status);
120 return Status;
121 }
122
123 if (Size < VACB_MAPPING_GRANULARITY)
124 {
125 RtlZeroMemory((char*)Vacb->BaseAddress + Size,
126 VACB_MAPPING_GRANULARITY - Size);
127 }
128
129 return STATUS_SUCCESS;
130 }
131
132 NTSTATUS
133 NTAPI
134 CcWriteVirtualAddress (
135 PROS_VACB Vacb)
136 {
137 ULONG Size;
138 PMDL Mdl;
139 NTSTATUS Status;
140 IO_STATUS_BLOCK IoStatus;
141 KEVENT Event;
142
143 Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
144 if (Size > VACB_MAPPING_GRANULARITY)
145 {
146 Size = VACB_MAPPING_GRANULARITY;
147 }
148 //
149 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
150 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
151 //
152 {
153 ULONG i = 0;
154 do
155 {
156 MmGetPfnForProcess(NULL, (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i << PAGE_SHIFT)));
157 } while (++i < (Size >> PAGE_SHIFT));
158 }
159
160 Mdl = IoAllocateMdl(Vacb->BaseAddress, Size, FALSE, FALSE, NULL);
161 if (!Mdl)
162 {
163 return STATUS_INSUFFICIENT_RESOURCES;
164 }
165
166 Status = STATUS_SUCCESS;
167 _SEH2_TRY
168 {
169 MmProbeAndLockPages(Mdl, KernelMode, IoReadAccess);
170 }
171 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
172 {
173 Status = _SEH2_GetExceptionCode();
174 KeBugCheck(CACHE_MANAGER);
175 } _SEH2_END;
176
177 if (NT_SUCCESS(Status))
178 {
179 KeInitializeEvent(&Event, NotificationEvent, FALSE);
180 Status = IoSynchronousPageWrite(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
181 if (Status == STATUS_PENDING)
182 {
183 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
184 Status = IoStatus.Status;
185 }
186
187 MmUnlockPages(Mdl);
188 }
189 IoFreeMdl(Mdl);
190 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
191 {
192 DPRINT1("IoPageWrite failed, Status %x\n", Status);
193 return Status;
194 }
195
196 return STATUS_SUCCESS;
197 }
198
199 NTSTATUS
200 ReadWriteOrZero(
201 _Inout_ PVOID BaseAddress,
202 _Inout_opt_ PVOID Buffer,
203 _In_ ULONG Length,
204 _In_ CC_COPY_OPERATION Operation)
205 {
206 NTSTATUS Status = STATUS_SUCCESS;
207
208 if (Operation == CcOperationZero)
209 {
210 /* Zero */
211 RtlZeroMemory(BaseAddress, Length);
212 }
213 else
214 {
215 _SEH2_TRY
216 {
217 if (Operation == CcOperationWrite)
218 RtlCopyMemory(BaseAddress, Buffer, Length);
219 else
220 RtlCopyMemory(Buffer, BaseAddress, Length);
221 }
222 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
223 {
224 Status = _SEH2_GetExceptionCode();
225 }
226 _SEH2_END;
227 }
228 return Status;
229 }
230
231 BOOLEAN
232 CcCopyData (
233 _In_ PFILE_OBJECT FileObject,
234 _In_ LONGLONG FileOffset,
235 _Inout_ PVOID Buffer,
236 _In_ LONGLONG Length,
237 _In_ CC_COPY_OPERATION Operation,
238 _In_ BOOLEAN Wait,
239 _Out_ PIO_STATUS_BLOCK IoStatus)
240 {
241 NTSTATUS Status;
242 LONGLONG CurrentOffset;
243 ULONG BytesCopied;
244 KIRQL OldIrql;
245 PROS_SHARED_CACHE_MAP SharedCacheMap;
246 PLIST_ENTRY ListEntry;
247 PROS_VACB Vacb;
248 ULONG PartialLength;
249 PVOID BaseAddress;
250 BOOLEAN Valid;
251
252 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
253 CurrentOffset = FileOffset;
254 BytesCopied = 0;
255
256 if (!Wait)
257 {
258 /* test if the requested data is available */
259 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
260 /* FIXME: this loop doesn't take into account areas that don't have
261 * a VACB in the list yet */
262 ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink;
263 while (ListEntry != &SharedCacheMap->CacheMapVacbListHead)
264 {
265 Vacb = CONTAINING_RECORD(ListEntry,
266 ROS_VACB,
267 CacheMapVacbListEntry);
268 ListEntry = ListEntry->Flink;
269 if (!Vacb->Valid &&
270 DoRangesIntersect(Vacb->FileOffset.QuadPart,
271 VACB_MAPPING_GRANULARITY,
272 CurrentOffset, Length))
273 {
274 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
275 /* data not available */
276 return FALSE;
277 }
278 if (Vacb->FileOffset.QuadPart >= CurrentOffset + Length)
279 break;
280 }
281 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
282 }
283
284 PartialLength = CurrentOffset % VACB_MAPPING_GRANULARITY;
285 if (PartialLength != 0)
286 {
287 PartialLength = min(Length, VACB_MAPPING_GRANULARITY - PartialLength);
288 Status = CcRosRequestVacb(SharedCacheMap,
289 ROUND_DOWN(CurrentOffset,
290 VACB_MAPPING_GRANULARITY),
291 &BaseAddress,
292 &Valid,
293 &Vacb);
294 if (!NT_SUCCESS(Status))
295 ExRaiseStatus(Status);
296 if (!Valid)
297 {
298 Status = CcReadVirtualAddress(Vacb);
299 if (!NT_SUCCESS(Status))
300 {
301 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
302 ExRaiseStatus(Status);
303 }
304 }
305 Status = ReadWriteOrZero((PUCHAR)BaseAddress + CurrentOffset % VACB_MAPPING_GRANULARITY,
306 Buffer,
307 PartialLength,
308 Operation);
309
310 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
311
312 if (!NT_SUCCESS(Status))
313 ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
314
315 Length -= PartialLength;
316 CurrentOffset += PartialLength;
317 BytesCopied += PartialLength;
318
319 if (Operation != CcOperationZero)
320 Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
321 }
322
323 while (Length > 0)
324 {
325 ASSERT(CurrentOffset % VACB_MAPPING_GRANULARITY == 0);
326 PartialLength = min(VACB_MAPPING_GRANULARITY, Length);
327 Status = CcRosRequestVacb(SharedCacheMap,
328 CurrentOffset,
329 &BaseAddress,
330 &Valid,
331 &Vacb);
332 if (!NT_SUCCESS(Status))
333 ExRaiseStatus(Status);
334 if (!Valid &&
335 (Operation == CcOperationRead ||
336 PartialLength < VACB_MAPPING_GRANULARITY))
337 {
338 Status = CcReadVirtualAddress(Vacb);
339 if (!NT_SUCCESS(Status))
340 {
341 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
342 ExRaiseStatus(Status);
343 }
344 }
345 Status = ReadWriteOrZero(BaseAddress, Buffer, PartialLength, Operation);
346
347 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
348
349 if (!NT_SUCCESS(Status))
350 ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
351
352 Length -= PartialLength;
353 CurrentOffset += PartialLength;
354 BytesCopied += PartialLength;
355
356 if (Operation != CcOperationZero)
357 Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
358 }
359 IoStatus->Status = STATUS_SUCCESS;
360 IoStatus->Information = BytesCopied;
361 return TRUE;
362 }
363
364 /*
365 * @unimplemented
366 */
367 BOOLEAN
368 NTAPI
369 CcCanIWrite (
370 IN PFILE_OBJECT FileObject,
371 IN ULONG BytesToWrite,
372 IN BOOLEAN Wait,
373 IN BOOLEAN Retrying)
374 {
375 PFSRTL_COMMON_FCB_HEADER Fcb;
376 PROS_SHARED_CACHE_MAP SharedCacheMap;
377
378 CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
379 FileObject, BytesToWrite, Wait, Retrying);
380
381 /* We cannot write if dirty pages count is above threshold */
382 if (CcTotalDirtyPages > CcDirtyPageThreshold)
383 {
384 return FALSE;
385 }
386
387 /* We cannot write if dirty pages count will bring use above
388 * XXX: Might not be accurate
389 */
390 if (CcTotalDirtyPages + (BytesToWrite / PAGE_SIZE) > CcDirtyPageThreshold)
391 {
392 return FALSE;
393 }
394
395 /* Is there a limit per file object? */
396 Fcb = FileObject->FsContext;
397 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
398 if (!BooleanFlagOn(Fcb->Flags, FSRTL_FLAG_LIMIT_MODIFIED_PAGES) ||
399 SharedCacheMap->DirtyPageThreshold == 0)
400 {
401 /* Nope, so that's fine, allow write operation */
402 return TRUE;
403 }
404
405 /* Is dirty page count above local threshold? */
406 if (SharedCacheMap->DirtyPages > SharedCacheMap->DirtyPageThreshold)
407 {
408 return FALSE;
409 }
410
411 /* We cannot write if dirty pages count will bring use above
412 * XXX: Might not be accurate
413 */
414 if (SharedCacheMap->DirtyPages + (BytesToWrite / PAGE_SIZE) > SharedCacheMap->DirtyPageThreshold)
415 {
416 return FALSE;
417 }
418
419 return TRUE;
420 }
421
422 /*
423 * @implemented
424 */
425 BOOLEAN
426 NTAPI
427 CcCopyRead (
428 IN PFILE_OBJECT FileObject,
429 IN PLARGE_INTEGER FileOffset,
430 IN ULONG Length,
431 IN BOOLEAN Wait,
432 OUT PVOID Buffer,
433 OUT PIO_STATUS_BLOCK IoStatus)
434 {
435 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d\n",
436 FileObject, FileOffset->QuadPart, Length, Wait);
437
438 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
439 "Length %lu, Wait %u, Buffer 0x%p, IoStatus 0x%p)\n",
440 FileObject, FileOffset->QuadPart, Length, Wait,
441 Buffer, IoStatus);
442
443 return CcCopyData(FileObject,
444 FileOffset->QuadPart,
445 Buffer,
446 Length,
447 CcOperationRead,
448 Wait,
449 IoStatus);
450 }
451
452 /*
453 * @implemented
454 */
455 BOOLEAN
456 NTAPI
457 CcCopyWrite (
458 IN PFILE_OBJECT FileObject,
459 IN PLARGE_INTEGER FileOffset,
460 IN ULONG Length,
461 IN BOOLEAN Wait,
462 IN PVOID Buffer)
463 {
464 IO_STATUS_BLOCK IoStatus;
465
466 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d Buffer=%p\n",
467 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
468
469 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
470 "Length %lu, Wait %u, Buffer 0x%p)\n",
471 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
472
473 return CcCopyData(FileObject,
474 FileOffset->QuadPart,
475 Buffer,
476 Length,
477 CcOperationWrite,
478 Wait,
479 &IoStatus);
480 }
481
482 /*
483 * @implemented
484 */
485 VOID
486 NTAPI
487 CcDeferWrite (
488 IN PFILE_OBJECT FileObject,
489 IN PCC_POST_DEFERRED_WRITE PostRoutine,
490 IN PVOID Context1,
491 IN PVOID Context2,
492 IN ULONG BytesToWrite,
493 IN BOOLEAN Retrying)
494 {
495 PDEFERRED_WRITE Context;
496
497 CCTRACE(CC_API_DEBUG, "FileObject=%p PostRoutine=%p Context1=%p Context2=%p BytesToWrite=%lu Retrying=%d\n",
498 FileObject, PostRoutine, Context1, Context2, BytesToWrite, Retrying);
499
500 /* Try to allocate a context for queueing the write operation */
501 Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEFERRED_WRITE), 'CcDw');
502 /* If it failed, immediately execute the operation! */
503 if (Context == NULL)
504 {
505 PostRoutine(Context1, Context2);
506 return;
507 }
508
509 /* Otherwise, initialize the context */
510 RtlZeroMemory(Context, sizeof(DEFERRED_WRITE));
511 Context->NodeTypeCode = NODE_TYPE_DEFERRED_WRITE;
512 Context->NodeByteSize = sizeof(DEFERRED_WRITE);
513 Context->FileObject = FileObject;
514 Context->PostRoutine = PostRoutine;
515 Context->Context1 = Context1;
516 Context->Context2 = Context2;
517 Context->BytesToWrite = BytesToWrite;
518
519 /* And queue it */
520 if (Retrying)
521 {
522 /* To the top, if that's a retry */
523 ExInterlockedInsertHeadList(&CcDeferredWrites,
524 &Context->DeferredWriteLinks,
525 &CcDeferredWriteSpinLock);
526 }
527 else
528 {
529 /* To the bottom, if that's a first time */
530 ExInterlockedInsertTailList(&CcDeferredWrites,
531 &Context->DeferredWriteLinks,
532 &CcDeferredWriteSpinLock);
533 }
534
535 /* FIXME: lock master */
536 if (!LazyWriter.ScanActive)
537 {
538 CcScheduleLazyWriteScan(FALSE);
539 }
540 }
541
542 /*
543 * @unimplemented
544 */
545 VOID
546 NTAPI
547 CcFastCopyRead (
548 IN PFILE_OBJECT FileObject,
549 IN ULONG FileOffset,
550 IN ULONG Length,
551 IN ULONG PageCount,
552 OUT PVOID Buffer,
553 OUT PIO_STATUS_BLOCK IoStatus)
554 {
555 LARGE_INTEGER LargeFileOffset;
556 BOOLEAN Success;
557
558 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu PageCount=%lu Buffer=%p\n",
559 FileObject, FileOffset, Length, PageCount, Buffer);
560
561 DBG_UNREFERENCED_PARAMETER(PageCount);
562
563 LargeFileOffset.QuadPart = FileOffset;
564 Success = CcCopyRead(FileObject,
565 &LargeFileOffset,
566 Length,
567 TRUE,
568 Buffer,
569 IoStatus);
570 ASSERT(Success == TRUE);
571 }
572
573 /*
574 * @unimplemented
575 */
576 VOID
577 NTAPI
578 CcFastCopyWrite (
579 IN PFILE_OBJECT FileObject,
580 IN ULONG FileOffset,
581 IN ULONG Length,
582 IN PVOID Buffer)
583 {
584 LARGE_INTEGER LargeFileOffset;
585 BOOLEAN Success;
586
587 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu Buffer=%p\n",
588 FileObject, FileOffset, Length, Buffer);
589
590 LargeFileOffset.QuadPart = FileOffset;
591 Success = CcCopyWrite(FileObject,
592 &LargeFileOffset,
593 Length,
594 TRUE,
595 Buffer);
596 ASSERT(Success == TRUE);
597 }
598
599 /*
600 * @implemented
601 */
602 BOOLEAN
603 NTAPI
604 CcZeroData (
605 IN PFILE_OBJECT FileObject,
606 IN PLARGE_INTEGER StartOffset,
607 IN PLARGE_INTEGER EndOffset,
608 IN BOOLEAN Wait)
609 {
610 NTSTATUS Status;
611 LARGE_INTEGER WriteOffset;
612 LONGLONG Length;
613 ULONG CurrentLength;
614 PMDL Mdl;
615 ULONG i;
616 IO_STATUS_BLOCK Iosb;
617 KEVENT Event;
618
619 CCTRACE(CC_API_DEBUG, "FileObject=%p StartOffset=%I64u EndOffset=%I64u Wait=%d\n",
620 FileObject, StartOffset->QuadPart, EndOffset->QuadPart, Wait);
621
622 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
623 "Wait %u)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
624 Wait);
625
626 Length = EndOffset->QuadPart - StartOffset->QuadPart;
627 WriteOffset.QuadPart = StartOffset->QuadPart;
628
629 if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
630 {
631 /* File is not cached */
632
633 Mdl = _alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
634
635 while (Length > 0)
636 {
637 if (Length + WriteOffset.QuadPart % PAGE_SIZE > MAX_ZERO_LENGTH)
638 {
639 CurrentLength = MAX_ZERO_LENGTH - WriteOffset.QuadPart % PAGE_SIZE;
640 }
641 else
642 {
643 CurrentLength = Length;
644 }
645 MmInitializeMdl(Mdl, (PVOID)(ULONG_PTR)WriteOffset.QuadPart, CurrentLength);
646 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
647 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
648 {
649 ((PPFN_NUMBER)(Mdl + 1))[i] = CcZeroPage;
650 }
651 KeInitializeEvent(&Event, NotificationEvent, FALSE);
652 Status = IoSynchronousPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
653 if (Status == STATUS_PENDING)
654 {
655 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
656 Status = Iosb.Status;
657 }
658 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
659 {
660 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
661 }
662 if (!NT_SUCCESS(Status))
663 {
664 return FALSE;
665 }
666 WriteOffset.QuadPart += CurrentLength;
667 Length -= CurrentLength;
668 }
669 }
670 else
671 {
672 IO_STATUS_BLOCK IoStatus;
673
674 return CcCopyData(FileObject,
675 WriteOffset.QuadPart,
676 NULL,
677 Length,
678 CcOperationZero,
679 Wait,
680 &IoStatus);
681 }
682
683 return TRUE;
684 }