2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/fastio.c
5 * PURPOSE: Provides Fast I/O entrypoints to the Cache Manager
6 * PROGRAMMERS: buzdelabuz2@gmail.com,alex.ionescu@reactos.org
9 /* INCLUDES ******************************************************************/
15 /* PUBLIC FUNCTIONS **********************************************************/
22 FsRtlIncrementCcFastReadResourceMiss(VOID
)
24 CcFastReadResourceMiss
++;
32 FsRtlIncrementCcFastReadNotPossible(VOID
)
34 CcFastReadNotPossible
++;
42 FsRtlIncrementCcFastReadWait(VOID
)
52 FsRtlIncrementCcFastReadNoWait(VOID
)
62 FsRtlCopyRead(IN PFILE_OBJECT FileObject
,
63 IN PLARGE_INTEGER FileOffset
,
68 OUT PIO_STATUS_BLOCK IoStatus
,
69 IN PDEVICE_OBJECT DeviceObject
)
72 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
74 PFAST_IO_DISPATCH FastIoDispatch
;
75 PDEVICE_OBJECT Device
;
76 BOOLEAN Result
= TRUE
;
77 ULONG PageCount
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(FileOffset
,Length
);
81 ASSERT(FileObject
->FsContext
);
87 IoStatus
->Status
= STATUS_SUCCESS
;
88 IoStatus
->Information
= 0;
92 if (MAXLONGLONG
< (LONGLONG
) FileOffset
->QuadPart
+ Length
) {
93 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
94 IoStatus
->Information
= 0;
98 /* Get the offset and FCB header */
99 Offset
.QuadPart
= FileOffset
->QuadPart
+ Length
;
100 FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
;
104 /* Use a Resource Acquire */
105 FsRtlEnterFileSystem();
107 ExAcquireResourceSharedLite(FcbHeader
->Resource
, TRUE
);
109 /* Acquire the resource without blocking */
110 /* Return false and the I/O manager will retry using the standard IRP method. */
111 /* Use a Resource Acquire */
112 FsRtlEnterFileSystem();
113 if (!ExAcquireResourceSharedLite(FcbHeader
->Resource
, FALSE
)) {
114 FsRtlExitFileSystem();
115 FsRtlIncrementCcFastReadResourceMiss();
121 /* Check if this is a fast I/O cached file */
122 if (!(FileObject
->PrivateCacheMap
) ||
123 (FcbHeader
->IsFastIoPossible
== FastIoIsNotPossible
)) {
124 /* It's not, so fail */
129 /* Check if we need to find out if fast I/O is available */
130 if (FcbHeader
->IsFastIoPossible
== FastIoIsQuestionable
)
133 ASSERT(!KeIsExecutingDpc());
135 /* Get the Fast I/O table */
136 Device
= IoGetRelatedDeviceObject(FileObject
);
137 FastIoDispatch
= Device
->DriverObject
->FastIoDispatch
;
140 ASSERT(FastIoDispatch
!= NULL
);
141 ASSERT(FastIoDispatch
->FastIoCheckIfPossible
!= NULL
);
143 /* Ask the driver if we can do it */
144 if (!FastIoDispatch
->FastIoCheckIfPossible(FileObject
,
159 /* Check if we read too much */
160 if (Offset
.QuadPart
> FcbHeader
->FileSize
.QuadPart
){
161 /* We did, check if the file offset is past the end */
162 if (FileOffset
->QuadPart
>= FcbHeader
->FileSize
.QuadPart
){
163 /* Set end of file */
164 IoStatus
->Status
= STATUS_END_OF_FILE
;
165 IoStatus
->Information
= 0;
169 /* Otherwise, just normalize the length */
170 Length
= (ULONG
)(FcbHeader
->FileSize
.QuadPart
- FileOffset
->QuadPart
);
173 /* Set this as top-level IRP */
174 PsGetCurrentThread()->TopLevelIrp
= FSRTL_FAST_IO_TOP_LEVEL_IRP
;
178 /* Make sure the IO and file size is below 4GB */
179 if (Wait
&& !(Offset
.HighPart
| FcbHeader
->FileSize
.HighPart
)) {
181 /* Call the cache controller */
182 CcFastCopyRead (FileObject
,FileOffset
->LowPart
,Length
,PageCount
,Buffer
,IoStatus
);
183 /* File was accessed */
184 FileObject
->Flags
|= FO_FILE_FAST_IO_READ
;
185 if (IoStatus
->Status
!= STATUS_END_OF_FILE
) {
186 ASSERT(( FcbHeader
->FileSize
.QuadPart
) >= (FileOffset
->QuadPart
+ IoStatus
->Information
));
191 /* Call the cache controller */
192 Result
= CcCopyRead(FileObject
, FileOffset
, Length
, Wait
,Buffer
, IoStatus
);
193 /* File was accessed */
194 FileObject
->Flags
|= FO_FILE_FAST_IO_READ
;
195 if (Result
== TRUE
) {
196 ASSERT( (IoStatus
->Status
== STATUS_END_OF_FILE
) ||
197 ((LONGLONG
)(FileOffset
->QuadPart
+ IoStatus
->Information
) <= FcbHeader
->FileSize
.QuadPart
)
202 /* Update the current file offset */
203 if (Result
== TRUE
) {
204 FileObject
->CurrentByteOffset
.QuadPart
+= IoStatus
->Information
;
207 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
)
212 PsGetCurrentThread()->TopLevelIrp
= 0;
214 /* Return to caller */
217 ExReleaseResourceLite(FcbHeader
->Resource
);
218 FsRtlExitFileSystem();
220 if (Result
== FALSE
) {
221 CcFastReadNotPossible
+= 1;
234 FsRtlCopyWrite(IN PFILE_OBJECT FileObject
,
235 IN PLARGE_INTEGER FileOffset
,
240 OUT PIO_STATUS_BLOCK IoStatus
,
241 IN PDEVICE_OBJECT DeviceObject
)
244 BOOLEAN Result
= TRUE
;
245 PFAST_IO_DISPATCH FastIoDispatch
;
246 PDEVICE_OBJECT Device
;
247 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
249 /* WDK doc. Offset=0xffffffffffffffff indicates append to the end of file */
250 BOOLEAN FileOffsetAppend
= ((FileOffset
->HighPart
== (LONG
)0xffffffff) && (FileOffset
->LowPart
== 0xffffffff));
251 BOOLEAN ResourceAquiredShared
= FALSE
;
253 BOOLEAN b_4GB
= FALSE
;
255 BOOLEAN FileSizeModified
= FALSE
;
256 LARGE_INTEGER OldFileSize
;
257 LARGE_INTEGER OldValidDataLength
;
259 LARGE_INTEGER NewSize
;
260 LARGE_INTEGER Offset
;
265 ASSERT(FileObject
->FsContext
);
267 /* Initialize some of the vars and pointers */
268 NewSize
.QuadPart
= 0;
269 Offset
.QuadPart
= FileOffset
->QuadPart
+ Length
;
270 FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
;
272 /* Nagar p.544 -- Check with Cc if we can write and check if the IO > 64kB (WDK macro) */
273 if ( (CcCanIWrite(FileObject
, Length
,Wait
, FALSE
) == FALSE
) ||
274 (CcCopyWriteWontFlush(FileObject
,FileOffset
,Length
) == FALSE
) ||
275 ((FileObject
->Flags
& FO_WRITE_THROUGH
)== TRUE
)
284 IoStatus
->Status
= STATUS_SUCCESS
;
285 IoStatus
->Information
= Length
;
289 FsRtlEnterFileSystem();
291 /* Nagar p.544/545 -- The CcFastCopyWrite doesn't deal with filesize beyond 4GB*/
292 if (Wait
&& (FcbHeader
->AllocationSize
.HighPart
== 0))
294 /* If the file offset is not past the file size, then we can acquire the lock shared */
295 if ((FileOffsetAppend
== FALSE
) && (Offset
.LowPart
<= FcbHeader
->ValidDataLength
.LowPart
)){
296 ExAcquireResourceSharedLite(FcbHeader
->Resource
,TRUE
);
297 ResourceAquiredShared
= TRUE
;
299 ExAcquireResourceExclusiveLite(FcbHeader
->Resource
,TRUE
);
302 /* Nagar p.544/545 -- If we append, use the file size as offset. Also, check that we aren't crossing the 4GB boundary */
303 if ((FileOffsetAppend
== TRUE
)) {
304 Offset
.LowPart
= FcbHeader
->FileSize
.LowPart
;
305 NewSize
.LowPart
= FcbHeader
->FileSize
.LowPart
+ Length
;
306 b_4GB
= (NewSize
.LowPart
< FcbHeader
->FileSize
.LowPart
);
309 Offset
.LowPart
= FileOffset
->LowPart
;
310 NewSize
.LowPart
= FileOffset
->LowPart
+ Length
;
311 b_4GB
= ((NewSize
.LowPart
< FileOffset
->LowPart
) || (FileOffset
->HighPart
!= 0));
315 Make sure that caching is initated.
316 That fast are allowed for this file stream.
317 That we are not extending past the allocated size
318 That we are not creating a hole bigger than 8k
319 That we are not crossing the 4GB boundary
321 if ( (FileObject
->PrivateCacheMap
!= NULL
) &&
322 (FcbHeader
->IsFastIoPossible
!= FastIoIsNotPossible
) &&
323 (FcbHeader
->AllocationSize
.LowPart
>= NewSize
.LowPart
) &&
324 (Offset
.LowPart
< (FcbHeader
->ValidDataLength
.LowPart
+ 0x2000) ) &&
328 /* If we are extending past the file size, we need to release the lock and acquire it
329 exclusively, because we are going to need to update the FcbHeader */
330 if (ResourceAquiredShared
&& (NewSize
.LowPart
> (FcbHeader
->ValidDataLength
.LowPart
+ 0x2000))) {
331 /* Then we need to acquire the resource exclusive */
332 ExReleaseResourceLite(FcbHeader
->Resource
);
333 ExAcquireResourceExclusiveLite(FcbHeader
->Resource
,TRUE
);
334 if (FileOffsetAppend
== TRUE
) {
335 Offset
.LowPart
= FcbHeader
->FileSize
.LowPart
; // ??
336 NewSize
.LowPart
= FcbHeader
->FileSize
.LowPart
+ Length
;
337 /* Make sure we don't cross the 4GB boundary */
338 b_4GB
= (NewSize
.LowPart
< Offset
.LowPart
);
341 /* Recheck some of the conditions since we let the lock go */
342 if ( (FileObject
->PrivateCacheMap
!= NULL
) &&
343 (FcbHeader
->IsFastIoPossible
!= FastIoIsNotPossible
) &&
344 (FcbHeader
->AllocationSize
.LowPart
>= NewSize
.LowPart
) &&
345 (FcbHeader
->AllocationSize
.HighPart
== 0) &&
360 /* Check if we need to find out if fast I/O is available */
361 if (FcbHeader
->IsFastIoPossible
== FastIoIsQuestionable
)
363 IO_STATUS_BLOCK FastIoCheckIfPossibleStatus
;
366 ASSERT(!KeIsExecutingDpc());
368 /* Get the Fast I/O table */
369 Device
= IoGetRelatedDeviceObject(FileObject
);
370 FastIoDispatch
= Device
->DriverObject
->FastIoDispatch
;
373 ASSERT(FastIoDispatch
!= NULL
);
374 ASSERT(FastIoDispatch
->FastIoCheckIfPossible
!= NULL
);
376 /* Ask the driver if we can do it */
377 if (!FastIoDispatch
->FastIoCheckIfPossible(FileObject
,
378 FileOffsetAppend
? &FcbHeader
->FileSize
:FileOffset
,
383 &FastIoCheckIfPossibleStatus
,
391 /* If we are going to extend the file then save the old file size
392 in case the operation fails
394 if (NewSize
.LowPart
> FcbHeader
->FileSize
.LowPart
) {
395 FileSizeModified
= TRUE
;
396 OldFileSize
.LowPart
= FcbHeader
->FileSize
.LowPart
;
397 OldValidDataLength
.LowPart
= FcbHeader
->ValidDataLength
.LowPart
;
398 FcbHeader
->FileSize
.LowPart
= NewSize
.LowPart
;
401 /* Set this as top-level IRP */
402 PsGetCurrentThread()->TopLevelIrp
= FSRTL_FAST_IO_TOP_LEVEL_IRP
;
406 if (Offset
.LowPart
> FcbHeader
->ValidDataLength
.LowPart
) {
407 LARGE_INTEGER OffsetVar
;
408 OffsetVar
.LowPart
= Offset
.LowPart
;
409 OffsetVar
.HighPart
= 0;
410 CcZeroData(FileObject
,&FcbHeader
->ValidDataLength
,&OffsetVar
,TRUE
);
413 /* Call the cache manager */
414 CcFastCopyWrite(FileObject
,Offset
.LowPart
,Length
,Buffer
);
416 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
)
421 /* Remove ourselves at the top level component after the IO is done */
422 PsGetCurrentThread()->TopLevelIrp
= 0;
424 /* Did the operation succeed ? */
425 if (Result
== TRUE
) {
426 /* Update the valid file size if necessary */
427 if (NewSize
.LowPart
> FcbHeader
->ValidDataLength
.LowPart
){
428 FcbHeader
->ValidDataLength
.LowPart
= NewSize
.LowPart
;
431 /* Flag the file as modified */
432 FileObject
->Flags
|= FO_FILE_MODIFIED
;
434 /* Update the strucutres if the file size changed */
435 if (FileSizeModified
) {
436 ((SHARED_CACHE_MAP
*) FileObject
->SectionObjectPointer
->SharedCacheMap
)->FileSize
.LowPart
= NewSize
.LowPart
;
437 FileObject
->Flags
|= FO_FILE_SIZE_CHANGED
;
440 /* Update the file object current file offset */
441 FileObject
->CurrentByteOffset
.QuadPart
= NewSize
.LowPart
;
445 /* Result == FALSE if we get here. */
446 if (FileSizeModified
) {
447 /* If the file size was modified then restore the old file size */
448 if(FcbHeader
->PagingIoResource
!= NULL
) {
449 // Nagar P.544 Restore the old file size if operation didn't succeed.
450 ExAcquireResourceExclusiveLite(FcbHeader
->PagingIoResource
,TRUE
);
451 FcbHeader
->FileSize
.LowPart
= OldFileSize
.LowPart
;
452 FcbHeader
->ValidDataLength
.LowPart
= OldValidDataLength
.LowPart
;
453 ExReleaseResourceLite(FcbHeader
->PagingIoResource
);
455 /* If there is no lock and do it without */
456 FcbHeader
->FileSize
.LowPart
= OldFileSize
.LowPart
;
457 FcbHeader
->ValidDataLength
.LowPart
= OldValidDataLength
.LowPart
;
467 LARGE_INTEGER OldFileSize
;
470 ASSERT(!KeIsExecutingDpc());
473 /* Check if we need to acquire the resource exclusive */
474 if ( (FileOffsetAppend
== FALSE
) &&
475 ( (FileOffset
->QuadPart
+ Length
) <= FcbHeader
->ValidDataLength
.QuadPart
)
478 /* Acquire the resource shared */
479 if (!ExAcquireResourceSharedLite(FcbHeader
->Resource
,Wait
)) {
480 goto LeaveCriticalAndFail
;
482 ResourceAquiredShared
=TRUE
;
484 /* Acquire the resource exclusive */
485 if (!ExAcquireResourceExclusiveLite(FcbHeader
->Resource
,Wait
)) {
486 goto LeaveCriticalAndFail
;
490 /* Check if we are appending */
491 if (FileOffsetAppend
== TRUE
) {
492 Offset
.QuadPart
= FcbHeader
->FileSize
.QuadPart
;
493 NewSize
.QuadPart
= FcbHeader
->FileSize
.QuadPart
+ Length
;
495 Offset
.QuadPart
= FileOffset
->QuadPart
;
496 NewSize
.QuadPart
+= FileOffset
->QuadPart
+ Length
;
500 Make sure that caching is initated.
501 That fast are allowed for this file stream.
502 That we are not extending past the allocated size
503 That we are not creating a hole bigger than 8k
505 if ( (FileObject
->PrivateCacheMap
!= NULL
) &&
506 (FcbHeader
->IsFastIoPossible
!= FastIoIsNotPossible
) &&
507 ((FcbHeader
->ValidDataLength
.QuadPart
+ 0x2000) > Offset
.QuadPart
) &&
508 (MAXLONGLONG
> (Offset
.QuadPart
+ Length
)) &&
509 (FcbHeader
->AllocationSize
.QuadPart
>= NewSize
.QuadPart
)
512 /* Check if we can keep the lock shared */
513 if (ResourceAquiredShared
&& (NewSize
.QuadPart
> FcbHeader
->ValidDataLength
.QuadPart
) ) {
514 ExReleaseResourceLite(FcbHeader
->Resource
);
515 if(!ExAcquireResourceExclusiveLite(FcbHeader
->Resource
,Wait
))
517 goto LeaveCriticalAndFail
;
520 /* Compute the offset and the new filesize */
521 if (FileOffsetAppend
) {
522 Offset
.QuadPart
= FcbHeader
->FileSize
.QuadPart
;
523 NewSize
.QuadPart
= FcbHeader
->FileSize
.QuadPart
+ Length
;
526 /* Recheck the above points since we released and reacquire the lock */
527 if ( (FileObject
->PrivateCacheMap
!= NULL
) &&
528 (FcbHeader
->IsFastIoPossible
!= FastIoIsNotPossible
) &&
529 (FcbHeader
->AllocationSize
.QuadPart
> NewSize
.QuadPart
)
538 /* Check if we need to find out if fast I/O is available */
539 if (FcbHeader
->IsFastIoPossible
== FastIoIsQuestionable
)
541 IO_STATUS_BLOCK FastIoCheckIfPossibleStatus
;
544 ASSERT(!KeIsExecutingDpc());
546 /* Get the Fast I/O table */
547 Device
= IoGetRelatedDeviceObject(FileObject
);
548 FastIoDispatch
= Device
->DriverObject
->FastIoDispatch
;
551 ASSERT(FastIoDispatch
!= NULL
);
552 ASSERT(FastIoDispatch
->FastIoCheckIfPossible
!= NULL
);
554 /* Ask the driver if we can do it */
555 if (!FastIoDispatch
->FastIoCheckIfPossible(FileObject
,
556 FileOffsetAppend
? &FcbHeader
->FileSize
:FileOffset
,
561 &FastIoCheckIfPossibleStatus
,
570 /* If we are going to modify the filesize, save the old fs in case the operation fails */
571 if (NewSize
.QuadPart
> FcbHeader
->FileSize
.QuadPart
) {
572 FileSizeModified
= TRUE
;
573 OldFileSize
.QuadPart
= FcbHeader
->FileSize
.QuadPart
;
574 OldValidDataLength
.QuadPart
= FcbHeader
->ValidDataLength
.QuadPart
;
576 /* If the high part of the filesize is going to change, grab the Paging IoResouce */
577 if (NewSize
.HighPart
!= FcbHeader
->FileSize
.HighPart
&& FcbHeader
->PagingIoResource
) {
578 ExAcquireResourceExclusiveLite(FcbHeader
->PagingIoResource
, TRUE
);
579 FcbHeader
->FileSize
.QuadPart
= NewSize
.QuadPart
;
580 ExReleaseResourceLite(FcbHeader
->PagingIoResource
);
582 FcbHeader
->FileSize
.QuadPart
= NewSize
.QuadPart
;
587 /* Set ourselves as top component */
588 PsGetCurrentThread()->TopLevelIrp
= FSRTL_FAST_IO_TOP_LEVEL_IRP
;
591 BOOLEAN CallCc
= TRUE
;
592 /* Check if there is a gap between the end of the file and the offset
593 If yes, then we have to zero the data
595 if (Offset
.QuadPart
> FcbHeader
->ValidDataLength
.QuadPart
) {
596 if (!(Result
= CcZeroData(FileObject
,&FcbHeader
->ValidDataLength
,&Offset
,Wait
))) {
597 /* If this operation fails, then we have to exit
598 We can jump outside the SEH, so I a using a variable to exit
605 /* Unless the CcZeroData failed, call the cache manager */
607 Result
= CcCopyWrite(FileObject
,&Offset
,Length
, Wait
, Buffer
);
609 }_SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
)
614 /* Reset the top component */
615 PsGetCurrentThread()->TopLevelIrp
= FSRTL_FAST_IO_TOP_LEVEL_IRP
;
617 /* Did the operation suceeded */
619 /* Check if we need to update the filesize */
620 if (NewSize
.QuadPart
> FcbHeader
->ValidDataLength
.QuadPart
) {
621 if (NewSize
.HighPart
!= FcbHeader
->ValidDataLength
.HighPart
&& FcbHeader
->PagingIoResource
) {
622 ExAcquireResourceExclusiveLite(FcbHeader
->PagingIoResource
, TRUE
);
623 FcbHeader
->ValidDataLength
.QuadPart
= NewSize
.QuadPart
;
624 ExReleaseResourceLite(FcbHeader
->PagingIoResource
);
626 FcbHeader
->ValidDataLength
.QuadPart
= NewSize
.QuadPart
;
630 /* Flag the file as modified */
631 FileObject
->Flags
|= FO_FILE_MODIFIED
;
632 /* Check if the filesize has changed */
633 if (FileSizeModified
) {
634 /* Update the file sizes */
635 ((SHARED_CACHE_MAP
*) FileObject
->SectionObjectPointer
->SharedCacheMap
)->FileSize
.QuadPart
= NewSize
.QuadPart
;
636 FileObject
->Flags
|= FO_FILE_SIZE_CHANGED
;
638 /* Update the current FO byte offset */
639 FileObject
->CurrentByteOffset
.QuadPart
= NewSize
.QuadPart
;
643 /* The operation did not succeed
644 Reset the file size to what it should be
646 if (FileSizeModified
) {
647 if (FcbHeader
->PagingIoResource
) {
648 ExAcquireResourceExclusiveLite(FcbHeader
->PagingIoResource
, TRUE
);
649 FcbHeader
->FileSize
.QuadPart
= OldFileSize
.QuadPart
;
650 FcbHeader
->ValidDataLength
.QuadPart
= OldValidDataLength
.QuadPart
;
651 ExReleaseResourceLite(FcbHeader
->PagingIoResource
);
653 FcbHeader
->FileSize
.QuadPart
= OldFileSize
.QuadPart
;
654 FcbHeader
->ValidDataLength
.QuadPart
= OldValidDataLength
.QuadPart
;
666 LeaveCriticalAndFail
:
667 FsRtlExitFileSystem();
673 ExReleaseResourceLite(FcbHeader
->Resource
);
674 FsRtlExitFileSystem();
679 ExReleaseResourceLite(FcbHeader
->Resource
);
680 FsRtlExitFileSystem();
689 FsRtlGetFileSize(IN PFILE_OBJECT FileObject
,
690 IN OUT PLARGE_INTEGER FileSize
)
692 FILE_STANDARD_INFORMATION Info
;
694 IO_STATUS_BLOCK IoStatus
;
695 PDEVICE_OBJECT DeviceObject
;
696 PFAST_IO_DISPATCH FastDispatch
;
698 PIO_STACK_LOCATION IoStackLocation
;
700 BOOLEAN OldHardError
;
705 /* Get Device Object and Fast Calls */
706 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
707 FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
;
709 /* Check if we support Fast Calls, and check FastIoQueryStandardInfo */
710 /* Call the function and see if it succeeds */
711 if ( !FastDispatch
||
712 !FastDispatch
->FastIoQueryStandardInfo
||
713 !FastDispatch
->FastIoQueryStandardInfo(FileObject
,TRUE
,
714 &Info
,&IoStatus
,DeviceObject
))
716 /* If any of the above failed, then we are going to send an IRP to the device object */
717 /* Initialize the even for the IO */
718 KeInitializeEvent(&Event
,NotificationEvent
,FALSE
);
719 /* Allocate the IRP */
720 Irp
= IoAllocateIrp(DeviceObject
->StackSize
,FALSE
);
723 return STATUS_INSUFFICIENT_RESOURCES
;
727 /* Don't process hard error */
728 OldHardError
= IoSetThreadHardErrorMode(FALSE
);
731 Irp
->UserIosb
= &IoStatus
;
732 Irp
->UserEvent
= &Event
;
733 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
734 Irp
->Flags
= IRP_SYNCHRONOUS_PAGING_IO
| IRP_PAGING_IO
;
735 Irp
->RequestorMode
= KernelMode
;
736 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
737 Irp
->AssociatedIrp
.SystemBuffer
= &Info
;
739 /* Setup out stack location */
740 IoStackLocation
= Irp
->Tail
.Overlay
.CurrentStackLocation
;
742 IoStackLocation
->MajorFunction
= IRP_MJ_QUERY_INFORMATION
;
743 IoStackLocation
->FileObject
= FileObject
;
744 IoStackLocation
->DeviceObject
= DeviceObject
;
745 IoStackLocation
->Parameters
.QueryFile
.Length
= ALIGN_UP(sizeof(FILE_INFORMATION_CLASS
),ULONG
);
746 IoStackLocation
->Parameters
.QueryFile
.FileInformationClass
= FileStandardInformation
;
748 /* Send the IRP to the related device object */
749 Status
= IoCallDriver(DeviceObject
,Irp
);
751 /* Standard DDK IRP result processing */
752 if (Status
== STATUS_PENDING
)
754 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
757 /* If there was a synchronous error, signal it */
758 if (!NT_SUCCESS(Status
))
760 IoStatus
.Status
= Status
;
763 IoSetThreadHardErrorMode(OldHardError
);
766 /* Check the sync/async IO result */
767 if (NT_SUCCESS(IoStatus
.Status
))
769 /* Was the request for a directory ? */
772 IoStatus
.Status
= STATUS_FILE_IS_A_DIRECTORY
;
776 FileSize
->QuadPart
= Info
.EndOfFile
.QuadPart
;
780 return IoStatus
.Status
;
789 FsRtlMdlRead(IN PFILE_OBJECT FileObject
,
790 IN PLARGE_INTEGER FileOffset
,
794 OUT PIO_STATUS_BLOCK IoStatus
)
796 PDEVICE_OBJECT DeviceObject
, BaseDeviceObject
;
797 PFAST_IO_DISPATCH FastDispatch
;
799 /* Get Device Object and Fast Calls */
800 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
801 FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
;
803 /* Check if we support Fast Calls, and check this one */
804 if (FastDispatch
&& FastDispatch
->MdlRead
)
806 /* Use the fast path */
807 return FastDispatch
->MdlRead(FileObject
,
816 /* Get the Base File System (Volume) and Fast Calls */
817 BaseDeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
818 FastDispatch
= BaseDeviceObject
->DriverObject
->FastIoDispatch
;
820 /* If the Base Device Object has its own FastDispatch Routine, fail */
821 if (FastDispatch
&& FastDispatch
->MdlRead
&&
822 BaseDeviceObject
!= DeviceObject
)
827 /* No fast path, use slow path */
828 return FsRtlMdlReadDev(FileObject
,
842 FsRtlMdlReadComplete(IN PFILE_OBJECT FileObject
,
843 IN OUT PMDL MdlChain
)
845 PDEVICE_OBJECT DeviceObject
, BaseDeviceObject
;
846 PFAST_IO_DISPATCH FastDispatch
;
848 /* Get Device Object and Fast Calls */
849 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
850 FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
;
852 /* Check if we support Fast Calls, and check this one */
853 if (FastDispatch
&& FastDispatch
->MdlReadComplete
)
855 /* Use the fast path */
856 return FastDispatch
->MdlReadComplete(FileObject
,
861 /* Get the Base File System (Volume) and Fast Calls */
862 BaseDeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
863 FastDispatch
= BaseDeviceObject
->DriverObject
->FastIoDispatch
;
865 /* If the Base Device Object has its own FastDispatch Routine, fail */
866 if ((BaseDeviceObject
!= DeviceObject
) && FastDispatch
867 && FastDispatch
->MdlReadComplete
)
872 /* No fast path, use slow path */
873 return FsRtlMdlReadCompleteDev(FileObject
, MdlChain
, DeviceObject
);
881 FsRtlMdlReadCompleteDev(IN PFILE_OBJECT FileObject
,
882 IN PMDL MemoryDescriptorList
,
883 IN PDEVICE_OBJECT DeviceObject
)
885 /* Call the Cache Manager */
886 CcMdlReadComplete2(MemoryDescriptorList
, FileObject
);
896 FsRtlMdlReadDev(IN PFILE_OBJECT FileObject
,
897 IN PLARGE_INTEGER FileOffset
,
901 OUT PIO_STATUS_BLOCK IoStatus
,
902 IN PDEVICE_OBJECT DeviceObject
)
904 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
905 BOOLEAN Result
= TRUE
;
906 LARGE_INTEGER Offset
;
907 PFAST_IO_DISPATCH FastIoDispatch
;
908 PDEVICE_OBJECT Device
;
915 IoStatus
->Status
= STATUS_SUCCESS
;
916 IoStatus
->Information
= 0;
921 ASSERT(MAXLONGLONG
- FileOffset
->QuadPart
>= (LONGLONG
)Length
);
923 /* Get the offset and FCB header */
924 Offset
.QuadPart
= FileOffset
->QuadPart
+ Length
;
925 FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
;
928 FsRtlEnterFileSystem();
932 ExAcquireResourceShared(FcbHeader
->Resource
, TRUE
);
934 /* Check if this is a fast I/O cached file */
935 if (!(FileObject
->PrivateCacheMap
) ||
936 (FcbHeader
->IsFastIoPossible
== FastIoIsNotPossible
))
938 /* It's not, so fail */
939 CcFastMdlReadNotPossible
+= 1;
944 /* Check if we need to find out if fast I/O is available */
945 if (FcbHeader
->IsFastIoPossible
== FastIoIsQuestionable
)
947 /* Get the Fast I/O table */
948 Device
= IoGetRelatedDeviceObject(FileObject
);
949 FastIoDispatch
= Device
->DriverObject
->FastIoDispatch
;
952 ASSERT(!KeIsExecutingDpc());
953 ASSERT(FastIoDispatch
!= NULL
);
954 ASSERT(FastIoDispatch
->FastIoCheckIfPossible
!= NULL
);
956 /* Ask the driver if we can do it */
957 if (!FastIoDispatch
->FastIoCheckIfPossible(FileObject
,
967 CcFastMdlReadNotPossible
+= 1;
973 /* Check if we read too much */
974 if (Offset
.QuadPart
> FcbHeader
->FileSize
.QuadPart
)
976 /* We did, check if the file offset is past the end */
977 if (FileOffset
->QuadPart
>= FcbHeader
->FileSize
.QuadPart
)
979 /* Set end of file */
980 IoStatus
->Status
= STATUS_END_OF_FILE
;
981 IoStatus
->Information
= 0;
985 /* Otherwise, just normalize the length */
986 Length
= (ULONG
)(FcbHeader
->FileSize
.QuadPart
- FileOffset
->QuadPart
);
989 /* Set this as top-level IRP */
990 PsGetCurrentThread()->TopLevelIrp
= FSRTL_FAST_IO_TOP_LEVEL_IRP
;
995 CcMdlRead(FileObject
, FileOffset
, Length
, MdlChain
, IoStatus
);
996 FileObject
->Flags
|= FO_FILE_FAST_IO_READ
;
998 _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
)
1004 /* Remove the top-level IRP flag */
1005 PsGetCurrentThread()->TopLevelIrp
= 0;
1007 /* Return to caller */
1009 ExReleaseResourceLite(FcbHeader
->Resource
);
1010 FsRtlExitFileSystem();
1019 FsRtlMdlWriteComplete(IN PFILE_OBJECT FileObject
,
1020 IN PLARGE_INTEGER FileOffset
,
1023 PDEVICE_OBJECT DeviceObject
, BaseDeviceObject
;
1024 PFAST_IO_DISPATCH FastDispatch
;
1026 /* Get Device Object and Fast Calls */
1027 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1028 FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
;
1030 /* Check if we support Fast Calls, and check this one */
1031 if (FastDispatch
&& FastDispatch
->MdlWriteComplete
)
1033 /* Use the fast path */
1034 return FastDispatch
->MdlWriteComplete(FileObject
,
1040 /* Get the Base File System (Volume) and Fast Calls */
1041 BaseDeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1042 FastDispatch
= BaseDeviceObject
->DriverObject
->FastIoDispatch
;
1044 /* If the Base Device Object has its own FastDispatch Routine, fail */
1045 if (FastDispatch
&& FastDispatch
->MdlWriteComplete
&&
1046 BaseDeviceObject
!= DeviceObject
)
1051 /* No fast path, use slow path */
1052 return FsRtlMdlWriteCompleteDev(FileObject
,
1063 FsRtlMdlWriteCompleteDev(IN PFILE_OBJECT FileObject
,
1064 IN PLARGE_INTEGER FileOffset
,
1066 IN PDEVICE_OBJECT DeviceObject
)
1068 if (FileObject
->Flags
& FO_WRITE_THROUGH
)
1074 /* Call the Cache Manager */
1075 CcMdlWriteComplete2(FileObject
,FileOffset
,MdlChain
);
1084 FsRtlPrepareMdlWrite(IN PFILE_OBJECT FileObject
,
1085 IN PLARGE_INTEGER FileOffset
,
1089 OUT PIO_STATUS_BLOCK IoStatus
)
1091 PDEVICE_OBJECT DeviceObject
, BaseDeviceObject
;
1092 PFAST_IO_DISPATCH FastDispatch
;
1094 /* Get Device Object and Fast Calls */
1095 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1096 FastDispatch
= DeviceObject
->DriverObject
->FastIoDispatch
;
1098 /* Check if we support Fast Calls, and check this one */
1099 if (FastDispatch
&& FastDispatch
->PrepareMdlWrite
)
1101 /* Use the fast path */
1102 return FastDispatch
->PrepareMdlWrite(FileObject
,
1111 /* Get the Base File System (Volume) and Fast Calls */
1112 BaseDeviceObject
= IoGetBaseFileSystemDeviceObject(FileObject
);
1113 FastDispatch
= BaseDeviceObject
->DriverObject
->FastIoDispatch
;
1115 /* If the Base Device Object has its own FastDispatch Routine, fail */
1116 if (FastDispatch
&& FastDispatch
->PrepareMdlWrite
&&
1117 BaseDeviceObject
!= DeviceObject
)
1122 /* No fast path, use slow path */
1123 return FsRtlPrepareMdlWriteDev(FileObject
,
1137 FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject
,
1138 IN PLARGE_INTEGER FileOffset
,
1142 OUT PIO_STATUS_BLOCK IoStatus
,
1143 IN PDEVICE_OBJECT DeviceObject
)
1145 BOOLEAN Result
= TRUE
;
1146 PFAST_IO_DISPATCH FastIoDispatch
;
1147 PDEVICE_OBJECT Device
;
1148 PFSRTL_COMMON_FCB_HEADER FcbHeader
;
1150 LARGE_INTEGER OldFileSize
;
1151 LARGE_INTEGER OldValidDataLength
;
1152 LARGE_INTEGER NewSize
;
1153 LARGE_INTEGER Offset
;
1155 /* WDK doc. Offset=0xffffffffffffffff indicates append to the end of file */
1156 BOOLEAN FileOffsetAppend
= ((FileOffset
->HighPart
== (LONG
)0xffffffff) && (FileOffset
->LowPart
== 0xffffffff));
1157 BOOLEAN FileSizeModified
= FALSE
;
1158 BOOLEAN ResourceAquiredShared
= FALSE
;
1160 /* Initialize some of the vars and pointers */
1161 OldFileSize
.QuadPart
= 0;
1162 OldValidDataLength
.QuadPart
= 0;
1166 Offset
.QuadPart
= FileOffset
->QuadPart
+ Length
;
1168 /* Nagar p.544 -- Check with Cc if we can write */
1169 if ( (!CcCanIWrite(FileObject
, Length
,TRUE
,FALSE
))||
1170 (FileObject
->Flags
& FO_WRITE_THROUGH
))
1175 IoStatus
->Status
= STATUS_SUCCESS
;
1177 /* No actual read */
1183 FcbHeader
= (PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
;
1184 FsRtlEnterFileSystem();
1186 /* Check we are going to extend the file */
1187 if ( (FileOffsetAppend
== FALSE
) &&
1188 ( (FileOffset
->QuadPart
+ Length
) <= FcbHeader
->ValidDataLength
.QuadPart
)
1191 /* Acquire the resource shared */
1192 ExAcquireResourceSharedLite(FcbHeader
->Resource
,TRUE
);
1193 ResourceAquiredShared
=TRUE
;
1196 /* Acquire the resource exclusive */
1197 ExAcquireResourceExclusiveLite(FcbHeader
->Resource
,TRUE
);
1200 /* Check if we are appending */
1201 if (FileOffsetAppend
== TRUE
) {
1202 Offset
.QuadPart
= FcbHeader
->FileSize
.QuadPart
;
1203 NewSize
.QuadPart
= FcbHeader
->FileSize
.QuadPart
+ Length
;
1206 Offset
.QuadPart
= FileOffset
->QuadPart
;
1207 NewSize
.QuadPart
= FileOffset
->QuadPart
+ Length
;
1210 if ( (FileObject
->PrivateCacheMap
) &&
1211 (FcbHeader
->IsFastIoPossible
) &&
1212 (MAXLONGLONG
>= (LONGLONG
) FileOffset
->QuadPart
+ Length
) &&
1213 (NewSize
.QuadPart
<= FcbHeader
->AllocationSize
.QuadPart
) )
1215 /* Check if we can keep the lock shared */
1216 if (ResourceAquiredShared
&& (NewSize
.QuadPart
> FcbHeader
->ValidDataLength
.QuadPart
) ) {
1217 ExReleaseResourceLite(FcbHeader
->Resource
);
1218 ExAcquireResourceExclusiveLite(FcbHeader
->Resource
,TRUE
);
1220 /* Compute the offset and the new filesize */
1221 if (FileOffsetAppend
) {
1222 Offset
.QuadPart
= FcbHeader
->FileSize
.QuadPart
;
1223 NewSize
.QuadPart
= FcbHeader
->FileSize
.QuadPart
+ Length
;
1226 /* Recheck the above points since we released and reacquire the lock */
1227 if ( (FileObject
->PrivateCacheMap
!= NULL
) &&
1228 (FcbHeader
->IsFastIoPossible
!= FastIoIsNotPossible
) &&
1229 (FcbHeader
->AllocationSize
.QuadPart
> NewSize
.QuadPart
)
1234 goto FailAndCleanup
;
1238 /* Check if we need to find out if fast I/O is available */
1239 if (FcbHeader
->IsFastIoPossible
== FastIoIsQuestionable
)
1242 /* ASSERT(!KeIsExecutingDpc()); */
1244 /* Get the Fast I/O table */
1245 Device
= IoGetRelatedDeviceObject(FileObject
);
1246 FastIoDispatch
= Device
->DriverObject
->FastIoDispatch
;
1249 ASSERT(FastIoDispatch
!= NULL
);
1250 ASSERT(FastIoDispatch
->FastIoCheckIfPossible
!= NULL
);
1252 /* Ask the driver if we can do it */
1253 if (!FastIoDispatch
->FastIoCheckIfPossible(FileObject
,
1262 /* It's not, fail */
1263 goto FailAndCleanup
;
1267 /* If we are going to modify the filesize, save the old fs in case the operation fails */
1268 if (NewSize
.QuadPart
> FcbHeader
->FileSize
.QuadPart
)
1270 FileSizeModified
= TRUE
;
1271 OldFileSize
.QuadPart
= FcbHeader
->FileSize
.QuadPart
;
1272 OldValidDataLength
.QuadPart
= FcbHeader
->ValidDataLength
.QuadPart
;
1274 /* If the high part of the filesize is going to change, grab the Paging IoResouce */
1275 if (NewSize
.HighPart
!= FcbHeader
->FileSize
.HighPart
&& FcbHeader
->PagingIoResource
)
1277 ExAcquireResourceExclusiveLite(FcbHeader
->PagingIoResource
, TRUE
);
1278 FcbHeader
->FileSize
.QuadPart
= NewSize
.QuadPart
;
1279 ExReleaseResourceLite(FcbHeader
->PagingIoResource
);
1281 FcbHeader
->FileSize
.QuadPart
= NewSize
.QuadPart
;
1287 /* Set ourselves as top component */
1288 PsGetCurrentThread()->TopLevelIrp
= FSRTL_FAST_IO_TOP_LEVEL_IRP
;
1291 /* Check if there is a gap between the end of the file and the offset
1292 If yes, then we have to zero the data
1294 if (Offset
.QuadPart
> FcbHeader
->ValidDataLength
.QuadPart
) {
1295 Result
= CcZeroData(FileObject
,&FcbHeader
->ValidDataLength
,&Offset
,TRUE
);
1298 CcPrepareMdlWrite(FileObject
,&Offset
,Length
,MdlChain
,IoStatus
);
1301 CcPrepareMdlWrite(FileObject
,&Offset
,Length
,MdlChain
,IoStatus
);
1304 }_SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
)
1309 /* Reset the top component */
1310 PsGetCurrentThread()->TopLevelIrp
= 0;
1312 /* Did the operation suceeded */
1314 /* Check if we need to update the filesize */
1315 if (NewSize
.QuadPart
> FcbHeader
->ValidDataLength
.QuadPart
) {
1316 if (NewSize
.HighPart
!= FcbHeader
->ValidDataLength
.HighPart
&& FcbHeader
->PagingIoResource
) {
1317 ExAcquireResourceExclusiveLite(FcbHeader
->PagingIoResource
, TRUE
);
1318 FcbHeader
->ValidDataLength
.QuadPart
= NewSize
.QuadPart
;
1319 ExReleaseResourceLite(FcbHeader
->PagingIoResource
);
1321 FcbHeader
->ValidDataLength
.QuadPart
= NewSize
.QuadPart
;
1325 /* Flag the file as modified */
1326 FileObject
->Flags
|= FO_FILE_MODIFIED
;
1327 /* Check if the filesize has changed */
1328 if (FileSizeModified
) {
1329 /* Update the file sizes */
1330 ((SHARED_CACHE_MAP
*) FileObject
->SectionObjectPointer
->SharedCacheMap
)->FileSize
.QuadPart
= NewSize
.QuadPart
;
1331 FileObject
->Flags
|= FO_FILE_SIZE_CHANGED
;
1337 /* The operation did not succeed
1338 Reset the file size to what it should be
1340 if (FileSizeModified
) {
1341 if (FcbHeader
->PagingIoResource
) {
1342 ExAcquireResourceExclusiveLite(FcbHeader
->PagingIoResource
, TRUE
);
1343 FcbHeader
->FileSize
.QuadPart
= OldFileSize
.QuadPart
;
1344 FcbHeader
->ValidDataLength
.QuadPart
= OldValidDataLength
.QuadPart
;
1345 ExReleaseResourceLite(FcbHeader
->PagingIoResource
);
1347 FcbHeader
->FileSize
.QuadPart
= OldFileSize
.QuadPart
;
1348 FcbHeader
->ValidDataLength
.QuadPart
= OldValidDataLength
.QuadPart
;
1358 goto FailAndCleanup
;
1364 ExReleaseResourceLite(FcbHeader
->Resource
);
1365 FsRtlExitFileSystem();
1370 ExReleaseResourceLite(FcbHeader
->Resource
);
1371 FsRtlExitFileSystem();
1381 FsRtlAcquireFileExclusive(IN PFILE_OBJECT FileObject
)
1385 FsRtlAcquireFileExclusiveCommon(FileObject,0,0);
1387 KeBugCheck(FILE_SYSTEM
);
1395 FsRtlReleaseFile(IN PFILE_OBJECT FileObject
)
1398 KeBugCheck(FILE_SYSTEM
);
1402 * @name FsRtlRegisterFileSystemFilterCallbacks
1407 * @param FilterDriverObject
1420 FsRtlRegisterFileSystemFilterCallbacks(IN PDRIVER_OBJECT FilterDriverObject
,
1421 IN PFS_FILTER_CALLBACKS Callbacks
)
1424 return STATUS_NOT_IMPLEMENTED
;