Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1402 lines
32 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. FatData.c
  5. Abstract:
  6. This module declares the global data used by the Fat file system.
  7. // @@BEGIN_DDKSPLIT
  8. Author:
  9. Gary Kimura [GaryKi] 28-Dec-1989
  10. Revision History:
  11. // @@END_DDKSPLIT
  12. --*/
  13. #include "FatProcs.h"
  14. //
  15. // The Bug check file id for this module
  16. //
  17. #define BugCheckFileId (FAT_BUG_CHECK_FATDATA)
  18. //
  19. // The debug trace level
  20. //
  21. #define Dbg (DEBUG_TRACE_CATCH_EXCEPTIONS)
  22. #ifdef ALLOC_PRAGMA
  23. #if DBG
  24. #pragma alloc_text(PAGE, FatBugCheckExceptionFilter)
  25. #endif
  26. #pragma alloc_text(PAGE, FatCompleteRequest_Real)
  27. #pragma alloc_text(PAGE, FatFastIoCheckIfPossible)
  28. #pragma alloc_text(PAGE, FatFastQueryBasicInfo)
  29. #pragma alloc_text(PAGE, FatFastQueryNetworkOpenInfo)
  30. #pragma alloc_text(PAGE, FatFastQueryStdInfo)
  31. #pragma alloc_text(PAGE, FatIsIrpTopLevel)
  32. #pragma alloc_text(PAGE, FatPopUpFileCorrupt)
  33. #pragma alloc_text(PAGE, FatProcessException)
  34. #endif
  35. //
  36. // The global fsd data record, and zero large integer
  37. //
  38. FAT_DATA FatData;
  39. PDEVICE_OBJECT FatDiskFileSystemDeviceObject;
  40. PDEVICE_OBJECT FatCdromFileSystemDeviceObject;
  41. LARGE_INTEGER FatLargeZero = {0,0};
  42. LARGE_INTEGER FatMaxLarge = {MAXULONG,MAXLONG};
  43. LARGE_INTEGER Fat30Milliseconds = {(ULONG)(-30 * 1000 * 10), -1};
  44. LARGE_INTEGER Fat100Milliseconds = {(ULONG)(-30 * 1000 * 10), -1};
  45. LARGE_INTEGER FatOneDay = {0x2a69c000, 0xc9};
  46. LARGE_INTEGER FatJanOne1980 = {0xe1d58000,0x01a8e79f};
  47. LARGE_INTEGER FatDecThirtyOne1979 = {0xb76bc000,0x01a8e6d6};
  48. FAT_TIME_STAMP FatTimeJanOne1980 = {{0,0,0},{1,1,0}};
  49. LARGE_INTEGER FatMagic10000 = {0xe219652c, 0xd1b71758};
  50. LARGE_INTEGER FatMagic86400000 = {0xfa67b90e, 0xc6d750eb};
  51. FAST_IO_DISPATCH FatFastIoDispatch;
  52. //
  53. // Our lookaside lists.
  54. //
  55. NPAGED_LOOKASIDE_LIST FatIrpContextLookasideList;
  56. NPAGED_LOOKASIDE_LIST FatNonPagedFcbLookasideList;
  57. NPAGED_LOOKASIDE_LIST FatEResourceLookasideList;
  58. SLIST_HEADER FatCloseContextSList;
  59. //
  60. // Synchronization for the close queue
  61. //
  62. FAST_MUTEX FatCloseQueueMutex;
  63. //
  64. // Reserve MDL for paging file operations.
  65. //
  66. PMDL FatReserveMdl = NULL;
  67. KEVENT FatReserveEvent;
  68. #ifdef FASTFATDBG
  69. LONG FatDebugTraceLevel = 0x00000009;
  70. LONG FatDebugTraceIndent = 0;
  71. ULONG FatFsdEntryCount = 0;
  72. ULONG FatFspEntryCount = 0;
  73. ULONG FatIoCallDriverCount = 0;
  74. LONG FatPerformanceTimerLevel = 0x00000000;
  75. ULONG FatTotalTicks[32] = { 0 };
  76. //
  77. // I need this because C can't support conditional compilation within
  78. // a macro.
  79. //
  80. PVOID FatNull = NULL;
  81. #endif // FASTFATDBG
  82. #if DBG
  83. NTSTATUS FatAssertNotStatus = STATUS_SUCCESS;
  84. BOOLEAN FatTestRaisedStatus = FALSE;
  85. #endif
  86. #if DBG
  87. ULONG
  88. FatBugCheckExceptionFilter (
  89. IN PEXCEPTION_POINTERS ExceptionPointer
  90. )
  91. /*++
  92. Routine Description:
  93. An exception filter which acts as an assert that the exception should
  94. never occur.
  95. This is only valid on debug builds, we don't want the overhead on retail.
  96. Arguments:
  97. ExceptionPointers - The result of GetExceptionInformation() in the context
  98. of the exception.
  99. Return Value:
  100. Bugchecks.
  101. --*/
  102. {
  103. FatBugCheck( (ULONG_PTR)ExceptionPointer->ExceptionRecord,
  104. (ULONG_PTR)ExceptionPointer->ContextRecord,
  105. (ULONG_PTR)ExceptionPointer->ExceptionRecord->ExceptionAddress );
  106. return EXCEPTION_EXECUTE_HANDLER;
  107. }
  108. #endif
  109. ULONG
  110. FatExceptionFilter (
  111. IN PIRP_CONTEXT IrpContext,
  112. IN PEXCEPTION_POINTERS ExceptionPointer
  113. )
  114. /*++
  115. Routine Description:
  116. This routine is used to decide if we should or should not handle
  117. an exception status that is being raised. It inserts the status
  118. into the IrpContext and either indicates that we should handle
  119. the exception or bug check the system.
  120. Arguments:
  121. ExceptionPointers - The result of GetExceptionInformation() in the context
  122. of the exception.
  123. Return Value:
  124. ULONG - returns EXCEPTION_EXECUTE_HANDLER or bugchecks
  125. --*/
  126. {
  127. NTSTATUS ExceptionCode;
  128. ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
  129. DebugTrace(0, DEBUG_TRACE_UNWIND, "FatExceptionFilter %X\n", ExceptionCode);
  130. DebugDump("FatExceptionFilter\n", Dbg, NULL );
  131. //
  132. // If the exception is STATUS_IN_PAGE_ERROR, get the I/O error code
  133. // from the exception record.
  134. //
  135. if (ExceptionCode == STATUS_IN_PAGE_ERROR) {
  136. if (ExceptionPointer->ExceptionRecord->NumberParameters >= 3) {
  137. ExceptionCode = (NTSTATUS)ExceptionPointer->ExceptionRecord->ExceptionInformation[2];
  138. }
  139. }
  140. //
  141. // If there is not an irp context, we must have had insufficient resources.
  142. //
  143. if ( !ARGUMENT_PRESENT( IrpContext ) ) {
  144. if (!FsRtlIsNtstatusExpected( ExceptionCode )) {
  145. FatBugCheck( (ULONG_PTR)ExceptionPointer->ExceptionRecord,
  146. (ULONG_PTR)ExceptionPointer->ContextRecord,
  147. (ULONG_PTR)ExceptionPointer->ExceptionRecord->ExceptionAddress );
  148. }
  149. return EXCEPTION_EXECUTE_HANDLER;
  150. }
  151. //
  152. // For the purposes of processing this exception, let's mark this
  153. // request as being able to wait and disable write through if we
  154. // aren't posting it.
  155. //
  156. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
  157. if ( (ExceptionCode != STATUS_CANT_WAIT) &&
  158. (ExceptionCode != STATUS_VERIFY_REQUIRED) ) {
  159. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH);
  160. }
  161. if ( IrpContext->ExceptionStatus == 0 ) {
  162. if (FsRtlIsNtstatusExpected( ExceptionCode )) {
  163. IrpContext->ExceptionStatus = ExceptionCode;
  164. return EXCEPTION_EXECUTE_HANDLER;
  165. } else {
  166. FatBugCheck( (ULONG_PTR)ExceptionPointer->ExceptionRecord,
  167. (ULONG_PTR)ExceptionPointer->ContextRecord,
  168. (ULONG_PTR)ExceptionPointer->ExceptionRecord->ExceptionAddress );
  169. }
  170. } else {
  171. //
  172. // We raised this code explicitly ourselves, so it had better be
  173. // expected.
  174. //
  175. ASSERT( IrpContext->ExceptionStatus == ExceptionCode );
  176. ASSERT( FsRtlIsNtstatusExpected( ExceptionCode ) );
  177. }
  178. return EXCEPTION_EXECUTE_HANDLER;
  179. }
  180. NTSTATUS
  181. FatProcessException (
  182. IN PIRP_CONTEXT IrpContext,
  183. IN PIRP Irp,
  184. IN NTSTATUS ExceptionCode
  185. )
  186. /*++
  187. Routine Description:
  188. This routine process an exception. It either completes the request
  189. with the saved exception status or it sends it off to IoRaiseHardError()
  190. Arguments:
  191. Irp - Supplies the Irp being processed
  192. ExceptionCode - Supplies the normalized exception status being handled
  193. Return Value:
  194. NTSTATUS - Returns the results of either posting the Irp or the
  195. saved completion status.
  196. --*/
  197. {
  198. PVCB Vcb;
  199. PIO_STACK_LOCATION IrpSp;
  200. FAT_VOLUME_STATE TransitionState = VolumeDirty;
  201. ULONG SavedFlags;
  202. DebugTrace(0, Dbg, "FatProcessException\n", 0);
  203. //
  204. // If there is not an irp context, we must have had insufficient resources.
  205. //
  206. if ( !ARGUMENT_PRESENT( IrpContext ) ) {
  207. FatCompleteRequest( FatNull, Irp, ExceptionCode );
  208. return ExceptionCode;
  209. }
  210. //
  211. // Get the real exception status from IrpContext->ExceptionStatus, and
  212. // reset it.
  213. //
  214. ExceptionCode = IrpContext->ExceptionStatus;
  215. FatResetExceptionState( IrpContext );
  216. //
  217. // If we are going to post the request, we may have to lock down the
  218. // user's buffer, so do it here in a try except so that we failed the
  219. // request if the LockPages fails.
  220. //
  221. // Also unpin any repinned Bcbs, protected by the try {} except {} filter.
  222. //
  223. try {
  224. SavedFlags = IrpContext->Flags;
  225. //
  226. // Make sure we don't try to write through Bcbs
  227. //
  228. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH);
  229. FatUnpinRepinnedBcbs( IrpContext );
  230. IrpContext->Flags = SavedFlags;
  231. //
  232. // If we will have to post the request, do it here. Note
  233. // that the last thing FatPrePostIrp() does is mark the Irp pending,
  234. // so it is critical that we actually return PENDING. Nothing
  235. // from this point to return can fail, so we are OK.
  236. //
  237. // We cannot do a verify operations at APC level because we
  238. // have to wait for Io operations to complete.
  239. //
  240. if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) &&
  241. (((ExceptionCode == STATUS_VERIFY_REQUIRED) && (KeGetCurrentIrql() >= APC_LEVEL)) ||
  242. (ExceptionCode == STATUS_CANT_WAIT))) {
  243. ExceptionCode = FatFsdPostRequest( IrpContext, Irp );
  244. }
  245. } except( FatExceptionFilter( IrpContext, GetExceptionInformation() ) ) {
  246. ExceptionCode = IrpContext->ExceptionStatus;
  247. IrpContext->ExceptionStatus = 0;
  248. IrpContext->Flags = SavedFlags;
  249. }
  250. //
  251. // If we posted the request, just return here.
  252. //
  253. if (ExceptionCode == STATUS_PENDING) {
  254. return ExceptionCode;
  255. }
  256. Irp->IoStatus.Status = ExceptionCode;
  257. //
  258. // If this request is not a "top-level" irp, just complete it.
  259. //
  260. if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL)) {
  261. //
  262. // If there is a cache operation above us, commute verify
  263. // to a lock conflict. This will cause retries so that
  264. // we have a chance of getting through without needing
  265. // to return an unaesthetic error for the operation.
  266. //
  267. if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP &&
  268. ExceptionCode == STATUS_VERIFY_REQUIRED) {
  269. ExceptionCode = STATUS_FILE_LOCK_CONFLICT;
  270. }
  271. FatCompleteRequest( IrpContext, Irp, ExceptionCode );
  272. return ExceptionCode;
  273. }
  274. if (IoIsErrorUserInduced(ExceptionCode)) {
  275. //
  276. // Check for the various error conditions that can be caused by,
  277. // and possibly resolved by the user.
  278. //
  279. if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
  280. PDEVICE_OBJECT Device;
  281. DebugTrace(0, Dbg, "Perform Verify Operation\n", 0);
  282. //
  283. // Now we are at the top level file system entry point.
  284. //
  285. // Grab the device to verify from the thread local storage
  286. // and stick it in the information field for transportation
  287. // to the fsp. We also clear the field at this time.
  288. //
  289. Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread );
  290. IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL );
  291. if ( Device == NULL ) {
  292. Device = IoGetDeviceToVerify( PsGetCurrentThread() );
  293. IoSetDeviceToVerify( PsGetCurrentThread(), NULL );
  294. ASSERT( Device != NULL );
  295. }
  296. //
  297. // Let's not BugCheck just because the driver messed up.
  298. //
  299. if (Device == NULL) {
  300. ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR;
  301. FatCompleteRequest( IrpContext, Irp, ExceptionCode );
  302. return ExceptionCode;
  303. }
  304. //
  305. // FatPerformVerify() will do the right thing with the Irp.
  306. return FatPerformVerify( IrpContext, Irp, Device );
  307. }
  308. //
  309. // The other user induced conditions generate an error unless
  310. // they have been disabled for this request.
  311. //
  312. if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS)) {
  313. FatCompleteRequest( IrpContext, Irp, ExceptionCode );
  314. return ExceptionCode;
  315. } else {
  316. //
  317. // Generate a pop-up
  318. //
  319. PDEVICE_OBJECT RealDevice;
  320. PVPB Vpb;
  321. PETHREAD Thread;
  322. if (IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL) {
  323. Vpb = IoGetCurrentIrpStackLocation(Irp)->FileObject->Vpb;
  324. } else {
  325. Vpb = NULL;
  326. }
  327. //
  328. // The device to verify is either in my thread local storage
  329. // or that of the thread that owns the Irp.
  330. //
  331. Thread = Irp->Tail.Overlay.Thread;
  332. RealDevice = IoGetDeviceToVerify( Thread );
  333. if ( RealDevice == NULL ) {
  334. Thread = PsGetCurrentThread();
  335. RealDevice = IoGetDeviceToVerify( Thread );
  336. ASSERT( RealDevice != NULL );
  337. }
  338. //
  339. // Let's not BugCheck just because the driver messed up.
  340. //
  341. if (RealDevice == NULL) {
  342. FatCompleteRequest( IrpContext, Irp, ExceptionCode );
  343. return ExceptionCode;
  344. }
  345. //
  346. // This routine actually causes the pop-up. It usually
  347. // does this by queuing an APC to the callers thread,
  348. // but in some cases it will complete the request immediately,
  349. // so it is very important to IoMarkIrpPending() first.
  350. //
  351. IoMarkIrpPending( Irp );
  352. IoRaiseHardError( Irp, Vpb, RealDevice );
  353. //
  354. // We will be handing control back to the caller here, so
  355. // reset the saved device object.
  356. //
  357. IoSetDeviceToVerify( Thread, NULL );
  358. //
  359. // The Irp will be completed by Io or resubmitted. In either
  360. // case we must clean up the IrpContext here.
  361. //
  362. FatDeleteIrpContext( IrpContext );
  363. return STATUS_PENDING;
  364. }
  365. }
  366. //
  367. // This is just a run of the mill error. If is a STATUS that we
  368. // raised ourselves, and the information would be use for the
  369. // user, raise an informational pop-up.
  370. //
  371. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  372. Vcb = IrpContext->Vcb;
  373. //
  374. // Now, if the Vcb is unknown to us this means that the error was raised
  375. // in the process of a mount and before we even had a chance to build
  376. // a full Vcb - and was really handled there.
  377. //
  378. if (Vcb != NULL) {
  379. if ( !FatDeviceIsFatFsdo( IrpSp->DeviceObject) &&
  380. !NT_SUCCESS(ExceptionCode) &&
  381. !FsRtlIsTotalDeviceFailure(ExceptionCode) ) {
  382. TransitionState = VolumeDirtyWithSurfaceTest;
  383. }
  384. //
  385. // If this was a STATUS_FILE_CORRUPT or similar error indicating some
  386. // nastiness out on the media, then mark the volume permanently dirty.
  387. //
  388. if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS) &&
  389. ( TransitionState == VolumeDirtyWithSurfaceTest ||
  390. (ExceptionCode == STATUS_FILE_CORRUPT_ERROR) ||
  391. (ExceptionCode == STATUS_DISK_CORRUPT_ERROR) ||
  392. (ExceptionCode == STATUS_EA_CORRUPT_ERROR) ||
  393. (ExceptionCode == STATUS_INVALID_EA_NAME) ||
  394. (ExceptionCode == STATUS_EA_LIST_INCONSISTENT) ||
  395. (ExceptionCode == STATUS_NO_EAS_ON_FILE) )) {
  396. ASSERT( NodeType(Vcb) == FAT_NTC_VCB );
  397. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
  398. //
  399. // Do the "dirty" work, ignoring any error.
  400. //
  401. try {
  402. FatMarkVolume( IrpContext, Vcb, TransitionState );
  403. } except( FatExceptionFilter( IrpContext, GetExceptionInformation() ) ) {
  404. NOTHING;
  405. }
  406. }
  407. }
  408. FatCompleteRequest( IrpContext, Irp, ExceptionCode );
  409. return ExceptionCode;
  410. }
  411. VOID
  412. FatCompleteRequest_Real (
  413. IN PIRP_CONTEXT IrpContext OPTIONAL,
  414. IN PIRP Irp OPTIONAL,
  415. IN NTSTATUS Status
  416. )
  417. /*++
  418. Routine Description:
  419. This routine completes a Irp
  420. Arguments:
  421. Irp - Supplies the Irp being processed
  422. Status - Supplies the status to complete the Irp with
  423. Return Value:
  424. None.
  425. --*/
  426. {
  427. //
  428. // If we have an Irp Context then unpin all of the repinned bcbs
  429. // we might have collected.
  430. //
  431. if (IrpContext != NULL) {
  432. ASSERT( IrpContext->Repinned.Bcb[0] == NULL );
  433. FatUnpinRepinnedBcbs( IrpContext );
  434. }
  435. //
  436. // Delete the Irp context before completing the IRP so if
  437. // we run into some of the asserts, we can still backtrack
  438. // through the IRP.
  439. //
  440. if (IrpContext != NULL) {
  441. FatDeleteIrpContext( IrpContext );
  442. }
  443. //
  444. // If we have an Irp then complete the irp.
  445. //
  446. if (Irp != NULL) {
  447. //
  448. // We got an error, so zero out the information field before
  449. // completing the request if this was an input operation.
  450. // Otherwise IopCompleteRequest will try to copy to the user's buffer.
  451. //
  452. if ( NT_ERROR(Status) &&
  453. FlagOn(Irp->Flags, IRP_INPUT_OPERATION) ) {
  454. Irp->IoStatus.Information = 0;
  455. }
  456. Irp->IoStatus.Status = Status;
  457. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  458. }
  459. return;
  460. }
  461. BOOLEAN
  462. FatIsIrpTopLevel (
  463. IN PIRP Irp
  464. )
  465. /*++
  466. Routine Description:
  467. This routine detects if an Irp is the Top level requestor, ie. if it os OK
  468. to do a verify or pop-up now. If TRUE is returned, then no file system
  469. resources are held above us.
  470. Arguments:
  471. Irp - Supplies the Irp being processed
  472. Status - Supplies the status to complete the Irp with
  473. Return Value:
  474. None.
  475. --*/
  476. {
  477. if ( IoGetTopLevelIrp() == NULL ) {
  478. IoSetTopLevelIrp( Irp );
  479. return TRUE;
  480. } else {
  481. return FALSE;
  482. }
  483. }
  484. BOOLEAN
  485. FatFastIoCheckIfPossible (
  486. IN PFILE_OBJECT FileObject,
  487. IN PLARGE_INTEGER FileOffset,
  488. IN ULONG Length,
  489. IN BOOLEAN Wait,
  490. IN ULONG LockKey,
  491. IN BOOLEAN CheckForReadOperation,
  492. OUT PIO_STATUS_BLOCK IoStatus,
  493. IN PDEVICE_OBJECT DeviceObject
  494. )
  495. /*++
  496. Routine Description:
  497. This routine checks if fast i/o is possible for a read/write operation
  498. Arguments:
  499. FileObject - Supplies the file object used in the query
  500. FileOffset - Supplies the starting byte offset for the read/write operation
  501. Length - Supplies the length, in bytes, of the read/write operation
  502. Wait - Indicates if we can wait
  503. LockKey - Supplies the lock key
  504. CheckForReadOperation - Indicates if this is a check for a read or write
  505. operation
  506. IoStatus - Receives the status of the operation if our return value is
  507. FastIoReturnError
  508. Return Value:
  509. BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs
  510. to take the long route.
  511. --*/
  512. {
  513. PVCB Vcb;
  514. PFCB Fcb;
  515. PCCB Ccb;
  516. LARGE_INTEGER LargeLength;
  517. //
  518. // Decode the file object to get our fcb, the only one we want
  519. // to deal with is a UserFileOpen
  520. //
  521. if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) {
  522. return FALSE;
  523. }
  524. LargeLength.QuadPart = Length;
  525. //
  526. // Based on whether this is a read or write operation we call
  527. // fsrtl check for read/write
  528. //
  529. if (CheckForReadOperation) {
  530. if (FsRtlFastCheckLockForRead( &Fcb->Specific.Fcb.FileLock,
  531. FileOffset,
  532. &LargeLength,
  533. LockKey,
  534. FileObject,
  535. PsGetCurrentProcess() )) {
  536. return TRUE;
  537. }
  538. } else {
  539. //
  540. // Also check for a write-protected volume here.
  541. //
  542. if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) &&
  543. FsRtlFastCheckLockForWrite( &Fcb->Specific.Fcb.FileLock,
  544. FileOffset,
  545. &LargeLength,
  546. LockKey,
  547. FileObject,
  548. PsGetCurrentProcess() )) {
  549. return TRUE;
  550. }
  551. }
  552. return FALSE;
  553. }
  554. BOOLEAN
  555. FatFastQueryBasicInfo (
  556. IN PFILE_OBJECT FileObject,
  557. IN BOOLEAN Wait,
  558. IN OUT PFILE_BASIC_INFORMATION Buffer,
  559. OUT PIO_STATUS_BLOCK IoStatus,
  560. IN PDEVICE_OBJECT DeviceObject
  561. )
  562. /*++
  563. Routine Description:
  564. This routine is for the fast query call for basic file information.
  565. Arguments:
  566. FileObject - Supplies the file object used in this operation
  567. Wait - Indicates if we are allowed to wait for the information
  568. Buffer - Supplies the output buffer to receive the basic information
  569. IoStatus - Receives the final status of the operation
  570. Return Value:
  571. BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
  572. needs to take the long route.
  573. --*/
  574. {
  575. BOOLEAN Results = FALSE;
  576. IRP_CONTEXT IrpContext;
  577. TYPE_OF_OPEN TypeOfOpen;
  578. PVCB Vcb;
  579. PFCB Fcb;
  580. PCCB Ccb;
  581. BOOLEAN FcbAcquired = FALSE;
  582. //
  583. // Prepare the dummy irp context
  584. //
  585. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
  586. IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT;
  587. IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
  588. if (Wait) {
  589. SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
  590. } else {
  591. ClearFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
  592. }
  593. //
  594. // Determine the type of open for the input file object and only accept
  595. // the user file or directory open
  596. //
  597. TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  598. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  599. return Results;
  600. }
  601. FsRtlEnterFileSystem();
  602. //
  603. // Get access to the Fcb but only if it is not the paging file
  604. //
  605. if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  606. if (!ExAcquireResourceSharedLite( Fcb->Header.Resource, Wait )) {
  607. FsRtlExitFileSystem();
  608. return Results;
  609. }
  610. FcbAcquired = TRUE;
  611. }
  612. try {
  613. //
  614. // If the Fcb is not in a good state, return FALSE.
  615. //
  616. if (Fcb->FcbCondition != FcbGood) {
  617. try_return( Results );
  618. }
  619. Buffer->FileAttributes = 0;
  620. //
  621. // If the fcb is not the root dcb then we will fill in the
  622. // buffer otherwise it is all setup for us.
  623. //
  624. if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) {
  625. //
  626. // Extract the data and fill in the non zero fields of the output
  627. // buffer
  628. //
  629. Buffer->LastWriteTime = Fcb->LastWriteTime;
  630. Buffer->CreationTime = Fcb->CreationTime;
  631. Buffer->LastAccessTime = Fcb->LastAccessTime;
  632. //
  633. // Zero out the field we don't support.
  634. //
  635. Buffer->ChangeTime.QuadPart = 0;
  636. Buffer->FileAttributes = Fcb->DirentFatFlags;
  637. } else {
  638. Buffer->LastWriteTime.QuadPart = 0;
  639. Buffer->CreationTime.QuadPart = 0;
  640. Buffer->LastAccessTime.QuadPart = 0;
  641. Buffer->ChangeTime.QuadPart = 0;
  642. Buffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
  643. }
  644. //
  645. // If the temporary flag is set, then set it in the buffer.
  646. //
  647. if (FlagOn( Fcb->FcbState, FCB_STATE_TEMPORARY )) {
  648. SetFlag( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY );
  649. }
  650. //
  651. // If no attributes were set, set the normal bit.
  652. //
  653. if (Buffer->FileAttributes == 0) {
  654. Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
  655. }
  656. IoStatus->Status = STATUS_SUCCESS;
  657. IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
  658. Results = TRUE;
  659. try_exit: NOTHING;
  660. } finally {
  661. if (FcbAcquired) { ExReleaseResourceLite( Fcb->Header.Resource ); }
  662. FsRtlExitFileSystem();
  663. }
  664. //
  665. // And return to our caller
  666. //
  667. return Results;
  668. }
  669. BOOLEAN
  670. FatFastQueryStdInfo (
  671. IN PFILE_OBJECT FileObject,
  672. IN BOOLEAN Wait,
  673. IN OUT PFILE_STANDARD_INFORMATION Buffer,
  674. OUT PIO_STATUS_BLOCK IoStatus,
  675. IN PDEVICE_OBJECT DeviceObject
  676. )
  677. /*++
  678. Routine Description:
  679. This routine is for the fast query call for standard file information.
  680. Arguments:
  681. FileObject - Supplies the file object used in this operation
  682. Wait - Indicates if we are allowed to wait for the information
  683. Buffer - Supplies the output buffer to receive the basic information
  684. IoStatus - Receives the final status of the operation
  685. Return Value:
  686. BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
  687. needs to take the long route.
  688. --*/
  689. {
  690. BOOLEAN Results = FALSE;
  691. IRP_CONTEXT IrpContext;
  692. TYPE_OF_OPEN TypeOfOpen;
  693. PVCB Vcb;
  694. PFCB Fcb;
  695. PCCB Ccb;
  696. BOOLEAN FcbAcquired = FALSE;
  697. //
  698. // Prepare the dummy irp context
  699. //
  700. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
  701. IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT;
  702. IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
  703. if (Wait) {
  704. SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
  705. } else {
  706. ClearFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
  707. }
  708. //
  709. // Determine the type of open for the input file object and only accept
  710. // the user file or directory open
  711. //
  712. TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  713. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  714. return Results;
  715. }
  716. //
  717. // Get access to the Fcb but only if it is not the paging file
  718. //
  719. FsRtlEnterFileSystem();
  720. if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  721. if (!ExAcquireResourceSharedLite( Fcb->Header.Resource, Wait )) {
  722. FsRtlExitFileSystem();
  723. return Results;
  724. }
  725. FcbAcquired = TRUE;
  726. }
  727. try {
  728. //
  729. // If the Fcb is not in a good state, return FALSE.
  730. //
  731. if (Fcb->FcbCondition != FcbGood) {
  732. try_return( Results );
  733. }
  734. Buffer->NumberOfLinks = 1;
  735. Buffer->DeletePending = BooleanFlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
  736. //
  737. // Case on whether this is a file or a directory, and extract
  738. // the information and fill in the fcb/dcb specific parts
  739. // of the output buffer.
  740. //
  741. if (NodeType(Fcb) == FAT_NTC_FCB) {
  742. //
  743. // If we don't alread know the allocation size, we cannot look
  744. // it up in the fast path.
  745. //
  746. if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  747. try_return( Results );
  748. }
  749. Buffer->AllocationSize = Fcb->Header.AllocationSize;
  750. Buffer->EndOfFile = Fcb->Header.FileSize;
  751. Buffer->Directory = FALSE;
  752. } else {
  753. Buffer->AllocationSize = FatLargeZero;
  754. Buffer->EndOfFile = FatLargeZero;
  755. Buffer->Directory = TRUE;
  756. }
  757. IoStatus->Status = STATUS_SUCCESS;
  758. IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION);
  759. Results = TRUE;
  760. try_exit: NOTHING;
  761. } finally {
  762. if (FcbAcquired) { ExReleaseResourceLite( Fcb->Header.Resource ); }
  763. FsRtlExitFileSystem();
  764. }
  765. //
  766. // And return to our caller
  767. //
  768. return Results;
  769. }
  770. BOOLEAN
  771. FatFastQueryNetworkOpenInfo (
  772. IN PFILE_OBJECT FileObject,
  773. IN BOOLEAN Wait,
  774. IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
  775. OUT PIO_STATUS_BLOCK IoStatus,
  776. IN PDEVICE_OBJECT DeviceObject
  777. )
  778. /*++
  779. Routine Description:
  780. This routine is for the fast query call for network open information.
  781. Arguments:
  782. FileObject - Supplies the file object used in this operation
  783. Wait - Indicates if we are allowed to wait for the information
  784. Buffer - Supplies the output buffer to receive the information
  785. IoStatus - Receives the final status of the operation
  786. Return Value:
  787. BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
  788. needs to take the long route.
  789. --*/
  790. {
  791. BOOLEAN Results = FALSE;
  792. IRP_CONTEXT IrpContext;
  793. TYPE_OF_OPEN TypeOfOpen;
  794. PVCB Vcb;
  795. PFCB Fcb;
  796. PCCB Ccb;
  797. BOOLEAN FcbAcquired = FALSE;
  798. //
  799. // Prepare the dummy irp context
  800. //
  801. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
  802. IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT;
  803. IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
  804. if (Wait) {
  805. SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
  806. } else {
  807. ClearFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
  808. }
  809. //
  810. // Determine the type of open for the input file object and only accept
  811. // the user file or directory open
  812. //
  813. TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  814. if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) {
  815. return Results;
  816. }
  817. FsRtlEnterFileSystem();
  818. //
  819. // Get access to the Fcb but only if it is not the paging file
  820. //
  821. if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  822. if (!ExAcquireResourceSharedLite( Fcb->Header.Resource, Wait )) {
  823. FsRtlExitFileSystem();
  824. return Results;
  825. }
  826. FcbAcquired = TRUE;
  827. }
  828. try {
  829. //
  830. // If the Fcb is not in a good state, return FALSE.
  831. //
  832. if (Fcb->FcbCondition != FcbGood) {
  833. try_return( Results );
  834. }
  835. //
  836. // Extract the data and fill in the non zero fields of the output
  837. // buffer
  838. //
  839. //
  840. // Default the field we don't support to a reasonable value.
  841. //
  842. ExLocalTimeToSystemTime( &FatJanOne1980,
  843. &Buffer->ChangeTime );
  844. if (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB) {
  845. //
  846. // Reuse the default for the root dir.
  847. //
  848. Buffer->CreationTime =
  849. Buffer->LastAccessTime =
  850. Buffer->LastWriteTime = Buffer->ChangeTime;
  851. } else {
  852. Buffer->LastWriteTime = Fcb->LastWriteTime;
  853. Buffer->CreationTime = Fcb->CreationTime;
  854. Buffer->LastAccessTime = Fcb->LastAccessTime;
  855. }
  856. Buffer->FileAttributes = Fcb->DirentFatFlags;
  857. //
  858. // If the temporary flag is set, then set it in the buffer.
  859. //
  860. if (FlagOn( Fcb->FcbState, FCB_STATE_TEMPORARY )) {
  861. SetFlag( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY );
  862. }
  863. //
  864. // If no attributes were set, set the normal bit.
  865. //
  866. if (Buffer->FileAttributes == 0) {
  867. Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
  868. }
  869. if (NodeType(Fcb) == FAT_NTC_FCB) {
  870. //
  871. // If we don't already know the allocation size, we cannot
  872. // lock it up in the fast path.
  873. //
  874. if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  875. try_return( Results );
  876. }
  877. Buffer->AllocationSize = Fcb->Header.AllocationSize;
  878. Buffer->EndOfFile = Fcb->Header.FileSize;
  879. } else {
  880. Buffer->AllocationSize = FatLargeZero;
  881. Buffer->EndOfFile = FatLargeZero;
  882. }
  883. IoStatus->Status = STATUS_SUCCESS;
  884. IoStatus->Information = sizeof(FILE_NETWORK_OPEN_INFORMATION);
  885. Results = TRUE;
  886. try_exit: NOTHING;
  887. } finally {
  888. if (FcbAcquired) { ExReleaseResourceLite( Fcb->Header.Resource ); }
  889. FsRtlExitFileSystem();
  890. }
  891. //
  892. // And return to our caller
  893. //
  894. return Results;
  895. }
  896. VOID
  897. FatPopUpFileCorrupt (
  898. IN PIRP_CONTEXT IrpContext,
  899. IN PFCB Fcb
  900. )
  901. /*++
  902. Routine Description:
  903. The Following routine makes an informational popup that the file
  904. is corrupt.
  905. Arguments:
  906. Fcb - The file that is corrupt.
  907. Return Value:
  908. None.
  909. --*/
  910. {
  911. PKTHREAD Thread;
  912. //
  913. // Disable the popup on the root directory. It is important not
  914. // to generate them on objects which are part of the mount process.
  915. //
  916. if (NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
  917. return;
  918. }
  919. //
  920. // Got to grab the full filename now.
  921. //
  922. if (Fcb->FullFileName.Buffer == NULL) {
  923. FatSetFullFileNameInFcb( IrpContext, Fcb );
  924. }
  925. //
  926. // We never want to block a system thread waiting for the user to
  927. // press OK.
  928. //
  929. if (IoIsSystemThread(IrpContext->OriginatingIrp->Tail.Overlay.Thread)) {
  930. Thread = NULL;
  931. } else {
  932. Thread = IrpContext->OriginatingIrp->Tail.Overlay.Thread;
  933. }
  934. IoRaiseInformationalHardError( STATUS_FILE_CORRUPT_ERROR,
  935. &Fcb->FullFileName,
  936. Thread);
  937. }