3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module declares the global data used by the Fat file system.
19 // The Bug check file id for this module
22 #define BugCheckFileId (FAT_BUG_CHECK_FATDATA)
25 // The debug trace level
28 #define Dbg (DEBUG_TRACE_CATCH_EXCEPTIONS)
34 #pragma alloc_text(PAGE, FatBugCheckExceptionFilter)
38 #pragma alloc_text(PAGE, FatCompleteRequest_Real)
39 #pragma alloc_text(PAGE, FatFastIoCheckIfPossible)
40 #pragma alloc_text(PAGE, FatFastQueryBasicInfo)
41 #pragma alloc_text(PAGE, FatFastQueryNetworkOpenInfo)
42 #pragma alloc_text(PAGE, FatFastQueryStdInfo)
43 #pragma alloc_text(PAGE, FatIsIrpTopLevel)
44 #pragma alloc_text(PAGE, FatPopUpFileCorrupt)
45 #pragma alloc_text(PAGE, FatProcessException)
50 // The global fsd data record, and zero large integer
54 #pragma prefast( suppress:22112, "only applies to user mode processes" )
58 PDEVICE_OBJECT FatDiskFileSystemDeviceObject
;
59 PDEVICE_OBJECT FatCdromFileSystemDeviceObject
;
62 LARGE_INTEGER FatLargeZero
= {0,0};
63 LARGE_INTEGER FatMaxLarge
= {MAXULONG
,MAXLONG
};
65 LARGE_INTEGER FatLargeZero
= {.LowPart
= 0, .HighPart
= 0};
66 LARGE_INTEGER FatMaxLarge
= {.LowPart
= MAXULONG
, .HighPart
= MAXLONG
};
70 LARGE_INTEGER Fat30Milliseconds
= {(ULONG
)(-30 * 1000 * 10), -1};
71 LARGE_INTEGER Fat100Milliseconds
= {(ULONG
)(-30 * 1000 * 10), -1};
72 LARGE_INTEGER FatOneDay
= {0x2a69c000, 0xc9};
73 LARGE_INTEGER FatJanOne1980
= {0xe1d58000,0x01a8e79f};
74 LARGE_INTEGER FatDecThirtyOne1979
= {0xb76bc000,0x01a8e6d6};
76 LARGE_INTEGER Fat30Milliseconds
= {.LowPart
= (ULONG
)(-30 * 1000 * 10), .HighPart
= -1};
77 LARGE_INTEGER Fat100Milliseconds
= {.LowPart
= (ULONG
)(-30 * 1000 * 10), .HighPart
= -1};
78 LARGE_INTEGER FatOneDay
= {.LowPart
= 0x2a69c000, .HighPart
= 0xc9};
79 LARGE_INTEGER FatJanOne1980
= {.LowPart
= 0xe1d58000, .HighPart
= 0x01a8e79f};
80 LARGE_INTEGER FatDecThirtyOne1979
= {.LowPart
= 0xb76bc000, .HighPart
= 0x01a8e6d6};
83 FAT_TIME_STAMP FatTimeJanOne1980
= {{0,0,0},{1,1,0}};
86 LARGE_INTEGER FatMagic10000
= {0xe219652c, 0xd1b71758};
87 LARGE_INTEGER FatMagic86400000
= {0xfa67b90e, 0xc6d750eb};
89 LARGE_INTEGER FatMagic10000
= {.LowPart
= 0xe219652c, .HighPart
= 0xd1b71758};
90 LARGE_INTEGER FatMagic86400000
= {.LowPart
= 0xfa67b90e, .HighPart
= 0xc6d750eb};
94 #pragma prefast( suppress:22112, "only applies to user mode processes" )
96 FAST_IO_DISPATCH FatFastIoDispatch
;
99 // Our lookaside lists.
102 NPAGED_LOOKASIDE_LIST FatIrpContextLookasideList
;
103 NPAGED_LOOKASIDE_LIST FatNonPagedFcbLookasideList
;
104 NPAGED_LOOKASIDE_LIST FatEResourceLookasideList
;
106 SLIST_HEADER FatCloseContextSList
;
109 // Synchronization for the close queue
112 FAST_MUTEX FatCloseQueueMutex
;
115 // Reserve MDL for paging file operations.
119 PMDL FatReserveMdl
= NULL
;
121 volatile PMDL FatReserveMdl
= NULL
;
123 KEVENT FatReserveEvent
;
126 // Global disk accounting state, enabled or disabled
129 LOGICAL FatDiskAccountingEnabled
= FALSE
;
134 LONG FatDebugTraceLevel
= 0x00000009;
135 LONG FatDebugTraceIndent
= 0;
137 ULONG FatFsdEntryCount
= 0;
138 ULONG FatFspEntryCount
= 0;
139 ULONG FatIoCallDriverCount
= 0;
141 LONG FatPerformanceTimerLevel
= 0x00000000;
143 ULONG FatTotalTicks
[32] = { 0 };
146 // I need this because C can't support conditional compilation within
150 PVOID FatNull
= NULL
;
156 BOOLEAN FatTestRaisedStatus
= FALSE
;
158 NTSTATUS FatBreakOnInterestingIoCompletion
= STATUS_SUCCESS
;
159 NTSTATUS FatBreakOnInterestingExceptionStatus
= 0;
160 NTSTATUS FatBreakOnInterestingIrpCompletion
= 0;
167 FatBugCheckExceptionFilter (
168 IN PEXCEPTION_POINTERS ExceptionPointer
175 An exception filter which acts as an assert that the exception should
178 This is only valid on debug builds, we don't want the overhead on retail.
182 ExceptionPointers - The result of GetExceptionInformation() in the context
194 FatBugCheck( (ULONG_PTR
)ExceptionPointer
->ExceptionRecord
,
195 (ULONG_PTR
)ExceptionPointer
->ContextRecord
,
196 (ULONG_PTR
)ExceptionPointer
->ExceptionRecord
->ExceptionAddress
);
198 // return EXCEPTION_EXECUTE_HANDLER; // unreachable code
205 IN PIRP_CONTEXT IrpContext
,
206 IN PEXCEPTION_POINTERS ExceptionPointer
213 This routine is used to decide if we should or should not handle
214 an exception status that is being raised. It inserts the status
215 into the IrpContext and either indicates that we should handle
216 the exception or bug check the system.
220 ExceptionPointers - The result of GetExceptionInformation() in the context
225 ULONG - returns EXCEPTION_EXECUTE_HANDLER or bugchecks
230 NTSTATUS ExceptionCode
;
232 ExceptionCode
= ExceptionPointer
->ExceptionRecord
->ExceptionCode
;
233 DebugTrace(0, DEBUG_TRACE_UNWIND
, "FatExceptionFilter %X\n", ExceptionCode
);
234 DebugDump("FatExceptionFilter\n", Dbg
, NULL
);
238 if( FatBreakOnInterestingExceptionStatus
!= 0 && ExceptionCode
== FatBreakOnInterestingExceptionStatus
) {
245 // If the exception is STATUS_IN_PAGE_ERROR, get the I/O error code
246 // from the exception record.
249 if (ExceptionCode
== STATUS_IN_PAGE_ERROR
) {
250 if (ExceptionPointer
->ExceptionRecord
->NumberParameters
>= 3) {
251 ExceptionCode
= (NTSTATUS
)ExceptionPointer
->ExceptionRecord
->ExceptionInformation
[2];
256 // If there is not an irp context, we must have had insufficient resources.
259 if ( !ARGUMENT_PRESENT( IrpContext
) ) {
261 if (!FsRtlIsNtstatusExpected( ExceptionCode
)) {
264 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
266 FatBugCheck( (ULONG_PTR
)ExceptionPointer
->ExceptionRecord
,
267 (ULONG_PTR
)ExceptionPointer
->ContextRecord
,
268 (ULONG_PTR
)ExceptionPointer
->ExceptionRecord
->ExceptionAddress
);
271 return EXCEPTION_EXECUTE_HANDLER
;
275 // For the purposes of processing this exception, let's mark this
276 // request as being able to wait and disable write through if we
277 // aren't posting it.
280 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
282 if ( (ExceptionCode
!= STATUS_CANT_WAIT
) &&
283 (ExceptionCode
!= STATUS_VERIFY_REQUIRED
) ) {
285 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH
);
288 if ( IrpContext
->ExceptionStatus
== 0 ) {
290 if (FsRtlIsNtstatusExpected( ExceptionCode
)) {
292 IrpContext
->ExceptionStatus
= ExceptionCode
;
294 return EXCEPTION_EXECUTE_HANDLER
;
299 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
301 FatBugCheck( (ULONG_PTR
)ExceptionPointer
->ExceptionRecord
,
302 (ULONG_PTR
)ExceptionPointer
->ContextRecord
,
303 (ULONG_PTR
)ExceptionPointer
->ExceptionRecord
->ExceptionAddress
);
309 // We raised this code explicitly ourselves, so it had better be
313 NT_ASSERT( IrpContext
->ExceptionStatus
== ExceptionCode
);
314 NT_ASSERT( FsRtlIsNtstatusExpected( ExceptionCode
) );
317 return EXCEPTION_EXECUTE_HANDLER
;
320 _Requires_lock_held_(_Global_critical_region_
)
322 FatProcessException (
323 IN PIRP_CONTEXT IrpContext
,
325 IN NTSTATUS ExceptionCode
332 This routine process an exception. It either completes the request
333 with the saved exception status or it sends it off to IoRaiseHardError()
337 Irp - Supplies the Irp being processed
339 ExceptionCode - Supplies the normalized exception status being handled
343 NTSTATUS - Returns the results of either posting the Irp or the
344 saved completion status.
350 PIO_STACK_LOCATION IrpSp
;
351 FAT_VOLUME_STATE TransitionState
= VolumeDirty
;
352 ULONG SavedFlags
= 0;
356 DebugTrace(0, Dbg
, "FatProcessException\n", 0);
359 // If there is not an irp context, we must have had insufficient resources.
362 if ( !ARGUMENT_PRESENT( IrpContext
) ) {
364 FatCompleteRequest( FatNull
, Irp
, ExceptionCode
);
366 return ExceptionCode
;
370 // Get the real exception status from IrpContext->ExceptionStatus, and
374 ExceptionCode
= IrpContext
->ExceptionStatus
;
375 FatResetExceptionState( IrpContext
);
378 // If this is an Mdl write request, then take care of the Mdl
379 // here so that things get cleaned up properly. Cc now leaves
380 // the MDL in place so a filesystem can retry after clearing an
381 // internal condition (FAT does not).
384 if ((IrpContext
->MajorFunction
== IRP_MJ_WRITE
) &&
385 (FlagOn( IrpContext
->MinorFunction
, IRP_MN_COMPLETE_MDL
) == IRP_MN_COMPLETE_MDL
) &&
386 (Irp
->MdlAddress
!= NULL
)) {
388 PIO_STACK_LOCATION LocalIrpSp
= IoGetCurrentIrpStackLocation(Irp
);
390 CcMdlWriteAbort( LocalIrpSp
->FileObject
, Irp
->MdlAddress
);
391 Irp
->MdlAddress
= NULL
;
395 // If we are going to post the request, we may have to lock down the
396 // user's buffer, so do it here in a try except so that we failed the
397 // request if the LockPages fails.
399 // Also unpin any repinned Bcbs, protected by the try {} except {} filter.
404 SavedFlags
= IrpContext
->Flags
;
407 // Make sure we don't try to write through Bcbs
410 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH
);
412 FatUnpinRepinnedBcbs( IrpContext
);
414 IrpContext
->Flags
= SavedFlags
;
417 // If we will have to post the request, do it here. Note
418 // that the last thing FatPrePostIrp() does is mark the Irp pending,
419 // so it is critical that we actually return PENDING. Nothing
420 // from this point to return can fail, so we are OK.
422 // We cannot do a verify operations at APC level because we
423 // have to wait for Io operations to complete.
426 if (!FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_RECURSIVE_CALL
) &&
427 #if (NTDDI_VERSION >= NTDDI_VISTA)
428 (((ExceptionCode
== STATUS_VERIFY_REQUIRED
) && KeAreAllApcsDisabled()) ||
430 (((ExceptionCode
== STATUS_VERIFY_REQUIRED
) && (KeGetCurrentIrql() >= APC_LEVEL
)) ||
432 (ExceptionCode
== STATUS_CANT_WAIT
))) {
434 ExceptionCode
= FatFsdPostRequest( IrpContext
, Irp
);
437 } _SEH2_EXCEPT( FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() ) ) {
439 ExceptionCode
= IrpContext
->ExceptionStatus
;
440 IrpContext
->ExceptionStatus
= 0;
442 IrpContext
->Flags
= SavedFlags
;
446 // If we posted the request, just return here.
449 if (ExceptionCode
== STATUS_PENDING
) {
451 return ExceptionCode
;
454 Irp
->IoStatus
.Status
= ExceptionCode
;
458 // If this request is not a "top-level" irp, just complete it.
461 if (FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_RECURSIVE_CALL
)) {
464 // If there is a cache operation above us, commute verify
465 // to a lock conflict. This will cause retries so that
466 // we have a chance of getting through without needing
467 // to return an unaesthetic error for the operation.
470 if (IoGetTopLevelIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
&&
471 ExceptionCode
== STATUS_VERIFY_REQUIRED
) {
473 ExceptionCode
= STATUS_FILE_LOCK_CONFLICT
;
476 FatCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
478 return ExceptionCode
;
481 if (IoIsErrorUserInduced(ExceptionCode
)) {
484 // Check for the various error conditions that can be caused by,
485 // and possibly resolved by the user.
488 if (ExceptionCode
== STATUS_VERIFY_REQUIRED
) {
490 PDEVICE_OBJECT Device
= NULL
;
492 DebugTrace(0, Dbg
, "Perform Verify Operation\n", 0);
495 // Now we are at the top level file system entry point.
497 // Grab the device to verify from the thread local storage
498 // and stick it in the information field for transportation
499 // to the fsp. We also clear the field at this time.
502 Device
= IoGetDeviceToVerify( Irp
->Tail
.Overlay
.Thread
);
503 IoSetDeviceToVerify( Irp
->Tail
.Overlay
.Thread
, NULL
);
505 if ( Device
== NULL
) {
507 Device
= IoGetDeviceToVerify( PsGetCurrentThread() );
508 IoSetDeviceToVerify( PsGetCurrentThread(), NULL
);
510 NT_ASSERT( Device
!= NULL
);
514 // It turns out some storage drivers really do set invalid non-NULL device
515 // objects to verify.
517 // To work around this, completely ignore the device to verify in the thread,
518 // and just use our real device object instead.
521 if (IrpContext
->Vcb
) {
523 Device
= IrpContext
->Vcb
->Vpb
->RealDevice
;
528 // For FSCTLs, IrpContext->Vcb may not be populated, so get the IrpContext->RealDevice instead
531 Device
= IrpContext
->RealDevice
;
535 // Let's not BugCheck just because the device to verify is somehow still NULL.
538 if (Device
== NULL
) {
540 ExceptionCode
= STATUS_DRIVER_INTERNAL_ERROR
;
542 FatCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
544 return ExceptionCode
;
548 // FatPerformVerify() will do the right thing with the Irp.
550 return FatPerformVerify( IrpContext
, Irp
, Device
);
554 // The other user induced conditions generate an error unless
555 // they have been disabled for this request.
558 if (FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
)) {
560 FatCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
562 return ExceptionCode
;
570 PDEVICE_OBJECT RealDevice
= NULL
;
574 if (IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
) {
576 Vpb
= IoGetCurrentIrpStackLocation(Irp
)->FileObject
->Vpb
;
584 // The device to verify is either in my thread local storage
585 // or that of the thread that owns the Irp.
588 Thread
= Irp
->Tail
.Overlay
.Thread
;
589 RealDevice
= IoGetDeviceToVerify( Thread
);
591 if ( RealDevice
== NULL
) {
593 Thread
= PsGetCurrentThread();
594 RealDevice
= IoGetDeviceToVerify( Thread
);
596 NT_ASSERT( RealDevice
!= NULL
);
600 // It turns out some storage drivers really do set invalid non-NULL device
601 // objects to verify.
603 // To work around this, completely ignore the device to verify in the thread,
604 // and just use our real device object instead.
607 if (IrpContext
->Vcb
) {
609 RealDevice
= IrpContext
->Vcb
->Vpb
->RealDevice
;
614 // For FSCTLs, IrpContext->Vcb may not be populated, so get the IrpContext->RealDevice instead
617 RealDevice
= IrpContext
->RealDevice
;
621 // Let's not BugCheck just because the device to verify is somehow still NULL.
624 if (RealDevice
== NULL
) {
626 FatCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
628 return ExceptionCode
;
632 // This routine actually causes the pop-up. It usually
633 // does this by queuing an APC to the callers thread,
634 // but in some cases it will complete the request immediately,
635 // so it is very important to IoMarkIrpPending() first.
638 IoMarkIrpPending( Irp
);
639 IoRaiseHardError( Irp
, Vpb
, RealDevice
);
642 // We will be handing control back to the caller here, so
643 // reset the saved device object.
646 IoSetDeviceToVerify( Thread
, NULL
);
649 // The Irp will be completed by Io or resubmitted. In either
650 // case we must clean up the IrpContext here.
653 FatDeleteIrpContext( IrpContext
);
654 return STATUS_PENDING
;
659 // This is just a run of the mill error. If is a STATUS that we
660 // raised ourselves, and the information would be use for the
661 // user, raise an informational pop-up.
664 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
665 Vcb
= IrpContext
->Vcb
;
668 // Now, if the Vcb is unknown to us this means that the error was raised
669 // in the process of a mount and before we even had a chance to build
670 // a full Vcb - and was really handled there.
675 if ( !FatDeviceIsFatFsdo( IrpSp
->DeviceObject
) &&
676 !NT_SUCCESS(ExceptionCode
) &&
677 !FsRtlIsTotalDeviceFailure(ExceptionCode
) ) {
679 TransitionState
= VolumeDirtyWithSurfaceTest
;
683 // If this was a STATUS_FILE_CORRUPT or similar error indicating some
684 // nastiness out on the media, then mark the volume permanently dirty.
687 if (!FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
) &&
688 ( TransitionState
== VolumeDirtyWithSurfaceTest
||
689 (ExceptionCode
== STATUS_FILE_CORRUPT_ERROR
) ||
690 (ExceptionCode
== STATUS_DISK_CORRUPT_ERROR
) ||
691 (ExceptionCode
== STATUS_EA_CORRUPT_ERROR
) ||
692 (ExceptionCode
== STATUS_INVALID_EA_NAME
) ||
693 (ExceptionCode
== STATUS_EA_LIST_INCONSISTENT
) ||
694 (ExceptionCode
== STATUS_NO_EAS_ON_FILE
) )) {
696 NT_ASSERT( NodeType(Vcb
) == FAT_NTC_VCB
);
697 NT_ASSERT( !FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_RECURSIVE_CALL
));
699 SetFlag( Vcb
->VcbState
, VCB_STATE_FLAG_MOUNTED_DIRTY
);
700 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
703 // Do the "dirty" work, ignoring any error. We need to take the Vcb here
704 // to synchronize against the verify path tearing things down, since
705 // we dropped all synchronization when backing up due to the exception.
708 FatAcquireExclusiveVcbNoOpCheck( IrpContext
, Vcb
);
712 if (VcbGood
== Vcb
->VcbCondition
) {
714 FatMarkVolume( IrpContext
, Vcb
, TransitionState
);
717 _SEH2_EXCEPT( FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() ) ) {
722 FatReleaseVcb( IrpContext
, Vcb
);
726 FatCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
728 return ExceptionCode
;
733 FatCompleteRequest_Real (
734 IN PIRP_CONTEXT IrpContext OPTIONAL
,
735 IN PIRP Irp OPTIONAL
,
743 This routine completes a Irp
747 Irp - Supplies the Irp being processed
749 Status - Supplies the status to complete the Irp with
761 if ( (FatBreakOnInterestingIrpCompletion
!= 0) && (Status
== FatBreakOnInterestingIrpCompletion
) ) {
768 // If we have an Irp Context then unpin all of the repinned bcbs
769 // we might have collected.
772 if (IrpContext
!= NULL
) {
774 NT_ASSERT( IrpContext
->Repinned
.Bcb
[0] == NULL
);
776 FatUnpinRepinnedBcbs( IrpContext
);
780 // Delete the Irp context before completing the IRP so if
781 // we run into some of the asserts, we can still backtrack
785 if (IrpContext
!= NULL
) {
787 FatDeleteIrpContext( IrpContext
);
791 // If we have an Irp then complete the irp.
797 // We got an error, so zero out the information field before
798 // completing the request if this was an input operation.
799 // Otherwise IopCompleteRequest will try to copy to the user's buffer.
802 if ( NT_ERROR(Status
) &&
803 FlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
) ) {
805 Irp
->IoStatus
.Information
= 0;
808 Irp
->IoStatus
.Status
= Status
;
810 IoCompleteRequest( Irp
, IO_DISK_INCREMENT
);
825 This routine detects if an Irp is the Top level requestor, ie. if it os OK
826 to do a verify or pop-up now. If TRUE is returned, then no file system
827 resources are held above us.
831 Irp - Supplies the Irp being processed
833 Status - Supplies the status to complete the Irp with
844 if ( IoGetTopLevelIrp() == NULL
) {
846 IoSetTopLevelIrp( Irp
);
857 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE
)\f
860 FatFastIoCheckIfPossible (
861 IN PFILE_OBJECT FileObject
,
862 IN PLARGE_INTEGER FileOffset
,
866 IN BOOLEAN CheckForReadOperation
,
867 OUT PIO_STATUS_BLOCK IoStatus
,
868 IN PDEVICE_OBJECT DeviceObject
875 This routine checks if fast i/o is possible for a read/write operation
879 FileObject - Supplies the file object used in the query
881 FileOffset - Supplies the starting byte offset for the read/write operation
883 Length - Supplies the length, in bytes, of the read/write operation
885 Wait - Indicates if we can wait
887 LockKey - Supplies the lock key
889 CheckForReadOperation - Indicates if this is a check for a read or write
892 IoStatus - Receives the status of the operation if our return value is
897 BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs
898 to take the long route.
907 LARGE_INTEGER LargeLength
;
911 UNREFERENCED_PARAMETER( DeviceObject
);
912 UNREFERENCED_PARAMETER( IoStatus
);
913 UNREFERENCED_PARAMETER( Wait
);
915 // Decode the file object to get our fcb, the only one we want
916 // to deal with is a UserFileOpen
919 if (FatDecodeFileObject( FileObject
, &Vcb
, &Fcb
, &Ccb
) != UserFileOpen
) {
924 LargeLength
.QuadPart
= Length
;
927 // Based on whether this is a read or write operation we call
928 // fsrtl check for read/write
931 if (CheckForReadOperation
) {
933 if (FsRtlFastCheckLockForRead( &Fcb
->Specific
.Fcb
.FileLock
,
938 PsGetCurrentProcess() )) {
947 // Also check for a write-protected volume here.
950 if (!FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
) &&
951 FsRtlFastCheckLockForWrite( &Fcb
->Specific
.Fcb
.FileLock
,
956 PsGetCurrentProcess() )) {
966 _Function_class_(FAST_IO_QUERY_BASIC_INFO
) \f
969 FatFastQueryBasicInfo (
970 IN PFILE_OBJECT FileObject
,
972 IN OUT PFILE_BASIC_INFORMATION Buffer
,
973 OUT PIO_STATUS_BLOCK IoStatus
,
974 IN PDEVICE_OBJECT DeviceObject
981 This routine is for the fast query call for basic file information.
985 FileObject - Supplies the file object used in this operation
987 Wait - Indicates if we are allowed to wait for the information
989 Buffer - Supplies the output buffer to receive the basic information
991 IoStatus - Receives the final status of the operation
995 BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
996 needs to take the long route.
1001 BOOLEAN Results
= FALSE
;
1002 IRP_CONTEXT IrpContext
;
1004 TYPE_OF_OPEN TypeOfOpen
;
1009 BOOLEAN FcbAcquired
= FALSE
;
1012 UNREFERENCED_PARAMETER( DeviceObject
);
1015 // Prepare the dummy irp context
1018 RtlZeroMemory( &IrpContext
, sizeof(IRP_CONTEXT
) );
1019 IrpContext
.NodeTypeCode
= FAT_NTC_IRP_CONTEXT
;
1020 IrpContext
.NodeByteSize
= sizeof(IRP_CONTEXT
);
1024 SetFlag(IrpContext
.Flags
, IRP_CONTEXT_FLAG_WAIT
);
1028 ClearFlag(IrpContext
.Flags
, IRP_CONTEXT_FLAG_WAIT
);
1032 // Determine the type of open for the input file object and only accept
1033 // the user file or directory open
1036 TypeOfOpen
= FatDecodeFileObject( FileObject
, &Vcb
, &Fcb
, &Ccb
);
1038 if ((TypeOfOpen
!= UserFileOpen
) && (TypeOfOpen
!= UserDirectoryOpen
)) {
1043 FsRtlEnterFileSystem();
1046 // Get access to the Fcb but only if it is not the paging file
1049 if (!FlagOn( Fcb
->FcbState
, FCB_STATE_PAGING_FILE
)) {
1051 if (!ExAcquireResourceSharedLite( Fcb
->Header
.Resource
, Wait
)) {
1053 FsRtlExitFileSystem();
1063 // If the Fcb is not in a good state, return FALSE.
1066 if (Fcb
->FcbCondition
!= FcbGood
) {
1068 try_return( Results
);
1071 Buffer
->FileAttributes
= 0;
1074 // If the fcb is not the root dcb then we will fill in the
1075 // buffer otherwise it is all setup for us.
1078 if (NodeType(Fcb
) != FAT_NTC_ROOT_DCB
) {
1081 // Extract the data and fill in the non zero fields of the output
1085 Buffer
->LastWriteTime
= Fcb
->LastWriteTime
;
1086 Buffer
->CreationTime
= Fcb
->CreationTime
;
1087 Buffer
->LastAccessTime
= Fcb
->LastAccessTime
;
1090 // Zero out the field we don't support.
1093 Buffer
->ChangeTime
.QuadPart
= 0;
1094 Buffer
->FileAttributes
= Fcb
->DirentFatFlags
;
1098 Buffer
->LastWriteTime
.QuadPart
= 0;
1099 Buffer
->CreationTime
.QuadPart
= 0;
1100 Buffer
->LastAccessTime
.QuadPart
= 0;
1101 Buffer
->ChangeTime
.QuadPart
= 0;
1103 Buffer
->FileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
1108 // If the temporary flag is set, then set it in the buffer.
1111 if (FlagOn( Fcb
->FcbState
, FCB_STATE_TEMPORARY
)) {
1113 SetFlag( Buffer
->FileAttributes
, FILE_ATTRIBUTE_TEMPORARY
);
1117 // If no attributes were set, set the normal bit.
1120 if (Buffer
->FileAttributes
== 0) {
1122 Buffer
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
1125 IoStatus
->Status
= STATUS_SUCCESS
;
1126 IoStatus
->Information
= sizeof(FILE_BASIC_INFORMATION
);
1133 if (FcbAcquired
) { ExReleaseResourceLite( Fcb
->Header
.Resource
); }
1135 FsRtlExitFileSystem();
1139 // And return to our caller
1146 _Function_class_(FAST_IO_QUERY_STANDARD_INFO
)\f
1149 FatFastQueryStdInfo (
1150 IN PFILE_OBJECT FileObject
,
1152 IN OUT PFILE_STANDARD_INFORMATION Buffer
,
1153 OUT PIO_STATUS_BLOCK IoStatus
,
1154 IN PDEVICE_OBJECT DeviceObject
1159 Routine Description:
1161 This routine is for the fast query call for standard file information.
1165 FileObject - Supplies the file object used in this operation
1167 Wait - Indicates if we are allowed to wait for the information
1169 Buffer - Supplies the output buffer to receive the basic information
1171 IoStatus - Receives the final status of the operation
1175 BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
1176 needs to take the long route.
1181 BOOLEAN Results
= FALSE
;
1182 IRP_CONTEXT IrpContext
;
1184 TYPE_OF_OPEN TypeOfOpen
;
1189 BOOLEAN FcbAcquired
= FALSE
;
1193 UNREFERENCED_PARAMETER( DeviceObject
);
1196 // Prepare the dummy irp context
1199 RtlZeroMemory( &IrpContext
, sizeof(IRP_CONTEXT
) );
1200 IrpContext
.NodeTypeCode
= FAT_NTC_IRP_CONTEXT
;
1201 IrpContext
.NodeByteSize
= sizeof(IRP_CONTEXT
);
1205 SetFlag(IrpContext
.Flags
, IRP_CONTEXT_FLAG_WAIT
);
1209 ClearFlag(IrpContext
.Flags
, IRP_CONTEXT_FLAG_WAIT
);
1213 // Determine the type of open for the input file object and only accept
1214 // the user file or directory open
1217 TypeOfOpen
= FatDecodeFileObject( FileObject
, &Vcb
, &Fcb
, &Ccb
);
1219 if ((TypeOfOpen
!= UserFileOpen
) && (TypeOfOpen
!= UserDirectoryOpen
)) {
1225 // Get access to the Fcb but only if it is not the paging file
1228 FsRtlEnterFileSystem();
1230 if (!FlagOn( Fcb
->FcbState
, FCB_STATE_PAGING_FILE
)) {
1232 if (!ExAcquireResourceSharedLite( Fcb
->Header
.Resource
, Wait
)) {
1234 FsRtlExitFileSystem();
1244 // If the Fcb is not in a good state, return FALSE.
1247 if (Fcb
->FcbCondition
!= FcbGood
) {
1249 try_return( Results
);
1252 Buffer
->NumberOfLinks
= 1;
1253 Buffer
->DeletePending
= BooleanFlagOn( Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
);
1256 // Case on whether this is a file or a directory, and extract
1257 // the information and fill in the fcb/dcb specific parts
1258 // of the output buffer.
1261 if (NodeType(Fcb
) == FAT_NTC_FCB
) {
1264 // If we don't alread know the allocation size, we cannot look
1265 // it up in the fast path.
1268 if (Fcb
->Header
.AllocationSize
.QuadPart
== FCB_LOOKUP_ALLOCATIONSIZE_HINT
) {
1270 try_return( Results
);
1273 Buffer
->AllocationSize
= Fcb
->Header
.AllocationSize
;
1274 Buffer
->EndOfFile
= Fcb
->Header
.FileSize
;
1276 Buffer
->Directory
= FALSE
;
1280 Buffer
->AllocationSize
= FatLargeZero
;
1281 Buffer
->EndOfFile
= FatLargeZero
;
1283 Buffer
->Directory
= TRUE
;
1286 IoStatus
->Status
= STATUS_SUCCESS
;
1287 IoStatus
->Information
= sizeof(FILE_STANDARD_INFORMATION
);
1294 if (FcbAcquired
) { ExReleaseResourceLite( Fcb
->Header
.Resource
); }
1296 FsRtlExitFileSystem();
1300 // And return to our caller
1307 _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO
)
1310 FatFastQueryNetworkOpenInfo (
1311 IN PFILE_OBJECT FileObject
,
1313 IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer
,
1314 OUT PIO_STATUS_BLOCK IoStatus
,
1315 IN PDEVICE_OBJECT DeviceObject
1320 Routine Description:
1322 This routine is for the fast query call for network open information.
1326 FileObject - Supplies the file object used in this operation
1328 Wait - Indicates if we are allowed to wait for the information
1330 Buffer - Supplies the output buffer to receive the information
1332 IoStatus - Receives the final status of the operation
1336 BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
1337 needs to take the long route.
1342 BOOLEAN Results
= FALSE
;
1343 IRP_CONTEXT IrpContext
;
1345 TYPE_OF_OPEN TypeOfOpen
;
1350 BOOLEAN FcbAcquired
= FALSE
;
1354 UNREFERENCED_PARAMETER( DeviceObject
);
1357 // Prepare the dummy irp context
1360 RtlZeroMemory( &IrpContext
, sizeof(IRP_CONTEXT
) );
1361 IrpContext
.NodeTypeCode
= FAT_NTC_IRP_CONTEXT
;
1362 IrpContext
.NodeByteSize
= sizeof(IRP_CONTEXT
);
1366 SetFlag(IrpContext
.Flags
, IRP_CONTEXT_FLAG_WAIT
);
1370 ClearFlag(IrpContext
.Flags
, IRP_CONTEXT_FLAG_WAIT
);
1374 // Determine the type of open for the input file object and only accept
1375 // the user file or directory open
1378 TypeOfOpen
= FatDecodeFileObject( FileObject
, &Vcb
, &Fcb
, &Ccb
);
1380 if ((TypeOfOpen
!= UserFileOpen
) && (TypeOfOpen
!= UserDirectoryOpen
)) {
1385 FsRtlEnterFileSystem();
1388 // Get access to the Fcb but only if it is not the paging file
1391 if (!FlagOn( Fcb
->FcbState
, FCB_STATE_PAGING_FILE
)) {
1393 if (!ExAcquireResourceSharedLite( Fcb
->Header
.Resource
, Wait
)) {
1395 FsRtlExitFileSystem();
1405 // If the Fcb is not in a good state, return FALSE.
1408 if (Fcb
->FcbCondition
!= FcbGood
) {
1410 try_return( Results
);
1414 // Extract the data and fill in the non zero fields of the output
1419 // Default the field we don't support to a reasonable value.
1422 ExLocalTimeToSystemTime( &FatJanOne1980
,
1423 &Buffer
->ChangeTime
);
1425 Buffer
->FileAttributes
= Fcb
->DirentFatFlags
;
1427 if (Fcb
->Header
.NodeTypeCode
== FAT_NTC_ROOT_DCB
) {
1430 // Reuse the default for the root dir.
1433 Buffer
->CreationTime
=
1434 Buffer
->LastAccessTime
=
1435 Buffer
->LastWriteTime
= Buffer
->ChangeTime
;
1439 Buffer
->LastWriteTime
= Fcb
->LastWriteTime
;
1440 Buffer
->CreationTime
= Fcb
->CreationTime
;
1441 Buffer
->LastAccessTime
= Fcb
->LastAccessTime
;
1446 // If the temporary flag is set, then set it in the buffer.
1449 if (FlagOn( Fcb
->FcbState
, FCB_STATE_TEMPORARY
)) {
1451 SetFlag( Buffer
->FileAttributes
, FILE_ATTRIBUTE_TEMPORARY
);
1457 // If no attributes were set, set the normal bit.
1460 if (Buffer
->FileAttributes
== 0) {
1462 Buffer
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
1465 if (NodeType(Fcb
) == FAT_NTC_FCB
) {
1468 // If we don't already know the allocation size, we cannot
1469 // lock it up in the fast path.
1472 if (Fcb
->Header
.AllocationSize
.QuadPart
== FCB_LOOKUP_ALLOCATIONSIZE_HINT
) {
1474 try_return( Results
);
1477 Buffer
->AllocationSize
= Fcb
->Header
.AllocationSize
;
1478 Buffer
->EndOfFile
= Fcb
->Header
.FileSize
;
1482 Buffer
->AllocationSize
= FatLargeZero
;
1483 Buffer
->EndOfFile
= FatLargeZero
;
1486 IoStatus
->Status
= STATUS_SUCCESS
;
1487 IoStatus
->Information
= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1494 if (FcbAcquired
) { ExReleaseResourceLite( Fcb
->Header
.Resource
); }
1496 FsRtlExitFileSystem();
1500 // And return to our caller
1506 _Requires_lock_held_(_Global_critical_region_
)
1508 FatPopUpFileCorrupt (
1509 IN PIRP_CONTEXT IrpContext
,
1515 Routine Description:
1517 The Following routine makes an informational popup that the file
1522 Fcb - The file that is corrupt.
1536 // Disable the popup on the root directory. It is important not
1537 // to generate them on objects which are part of the mount process.
1540 if (NodeType(Fcb
) == FAT_NTC_ROOT_DCB
) {
1546 // Got to grab the full filename now.
1549 if (Fcb
->FullFileName
.Buffer
== NULL
) {
1551 FatSetFullFileNameInFcb( IrpContext
, Fcb
);
1555 // We never want to block a system thread waiting for the user to
1559 if (IoIsSystemThread(IrpContext
->OriginatingIrp
->Tail
.Overlay
.Thread
)) {
1566 Thread
= IrpContext
->OriginatingIrp
->Tail
.Overlay
.Thread
;
1568 Thread
= (PKTHREAD
)IrpContext
->OriginatingIrp
->Tail
.Overlay
.Thread
;
1572 IoRaiseInformationalHardError( STATUS_FILE_CORRUPT_ERROR
,