1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     FatData.c
8 
9 Abstract:
10 
11     This module declares the global data used by the Fat file system.
12 
13 
14 --*/
15 
16 #include "fatprocs.h"
17 
18 //
19 //  The Bug check file id for this module
20 //
21 
22 #define BugCheckFileId                   (FAT_BUG_CHECK_FATDATA)
23 
24 //
25 //  The debug trace level
26 //
27 
28 #define Dbg                              (DEBUG_TRACE_CATCH_EXCEPTIONS)
29 
30 #ifdef ALLOC_PRAGMA
31 
32 #if DBG
33 #ifdef _MSC_VER
34 #pragma alloc_text(PAGE, FatBugCheckExceptionFilter)
35 #endif
36 #endif
37 
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)
46 #endif
47 
48 
49 //
50 //  The global fsd data record, and zero large integer
51 //
52 
53 #ifdef _MSC_VER
54 #pragma prefast( suppress:22112, "only applies to user mode processes" )
55 #endif
56 FAT_DATA FatData;
57 
58 PDEVICE_OBJECT FatDiskFileSystemDeviceObject;
59 PDEVICE_OBJECT FatCdromFileSystemDeviceObject;
60 
61 #ifndef __REACTOS__
62 LARGE_INTEGER FatLargeZero = {0,0};
63 LARGE_INTEGER FatMaxLarge = {MAXULONG,MAXLONG};
64 #else
65 LARGE_INTEGER FatLargeZero = {{0,0}};
66 LARGE_INTEGER FatMaxLarge = {{MAXULONG,MAXLONG}};
67 #endif
68 
69 #ifndef __REACTOS__
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};
75 #else
76 LARGE_INTEGER Fat30Milliseconds = {{(ULONG)(-30 * 1000 * 10), -1}};
77 LARGE_INTEGER Fat100Milliseconds = {{(ULONG)(-30 * 1000 * 10), -1}};
78 LARGE_INTEGER FatOneDay = {{0x2a69c000, 0xc9}};
79 LARGE_INTEGER FatJanOne1980 = {{0xe1d58000,0x01a8e79f}};
80 LARGE_INTEGER FatDecThirtyOne1979 = {{0xb76bc000,0x01a8e6d6}};
81 #endif
82 
83 FAT_TIME_STAMP FatTimeJanOne1980 = {{0,0,0},{1,1,0}};
84 
85 #ifndef __REACTOS__
86 LARGE_INTEGER FatMagic10000    = {0xe219652c, 0xd1b71758};
87 LARGE_INTEGER FatMagic86400000 = {0xfa67b90e, 0xc6d750eb};
88 #else
89 LARGE_INTEGER FatMagic10000    = {{0xe219652c, 0xd1b71758}};
90 LARGE_INTEGER FatMagic86400000 = {{0xfa67b90e, 0xc6d750eb}};
91 #endif
92 
93 #ifdef _MSC_VER
94 #pragma prefast( suppress:22112, "only applies to user mode processes" )
95 #endif
96 FAST_IO_DISPATCH FatFastIoDispatch;
97 
98 //
99 //  Our lookaside lists.
100 //
101 
102 NPAGED_LOOKASIDE_LIST FatIrpContextLookasideList;
103 NPAGED_LOOKASIDE_LIST FatNonPagedFcbLookasideList;
104 NPAGED_LOOKASIDE_LIST FatEResourceLookasideList;
105 
106 SLIST_HEADER FatCloseContextSList;
107 
108 //
109 //  Synchronization for the close queue
110 //
111 
112 FAST_MUTEX FatCloseQueueMutex;
113 
114 //
115 //  Reserve MDL for paging file operations.
116 //
117 
118 #ifndef __REACTOS__
119 PMDL FatReserveMdl = NULL;
120 #else
121 volatile PMDL FatReserveMdl = NULL;
122 #endif
123 KEVENT FatReserveEvent;
124 
125 //
126 //  Global disk accounting state, enabled or disabled
127 //
128 
129 LOGICAL FatDiskAccountingEnabled = FALSE;
130 
131 
132 #ifdef FASTFATDBG
133 
134 LONG FatDebugTraceLevel = 0x00000009;
135 LONG FatDebugTraceIndent = 0;
136 
137 ULONG FatFsdEntryCount = 0;
138 ULONG FatFspEntryCount = 0;
139 ULONG FatIoCallDriverCount = 0;
140 
141 LONG FatPerformanceTimerLevel = 0x00000000;
142 
143 ULONG FatTotalTicks[32] = { 0 };
144 
145 //
146 //  I need this because C can't support conditional compilation within
147 //  a macro.
148 //
149 
150 PVOID FatNull = NULL;
151 
152 #endif // FASTFATDBG
153 
154 #if DBG
155 
156 BOOLEAN FatTestRaisedStatus = FALSE;
157 
158 NTSTATUS FatBreakOnInterestingIoCompletion = STATUS_SUCCESS;
159 NTSTATUS FatBreakOnInterestingExceptionStatus = 0;
160 NTSTATUS FatBreakOnInterestingIrpCompletion = 0;
161 
162 #endif
163 
164 
165 #if DBG
166 ULONG
167 FatBugCheckExceptionFilter (
168     IN PEXCEPTION_POINTERS ExceptionPointer
169     )
170 
171 /*++
172 
173 Routine Description:
174 
175     An exception filter which acts as an assert that the exception should
176     never occur.
177 
178     This is only valid on debug builds, we don't want the overhead on retail.
179 
180 Arguments:
181 
182     ExceptionPointers - The result of GetExceptionInformation() in the context
183         of the exception.
184 
185 Return Value:
186 
187     Bugchecks.
188 
189 --*/
190 
191 {
192     PAGED_CODE();
193 
194     FatBugCheck( (ULONG_PTR)ExceptionPointer->ExceptionRecord,
195                  (ULONG_PTR)ExceptionPointer->ContextRecord,
196                  (ULONG_PTR)ExceptionPointer->ExceptionRecord->ExceptionAddress );
197 
198 //    return EXCEPTION_EXECUTE_HANDLER; // unreachable code
199 }
200 #endif
201 
202 
203 ULONG
204 FatExceptionFilter (
205     IN PIRP_CONTEXT IrpContext,
206     IN PEXCEPTION_POINTERS ExceptionPointer
207     )
208 
209 /*++
210 
211 Routine Description:
212 
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.
217 
218 Arguments:
219 
220     ExceptionPointers - The result of GetExceptionInformation() in the context
221         of the exception.
222 
223 Return Value:
224 
225     ULONG - returns EXCEPTION_EXECUTE_HANDLER or bugchecks
226 
227 --*/
228 
229 {
230     NTSTATUS ExceptionCode;
231 
232     ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
233     DebugTrace(0, DEBUG_TRACE_UNWIND, "FatExceptionFilter %X\n", ExceptionCode);
234     DebugDump("FatExceptionFilter\n", Dbg, NULL );
235 
236 #if DBG
237 
238     if( FatBreakOnInterestingExceptionStatus != 0 && ExceptionCode == FatBreakOnInterestingExceptionStatus ) {
239         DbgBreakPoint();
240     }
241 
242 #endif
243 
244     //
245     // If the exception is STATUS_IN_PAGE_ERROR, get the I/O error code
246     // from the exception record.
247     //
248 
249     if (ExceptionCode == STATUS_IN_PAGE_ERROR) {
250         if (ExceptionPointer->ExceptionRecord->NumberParameters >= 3) {
251             ExceptionCode = (NTSTATUS)ExceptionPointer->ExceptionRecord->ExceptionInformation[2];
252         }
253     }
254 
255     //
256     //  If there is not an irp context, we must have had insufficient resources.
257     //
258 
259     if ( !ARGUMENT_PRESENT( IrpContext ) ) {
260 
261         if (!FsRtlIsNtstatusExpected( ExceptionCode )) {
262 
263 #ifdef _MSC_VER
264 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
265 #endif
266             FatBugCheck( (ULONG_PTR)ExceptionPointer->ExceptionRecord,
267                          (ULONG_PTR)ExceptionPointer->ContextRecord,
268                          (ULONG_PTR)ExceptionPointer->ExceptionRecord->ExceptionAddress );
269         }
270 
271         return EXCEPTION_EXECUTE_HANDLER;
272     }
273 
274     //
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.
278     //
279 
280     SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
281 
282     if ( (ExceptionCode != STATUS_CANT_WAIT) &&
283          (ExceptionCode != STATUS_VERIFY_REQUIRED) ) {
284 
285         SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH);
286     }
287 
288     if ( IrpContext->ExceptionStatus == 0 ) {
289 
290         if (FsRtlIsNtstatusExpected( ExceptionCode )) {
291 
292             IrpContext->ExceptionStatus = ExceptionCode;
293 
294             return EXCEPTION_EXECUTE_HANDLER;
295 
296         } else {
297 
298 #ifdef _MSC_VER
299 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
300 #endif
301             FatBugCheck( (ULONG_PTR)ExceptionPointer->ExceptionRecord,
302                          (ULONG_PTR)ExceptionPointer->ContextRecord,
303                          (ULONG_PTR)ExceptionPointer->ExceptionRecord->ExceptionAddress );
304         }
305 
306     } else {
307 
308         //
309         //  We raised this code explicitly ourselves, so it had better be
310         //  expected.
311         //
312 
313         NT_ASSERT( IrpContext->ExceptionStatus == ExceptionCode );
314         NT_ASSERT( FsRtlIsNtstatusExpected( ExceptionCode ) );
315     }
316 
317     return EXCEPTION_EXECUTE_HANDLER;
318 }
319 
320 _Requires_lock_held_(_Global_critical_region_)
321 NTSTATUS
322 FatProcessException (
323     IN PIRP_CONTEXT IrpContext,
324     IN PIRP Irp,
325     IN NTSTATUS ExceptionCode
326     )
327 
328 /*++
329 
330 Routine Description:
331 
332     This routine process an exception.  It either completes the request
333     with the saved exception status or it sends it off to IoRaiseHardError()
334 
335 Arguments:
336 
337     Irp - Supplies the Irp being processed
338 
339     ExceptionCode - Supplies the normalized exception status being handled
340 
341 Return Value:
342 
343     NTSTATUS - Returns the results of either posting the Irp or the
344         saved completion status.
345 
346 --*/
347 
348 {
349     PVCB Vcb;
350     PIO_STACK_LOCATION IrpSp;
351     FAT_VOLUME_STATE TransitionState = VolumeDirty;
352     ULONG SavedFlags = 0;
353 
354     PAGED_CODE();
355 
356     DebugTrace(0, Dbg, "FatProcessException\n", 0);
357 
358     //
359     //  If there is not an irp context, we must have had insufficient resources.
360     //
361 
362     if ( !ARGUMENT_PRESENT( IrpContext ) ) {
363 
364         FatCompleteRequest( FatNull, Irp, ExceptionCode );
365 
366         return ExceptionCode;
367     }
368 
369     //
370     //  Get the real exception status from IrpContext->ExceptionStatus, and
371     //  reset it.
372     //
373 
374     ExceptionCode = IrpContext->ExceptionStatus;
375     FatResetExceptionState( IrpContext );
376 
377     //
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).
382     //
383 
384     if ((IrpContext->MajorFunction == IRP_MJ_WRITE) &&
385         (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE_MDL ) == IRP_MN_COMPLETE_MDL) &&
386         (Irp->MdlAddress != NULL)) {
387 
388         PIO_STACK_LOCATION LocalIrpSp = IoGetCurrentIrpStackLocation(Irp);
389 
390         CcMdlWriteAbort( LocalIrpSp->FileObject, Irp->MdlAddress );
391         Irp->MdlAddress = NULL;
392     }
393 
394     //
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.
398     //
399     //  Also unpin any repinned Bcbs, protected by the try {} except {} filter.
400     //
401 
402     _SEH2_TRY {
403 
404         SavedFlags = IrpContext->Flags;
405 
406         //
407         //  Make sure we don't try to write through Bcbs
408         //
409 
410         SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH);
411 
412         FatUnpinRepinnedBcbs( IrpContext );
413 
414         IrpContext->Flags = SavedFlags;
415 
416         //
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.
421         //
422         //  We cannot do a verify operations at APC level because we
423         //  have to wait for Io operations to complete.
424         //
425 
426         if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) &&
427 #if (NTDDI_VERSION >= NTDDI_VISTA)
428             (((ExceptionCode == STATUS_VERIFY_REQUIRED) && KeAreAllApcsDisabled()) ||
429 #else
430             (((ExceptionCode == STATUS_VERIFY_REQUIRED) && (KeGetCurrentIrql() >= APC_LEVEL)) ||
431 #endif
432              (ExceptionCode == STATUS_CANT_WAIT))) {
433 
434             ExceptionCode = FatFsdPostRequest( IrpContext, Irp );
435         }
436 
437     } _SEH2_EXCEPT( FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() ) ) {
438 
439         ExceptionCode = IrpContext->ExceptionStatus;
440         IrpContext->ExceptionStatus = 0;
441 
442         IrpContext->Flags = SavedFlags;
443     } _SEH2_END;
444 
445     //
446     //  If we posted the request, just return here.
447     //
448 
449     if (ExceptionCode == STATUS_PENDING) {
450 
451         return ExceptionCode;
452     }
453 
454     Irp->IoStatus.Status = ExceptionCode;
455 
456 
457     //
458     //  If this request is not a "top-level" irp, just complete it.
459     //
460 
461     if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL)) {
462 
463         //
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.
468         //
469 
470         if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP &&
471             ExceptionCode == STATUS_VERIFY_REQUIRED) {
472 
473             ExceptionCode = STATUS_FILE_LOCK_CONFLICT;
474         }
475 
476         FatCompleteRequest( IrpContext, Irp, ExceptionCode );
477 
478         return ExceptionCode;
479     }
480 
481     if (IoIsErrorUserInduced(ExceptionCode)) {
482 
483         //
484         //  Check for the various error conditions that can be caused by,
485         //  and possibly resolved by the user.
486         //
487 
488         if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
489 
490             PDEVICE_OBJECT Device = NULL;
491 
492             DebugTrace(0, Dbg, "Perform Verify Operation\n", 0);
493 
494             //
495             //  Now we are at the top level file system entry point.
496             //
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.
500             //
501 
502             Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread );
503             IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL );
504 
505             if ( Device == NULL ) {
506 
507                 Device = IoGetDeviceToVerify( PsGetCurrentThread() );
508                 IoSetDeviceToVerify( PsGetCurrentThread(), NULL );
509 
510                 NT_ASSERT( Device != NULL );
511             }
512 
513             //
514             //  It turns out some storage drivers really do set invalid non-NULL device
515             //  objects to verify.
516             //
517             //  To work around this, completely ignore the device to verify in the thread,
518             //  and just use our real device object instead.
519             //
520 
521             if (IrpContext->Vcb) {
522 
523                 Device = IrpContext->Vcb->Vpb->RealDevice;
524 
525             } else {
526 
527                 //
528                 // For FSCTLs, IrpContext->Vcb may not be populated, so get the IrpContext->RealDevice instead
529                 //
530 
531                 Device = IrpContext->RealDevice;
532             }
533 
534             //
535             //  Let's not BugCheck just because the device to verify is somehow still NULL.
536             //
537 
538             if (Device == NULL) {
539 
540                 ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR;
541 
542                 FatCompleteRequest( IrpContext, Irp, ExceptionCode );
543 
544                 return ExceptionCode;
545             }
546 
547             //
548             //  FatPerformVerify() will do the right thing with the Irp.
549 
550             return FatPerformVerify( IrpContext, Irp, Device );
551         }
552 
553         //
554         //  The other user induced conditions generate an error unless
555         //  they have been disabled for this request.
556         //
557 
558         if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS)) {
559 
560             FatCompleteRequest( IrpContext, Irp, ExceptionCode );
561 
562             return ExceptionCode;
563 
564         } else {
565 
566             //
567             //  Generate a pop-up
568             //
569 
570             PDEVICE_OBJECT RealDevice = NULL;
571             PVPB Vpb;
572             PETHREAD Thread;
573 
574             if (IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL) {
575 
576                 Vpb = IoGetCurrentIrpStackLocation(Irp)->FileObject->Vpb;
577 
578             } else {
579 
580                 Vpb = NULL;
581             }
582 
583             //
584             //  The device to verify is either in my thread local storage
585             //  or that of the thread that owns the Irp.
586             //
587 
588             Thread = Irp->Tail.Overlay.Thread;
589             RealDevice = IoGetDeviceToVerify( Thread );
590 
591             if ( RealDevice == NULL ) {
592 
593                 Thread = PsGetCurrentThread();
594                 RealDevice = IoGetDeviceToVerify( Thread );
595 
596                 NT_ASSERT( RealDevice != NULL );
597             }
598 
599             //
600             //  It turns out some storage drivers really do set invalid non-NULL device
601             //  objects to verify.
602             //
603             //  To work around this, completely ignore the device to verify in the thread,
604             //  and just use our real device object instead.
605             //
606 
607             if (IrpContext->Vcb) {
608 
609                 RealDevice = IrpContext->Vcb->Vpb->RealDevice;
610 
611             } else {
612 
613                 //
614                 // For FSCTLs, IrpContext->Vcb may not be populated, so get the IrpContext->RealDevice instead
615                 //
616 
617                 RealDevice = IrpContext->RealDevice;
618             }
619 
620             //
621             //  Let's not BugCheck just because the device to verify is somehow still NULL.
622             //
623 
624             if (RealDevice == NULL) {
625 
626                 FatCompleteRequest( IrpContext, Irp, ExceptionCode );
627 
628                 return ExceptionCode;
629             }
630 
631             //
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.
636             //
637 
638             IoMarkIrpPending( Irp );
639             IoRaiseHardError( Irp, Vpb, RealDevice );
640 
641             //
642             //  We will be handing control back to the caller here, so
643             //  reset the saved device object.
644             //
645 
646             IoSetDeviceToVerify( Thread, NULL );
647 
648             //
649             //  The Irp will be completed by Io or resubmitted.  In either
650             //  case we must clean up the IrpContext here.
651             //
652 
653             FatDeleteIrpContext( IrpContext );
654             return STATUS_PENDING;
655         }
656     }
657 
658     //
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.
662     //
663 
664     IrpSp = IoGetCurrentIrpStackLocation( Irp );
665     Vcb = IrpContext->Vcb;
666 
667     //
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.
671     //
672 
673     if (Vcb != NULL) {
674 
675         if ( !FatDeviceIsFatFsdo( IrpSp->DeviceObject) &&
676              !NT_SUCCESS(ExceptionCode) &&
677              !FsRtlIsTotalDeviceFailure(ExceptionCode) ) {
678 
679             TransitionState = VolumeDirtyWithSurfaceTest;
680         }
681 
682         //
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.
685         //
686 
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) )) {
695 
696             NT_ASSERT( NodeType(Vcb) == FAT_NTC_VCB );
697             NT_ASSERT( !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL));
698 
699             SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
700             SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
701 
702             //
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.
706             //
707 
708             FatAcquireExclusiveVcbNoOpCheck( IrpContext, Vcb);
709 
710             _SEH2_TRY {
711 
712                 if (VcbGood == Vcb->VcbCondition) {
713 
714                     FatMarkVolume( IrpContext, Vcb, TransitionState );
715                 }
716             }
717             _SEH2_EXCEPT( FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() ) ) {
718 
719                 NOTHING;
720             } _SEH2_END;
721 
722             FatReleaseVcb( IrpContext, Vcb);
723         }
724     }
725 
726     FatCompleteRequest( IrpContext, Irp, ExceptionCode );
727 
728     return ExceptionCode;
729 }
730 
731 
732 VOID
733 FatCompleteRequest_Real (
734     IN PIRP_CONTEXT IrpContext OPTIONAL,
735     IN PIRP Irp OPTIONAL,
736     IN NTSTATUS Status
737     )
738 
739 /*++
740 
741 Routine Description:
742 
743     This routine completes a Irp
744 
745 Arguments:
746 
747     Irp - Supplies the Irp being processed
748 
749     Status - Supplies the status to complete the Irp with
750 
751 Return Value:
752 
753     None.
754 
755 --*/
756 
757 {
758     PAGED_CODE();
759 
760 #if DBG
761     if ( (FatBreakOnInterestingIrpCompletion != 0) && (Status == FatBreakOnInterestingIrpCompletion) ) {
762         DbgBreakPoint();
763     }
764 
765 #endif
766 
767     //
768     //  If we have an Irp Context then unpin all of the repinned bcbs
769     //  we might have collected.
770     //
771 
772     if (IrpContext != NULL) {
773 
774         NT_ASSERT( IrpContext->Repinned.Bcb[0] == NULL );
775 
776         FatUnpinRepinnedBcbs( IrpContext );
777     }
778 
779     //
780     //  Delete the Irp context before completing the IRP so if
781     //  we run into some of the asserts, we can still backtrack
782     //  through the IRP.
783     //
784 
785     if (IrpContext != NULL) {
786 
787         FatDeleteIrpContext( IrpContext );
788     }
789 
790     //
791     //  If we have an Irp then complete the irp.
792     //
793 
794     if (Irp != NULL) {
795 
796         //
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.
800         //
801 
802         if ( NT_ERROR(Status) &&
803              FlagOn(Irp->Flags, IRP_INPUT_OPERATION) ) {
804 
805             Irp->IoStatus.Information = 0;
806         }
807 
808         Irp->IoStatus.Status = Status;
809 
810         IoCompleteRequest( Irp, IO_DISK_INCREMENT );
811     }
812 
813     return;
814 }
815 
816 BOOLEAN
817 FatIsIrpTopLevel (
818     IN PIRP Irp
819     )
820 
821 /*++
822 
823 Routine Description:
824 
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.
828 
829 Arguments:
830 
831     Irp - Supplies the Irp being processed
832 
833     Status - Supplies the status to complete the Irp with
834 
835 Return Value:
836 
837     None.
838 
839 --*/
840 
841 {
842     PAGED_CODE();
843 
844     if ( IoGetTopLevelIrp() == NULL ) {
845 
846         IoSetTopLevelIrp( Irp );
847 
848         return TRUE;
849 
850     } else {
851 
852         return FALSE;
853     }
854 }
855 
856 
857 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE)
858 BOOLEAN
859 NTAPI
860 FatFastIoCheckIfPossible (
861     IN PFILE_OBJECT FileObject,
862     IN PLARGE_INTEGER FileOffset,
863     IN ULONG Length,
864     IN BOOLEAN Wait,
865     IN ULONG LockKey,
866     IN BOOLEAN CheckForReadOperation,
867     OUT PIO_STATUS_BLOCK IoStatus,
868     IN PDEVICE_OBJECT DeviceObject
869     )
870 
871 /*++
872 
873 Routine Description:
874 
875     This routine checks if fast i/o is possible for a read/write operation
876 
877 Arguments:
878 
879     FileObject - Supplies the file object used in the query
880 
881     FileOffset - Supplies the starting byte offset for the read/write operation
882 
883     Length - Supplies the length, in bytes, of the read/write operation
884 
885     Wait - Indicates if we can wait
886 
887     LockKey - Supplies the lock key
888 
889     CheckForReadOperation - Indicates if this is a check for a read or write
890         operation
891 
892     IoStatus - Receives the status of the operation if our return value is
893         FastIoReturnError
894 
895 Return Value:
896 
897     BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs
898         to take the long route.
899 
900 --*/
901 
902 {
903     PVCB Vcb;
904     PFCB Fcb;
905     PCCB Ccb;
906 
907     LARGE_INTEGER LargeLength;
908 
909     PAGED_CODE();
910 
911     UNREFERENCED_PARAMETER( DeviceObject );
912     UNREFERENCED_PARAMETER( IoStatus );
913     UNREFERENCED_PARAMETER( Wait );
914     //
915     //  Decode the file object to get our fcb, the only one we want
916     //  to deal with is a UserFileOpen
917     //
918 
919     if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) {
920 
921         return FALSE;
922     }
923 
924     LargeLength.QuadPart = Length;
925 
926     //
927     //  Based on whether this is a read or write operation we call
928     //  fsrtl check for read/write
929     //
930 
931     if (CheckForReadOperation) {
932 
933         if (FsRtlFastCheckLockForRead( &Fcb->Specific.Fcb.FileLock,
934                                        FileOffset,
935                                        &LargeLength,
936                                        LockKey,
937                                        FileObject,
938                                        PsGetCurrentProcess() )) {
939 
940             return TRUE;
941         }
942 
943     } else {
944 
945 
946         //
947         //  Also check for a write-protected volume here.
948         //
949 
950         if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) &&
951             FsRtlFastCheckLockForWrite( &Fcb->Specific.Fcb.FileLock,
952                                         FileOffset,
953                                         &LargeLength,
954                                         LockKey,
955                                         FileObject,
956                                         PsGetCurrentProcess() )) {
957 
958             return TRUE;
959         }
960     }
961 
962     return FALSE;
963 }
964 
965 
966 _Function_class_(FAST_IO_QUERY_BASIC_INFO)
967 BOOLEAN
968 NTAPI
969 FatFastQueryBasicInfo (
970     IN PFILE_OBJECT FileObject,
971     IN BOOLEAN Wait,
972     IN OUT PFILE_BASIC_INFORMATION Buffer,
973     OUT PIO_STATUS_BLOCK IoStatus,
974     IN PDEVICE_OBJECT DeviceObject
975     )
976 
977 /*++
978 
979 Routine Description:
980 
981     This routine is for the fast query call for basic file information.
982 
983 Arguments:
984 
985     FileObject - Supplies the file object used in this operation
986 
987     Wait - Indicates if we are allowed to wait for the information
988 
989     Buffer - Supplies the output buffer to receive the basic information
990 
991     IoStatus - Receives the final status of the operation
992 
993 Return Value:
994 
995     BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
996         needs to take the long route.
997 
998 --*/
999 
1000 {
1001     BOOLEAN Results = FALSE;
1002     IRP_CONTEXT IrpContext;
1003 
1004     TYPE_OF_OPEN TypeOfOpen;
1005     PVCB Vcb;
1006     PFCB Fcb;
1007     PCCB Ccb;
1008 
1009     BOOLEAN FcbAcquired = FALSE;
1010 
1011     PAGED_CODE();
1012     UNREFERENCED_PARAMETER( DeviceObject );
1013 
1014     //
1015     //  Prepare the dummy irp context
1016     //
1017 
1018     RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
1019     IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT;
1020     IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
1021 
1022     if (Wait) {
1023 
1024         SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
1025 
1026     } else {
1027 
1028         ClearFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
1029     }
1030 
1031     //
1032     //  Determine the type of open for the input file object and only accept
1033     //  the user file or directory open
1034     //
1035 
1036     TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
1037 
1038     if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
1039 
1040         return Results;
1041     }
1042 
1043     FsRtlEnterFileSystem();
1044 
1045     //
1046     //  Get access to the Fcb but only if it is not the paging file
1047     //
1048 
1049     if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
1050 
1051         if (!ExAcquireResourceSharedLite( Fcb->Header.Resource, Wait )) {
1052 
1053             FsRtlExitFileSystem();
1054             return Results;
1055         }
1056 
1057         FcbAcquired = TRUE;
1058     }
1059 
1060     _SEH2_TRY {
1061 
1062         //
1063         //  If the Fcb is not in a good state, return FALSE.
1064         //
1065 
1066         if (Fcb->FcbCondition != FcbGood) {
1067 
1068             try_return( Results );
1069         }
1070 
1071         Buffer->FileAttributes = 0;
1072 
1073         //
1074         //  If the fcb is not the root dcb then we will fill in the
1075         //  buffer otherwise it is all setup for us.
1076         //
1077 
1078         if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) {
1079 
1080             //
1081             //  Extract the data and fill in the non zero fields of the output
1082             //  buffer
1083             //
1084 
1085             Buffer->LastWriteTime = Fcb->LastWriteTime;
1086             Buffer->CreationTime = Fcb->CreationTime;
1087             Buffer->LastAccessTime = Fcb->LastAccessTime;
1088 
1089             //
1090             //  Zero out the field we don't support.
1091             //
1092 
1093             Buffer->ChangeTime.QuadPart = 0;
1094             Buffer->FileAttributes = Fcb->DirentFatFlags;
1095 
1096         } else {
1097 
1098             Buffer->LastWriteTime.QuadPart = 0;
1099             Buffer->CreationTime.QuadPart = 0;
1100             Buffer->LastAccessTime.QuadPart = 0;
1101             Buffer->ChangeTime.QuadPart = 0;
1102 
1103             Buffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1104         }
1105 
1106 
1107         //
1108         //  If the temporary flag is set, then set it in the buffer.
1109         //
1110 
1111         if (FlagOn( Fcb->FcbState, FCB_STATE_TEMPORARY )) {
1112 
1113             SetFlag( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY );
1114         }
1115 
1116         //
1117         //  If no attributes were set, set the normal bit.
1118         //
1119 
1120         if (Buffer->FileAttributes == 0) {
1121 
1122             Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
1123         }
1124 
1125         IoStatus->Status = STATUS_SUCCESS;
1126         IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
1127 
1128         Results = TRUE;
1129 
1130     try_exit: NOTHING;
1131     } _SEH2_FINALLY {
1132 
1133         if (FcbAcquired) { ExReleaseResourceLite( Fcb->Header.Resource ); }
1134 
1135         FsRtlExitFileSystem();
1136     } _SEH2_END;
1137 
1138     //
1139     //  And return to our caller
1140     //
1141 
1142     return Results;
1143 }
1144 
1145 
1146 _Function_class_(FAST_IO_QUERY_STANDARD_INFO)
1147 BOOLEAN
1148 NTAPI
1149 FatFastQueryStdInfo (
1150     IN PFILE_OBJECT FileObject,
1151     IN BOOLEAN Wait,
1152     IN OUT PFILE_STANDARD_INFORMATION Buffer,
1153     OUT PIO_STATUS_BLOCK IoStatus,
1154     IN PDEVICE_OBJECT DeviceObject
1155     )
1156 
1157 /*++
1158 
1159 Routine Description:
1160 
1161     This routine is for the fast query call for standard file information.
1162 
1163 Arguments:
1164 
1165     FileObject - Supplies the file object used in this operation
1166 
1167     Wait - Indicates if we are allowed to wait for the information
1168 
1169     Buffer - Supplies the output buffer to receive the basic information
1170 
1171     IoStatus - Receives the final status of the operation
1172 
1173 Return Value:
1174 
1175     BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
1176         needs to take the long route.
1177 
1178 --*/
1179 
1180 {
1181     BOOLEAN Results = FALSE;
1182     IRP_CONTEXT IrpContext;
1183 
1184     TYPE_OF_OPEN TypeOfOpen;
1185     PVCB Vcb;
1186     PFCB Fcb;
1187     PCCB Ccb;
1188 
1189     BOOLEAN FcbAcquired = FALSE;
1190 
1191     PAGED_CODE();
1192 
1193     UNREFERENCED_PARAMETER( DeviceObject );
1194 
1195     //
1196     //  Prepare the dummy irp context
1197     //
1198 
1199     RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
1200     IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT;
1201     IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
1202 
1203     if (Wait) {
1204 
1205         SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
1206 
1207     } else {
1208 
1209         ClearFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
1210     }
1211 
1212     //
1213     //  Determine the type of open for the input file object and only accept
1214     //  the user file or directory open
1215     //
1216 
1217     TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
1218 
1219     if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
1220 
1221         return Results;
1222     }
1223 
1224     //
1225     //  Get access to the Fcb but only if it is not the paging file
1226     //
1227 
1228     FsRtlEnterFileSystem();
1229 
1230     if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
1231 
1232         if (!ExAcquireResourceSharedLite( Fcb->Header.Resource, Wait )) {
1233 
1234             FsRtlExitFileSystem();
1235             return Results;
1236         }
1237 
1238         FcbAcquired = TRUE;
1239     }
1240 
1241     _SEH2_TRY {
1242 
1243         //
1244         //  If the Fcb is not in a good state, return FALSE.
1245         //
1246 
1247         if (Fcb->FcbCondition != FcbGood) {
1248 
1249             try_return( Results );
1250         }
1251 
1252         Buffer->NumberOfLinks = 1;
1253         Buffer->DeletePending = BooleanFlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
1254 
1255         //
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.
1259         //
1260 
1261         if (NodeType(Fcb) == FAT_NTC_FCB) {
1262 
1263             //
1264             //  If we don't alread know the allocation size, we cannot look
1265             //  it up in the fast path.
1266             //
1267 
1268             if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
1269 
1270                 try_return( Results );
1271             }
1272 
1273             Buffer->AllocationSize = Fcb->Header.AllocationSize;
1274             Buffer->EndOfFile = Fcb->Header.FileSize;
1275 
1276             Buffer->Directory = FALSE;
1277 
1278         } else {
1279 
1280             Buffer->AllocationSize = FatLargeZero;
1281             Buffer->EndOfFile = FatLargeZero;
1282 
1283             Buffer->Directory = TRUE;
1284         }
1285 
1286         IoStatus->Status = STATUS_SUCCESS;
1287         IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION);
1288 
1289         Results = TRUE;
1290 
1291     try_exit: NOTHING;
1292     } _SEH2_FINALLY {
1293 
1294         if (FcbAcquired) { ExReleaseResourceLite( Fcb->Header.Resource ); }
1295 
1296         FsRtlExitFileSystem();
1297     } _SEH2_END;
1298 
1299     //
1300     //  And return to our caller
1301     //
1302 
1303     return Results;
1304 }
1305 
1306 
1307 _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO)
1308 BOOLEAN
1309 NTAPI
1310 FatFastQueryNetworkOpenInfo (
1311     IN PFILE_OBJECT FileObject,
1312     IN BOOLEAN Wait,
1313     IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
1314     OUT PIO_STATUS_BLOCK IoStatus,
1315     IN PDEVICE_OBJECT DeviceObject
1316     )
1317 
1318 /*++
1319 
1320 Routine Description:
1321 
1322     This routine is for the fast query call for network open information.
1323 
1324 Arguments:
1325 
1326     FileObject - Supplies the file object used in this operation
1327 
1328     Wait - Indicates if we are allowed to wait for the information
1329 
1330     Buffer - Supplies the output buffer to receive the information
1331 
1332     IoStatus - Receives the final status of the operation
1333 
1334 Return Value:
1335 
1336     BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
1337         needs to take the long route.
1338 
1339 --*/
1340 
1341 {
1342     BOOLEAN Results = FALSE;
1343     IRP_CONTEXT IrpContext;
1344 
1345     TYPE_OF_OPEN TypeOfOpen;
1346     PVCB Vcb;
1347     PFCB Fcb;
1348     PCCB Ccb;
1349 
1350     BOOLEAN FcbAcquired = FALSE;
1351 
1352     PAGED_CODE();
1353 
1354     UNREFERENCED_PARAMETER( DeviceObject );
1355 
1356     //
1357     //  Prepare the dummy irp context
1358     //
1359 
1360     RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
1361     IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT;
1362     IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
1363 
1364     if (Wait) {
1365 
1366         SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
1367 
1368     } else {
1369 
1370         ClearFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
1371     }
1372 
1373     //
1374     //  Determine the type of open for the input file object and only accept
1375     //  the user file or directory open
1376     //
1377 
1378     TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
1379 
1380     if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
1381 
1382         return Results;
1383     }
1384 
1385     FsRtlEnterFileSystem();
1386 
1387     //
1388     //  Get access to the Fcb but only if it is not the paging file
1389     //
1390 
1391     if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
1392 
1393         if (!ExAcquireResourceSharedLite( Fcb->Header.Resource, Wait )) {
1394 
1395             FsRtlExitFileSystem();
1396             return Results;
1397         }
1398 
1399         FcbAcquired = TRUE;
1400     }
1401 
1402     _SEH2_TRY {
1403 
1404         //
1405         //  If the Fcb is not in a good state, return FALSE.
1406         //
1407 
1408         if (Fcb->FcbCondition != FcbGood) {
1409 
1410             try_return( Results );
1411         }
1412 
1413         //
1414         //  Extract the data and fill in the non zero fields of the output
1415         //  buffer
1416         //
1417 
1418         //
1419         //  Default the field we don't support to a reasonable value.
1420         //
1421 
1422         ExLocalTimeToSystemTime( &FatJanOne1980,
1423                                  &Buffer->ChangeTime );
1424 
1425         Buffer->FileAttributes = Fcb->DirentFatFlags;
1426 
1427         if (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB) {
1428 
1429             //
1430             //  Reuse the default for the root dir.
1431             //
1432 
1433             Buffer->CreationTime =
1434             Buffer->LastAccessTime =
1435             Buffer->LastWriteTime = Buffer->ChangeTime;
1436 
1437         } else {
1438 
1439             Buffer->LastWriteTime = Fcb->LastWriteTime;
1440             Buffer->CreationTime = Fcb->CreationTime;
1441             Buffer->LastAccessTime = Fcb->LastAccessTime;
1442 
1443         }
1444 
1445         //
1446         //  If the temporary flag is set, then set it in the buffer.
1447         //
1448 
1449         if (FlagOn( Fcb->FcbState, FCB_STATE_TEMPORARY )) {
1450 
1451             SetFlag( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY );
1452         }
1453 
1454 
1455 
1456         //
1457         //  If no attributes were set, set the normal bit.
1458         //
1459 
1460         if (Buffer->FileAttributes == 0) {
1461 
1462             Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
1463         }
1464 
1465         if (NodeType(Fcb) == FAT_NTC_FCB) {
1466 
1467             //
1468             //  If we don't already know the allocation size, we cannot
1469             //  lock it up in the fast path.
1470             //
1471 
1472             if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
1473 
1474                 try_return( Results );
1475             }
1476 
1477             Buffer->AllocationSize = Fcb->Header.AllocationSize;
1478             Buffer->EndOfFile = Fcb->Header.FileSize;
1479 
1480         } else {
1481 
1482             Buffer->AllocationSize = FatLargeZero;
1483             Buffer->EndOfFile = FatLargeZero;
1484         }
1485 
1486         IoStatus->Status = STATUS_SUCCESS;
1487         IoStatus->Information = sizeof(FILE_NETWORK_OPEN_INFORMATION);
1488 
1489         Results = TRUE;
1490 
1491     try_exit: NOTHING;
1492     } _SEH2_FINALLY {
1493 
1494         if (FcbAcquired) { ExReleaseResourceLite( Fcb->Header.Resource ); }
1495 
1496         FsRtlExitFileSystem();
1497     } _SEH2_END;
1498 
1499     //
1500     //  And return to our caller
1501     //
1502 
1503     return Results;
1504 }
1505 
1506 _Requires_lock_held_(_Global_critical_region_)
1507 VOID
1508 FatPopUpFileCorrupt (
1509     IN PIRP_CONTEXT IrpContext,
1510     IN PFCB Fcb
1511     )
1512 
1513 /*++
1514 
1515 Routine Description:
1516 
1517     The Following routine makes an informational popup that the file
1518     is corrupt.
1519 
1520 Arguments:
1521 
1522     Fcb - The file that is corrupt.
1523 
1524 Return Value:
1525 
1526     None.
1527 
1528 --*/
1529 
1530 {
1531     PKTHREAD Thread;
1532 
1533     PAGED_CODE();
1534 
1535     //
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.
1538     //
1539 
1540     if (NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
1541 
1542         return;
1543     }
1544 
1545     //
1546     //  Got to grab the full filename now.
1547     //
1548 
1549     if (Fcb->FullFileName.Buffer == NULL) {
1550 
1551         FatSetFullFileNameInFcb( IrpContext, Fcb );
1552     }
1553 
1554     //
1555     //  We never want to block a system thread waiting for the user to
1556     //  press OK.
1557     //
1558 
1559     if (IoIsSystemThread(IrpContext->OriginatingIrp->Tail.Overlay.Thread)) {
1560 
1561        Thread = NULL;
1562 
1563     } else {
1564 
1565 #ifndef __REACTOS__
1566        Thread = IrpContext->OriginatingIrp->Tail.Overlay.Thread;
1567 #else
1568        Thread = (PKTHREAD)IrpContext->OriginatingIrp->Tail.Overlay.Thread;
1569 #endif
1570     }
1571 
1572     IoRaiseInformationalHardError( STATUS_FILE_CORRUPT_ERROR,
1573                                    &Fcb->FullFileName,
1574                                    Thread);
1575 }
1576 
1577