[BTRFS] Fix booting with runtime checks
[reactos.git] / drivers / filesystems / fastfat_new / fatdata.c
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 = {.LowPart = 0, .HighPart = 0};
66 LARGE_INTEGER FatMaxLarge = {.LowPart = MAXULONG, .HighPart = 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 = {.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};
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 = {.LowPart = 0xe219652c, .HighPart = 0xd1b71758};
90 LARGE_INTEGER FatMagic86400000 = {.LowPart = 0xfa67b90e, .HighPart = 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 \f
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 \f
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 #ifdef 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 \f
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)\f
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) \f
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)\f
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 \f
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 \f
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