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.

3560 lines
95 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. NtfsData.c
  5. Abstract:
  6. This module declares the global data used by the Ntfs file system.
  7. Author:
  8. Gary Kimura [GaryKi] 21-May-1991
  9. Revision History:
  10. --*/
  11. #include "NtfsProc.h"
  12. //
  13. // The Bug check file id for this module
  14. //
  15. #define BugCheckFileId (NTFS_BUG_CHECK_NTFSDATA)
  16. //
  17. // The debug trace level
  18. //
  19. #define Dbg (DEBUG_TRACE_CATCH_EXCEPTIONS)
  20. //
  21. // Debugging control variables
  22. //
  23. PUCHAR NtfsPageInAddress = NULL;
  24. LONGLONG NtfsMapOffset = -1;
  25. //
  26. // Define a tag for general pool allocations from this module
  27. //
  28. #undef MODULE_POOL_TAG
  29. #define MODULE_POOL_TAG ('NFtN')
  30. #define CollectExceptionStats(VCB,EXCEPTION_CODE) { \
  31. if ((VCB) != NULL) { \
  32. PFILE_SYSTEM_STATISTICS FsStat = &(VCB)->Statistics[KeGetCurrentProcessorNumber()]; \
  33. if ((EXCEPTION_CODE) == STATUS_LOG_FILE_FULL) { \
  34. FsStat->Ntfs.LogFileFullExceptions += 1; \
  35. } else { \
  36. FsStat->Ntfs.OtherExceptions += 1; \
  37. } \
  38. } \
  39. }
  40. //
  41. // The global fsd data record
  42. //
  43. NTFS_DATA NtfsData;
  44. //
  45. // Mutex to synchronize creation of stream files.
  46. //
  47. KMUTANT StreamFileCreationMutex;
  48. //
  49. // Notification event for creation of encrypted files.
  50. //
  51. KEVENT NtfsEncryptionPendingEvent;
  52. #ifdef KEITHKA
  53. ULONG EncryptionPendingCount = 0;
  54. #endif
  55. //
  56. // A mutex and queue of NTFS MCBS that will be freed
  57. // if we reach over a certain threshold
  58. //
  59. FAST_MUTEX NtfsMcbFastMutex;
  60. LIST_ENTRY NtfsMcbLruQueue;
  61. ULONG NtfsMcbHighWaterMark;
  62. ULONG NtfsMcbLowWaterMark;
  63. ULONG NtfsMcbCurrentLevel;
  64. BOOLEAN NtfsMcbCleanupInProgress;
  65. WORK_QUEUE_ITEM NtfsMcbWorkItem;
  66. //
  67. // The global large integer constants
  68. //
  69. LARGE_INTEGER NtfsLarge0 = {0x00000000,0x00000000};
  70. LARGE_INTEGER NtfsLarge1 = {0x00000001,0x00000000};
  71. LARGE_INTEGER NtfsLargeMax = {0xffffffff,0x7fffffff};
  72. LARGE_INTEGER NtfsLargeEof = {0xffffffff,0xffffffff};
  73. LONGLONG NtfsLastAccess;
  74. //
  75. // The following fields are used to allocate nonpaged structures
  76. // using a lookaside list, and other fixed sized structures from a
  77. // small cache.
  78. //
  79. NPAGED_LOOKASIDE_LIST NtfsIoContextLookasideList;
  80. NPAGED_LOOKASIDE_LIST NtfsIrpContextLookasideList;
  81. NPAGED_LOOKASIDE_LIST NtfsKeventLookasideList;
  82. NPAGED_LOOKASIDE_LIST NtfsScbNonpagedLookasideList;
  83. NPAGED_LOOKASIDE_LIST NtfsScbSnapshotLookasideList;
  84. NPAGED_LOOKASIDE_LIST NtfsCompressSyncLookasideList;
  85. PAGED_LOOKASIDE_LIST NtfsCcbLookasideList;
  86. PAGED_LOOKASIDE_LIST NtfsCcbDataLookasideList;
  87. PAGED_LOOKASIDE_LIST NtfsDeallocatedRecordsLookasideList;
  88. PAGED_LOOKASIDE_LIST NtfsFcbDataLookasideList;
  89. PAGED_LOOKASIDE_LIST NtfsFcbIndexLookasideList;
  90. PAGED_LOOKASIDE_LIST NtfsIndexContextLookasideList;
  91. PAGED_LOOKASIDE_LIST NtfsLcbLookasideList;
  92. PAGED_LOOKASIDE_LIST NtfsNukemLookasideList;
  93. PAGED_LOOKASIDE_LIST NtfsScbDataLookasideList;
  94. //
  95. // Useful constant Unicode strings.
  96. //
  97. //
  98. // This is the string for the name of the index allocation attributes.
  99. //
  100. const UNICODE_STRING NtfsFileNameIndex = CONSTANT_UNICODE_STRING( L"$I30" );
  101. //
  102. // This is the string for the attribute code for index allocation.
  103. // $INDEX_ALLOCATION.
  104. //
  105. const UNICODE_STRING NtfsIndexAllocation = CONSTANT_UNICODE_STRING( L"$INDEX_ALLOCATION" );
  106. //
  107. // This is the string for the data attribute, $DATA.
  108. //
  109. const UNICODE_STRING NtfsDataString = CONSTANT_UNICODE_STRING( L"$DATA" );
  110. //
  111. // This is the string for the bitmap attribute
  112. //
  113. const UNICODE_STRING NtfsBitmapString = CONSTANT_UNICODE_STRING( L"$BITMAP" );
  114. //
  115. // This is the string for the attribute list attribute
  116. //
  117. const UNICODE_STRING NtfsAttrListString = CONSTANT_UNICODE_STRING( L"$ATTRIBUTE_LIST" );
  118. //
  119. // This is the string for the attribute list attribute
  120. //
  121. const UNICODE_STRING NtfsReparsePointString = CONSTANT_UNICODE_STRING( L"$REPARSE_POINT" );
  122. //
  123. // These strings are used as the Scb->AttributeName for
  124. // user-opened general indices. Declaring them here avoids
  125. // having to marshal allocating & freeing them.
  126. //
  127. const UNICODE_STRING NtfsObjId = CONSTANT_UNICODE_STRING( L"$O" );
  128. const UNICODE_STRING NtfsQuota = CONSTANT_UNICODE_STRING( L"$Q" );
  129. //
  130. // The following is the name of the data stream for the Usn journal.
  131. //
  132. const UNICODE_STRING JournalStreamName = CONSTANT_UNICODE_STRING( L"$J" );
  133. //
  134. // These are the strings for the files in the extend directory.
  135. //
  136. const UNICODE_STRING NtfsExtendName = CONSTANT_UNICODE_STRING( L"$Extend" );
  137. const UNICODE_STRING NtfsUsnJrnlName = CONSTANT_UNICODE_STRING( L"$UsnJrnl" );
  138. const UNICODE_STRING NtfsQuotaName = CONSTANT_UNICODE_STRING( L"$Quota" );
  139. const UNICODE_STRING NtfsObjectIdName = CONSTANT_UNICODE_STRING( L"$ObjId" );
  140. const UNICODE_STRING NtfsMountTableName = CONSTANT_UNICODE_STRING( L"$Reparse" );
  141. //
  142. // This strings are used for informational popups.
  143. //
  144. const UNICODE_STRING NtfsSystemFiles[] = {
  145. CONSTANT_UNICODE_STRING( L"\\$Mft" ),
  146. CONSTANT_UNICODE_STRING( L"\\$MftMirr" ),
  147. CONSTANT_UNICODE_STRING( L"\\$LogFile" ),
  148. CONSTANT_UNICODE_STRING( L"\\$Volume" ),
  149. CONSTANT_UNICODE_STRING( L"\\$AttrDef" ),
  150. CONSTANT_UNICODE_STRING( L"\\" ),
  151. CONSTANT_UNICODE_STRING( L"\\$BitMap" ),
  152. CONSTANT_UNICODE_STRING( L"\\$Boot" ),
  153. CONSTANT_UNICODE_STRING( L"\\$BadClus" ),
  154. CONSTANT_UNICODE_STRING( L"\\$Secure" ),
  155. CONSTANT_UNICODE_STRING( L"\\$UpCase" ),
  156. CONSTANT_UNICODE_STRING( L"\\$Extend" ),
  157. };
  158. const UNICODE_STRING NtfsInternalUseFile[] = {
  159. CONSTANT_UNICODE_STRING( L"\\$ChangeAttributeValue" ),
  160. CONSTANT_UNICODE_STRING( L"\\$ChangeAttributeValue2" ),
  161. CONSTANT_UNICODE_STRING( L"\\$CommonCleanup" ),
  162. CONSTANT_UNICODE_STRING( L"\\$ConvertToNonresident" ),
  163. CONSTANT_UNICODE_STRING( L"\\$CreateNonresidentWithValue" ),
  164. CONSTANT_UNICODE_STRING( L"\\$DeallocateRecord" ),
  165. CONSTANT_UNICODE_STRING( L"\\$DeleteAllocationFromRecord" ),
  166. CONSTANT_UNICODE_STRING( L"\\$Directory" ),
  167. CONSTANT_UNICODE_STRING( L"\\$InitializeRecordAllocation" ),
  168. CONSTANT_UNICODE_STRING( L"\\$MapAttributeValue" ),
  169. CONSTANT_UNICODE_STRING( L"\\$NonCachedIo" ),
  170. CONSTANT_UNICODE_STRING( L"\\$PerformHotFix" ),
  171. CONSTANT_UNICODE_STRING( L"\\$PrepareToShrinkFileSize" ),
  172. CONSTANT_UNICODE_STRING( L"\\$ReplaceAttribute" ),
  173. CONSTANT_UNICODE_STRING( L"\\$ReplaceAttribute2" ),
  174. CONSTANT_UNICODE_STRING( L"\\$SetAllocationInfo" ),
  175. CONSTANT_UNICODE_STRING( L"\\$SetEndOfFileInfo" ),
  176. CONSTANT_UNICODE_STRING( L"\\$ZeroRangeInStream" ),
  177. CONSTANT_UNICODE_STRING( L"\\$ZeroRangeInStream2" ),
  178. CONSTANT_UNICODE_STRING( L"\\$ZeroRangeInStream3" ),
  179. };
  180. const UNICODE_STRING NtfsUnknownFile =
  181. CONSTANT_UNICODE_STRING( L"\\????" );
  182. const UNICODE_STRING NtfsRootIndexString =
  183. CONSTANT_UNICODE_STRING( L"." );
  184. //
  185. // This is the empty string. This can be used to pass a string with
  186. // no length.
  187. //
  188. const UNICODE_STRING NtfsEmptyString =
  189. CONSTANT_UNICODE_STRING( L"" );
  190. //
  191. // The following file references are used to identify system files.
  192. //
  193. const FILE_REFERENCE MftFileReference = { MASTER_FILE_TABLE_NUMBER, 0, MASTER_FILE_TABLE_NUMBER };
  194. const FILE_REFERENCE Mft2FileReference = { MASTER_FILE_TABLE2_NUMBER, 0, MASTER_FILE_TABLE2_NUMBER };
  195. const FILE_REFERENCE LogFileReference = { LOG_FILE_NUMBER, 0, LOG_FILE_NUMBER };
  196. const FILE_REFERENCE VolumeFileReference = { VOLUME_DASD_NUMBER, 0, VOLUME_DASD_NUMBER };
  197. const FILE_REFERENCE AttrDefFileReference = { ATTRIBUTE_DEF_TABLE_NUMBER, 0, ATTRIBUTE_DEF_TABLE_NUMBER };
  198. const FILE_REFERENCE RootIndexFileReference = { ROOT_FILE_NAME_INDEX_NUMBER, 0, ROOT_FILE_NAME_INDEX_NUMBER };
  199. const FILE_REFERENCE BitmapFileReference = { BIT_MAP_FILE_NUMBER, 0, BIT_MAP_FILE_NUMBER };
  200. const FILE_REFERENCE BootFileReference = { BOOT_FILE_NUMBER, 0, BOOT_FILE_NUMBER };
  201. const FILE_REFERENCE ExtendFileReference = { EXTEND_NUMBER, 0, EXTEND_NUMBER };
  202. const FILE_REFERENCE FirstUserFileReference = { FIRST_USER_FILE_NUMBER, 0, 0 };
  203. //
  204. // The following are used to determine what level of protection to attach
  205. // to system files and attributes.
  206. //
  207. BOOLEAN NtfsProtectSystemFiles = TRUE;
  208. BOOLEAN NtfsProtectSystemAttributes = TRUE;
  209. //
  210. // The following is used to indicate the multiplier value for the Mft zone.
  211. //
  212. ULONG NtfsMftZoneMultiplier;
  213. //
  214. // Debug code for finding corruption.
  215. //
  216. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  217. BOOLEAN NtfsBreakOnCorrupt = TRUE;
  218. #else
  219. BOOLEAN NtfsBreakOnCorrupt = FALSE;
  220. #endif
  221. //#endif
  222. //
  223. // Enable compression on the wire.
  224. //
  225. BOOLEAN NtfsEnableCompressedIO = FALSE;
  226. //
  227. // FsRtl fast I/O call backs
  228. //
  229. FAST_IO_DISPATCH NtfsFastIoDispatch;
  230. #ifdef BRIANDBG
  231. ULONG NtfsIgnoreReserved = FALSE;
  232. #endif
  233. #ifdef NTFS_LOG_FULL_TEST
  234. LONG NtfsFailCheck = 0;
  235. LONG NtfsFailFrequency = 0;
  236. LONG NtfsPeriodicFail = 0;
  237. #endif
  238. #ifdef NTFSDBG
  239. LONG NtfsDebugTraceLevel = DEBUG_TRACE_ERROR;
  240. LONG NtfsDebugTraceIndent = 0;
  241. ULONG NtfsFsdEntryCount = 0;
  242. ULONG NtfsFspEntryCount = 0;
  243. ULONG NtfsIoCallDriverCount = 0;
  244. LONG NtfsReturnStatusFilter = 0xf0ffffffL; // just an non-existent error code
  245. #endif // NTFSDBG
  246. //
  247. // Default restart version.
  248. //
  249. #ifdef _WIN64
  250. ULONG NtfsDefaultRestartVersion = 1;
  251. #else
  252. ULONG NtfsDefaultRestartVersion = 0;
  253. #endif
  254. //
  255. // Performance statistics
  256. //
  257. ULONG NtfsMaxDelayedCloseCount;
  258. ULONG NtfsMinDelayedCloseCount;
  259. ULONG NtfsThrottleCreates;
  260. ULONG NtfsFailedHandedOffPagingFileOps = 0;
  261. ULONG NtfsFailedPagingFileOps = 0;
  262. ULONG NtfsFailedAborts = 0;
  263. ULONG NtfsFailedLfsRestart = 0;
  264. ULONG NtfsCleanCheckpoints = 0;
  265. ULONG NtfsPostRequests = 0;
  266. const UCHAR BaadSignature[4] = {'B', 'A', 'A', 'D'};
  267. const UCHAR IndexSignature[4] = {'I', 'N', 'D', 'X'};
  268. const UCHAR FileSignature[4] = {'F', 'I', 'L', 'E'};
  269. const UCHAR HoleSignature[4] = {'H', 'O', 'L', 'E'};
  270. const UCHAR ChkdskSignature[4] = {'C', 'H', 'K', 'D'};
  271. //
  272. // Large Reserved Buffer Context
  273. //
  274. ULONG NtfsReservedInUse = 0;
  275. PVOID NtfsReserved1 = NULL;
  276. PVOID NtfsReserved2 = NULL;
  277. ULONG NtfsReserved2Count = 0;
  278. PVOID NtfsReserved3 = NULL;
  279. PVOID NtfsReserved1Thread = NULL;
  280. PVOID NtfsReserved2Thread = NULL;
  281. PVOID NtfsReserved3Thread = NULL;
  282. PFCB NtfsReserved12Fcb = NULL;
  283. PFCB NtfsReserved3Fcb = NULL;
  284. PVOID NtfsReservedBufferThread = NULL;
  285. BOOLEAN NtfsBufferAllocationFailure = FALSE;
  286. FAST_MUTEX NtfsReservedBufferMutex;
  287. ERESOURCE NtfsReservedBufferResource;
  288. LARGE_INTEGER NtfsShortDelay = {(ULONG)-100000, -1}; // 10 milliseconds
  289. FAST_MUTEX NtfsScavengerLock;
  290. PIRP_CONTEXT NtfsScavengerWorkList;
  291. BOOLEAN NtfsScavengerRunning;
  292. ULONGLONG NtfsMaxQuotaNotifyRate = MIN_QUOTA_NOTIFY_TIME;
  293. ULONG NtfsAsyncPostThreshold;
  294. UCHAR NtfsZeroExtendedInfo[48];
  295. typedef struct _VOLUME_ERROR_PACKET {
  296. NTSTATUS Status;
  297. UNICODE_STRING FileName;
  298. PKTHREAD Thread;
  299. } VOLUME_ERROR_PACKET, *PVOLUME_ERROR_PACKET;
  300. #ifdef NTFS_RWC_DEBUG
  301. //
  302. // Range to include in COW checks.
  303. //
  304. LONGLONG NtfsRWCLowThreshold = 0;
  305. LONGLONG NtfsRWCHighThreshold = 0x7fffffffffffffff;
  306. #endif
  307. VOID
  308. NtfsResolveVolumeAndRaiseErrorSpecial (
  309. IN PIRP_CONTEXT IrpContext,
  310. IN OUT PVOID Context
  311. );
  312. NTSTATUS
  313. NtfsFsdDispatchSwitch (
  314. IN PIRP_CONTEXT StackIrpContext OPTIONAL,
  315. IN PIRP Irp,
  316. IN BOOLEAN Wait
  317. );
  318. //
  319. // Locals used to track specific failures.
  320. //
  321. BOOLEAN NtfsTestStatus = FALSE;
  322. BOOLEAN NtfsTestFilter = FALSE;
  323. NTSTATUS NtfsTestStatusCode = STATUS_SUCCESS;
  324. #ifdef ALLOC_PRAGMA
  325. #pragma alloc_text(PAGE, NtfsFastIoCheckIfPossible)
  326. #pragma alloc_text(PAGE, NtfsFastQueryBasicInfo)
  327. #pragma alloc_text(PAGE, NtfsFastQueryStdInfo)
  328. #pragma alloc_text(PAGE, NtfsFastQueryNetworkOpenInfo)
  329. #pragma alloc_text(PAGE, NtfsFastIoQueryCompressionInfo)
  330. #pragma alloc_text(PAGE, NtfsFastIoQueryCompressedSize)
  331. #pragma alloc_text(PAGE, NtfsFsdDispatch)
  332. #pragma alloc_text(PAGE, NtfsFsdDispatchWait)
  333. #pragma alloc_text(PAGE, NtfsFsdDispatchSwitch)
  334. #pragma alloc_text(PAGE, NtfsResolveVolumeAndRaiseErrorSpecial)
  335. #endif
  336. //
  337. // Internal support routines
  338. //
  339. LONG
  340. NtfsProcessExceptionFilter (
  341. IN PEXCEPTION_POINTERS ExceptionPointer
  342. )
  343. {
  344. UNREFERENCED_PARAMETER( ExceptionPointer );
  345. ASSERT( ExceptionPointer->ExceptionRecord->ExceptionCode != STATUS_LOG_FILE_FULL );
  346. #ifndef LFS_CLUSTER_CHECK
  347. ASSERT( NT_SUCCESS( ExceptionPointer->ExceptionRecord->ExceptionCode ));
  348. #endif
  349. return EXCEPTION_EXECUTE_HANDLER;
  350. }
  351. ULONG
  352. NtfsRaiseStatusFunction (
  353. IN PIRP_CONTEXT IrpContext,
  354. IN NTSTATUS Status
  355. )
  356. /*++
  357. Routine Description:
  358. This routine is only required by the NtfsDecodeFileObject macro. It is
  359. a function wrapper around NtfsRaiseStatus.
  360. Arguments:
  361. Status - Status to raise
  362. Return Value:
  363. 0 - but no one will see it!
  364. --*/
  365. {
  366. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  367. return 0;
  368. }
  369. VOID
  370. NtfsRaiseStatus (
  371. IN PIRP_CONTEXT IrpContext,
  372. IN NTSTATUS Status,
  373. IN PFILE_REFERENCE FileReference OPTIONAL,
  374. IN PFCB Fcb OPTIONAL
  375. )
  376. {
  377. //
  378. // If the caller is declaring corruption, then let's mark the
  379. // the volume corrupt appropriately, and maybe generate a popup.
  380. //
  381. if ((Status == STATUS_DISK_CORRUPT_ERROR) ||
  382. (Status == STATUS_FILE_CORRUPT_ERROR) ||
  383. (Status == STATUS_EA_CORRUPT_ERROR)) {
  384. if ((IrpContext->Vcb != NULL) &&
  385. (IRP_MJ_FILE_SYSTEM_CONTROL == IrpContext->MajorFunction) &&
  386. (IRP_MN_MOUNT_VOLUME == IrpContext->MinorFunction) &&
  387. FlagOn( IrpContext->Vcb->Vpb->RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION ) &&
  388. !FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS )) {
  389. NtfsBugCheck( (ULONG_PTR)IrpContext, (ULONG_PTR)Status, 0 );
  390. }
  391. NtfsPostVcbIsCorrupt( IrpContext, Status, FileReference, Fcb );
  392. }
  393. //
  394. // Set a flag to indicate that we raised this status code and store
  395. // it in the IrpContext.
  396. //
  397. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RAISED_STATUS );
  398. if (NT_SUCCESS( IrpContext->ExceptionStatus )) {
  399. //
  400. // If this is a paging io request and we got a Quota Exceeded error
  401. // then translate the status to FILE_LOCK_CONFLICT so that this
  402. // is a retryable condition in the write path.
  403. //
  404. if ((Status == STATUS_QUOTA_EXCEEDED) &&
  405. (IrpContext->MajorFunction == IRP_MJ_WRITE) &&
  406. (IrpContext->OriginatingIrp != NULL) &&
  407. (FlagOn( IrpContext->OriginatingIrp->Flags, IRP_PAGING_IO ))) {
  408. Status = STATUS_FILE_LOCK_CONFLICT;
  409. }
  410. IrpContext->ExceptionStatus = Status;
  411. }
  412. //
  413. // Now finally raise the status, and make sure we do not come back.
  414. //
  415. ExRaiseStatus( IrpContext->ExceptionStatus );
  416. }
  417. LONG
  418. NtfsExceptionFilter (
  419. IN PIRP_CONTEXT IrpContext OPTIONAL,
  420. IN PEXCEPTION_POINTERS ExceptionPointer
  421. )
  422. /*++
  423. Routine Description:
  424. This routine is used to decide if we should or should not handle
  425. an exception status that is being raised. It inserts the status
  426. into the IrpContext and either indicates that we should handle
  427. the exception or bug check the system.
  428. Arguments:
  429. ExceptionPointer - Supplies the exception record to being checked.
  430. Return Value:
  431. ULONG - returns EXCEPTION_EXECUTE_HANDLER or bugchecks
  432. --*/
  433. {
  434. NTSTATUS ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
  435. ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
  436. DebugTrace( 0, DEBUG_TRACE_UNWIND, ("NtfsExceptionFilter %X\n", ExceptionCode) );
  437. //
  438. // Check if this status is the status we are watching for.
  439. //
  440. if (NtfsTestFilter && (NtfsTestStatusCode == ExceptionCode)) {
  441. NtfsTestStatusProc();
  442. }
  443. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  444. //
  445. // We should not raise insufficient resources during paging file reads
  446. //
  447. if (ARGUMENT_PRESENT( IrpContext ) && (IrpContext->OriginatingIrp != NULL)) {
  448. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
  449. PSCB Scb = NULL;
  450. if (IrpSp->FileObject != NULL) {
  451. Scb = (PSCB)IrpSp->FileObject->FsContext;
  452. }
  453. ASSERT( (IrpContext->MajorFunction != IRP_MJ_READ) ||
  454. (ExceptionCode != STATUS_INSUFFICIENT_RESOURCES) ||
  455. (Scb == NULL) ||
  456. (!FlagOn( Scb->Fcb->FcbState, FCB_STATE_PAGING_FILE )) );
  457. }
  458. #endif
  459. //
  460. // If the exception is an in page error, then get the real I/O error code
  461. // from the exception record
  462. //
  463. if ((ExceptionCode == STATUS_IN_PAGE_ERROR) &&
  464. (ExceptionPointer->ExceptionRecord->NumberParameters >= 3)) {
  465. ExceptionCode = (NTSTATUS) ExceptionPointer->ExceptionRecord->ExceptionInformation[2];
  466. //
  467. // If we got FILE_LOCK_CONFLICT from a paging request then change it
  468. // to STATUS_CANT_WAIT. This means that we couldn't wait for a
  469. // reserved buffer or some other retryable condition. In the write
  470. // case the correct error is already in the IrpContext. The read
  471. // case doesn't pass the error back via the top-level irp context
  472. // however.
  473. //
  474. if (ExceptionCode == STATUS_FILE_LOCK_CONFLICT) {
  475. ExceptionCode = STATUS_CANT_WAIT;
  476. }
  477. }
  478. //
  479. // If there is not an irp context, we must have had insufficient resources
  480. //
  481. if (!ARGUMENT_PRESENT(IrpContext)) {
  482. //
  483. // Check whether this is a fatal error and bug check if so.
  484. // Typically the only error is insufficient resources but
  485. // it is possible that pool has been corrupted.
  486. //
  487. if (!FsRtlIsNtstatusExpected( ExceptionCode )) {
  488. NtfsBugCheck( (ULONG_PTR)ExceptionPointer->ExceptionRecord,
  489. (ULONG_PTR)ExceptionPointer->ContextRecord,
  490. (ULONG_PTR)ExceptionPointer->ExceptionRecord->ExceptionAddress );
  491. }
  492. return EXCEPTION_EXECUTE_HANDLER;
  493. }
  494. //
  495. // For now break if we catch corruption errors on both free and checked
  496. // TODO: Remove this before we ship
  497. //
  498. if (NtfsBreakOnCorrupt &&
  499. ((ExceptionCode == STATUS_FILE_CORRUPT_ERROR) ||
  500. (ExceptionCode == STATUS_DISK_CORRUPT_ERROR))) {
  501. if (*KdDebuggerEnabled) {
  502. DbgPrint("*******************************************\n");
  503. DbgPrint("NTFS detected corruption on your volume\n");
  504. DbgPrint("IrpContext=0x%08x, VCB=0x%08x\n",IrpContext,IrpContext->Vcb);
  505. DbgPrint("Send email to NTFSDEV\n");
  506. DbgPrint("*******************************************\n");
  507. DbgBreakPoint();
  508. while (NtfsPageInAddress) {
  509. volatile CHAR test;
  510. if (NtfsMapOffset != -1) {
  511. PBCB Bcb;
  512. PVOID Buffer;
  513. CcMapData( IrpContext->Vcb->LogFileObject, (PLARGE_INTEGER)&NtfsMapOffset, PAGE_SIZE, TRUE, &Bcb, &Buffer );
  514. }
  515. test = *NtfsPageInAddress;
  516. DbgBreakPoint();
  517. }
  518. }
  519. }
  520. /*
  521. #if (DBG || defined( NTFS_FREE_ASSERTS ) || NTFS_RESTART)
  522. ASSERT( !NtfsBreakOnCorrupt ||
  523. ((ExceptionCode != STATUS_FILE_CORRUPT_ERROR) &&
  524. (ExceptionCode != STATUS_DISK_CORRUPT_ERROR) ));
  525. #endif
  526. */
  527. //
  528. // When processing any exceptions we always can wait. Remember the
  529. // current state of the wait flag so we can restore while processing
  530. // the exception.
  531. //
  532. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT )) {
  533. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  534. }
  535. SetFlag(IrpContext->State, IRP_CONTEXT_STATE_WAIT);
  536. //
  537. // If someone got STATUS_LOG_FILE_FULL or STATUS_CANT_WAIT, let's
  538. // handle that. Note any other error that also happens will
  539. // probably not go away and will just reoccur. If it does go
  540. // away, that's ok too.
  541. //
  542. if (IrpContext->TopLevelIrpContext == IrpContext) {
  543. if ((IrpContext->ExceptionStatus == STATUS_LOG_FILE_FULL) ||
  544. (IrpContext->ExceptionStatus == STATUS_CANT_WAIT)) {
  545. ExceptionCode = IrpContext->ExceptionStatus;
  546. }
  547. }
  548. //
  549. // If we didn't raise this status code then we need to check if
  550. // we should handle this exception.
  551. //
  552. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_RAISED_STATUS )) {
  553. if (FsRtlIsNtstatusExpected( ExceptionCode )) {
  554. //
  555. // If we got an allocation failure doing paging Io then convert
  556. // this to FILE_LOCK_CONFLICT.
  557. //
  558. if ((ExceptionCode == STATUS_QUOTA_EXCEEDED) &&
  559. (IrpContext->MajorFunction == IRP_MJ_WRITE) &&
  560. (IrpContext->OriginatingIrp != NULL) &&
  561. (FlagOn( IrpContext->OriginatingIrp->Flags, IRP_PAGING_IO ))) {
  562. ExceptionCode = STATUS_FILE_LOCK_CONFLICT;
  563. }
  564. IrpContext->ExceptionStatus = ExceptionCode;
  565. } else {
  566. NtfsBugCheck( (ULONG_PTR)ExceptionPointer->ExceptionRecord,
  567. (ULONG_PTR)ExceptionPointer->ContextRecord,
  568. (ULONG_PTR)ExceptionPointer->ExceptionRecord->ExceptionAddress );
  569. }
  570. } else {
  571. //
  572. // We raised this code explicitly ourselves, so it had better be
  573. // expected.
  574. //
  575. ASSERT( ExceptionCode == IrpContext->ExceptionStatus );
  576. ASSERT( FsRtlIsNtstatusExpected( ExceptionCode ) );
  577. }
  578. #ifdef LFS_CLUSTER_CHECK
  579. ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DISMOUNT_LOG_FLUSH ) ||
  580. ((IrpContext->ExceptionStatus != STATUS_NO_SUCH_DEVICE) &&
  581. (IrpContext->ExceptionStatus != STATUS_DEVICE_BUSY) &&
  582. (IrpContext->ExceptionStatus != STATUS_DEVICE_OFF_LINE) ));
  583. #endif
  584. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RAISED_STATUS );
  585. //
  586. // If the exception code is log file full, then remember the current
  587. // RestartAreaLsn in the Vcb, so we can see if we are the ones to flush
  588. // the log file later. Note, this does not have to be synchronized,
  589. // because we are just using it to arbitrate who must do the flush, but
  590. // eventually someone will anyway.
  591. //
  592. if (ExceptionCode == STATUS_LOG_FILE_FULL) {
  593. IrpContext->TopLevelIrpContext->LastRestartArea = IrpContext->Vcb->LastRestartArea;
  594. IrpContext->Vcb->LogFileFullCount += 1;
  595. }
  596. return EXCEPTION_EXECUTE_HANDLER;
  597. }
  598. NTSTATUS
  599. NtfsProcessException (
  600. IN PIRP_CONTEXT IrpContext OPTIONAL,
  601. IN PIRP Irp OPTIONAL,
  602. IN NTSTATUS ExceptionCode
  603. )
  604. /*++
  605. Routine Description:
  606. This routine process an exception. It either completes the request
  607. with the saved exception status or it sends the request off to the Fsp
  608. Arguments:
  609. Irp - Supplies the Irp being processed
  610. ExceptionCode - Supplies the normalized exception status being handled
  611. Return Value:
  612. NTSTATUS - Returns the results of either posting the Irp or the
  613. saved completion status.
  614. --*/
  615. {
  616. PVCB Vcb;
  617. PIRP_CONTEXT PostIrpContext = NULL;
  618. BOOLEAN Retry = FALSE;
  619. PUSN_FCB ThisUsn, LastUsn;
  620. BOOLEAN ReleaseBitmap = FALSE;
  621. ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
  622. ASSERT_OPTIONAL_IRP( Irp );
  623. DebugTrace( 0, Dbg, ("NtfsProcessException\n") );
  624. //
  625. // If there is not an irp context, we must have had insufficient resources
  626. //
  627. if (IrpContext == NULL) {
  628. NtfsCompleteRequest( NULL, Irp, ExceptionCode );
  629. return ExceptionCode;
  630. }
  631. //
  632. // Get the real exception status from the Irp Context.
  633. //
  634. ExceptionCode = IrpContext->ExceptionStatus;
  635. //
  636. // All errors which could possibly have started a transaction must go
  637. // through here. Abort the transaction.
  638. //
  639. //
  640. // Increment the appropriate performance counters.
  641. //
  642. Vcb = IrpContext->Vcb;
  643. CollectExceptionStats( Vcb, ExceptionCode );
  644. try {
  645. //
  646. // If this is an Mdl write request, then take care of the Mdl
  647. // here so that things get cleaned up properly, and in the
  648. // case of log file full we will just create a new Mdl. By
  649. // getting rid of this Mdl now, the pages will not be locked
  650. // if we try to truncate the file while restoring snapshots.
  651. //
  652. if ((IrpContext->MajorFunction == IRP_MJ_WRITE) &&
  653. (FlagOn( IrpContext->MinorFunction, IRP_MN_MDL | IRP_MN_COMPLETE ) == IRP_MN_MDL) &&
  654. (Irp->MdlAddress != NULL)) {
  655. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  656. CcMdlWriteAbort( IrpSp->FileObject, Irp->MdlAddress );
  657. Irp->MdlAddress = NULL;
  658. }
  659. //
  660. // On a failed mount this value will be NULL. Don't perform the
  661. // abort in that case or we will fail when looking at the Vcb
  662. // in the Irp COntext.
  663. //
  664. if (Vcb != NULL) {
  665. //
  666. // To make sure that we can access all of our streams correctly,
  667. // we first restore all of the higher sizes before aborting the
  668. // transaction. Then we restore all of the lower sizes after
  669. // the abort, so that all Scbs are finally restored.
  670. //
  671. NtfsRestoreScbSnapshots( IrpContext, TRUE );
  672. //
  673. // If we modified the volume bitmap during this transaction we
  674. // want to acquire it and hold it throughout the abort process.
  675. // Otherwise this abort could constantly be setting the rescan
  676. // bitmap flag at the same time as some interleaved transaction
  677. // is performing bitmap operations and we will thrash performing
  678. // bitmap scans.
  679. //
  680. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MODIFIED_BITMAP ) &&
  681. (IrpContext->TransactionId != 0)) {
  682. //
  683. // Acquire the resource and remember we need to release it.
  684. //
  685. NtfsAcquireResourceExclusive( IrpContext, Vcb->BitmapScb, TRUE );
  686. //
  687. // Restore the free cluster count in the Vcb.
  688. //
  689. Vcb->FreeClusters -= IrpContext->FreeClusterChange;
  690. ReleaseBitmap = TRUE;
  691. }
  692. //
  693. // If we are aborting a transaction, then it is important to clear out the
  694. // Usn reasons, so we do not try to write a Usn Journal record for
  695. // somthing that did not happen! Worse yet if we get a log file full
  696. // we fail the abort, which is not allowed.
  697. //
  698. // First, reset the bits in the Fcb, so we will not fail to allow posting
  699. // and writing these bits later. Note that all the reversible changes are
  700. // done with the Fcb exclusive, and they are actually backed out anyway.
  701. // All the nonreversible ones (only unnamed and named data overwrite) are
  702. // forced out first anyway before the data is actually modified.
  703. //
  704. ThisUsn = &IrpContext->Usn;
  705. do {
  706. PFCB UsnFcb;
  707. if (ThisUsn->CurrentUsnFcb != NULL) {
  708. UsnFcb = ThisUsn->CurrentUsnFcb;
  709. NtfsLockFcb( IrpContext, UsnFcb );
  710. //
  711. // We may hold nothing here (write path) so we have to retest for the usn
  712. // after locking it down in case of the deleteusnjournal worker
  713. //
  714. if (UsnFcb->FcbUsnRecord != NULL) {
  715. //
  716. // If any rename flags are part of the new reasons then
  717. // make sure to look the name up again.
  718. //
  719. if (FlagOn( ThisUsn->NewReasons,
  720. USN_REASON_RENAME_NEW_NAME | USN_REASON_RENAME_OLD_NAME )) {
  721. ClearFlag( UsnFcb->FcbState, FCB_STATE_VALID_USN_NAME );
  722. }
  723. //
  724. // Now restore the reason and source info fields.
  725. //
  726. ClearFlag( UsnFcb->FcbUsnRecord->UsnRecord.Reason,
  727. ThisUsn->NewReasons );
  728. if (UsnFcb->FcbUsnRecord->UsnRecord.Reason == 0) {
  729. UsnFcb->FcbUsnRecord->UsnRecord.SourceInfo = 0;
  730. } else {
  731. SetFlag( UsnFcb->FcbUsnRecord->UsnRecord.SourceInfo,
  732. ThisUsn->RemovedSourceInfo );
  733. }
  734. }
  735. NtfsUnlockFcb( IrpContext, UsnFcb );
  736. //
  737. // Zero out the structure.
  738. //
  739. ThisUsn->CurrentUsnFcb = NULL;
  740. ThisUsn->NewReasons = 0;
  741. ThisUsn->RemovedSourceInfo = 0;
  742. ThisUsn->UsnFcbFlags = 0;
  743. if (ThisUsn != &IrpContext->Usn) {
  744. LastUsn->NextUsnFcb = ThisUsn->NextUsnFcb;
  745. NtfsFreePool( ThisUsn );
  746. ThisUsn = LastUsn;
  747. }
  748. }
  749. if (ThisUsn->NextUsnFcb == NULL) {
  750. break;
  751. }
  752. LastUsn = ThisUsn;
  753. ThisUsn = ThisUsn->NextUsnFcb;
  754. } while (TRUE);
  755. //
  756. // Only abort the transaction if the volume is still mounted.
  757. //
  758. if (FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  759. NtfsAbortTransaction( IrpContext, Vcb, NULL );
  760. }
  761. if (ReleaseBitmap) {
  762. NtfsReleaseResource( IrpContext, Vcb->BitmapScb );
  763. ReleaseBitmap = FALSE;
  764. }
  765. NtfsRestoreScbSnapshots( IrpContext, FALSE );
  766. NtfsAcquireCheckpoint( IrpContext, Vcb );
  767. SetFlag( Vcb->MftDefragState, VCB_MFT_DEFRAG_ENABLED );
  768. NtfsReleaseCheckpoint( IrpContext, Vcb );
  769. //
  770. // It is a rare path where the user is extending a volume and has hit
  771. // an exception. In that case we need to roll back the total clusters
  772. // in the Vcb. We detect this case is possible by comparing the
  773. // snapshot value for total clusters in the Vcb.
  774. //
  775. if (Vcb->TotalClusters != Vcb->PreviousTotalClusters) {
  776. //
  777. // Someone is changing this value but is it us.
  778. //
  779. if ((Vcb->BitmapScb != NULL) &&
  780. NtfsIsExclusiveScb( Vcb->BitmapScb )) {
  781. Vcb->TotalClusters = Vcb->PreviousTotalClusters;
  782. }
  783. }
  784. }
  785. //
  786. // Exceptions at this point are pretty bad, we failed to undo everything.
  787. //
  788. } except(NtfsProcessExceptionFilter( GetExceptionInformation() )) {
  789. PSCB_SNAPSHOT ScbSnapshot;
  790. PSCB NextScb;
  791. //
  792. // Update counter
  793. //
  794. NtfsFailedAborts += 1;
  795. //
  796. // If we get an exception doing this then things are in really bad
  797. // shape but we still don't want to bugcheck the system so we
  798. // need to protect ourselves
  799. //
  800. try {
  801. NtfsPostVcbIsCorrupt( IrpContext, 0, NULL, NULL );
  802. } except(NtfsProcessExceptionFilter( GetExceptionInformation() )) {
  803. NOTHING;
  804. }
  805. if (ReleaseBitmap) {
  806. //
  807. // Since we had an unexpected failure and we know that
  808. // we have modified the bitmap we need to do a complete
  809. // scan to accurately know the free cluster count.
  810. //
  811. SetFlag( Vcb->VcbState, VCB_STATE_RELOAD_FREE_CLUSTERS );
  812. NtfsReleaseResource( IrpContext, Vcb->BitmapScb );
  813. ReleaseBitmap = FALSE;
  814. }
  815. //
  816. // We have taken all the steps possible to cleanup the current
  817. // transaction and it has failed. Any of the Scb's involved in
  818. // this transaction could now be out of ssync with the on-disk
  819. // structures. We can't go to disk to restore this so we will
  820. // clean up the in-memory structures as best we can so that the
  821. // system won't crash.
  822. //
  823. // We will go through the Scb snapshot list and knock down the
  824. // sizes to the lower of the two values. We will also truncate
  825. // the Mcb to that allocation. If this is a normal data stream
  826. // we will actually empty the Mcb.
  827. //
  828. ScbSnapshot = &IrpContext->ScbSnapshot;
  829. //
  830. // There is no snapshot data to restore if the Flink is still NULL.
  831. //
  832. if (ScbSnapshot->SnapshotLinks.Flink != NULL) {
  833. //
  834. // Loop to retore first the Scb data from the snapshot in the
  835. // IrpContext, and then 0 or more additional snapshots linked
  836. // to the IrpContext.
  837. //
  838. do {
  839. NextScb = ScbSnapshot->Scb;
  840. if (NextScb == NULL) {
  841. ScbSnapshot = (PSCB_SNAPSHOT)ScbSnapshot->SnapshotLinks.Flink;
  842. continue;
  843. }
  844. //
  845. // Unload all information from memory and force future references to resynch to disk
  846. // for all regular files. For system files / paging files truncate all sizes
  847. // and unload based on the snapshot
  848. //
  849. if (!FlagOn( NextScb->Fcb->FcbState, FCB_STATE_SYSTEM_FILE | FCB_STATE_PAGING_FILE )) {
  850. ClearFlag( NextScb->ScbState, SCB_STATE_HEADER_INITIALIZED | SCB_STATE_FILE_SIZE_LOADED );
  851. NextScb->Header.AllocationSize.QuadPart =
  852. NextScb->Header.FileSize.QuadPart =
  853. NextScb->Header.ValidDataLength.QuadPart = 0;
  854. //
  855. // Remove all of the mappings in the Mcb.
  856. //
  857. NtfsUnloadNtfsMcbRange( &NextScb->Mcb, (LONGLONG)0, MAXLONGLONG, FALSE, FALSE );
  858. //
  859. // If there is any caching tear it down so that we reinit it with values off disk
  860. //
  861. if (NextScb->FileObject) {
  862. NtfsDeleteInternalAttributeStream( NextScb, TRUE, FALSE );
  863. }
  864. } else {
  865. //
  866. // Go through each of the sizes and use the lower value for system files.
  867. //
  868. if (ScbSnapshot->AllocationSize < NextScb->Header.AllocationSize.QuadPart) {
  869. NextScb->Header.AllocationSize.QuadPart = ScbSnapshot->AllocationSize;
  870. }
  871. if (ScbSnapshot->FileSize < NextScb->Header.FileSize.QuadPart) {
  872. NextScb->Header.FileSize.QuadPart = ScbSnapshot->FileSize;
  873. }
  874. if (ScbSnapshot->ValidDataLength < NextScb->Header.ValidDataLength.QuadPart) {
  875. NextScb->Header.ValidDataLength.QuadPart = ScbSnapshot->ValidDataLength;
  876. }
  877. NtfsUnloadNtfsMcbRange( &NextScb->Mcb,
  878. Int64ShraMod32(NextScb->Header.AllocationSize.QuadPart, NextScb->Vcb->ClusterShift),
  879. MAXLONGLONG,
  880. TRUE,
  881. FALSE );
  882. //
  883. // For the mft set the record allocation context size so that it
  884. // will be reininitialized the next time its used
  885. //
  886. if (NextScb->Header.NodeTypeCode == NTFS_NTC_SCB_MFT) {
  887. NextScb->ScbType.Mft.RecordAllocationContext.CurrentBitmapSize = MAXULONG;
  888. }
  889. }
  890. //
  891. // Update the FastIoField.
  892. //
  893. NtfsAcquireFsrtlHeader( NextScb );
  894. NextScb->Header.IsFastIoPossible = FastIoIsNotPossible;
  895. NtfsReleaseFsrtlHeader( NextScb );
  896. ScbSnapshot = (PSCB_SNAPSHOT)ScbSnapshot->SnapshotLinks.Flink;
  897. } while (ScbSnapshot != &IrpContext->ScbSnapshot);
  898. }
  899. //
  900. // It is a rare path where the user is extending a volume and has hit
  901. // an exception. In that case we need to roll back the total clusters
  902. // in the Vcb. We detect this case is possible by comparing the
  903. // snapshot value for total clusters in the Vcb.
  904. //
  905. if ((Vcb != NULL) && (Vcb->TotalClusters != Vcb->PreviousTotalClusters)) {
  906. //
  907. // Someone is changing this value but is it us.
  908. //
  909. if ((Vcb->BitmapScb != NULL) &&
  910. NtfsIsExclusiveScb( Vcb->BitmapScb )) {
  911. Vcb->TotalClusters = Vcb->PreviousTotalClusters;
  912. }
  913. }
  914. //ASSERTMSG( "***Failed to abort transaction, volume is corrupt", FALSE );
  915. //
  916. // Clear the transaction Id in the IrpContext to make sure we don't
  917. // try to write any log records in the complete request.
  918. //
  919. IrpContext->TransactionId = 0;
  920. }
  921. //
  922. // If this isn't the top-level request then make sure to pass the real
  923. // error back to the top level.
  924. //
  925. if (IrpContext != IrpContext->TopLevelIrpContext) {
  926. //
  927. // Make sure this error is returned to the top level guy.
  928. // If the status is FILE_LOCK_CONFLICT then we are using this
  929. // value to stop some lower level request. Convert it to
  930. // STATUS_CANT_WAIT so the top-level request will retry.
  931. //
  932. if (NT_SUCCESS( IrpContext->TopLevelIrpContext->ExceptionStatus )) {
  933. if (ExceptionCode == STATUS_FILE_LOCK_CONFLICT) {
  934. IrpContext->TopLevelIrpContext->ExceptionStatus = STATUS_CANT_WAIT;
  935. } else {
  936. IrpContext->TopLevelIrpContext->ExceptionStatus = ExceptionCode;
  937. }
  938. }
  939. }
  940. //
  941. // We want to look at the LOG_FILE_FULL or CANT_WAIT cases and consider
  942. // if we want to post the request. We only post requests at the top
  943. // level.
  944. //
  945. if (ExceptionCode == STATUS_LOG_FILE_FULL ||
  946. ExceptionCode == STATUS_CANT_WAIT) {
  947. //
  948. // If we are top level, we will either post it or retry. Also, make
  949. // sure we always take this path for close, because we should never delete
  950. // his IrpContext.
  951. //
  952. if (NtfsIsTopLevelRequest( IrpContext ) || (IrpContext->MajorFunction == IRP_MJ_CLOSE)) {
  953. //
  954. // See if we are supposed to post the request.
  955. //
  956. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST )) {
  957. PostIrpContext = IrpContext;
  958. //
  959. // Otherwise we will retry this request in the original thread.
  960. //
  961. } else {
  962. Retry = TRUE;
  963. }
  964. //
  965. // Otherwise we will complete the request, see if there is any
  966. // related processing to do.
  967. //
  968. } else {
  969. //
  970. // We are the top level Ntfs call. If we are processing a
  971. // LOG_FILE_FULL condition then there may be no one above us
  972. // who can do the checkpoint. Go ahead and fire off a dummy
  973. // request. Do an unsafe test on the flag since it won't hurt
  974. // to generate an occasional additional request.
  975. //
  976. if ((ExceptionCode == STATUS_LOG_FILE_FULL) &&
  977. (IrpContext->TopLevelIrpContext == IrpContext) &&
  978. !FlagOn( Vcb->CheckpointFlags, VCB_DUMMY_CHECKPOINT_POSTED )) {
  979. //
  980. // Create a dummy IrpContext but protect this request with
  981. // a try-except to catch any allocation failures.
  982. //
  983. if ((ExceptionCode == STATUS_LOG_FILE_FULL) &&
  984. (IrpContext->TopLevelIrpContext == IrpContext)) {
  985. //
  986. // If this is the lazy writer then we will just set a flag
  987. // in the top level field to signal ourselves to perform
  988. // the clean checkpoint when the cache manager releases
  989. // the Scb.
  990. //
  991. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_LAZY_WRITE ) &&
  992. (NtfsGetTopLevelContext()->SavedTopLevelIrp == (PIRP) FSRTL_CACHE_TOP_LEVEL_IRP)) {
  993. SetFlag( (ULONG_PTR) NtfsGetTopLevelContext()->SavedTopLevelIrp, 0x80000000 );
  994. } else if (!FlagOn( Vcb->CheckpointFlags, VCB_DUMMY_CHECKPOINT_POSTED )) {
  995. //
  996. // Create a dummy IrpContext but protect this request with
  997. // a try-except to catch any allocation failures.
  998. //
  999. try {
  1000. PostIrpContext = NULL;
  1001. NtfsInitializeIrpContext( NULL, TRUE, &PostIrpContext );
  1002. PostIrpContext->Vcb = Vcb;
  1003. PostIrpContext->LastRestartArea = PostIrpContext->Vcb->LastRestartArea;
  1004. NtfsAcquireCheckpoint( IrpContext, Vcb );
  1005. SetFlag( Vcb->CheckpointFlags, VCB_DUMMY_CHECKPOINT_POSTED );
  1006. NtfsReleaseCheckpoint( IrpContext, Vcb );
  1007. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1008. NOTHING;
  1009. }
  1010. }
  1011. }
  1012. }
  1013. //
  1014. // If this is a paging write and we are not the top level
  1015. // request then we need to return STATUS_FILE_LOCk_CONFLICT
  1016. // to make MM happy (and keep the pages dirty) and to
  1017. // prevent this request from retrying the request.
  1018. //
  1019. ExceptionCode = STATUS_FILE_LOCK_CONFLICT;
  1020. }
  1021. }
  1022. if (PostIrpContext) {
  1023. NTSTATUS PostStatus;
  1024. //
  1025. // Clear the current error code.
  1026. //
  1027. PostIrpContext->ExceptionStatus = 0;
  1028. //
  1029. // We need a try-except in case the Lock buffer call fails.
  1030. //
  1031. try {
  1032. PostStatus = NtfsPostRequest( PostIrpContext, PostIrpContext->OriginatingIrp );
  1033. //
  1034. // If we posted the original request we don't have any
  1035. // completion work to do.
  1036. //
  1037. if (PostIrpContext == IrpContext) {
  1038. Irp = NULL;
  1039. IrpContext = NULL;
  1040. ExceptionCode = PostStatus;
  1041. }
  1042. } except (EXCEPTION_EXECUTE_HANDLER) {
  1043. //
  1044. // If we don't have an error in the IrpContext then
  1045. // generate a generic IO error. We can't use the
  1046. // original status code if either LOG_FILE_FULL or
  1047. // CANT_WAIT. We would complete the Irp yet retry the
  1048. // request.
  1049. //
  1050. if (IrpContext == PostIrpContext) {
  1051. if (PostIrpContext->ExceptionStatus == 0) {
  1052. if ((ExceptionCode == STATUS_LOG_FILE_FULL) ||
  1053. (ExceptionCode == STATUS_CANT_WAIT)) {
  1054. ExceptionCode = STATUS_UNEXPECTED_IO_ERROR;
  1055. }
  1056. } else {
  1057. ExceptionCode = PostIrpContext->ExceptionStatus;
  1058. }
  1059. }
  1060. }
  1061. }
  1062. //
  1063. // If this is a top level Ntfs request and we still have the Irp
  1064. // it means we will be retrying the request. In that case
  1065. // mark the Irp Context so it doesn't go away.
  1066. //
  1067. if (Retry) {
  1068. //
  1069. // Cleanup but don't delete the IrpContext. Don't delete the Irp.
  1070. //
  1071. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DONT_DELETE );
  1072. Irp = NULL;
  1073. //
  1074. // Clear the status code in the IrpContext, because we'll be retrying.
  1075. //
  1076. IrpContext->ExceptionStatus = 0;
  1077. //
  1078. // If this is a create then sometimes we want to complete the Irp. Otherwise
  1079. // save the Irp. Save the Irp by clearing it here.
  1080. //
  1081. } else if ((IrpContext != NULL) &&
  1082. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ) &&
  1083. FlagOn( IrpContext->State, IRP_CONTEXT_STATE_EFS_CREATE )) {
  1084. Irp = NULL;
  1085. }
  1086. NtfsCompleteRequest( IrpContext, Irp, ExceptionCode );
  1087. return ExceptionCode;
  1088. }
  1089. VOID
  1090. NtfsCompleteRequest (
  1091. IN OUT PIRP_CONTEXT IrpContext OPTIONAL,
  1092. IN OUT PIRP Irp OPTIONAL,
  1093. IN NTSTATUS Status
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. This routine completes an IRP and deallocates the IrpContext
  1098. Arguments:
  1099. IrpContext - Supplies the IrpContext being completed
  1100. Irp - Supplies the Irp being processed
  1101. Status - Supplies the status to complete the Irp with
  1102. Return Value:
  1103. None.
  1104. --*/
  1105. {
  1106. //
  1107. // If we have an Irp Context then unpin all of the repinned bcbs
  1108. // we might have collected, and delete the Irp context. Delete Irp
  1109. // Context will zero out our pointer for us.
  1110. //
  1111. if (ARGUMENT_PRESENT( IrpContext )) {
  1112. ASSERT_IRP_CONTEXT( IrpContext );
  1113. //
  1114. // If we have posted any Usn journal changes, then they better be written,
  1115. // because commit is not supposed to fail for log file full.
  1116. //
  1117. ASSERT( (IrpContext->Usn.NewReasons == 0) &&
  1118. (IrpContext->Usn.RemovedSourceInfo == 0) );
  1119. if (IrpContext->TransactionId != 0) {
  1120. NtfsCommitCurrentTransaction( IrpContext );
  1121. }
  1122. //
  1123. // Always store the status in the top level Irp Context unless
  1124. // there is already an error code.
  1125. //
  1126. if ((IrpContext != IrpContext->TopLevelIrpContext) &&
  1127. NT_SUCCESS( IrpContext->TopLevelIrpContext->ExceptionStatus )) {
  1128. IrpContext->TopLevelIrpContext->ExceptionStatus = Status;
  1129. }
  1130. NtfsCleanupIrpContext( IrpContext, TRUE );
  1131. }
  1132. //
  1133. // If we have an Irp then complete the irp.
  1134. //
  1135. if (ARGUMENT_PRESENT( Irp )) {
  1136. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1137. PSCB Scb = NULL;
  1138. if (IrpSp->FileObject) {
  1139. Scb = (PSCB) IrpSp->FileObject->FsContext;
  1140. }
  1141. ASSERT_IRP( Irp );
  1142. if (NT_ERROR( Status ) &&
  1143. FlagOn( Irp->Flags, IRP_INPUT_OPERATION )) {
  1144. Irp->IoStatus.Information = 0;
  1145. }
  1146. Irp->IoStatus.Status = Status;
  1147. #ifdef NTFS_RWC_DEBUG
  1148. ASSERT( (Status != STATUS_FILE_LOCK_CONFLICT) ||
  1149. (IrpSp->MajorFunction != IRP_MJ_READ) ||
  1150. !FlagOn( Irp->Flags, IRP_PAGING_IO ));
  1151. #endif
  1152. //
  1153. // Update counter for any failed paging file reads or writes
  1154. //
  1155. if (((IrpSp->MajorFunction == IRP_MJ_READ) ||
  1156. (IrpSp->MajorFunction == IRP_MJ_WRITE)) &&
  1157. (Status == STATUS_INSUFFICIENT_RESOURCES) &&
  1158. (Scb != NULL) &&
  1159. FlagOn( Scb->Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
  1160. NtfsFailedPagingFileOps++;
  1161. }
  1162. ASSERT( (IrpSp->MajorFunction != IRP_MJ_READ) ||
  1163. (Status != STATUS_INSUFFICIENT_RESOURCES) ||
  1164. (Scb == NULL) ||
  1165. (!FlagOn( Scb->Fcb->FcbState, FCB_STATE_PAGING_FILE )) );
  1166. //
  1167. // We should never return STATUS_CANT_WAIT on a create.
  1168. //
  1169. ASSERT( (Status != STATUS_CANT_WAIT ) ||
  1170. (IrpSp->MajorFunction != IRP_MJ_CREATE) );
  1171. #ifdef LFS_CLUSTER_CHECK
  1172. ASSERT( (IrpSp->MajorFunction != IRP_MJ_FILE_SYSTEM_CONTROL) ||
  1173. (IrpSp->MinorFunction != IRP_MN_USER_FS_REQUEST) ||
  1174. (IrpSp->Parameters.FileSystemControl.FsControlCode != FSCTL_DISMOUNT_VOLUME) ||
  1175. ((Status != STATUS_NO_SUCH_DEVICE) &&
  1176. (Status != STATUS_DEVICE_BUSY) &&
  1177. (Status != STATUS_DEVICE_OFF_LINE)) );
  1178. #endif
  1179. //
  1180. // Check if this status is the status we are watching for.
  1181. //
  1182. if (NtfsTestStatus && (NtfsTestStatusCode == Status)) {
  1183. NtfsTestStatusProc();
  1184. }
  1185. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  1186. }
  1187. return;
  1188. }
  1189. BOOLEAN
  1190. NtfsFastIoCheckIfPossible (
  1191. IN PFILE_OBJECT FileObject,
  1192. IN PLARGE_INTEGER FileOffset,
  1193. IN ULONG Length,
  1194. IN BOOLEAN Wait,
  1195. IN ULONG LockKey,
  1196. IN BOOLEAN CheckForReadOperation,
  1197. OUT PIO_STATUS_BLOCK IoStatus,
  1198. IN PDEVICE_OBJECT DeviceObject
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. This routine checks if fast i/o is possible for a read/write operation
  1203. Arguments:
  1204. FileObject - Supplies the file object used in the query
  1205. FileOffset - Supplies the starting byte offset for the read/write operation
  1206. Length - Supplies the length, in bytes, of the read/write operation
  1207. Wait - Indicates if we can wait
  1208. LockKey - Supplies the lock key
  1209. CheckForReadOperation - Indicates if this is a check for a read or write
  1210. operation
  1211. IoStatus - Receives the status of the operation if our return value is
  1212. FastIoReturnError
  1213. Return Value:
  1214. BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs
  1215. to take the long route
  1216. --*/
  1217. {
  1218. PSCB Scb;
  1219. PFCB Fcb;
  1220. LARGE_INTEGER LargeLength;
  1221. ULONG Extend, Overwrite;
  1222. UNREFERENCED_PARAMETER( DeviceObject );
  1223. UNREFERENCED_PARAMETER( IoStatus );
  1224. UNREFERENCED_PARAMETER( Wait );
  1225. PAGED_CODE();
  1226. #ifdef NTFS_NO_FASTIO
  1227. UNREFERENCED_PARAMETER( FileObject );
  1228. UNREFERENCED_PARAMETER( FileOffset );
  1229. UNREFERENCED_PARAMETER( Length );
  1230. UNREFERENCED_PARAMETER( LockKey );
  1231. UNREFERENCED_PARAMETER( CheckForReadOperation );
  1232. return FALSE;
  1233. #endif
  1234. //
  1235. // Decode the file object to get our fcb, the only one we want
  1236. // to deal with is a UserFileOpen
  1237. //
  1238. #ifdef COMPRESS_ON_WIRE
  1239. if (((Scb = NtfsFastDecodeUserFileOpen( FileObject )) == NULL) ||
  1240. ((Scb->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) && (Scb->Header.FileObjectC == NULL))) {
  1241. return FALSE;
  1242. }
  1243. #else
  1244. if ((Scb = NtfsFastDecodeUserFileOpen( FileObject )) == NULL) {
  1245. return FALSE;
  1246. }
  1247. #endif
  1248. LargeLength = RtlConvertUlongToLargeInteger( Length );
  1249. //
  1250. // Based on whether this is a read or write operation we call
  1251. // fsrtl check for read/write
  1252. //
  1253. if (CheckForReadOperation) {
  1254. if (Scb->ScbType.Data.FileLock == NULL
  1255. || FsRtlFastCheckLockForRead( Scb->ScbType.Data.FileLock,
  1256. FileOffset,
  1257. &LargeLength,
  1258. LockKey,
  1259. FileObject,
  1260. PsGetCurrentProcess() )) {
  1261. return TRUE;
  1262. }
  1263. } else {
  1264. ULONG Reason = 0;
  1265. Overwrite = (FileOffset->QuadPart < Scb->Header.FileSize.QuadPart);
  1266. Extend = ((FileOffset->QuadPart + Length) > Scb->Header.FileSize.QuadPart);
  1267. if (Scb->ScbType.Data.FileLock == NULL
  1268. || FsRtlFastCheckLockForWrite( Scb->ScbType.Data.FileLock,
  1269. FileOffset,
  1270. &LargeLength,
  1271. LockKey,
  1272. FileObject,
  1273. PsGetCurrentProcess() )) {
  1274. //
  1275. // Make sure we don't have to post a Usn change.
  1276. //
  1277. Fcb = Scb->Fcb;
  1278. NtfsLockFcb( NULL, Fcb );
  1279. if (Fcb->FcbUsnRecord != NULL) {
  1280. Reason = Fcb->FcbUsnRecord->UsnRecord.Reason;
  1281. }
  1282. NtfsUnlockFcb( NULL, Fcb );
  1283. if (((Scb->AttributeName.Length != 0) ?
  1284. ((!Overwrite || FlagOn(Reason, USN_REASON_NAMED_DATA_OVERWRITE)) &&
  1285. (!Extend || FlagOn(Reason, USN_REASON_NAMED_DATA_EXTEND))) :
  1286. ((!Overwrite || FlagOn(Reason, USN_REASON_DATA_OVERWRITE)) &&
  1287. (!Extend || FlagOn(Reason, USN_REASON_DATA_EXTEND))))
  1288. &&
  1289. //
  1290. // If the file is compressed, reserve clusters for it.
  1291. //
  1292. ((Scb->CompressionUnit == 0) ||
  1293. NtfsReserveClusters( NULL, Scb, FileOffset->QuadPart, Length))) {
  1294. return TRUE;
  1295. }
  1296. }
  1297. }
  1298. return FALSE;
  1299. }
  1300. BOOLEAN
  1301. NtfsFastQueryBasicInfo (
  1302. IN PFILE_OBJECT FileObject,
  1303. IN BOOLEAN Wait,
  1304. IN OUT PFILE_BASIC_INFORMATION Buffer,
  1305. OUT PIO_STATUS_BLOCK IoStatus,
  1306. IN PDEVICE_OBJECT DeviceObject
  1307. )
  1308. /*++
  1309. Routine Description:
  1310. This routine is for the fast query call for basic file information.
  1311. Arguments:
  1312. FileObject - Supplies the file object used in this operation
  1313. Wait - Indicates if we are allowed to wait for the information
  1314. Buffer - Supplies the output buffer to receive the basic information
  1315. IoStatus - Receives the final status of the operation
  1316. Return Value:
  1317. BOOLEAN _ TRUE if the operation is successful and FALSE if the caller
  1318. needs to take the long route.
  1319. --*/
  1320. {
  1321. BOOLEAN Results = FALSE;
  1322. IRP_CONTEXT IrpContext;
  1323. TYPE_OF_OPEN TypeOfOpen;
  1324. PVCB Vcb;
  1325. PFCB Fcb;
  1326. PSCB Scb;
  1327. PCCB Ccb;
  1328. BOOLEAN FcbAcquired = FALSE;
  1329. PAGED_CODE();
  1330. //
  1331. // Prepare the dummy irp context
  1332. //
  1333. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
  1334. IrpContext.NodeTypeCode = NTFS_NTC_IRP_CONTEXT;
  1335. IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
  1336. if (Wait) {
  1337. SetFlag(IrpContext.State, IRP_CONTEXT_STATE_WAIT);
  1338. } else {
  1339. ClearFlag(IrpContext.State, IRP_CONTEXT_STATE_WAIT);
  1340. }
  1341. //
  1342. // Determine the type of open for the input file object. The callee really
  1343. // ignores the irp context for us.
  1344. //
  1345. TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  1346. FsRtlEnterFileSystem();
  1347. try {
  1348. switch (TypeOfOpen) {
  1349. case UserFileOpen:
  1350. case UserDirectoryOpen:
  1351. case StreamFileOpen:
  1352. if (ExAcquireResourceSharedLite( Fcb->Resource, Wait )) {
  1353. FcbAcquired = TRUE;
  1354. if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED ) ||
  1355. FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  1356. leave;
  1357. }
  1358. } else {
  1359. leave;
  1360. }
  1361. NtfsFillBasicInfo( Buffer, Scb );
  1362. Results = TRUE;
  1363. IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
  1364. IoStatus->Status = STATUS_SUCCESS;
  1365. break;
  1366. default:
  1367. NOTHING;
  1368. }
  1369. } finally {
  1370. if (FcbAcquired) { ExReleaseResourceLite( Fcb->Resource ); }
  1371. FsRtlExitFileSystem();
  1372. }
  1373. //
  1374. // Return to our caller
  1375. //
  1376. return Results;
  1377. UNREFERENCED_PARAMETER( DeviceObject );
  1378. }
  1379. BOOLEAN
  1380. NtfsFastQueryStdInfo (
  1381. IN PFILE_OBJECT FileObject,
  1382. IN BOOLEAN Wait,
  1383. IN OUT PFILE_STANDARD_INFORMATION Buffer,
  1384. OUT PIO_STATUS_BLOCK IoStatus,
  1385. IN PDEVICE_OBJECT DeviceObject
  1386. )
  1387. /*++
  1388. Routine Description:
  1389. This routine is for the fast query call for standard file information.
  1390. Arguments:
  1391. FileObject - Supplies the file object used in this operation
  1392. Wait - Indicates if we are allowed to wait for the information
  1393. Buffer - Supplies the output buffer to receive the basic information
  1394. IoStatus - Receives the final status of the operation
  1395. Return Value:
  1396. BOOLEAN _ TRUE if the operation is successful and FALSE if the caller
  1397. needs to take the long route.
  1398. --*/
  1399. {
  1400. BOOLEAN Results = FALSE;
  1401. IRP_CONTEXT IrpContext;
  1402. TYPE_OF_OPEN TypeOfOpen;
  1403. PVCB Vcb;
  1404. PFCB Fcb;
  1405. PSCB Scb;
  1406. PCCB Ccb;
  1407. BOOLEAN FcbAcquired = FALSE;
  1408. BOOLEAN FsRtlHeaderLocked = FALSE;
  1409. PAGED_CODE();
  1410. //
  1411. // Prepare the dummy irp context
  1412. //
  1413. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
  1414. IrpContext.NodeTypeCode = NTFS_NTC_IRP_CONTEXT;
  1415. IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
  1416. if (Wait) {
  1417. SetFlag(IrpContext.State, IRP_CONTEXT_STATE_WAIT);
  1418. } else {
  1419. ClearFlag(IrpContext.State, IRP_CONTEXT_STATE_WAIT);
  1420. }
  1421. //
  1422. // Determine the type of open for the input file object. The callee really
  1423. // ignores the irp context for us.
  1424. //
  1425. TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  1426. FsRtlEnterFileSystem();
  1427. try {
  1428. switch (TypeOfOpen) {
  1429. case UserFileOpen:
  1430. case UserDirectoryOpen:
  1431. case StreamFileOpen:
  1432. if (Scb->Header.PagingIoResource != NULL) {
  1433. ExAcquireResourceSharedLite( Scb->Header.PagingIoResource, TRUE );
  1434. }
  1435. FsRtlLockFsRtlHeader( &Scb->Header );
  1436. FsRtlHeaderLocked = TRUE;
  1437. if (ExAcquireResourceSharedLite( Fcb->Resource, Wait )) {
  1438. FcbAcquired = TRUE;
  1439. if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED ) ||
  1440. FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  1441. leave;
  1442. }
  1443. } else {
  1444. leave;
  1445. }
  1446. //
  1447. // Fill in the standard information fields. If the
  1448. // Scb is not initialized then take the long route
  1449. //
  1450. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED) &&
  1451. (Scb->AttributeTypeCode != $INDEX_ALLOCATION)) {
  1452. NOTHING;
  1453. } else {
  1454. NtfsFillStandardInfo( Buffer, Scb, Ccb );
  1455. IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION);
  1456. IoStatus->Status = STATUS_SUCCESS;
  1457. Results = TRUE;
  1458. }
  1459. break;
  1460. default:
  1461. NOTHING;
  1462. }
  1463. } finally {
  1464. if (FcbAcquired) { ExReleaseResourceLite( Fcb->Resource ); }
  1465. if (FsRtlHeaderLocked) {
  1466. FsRtlUnlockFsRtlHeader( &Scb->Header );
  1467. if (Scb->Header.PagingIoResource != NULL) {
  1468. ExReleaseResourceLite( Scb->Header.PagingIoResource );
  1469. }
  1470. }
  1471. FsRtlExitFileSystem();
  1472. }
  1473. //
  1474. // And return to our caller
  1475. //
  1476. return Results;
  1477. UNREFERENCED_PARAMETER( DeviceObject );
  1478. }
  1479. BOOLEAN
  1480. NtfsFastQueryNetworkOpenInfo (
  1481. IN PFILE_OBJECT FileObject,
  1482. IN BOOLEAN Wait,
  1483. OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
  1484. OUT PIO_STATUS_BLOCK IoStatus,
  1485. IN PDEVICE_OBJECT DeviceObject
  1486. )
  1487. /*++
  1488. Routine Description:
  1489. This routine is for the fast query network open call.
  1490. Arguments:
  1491. FileObject - Supplies the file object used in this operation
  1492. Wait - Indicates if we are allowed to wait for the information
  1493. Buffer - Supplies the output buffer to receive the information
  1494. IoStatus - Receives the final status of the operation
  1495. Return Value:
  1496. BOOLEAN _ TRUE if the operation is successful and FALSE if the caller
  1497. needs to take the long route.
  1498. --*/
  1499. {
  1500. BOOLEAN Results = FALSE;
  1501. IRP_CONTEXT IrpContext;
  1502. TYPE_OF_OPEN TypeOfOpen;
  1503. PVCB Vcb;
  1504. PFCB Fcb;
  1505. PSCB Scb;
  1506. PCCB Ccb;
  1507. BOOLEAN FcbAcquired = FALSE;
  1508. PAGED_CODE();
  1509. //
  1510. // Prepare the dummy irp context
  1511. //
  1512. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
  1513. IrpContext.NodeTypeCode = NTFS_NTC_IRP_CONTEXT;
  1514. IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
  1515. if (Wait) {
  1516. SetFlag(IrpContext.State, IRP_CONTEXT_STATE_WAIT);
  1517. } else {
  1518. ClearFlag(IrpContext.State, IRP_CONTEXT_STATE_WAIT);
  1519. }
  1520. //
  1521. // Determine the type of open for the input file object. The callee really
  1522. // ignores the irp context for us.
  1523. //
  1524. TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );
  1525. FsRtlEnterFileSystem();
  1526. try {
  1527. switch (TypeOfOpen) {
  1528. case UserFileOpen:
  1529. case UserDirectoryOpen:
  1530. case StreamFileOpen:
  1531. if (ExAcquireResourceSharedLite( Fcb->Resource, Wait )) {
  1532. FcbAcquired = TRUE;
  1533. if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED ) ||
  1534. FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED ) ||
  1535. (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED) &&
  1536. (Scb->AttributeTypeCode != $INDEX_ALLOCATION))) {
  1537. leave;
  1538. }
  1539. } else {
  1540. leave;
  1541. }
  1542. NtfsFillNetworkOpenInfo( Buffer, Scb );
  1543. IoStatus->Information = sizeof(FILE_NETWORK_OPEN_INFORMATION);
  1544. IoStatus->Status = STATUS_SUCCESS;
  1545. Results = TRUE;
  1546. break;
  1547. default:
  1548. NOTHING;
  1549. }
  1550. } finally {
  1551. if (FcbAcquired) { ExReleaseResourceLite( Fcb->Resource ); }
  1552. FsRtlExitFileSystem();
  1553. }
  1554. //
  1555. // And return to our caller
  1556. //
  1557. return Results;
  1558. UNREFERENCED_PARAMETER( DeviceObject );
  1559. }
  1560. VOID
  1561. NtfsFastIoQueryCompressionInfo (
  1562. IN PFILE_OBJECT FileObject,
  1563. OUT PFILE_COMPRESSION_INFORMATION Buffer,
  1564. OUT PIO_STATUS_BLOCK IoStatus
  1565. )
  1566. /*++
  1567. Routine Description:
  1568. This routine is a fast call for returning the comprssion information
  1569. for a file. It assumes that the caller has an exception handler and
  1570. will treat exceptions as an error. Therefore, this routine only uses
  1571. a finally clause to cleanup any resources, and it does not worry about
  1572. returning errors in the IoStatus.
  1573. Arguments:
  1574. FileObject - FileObject for the file on which the compressed information
  1575. is desired.
  1576. Buffer - Buffer to receive the compressed data information (as defined
  1577. in ntioapi.h)
  1578. IoStatus - Returns STATUS_SUCCESS and the size of the information being
  1579. returned.
  1580. Return Value:
  1581. None.
  1582. --*/
  1583. {
  1584. IRP_CONTEXT IrpContext;
  1585. TYPE_OF_OPEN TypeOfOpen;
  1586. PVCB Vcb;
  1587. PFCB Fcb;
  1588. PSCB Scb;
  1589. PCCB Ccb;
  1590. BOOLEAN ScbAcquired = FALSE;
  1591. PAGED_CODE();
  1592. //
  1593. // Prepare the dummy irp context
  1594. //
  1595. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
  1596. IrpContext.NodeTypeCode = NTFS_NTC_IRP_CONTEXT;
  1597. IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
  1598. SetFlag(IrpContext.State, IRP_CONTEXT_STATE_WAIT);
  1599. //
  1600. // Assume success (otherwise caller should see the exception)
  1601. //
  1602. IoStatus->Status = STATUS_SUCCESS;
  1603. IoStatus->Information = sizeof(FILE_COMPRESSION_INFORMATION);
  1604. //
  1605. // Determine the type of open for the input file object. The callee really
  1606. // ignores the irp context for us.
  1607. //
  1608. TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE);
  1609. if (TypeOfOpen == UnopenedFileObject) {
  1610. ExRaiseStatus( STATUS_INVALID_PARAMETER );
  1611. }
  1612. FsRtlEnterFileSystem();
  1613. try {
  1614. NtfsAcquireSharedScb( &IrpContext, Scb );
  1615. ScbAcquired = TRUE;
  1616. //
  1617. // Now return the compressed data information.
  1618. //
  1619. Buffer->CompressedFileSize.QuadPart = Scb->TotalAllocated;
  1620. Buffer->CompressionFormat = (USHORT)(Scb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK);
  1621. if (Buffer->CompressionFormat != 0) {
  1622. Buffer->CompressionFormat += 1;
  1623. }
  1624. Buffer->CompressionUnitShift = (UCHAR)(Scb->CompressionUnitShift + Vcb->ClusterShift);
  1625. Buffer->ChunkShift = NTFS_CHUNK_SHIFT;
  1626. Buffer->ClusterShift = (UCHAR)Vcb->ClusterShift;
  1627. Buffer->Reserved[0] = Buffer->Reserved[1] = Buffer->Reserved[2] = 0;
  1628. } finally {
  1629. if (ScbAcquired) {NtfsReleaseScb( &IrpContext, Scb );}
  1630. FsRtlExitFileSystem();
  1631. }
  1632. }
  1633. VOID
  1634. NtfsFastIoQueryCompressedSize (
  1635. IN PFILE_OBJECT FileObject,
  1636. IN PLARGE_INTEGER FileOffset,
  1637. OUT PULONG CompressedSize
  1638. )
  1639. /*++
  1640. Routine Description:
  1641. This routine is a fast call for returning the the size of a specified
  1642. compression unit. It assumes that the caller has an exception handler and
  1643. will treat exceptions as an error. Therefore, this routine does not even
  1644. have a finally clause, since it does not acquire any resources directly.
  1645. Arguments:
  1646. FileObject - FileObject for the file on which the compressed information
  1647. is desired.
  1648. FileOffset - FileOffset for a compression unit for which the allocated size
  1649. is desired.
  1650. CompressedSize - Returns the allocated size of the compression unit.
  1651. Return Value:
  1652. None.
  1653. --*/
  1654. {
  1655. IRP_CONTEXT IrpContext;
  1656. TYPE_OF_OPEN TypeOfOpen;
  1657. PVCB Vcb;
  1658. PFCB Fcb;
  1659. PSCB Scb;
  1660. PCCB Ccb;
  1661. VCN Vcn;
  1662. LCN Lcn;
  1663. LONGLONG SizeInBytes;
  1664. LONGLONG ClusterCount = 0;
  1665. PAGED_CODE();
  1666. //
  1667. // Prepare the dummy irp context
  1668. //
  1669. RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
  1670. IrpContext.NodeTypeCode = NTFS_NTC_IRP_CONTEXT;
  1671. IrpContext.NodeByteSize = sizeof(IRP_CONTEXT);
  1672. SetFlag(IrpContext.State, IRP_CONTEXT_STATE_WAIT);
  1673. //
  1674. // Determine the type of open for the input file object. The callee really
  1675. // ignores the irp context for us.
  1676. //
  1677. TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE);
  1678. IrpContext.Vcb = Vcb;
  1679. ASSERT(Scb->CompressionUnit != 0);
  1680. ASSERT((FileOffset->QuadPart & (Scb->CompressionUnit - 1)) == 0);
  1681. //
  1682. // Calculate the Vcn the caller wants, and initialize our output.
  1683. //
  1684. Vcn = LlClustersFromBytes( Vcb, FileOffset->QuadPart );
  1685. *CompressedSize = 0;
  1686. //
  1687. // Loop as long as we are looking up allocated Vcns.
  1688. //
  1689. while (NtfsLookupAllocation(&IrpContext, Scb, Vcn, &Lcn, &ClusterCount, NULL, NULL)) {
  1690. SizeInBytes = LlBytesFromClusters( Vcb, ClusterCount );
  1691. //
  1692. // If this allocated run goes beyond the end of the compresion unit, then
  1693. // we know it is fully allocated.
  1694. //
  1695. if ((SizeInBytes + *CompressedSize) > Scb->CompressionUnit) {
  1696. *CompressedSize = Scb->CompressionUnit;
  1697. break;
  1698. }
  1699. *CompressedSize += (ULONG)SizeInBytes;
  1700. Vcn += ClusterCount;
  1701. }
  1702. }
  1703. VOID
  1704. NtfsRaiseInformationHardError (
  1705. IN PIRP_CONTEXT IrpContext,
  1706. IN NTSTATUS Status,
  1707. IN PFILE_REFERENCE FileReference OPTIONAL,
  1708. IN PFCB Fcb OPTIONAL
  1709. )
  1710. /*++
  1711. Routine Description:
  1712. This routine is used to generate a popup in the event a corrupt file
  1713. or disk is encountered. The main purpose of the routine is to find
  1714. a name to pass to the popup package. If there is no Fcb we will take
  1715. the volume name out of the Vcb. If the Fcb has an Lcb in its Lcb list,
  1716. we will construct the name by walking backwards through the Lcb's.
  1717. If the Fcb has no Lcb but represents a system file, we will return
  1718. a default system string. If the Fcb represents a user file, but we
  1719. have no Lcb, we will use the name in the file object for the current
  1720. request.
  1721. Arguments:
  1722. Status - Error status.
  1723. FileReference - File reference being accessed in Mft when error occurred.
  1724. Fcb - If specified, this is the Fcb being used when the error was encountered.
  1725. Return Value:
  1726. None.
  1727. --*/
  1728. {
  1729. FCB_TABLE_ELEMENT Key;
  1730. PFCB_TABLE_ELEMENT Entry = NULL;
  1731. PKTHREAD Thread;
  1732. UNICODE_STRING Name;
  1733. ULONG NameLength = 0;
  1734. PFILE_OBJECT FileObject;
  1735. WCHAR *NewBuffer = NULL;
  1736. PIRP Irp = NULL;
  1737. PIO_STACK_LOCATION IrpSp;
  1738. PUNICODE_STRING FileName = NULL;
  1739. PUNICODE_STRING RelatedFileName = NULL;
  1740. BOOLEAN UseLcb = FALSE;
  1741. PVOLUME_ERROR_PACKET VolumeErrorPacket = NULL;
  1742. ULONG OldCount;
  1743. //
  1744. // Return if there is no originating Irp, for example when originating
  1745. // from NtfsPerformHotFix or if the originating irp type doesn't match an irp
  1746. //
  1747. if ((IrpContext->OriginatingIrp == NULL) ||
  1748. (IrpContext->OriginatingIrp->Type != IO_TYPE_IRP)) {
  1749. return;
  1750. }
  1751. Irp = IrpContext->OriginatingIrp;
  1752. IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
  1753. FileObject = IrpSp->FileObject;
  1754. //
  1755. // Use a try-finally to facilitate cleanup.
  1756. //
  1757. try {
  1758. //
  1759. // If the Fcb isn't specified and the file reference is, then
  1760. // try to get the Fcb from the Fcb table.
  1761. //
  1762. if (!ARGUMENT_PRESENT( Fcb )
  1763. && ARGUMENT_PRESENT( FileReference )) {
  1764. Key.FileReference = *FileReference;
  1765. NtfsAcquireFcbTable( IrpContext, IrpContext->Vcb );
  1766. Entry = RtlLookupElementGenericTable( &IrpContext->Vcb->FcbTable,
  1767. &Key );
  1768. NtfsReleaseFcbTable( IrpContext, IrpContext->Vcb );
  1769. if (Entry != NULL) {
  1770. Fcb = Entry->Fcb;
  1771. }
  1772. }
  1773. if (Irp == NULL ||
  1774. IoIsSystemThread( IrpContext->OriginatingIrp->Tail.Overlay.Thread )) {
  1775. Thread = NULL;
  1776. } else {
  1777. Thread = (PKTHREAD)IrpContext->OriginatingIrp->Tail.Overlay.Thread;
  1778. }
  1779. //
  1780. // If there is no fcb assume the error occurred in a system file.
  1781. // if its fileref is outside of this range default to $MFT
  1782. //
  1783. if (!ARGUMENT_PRESENT( Fcb )) {
  1784. if (ARGUMENT_PRESENT( FileReference )) {
  1785. if (NtfsSegmentNumber( FileReference ) <= UPCASE_TABLE_NUMBER) {
  1786. FileName = (PUNICODE_STRING)(&(NtfsSystemFiles[NtfsSegmentNumber( FileReference )]));
  1787. } else {
  1788. FileName = (PUNICODE_STRING)(&(NtfsSystemFiles[0]));
  1789. }
  1790. }
  1791. //
  1792. // If the name has an Lcb, we will contruct a name with a chain of Lcb's.
  1793. //
  1794. } else if (!IsListEmpty( &Fcb->LcbQueue )) {
  1795. UseLcb = TRUE;
  1796. //
  1797. // Check if this is a system file.
  1798. //
  1799. } else if (NtfsSegmentNumber( &Fcb->FileReference ) < FIRST_USER_FILE_NUMBER) {
  1800. if (NtfsSegmentNumber( &Fcb->FileReference ) <= UPCASE_TABLE_NUMBER) {
  1801. FileName = (PUNICODE_STRING)(&(NtfsSystemFiles[NtfsSegmentNumber( &Fcb->FileReference )]));
  1802. } else {
  1803. FileName = (PUNICODE_STRING)(&(NtfsSystemFiles[0]));
  1804. }
  1805. //
  1806. // In this case we contruct a name out of the file objects in the
  1807. // Originating Irp. If there is no file object or file object buffer
  1808. // we generate an unknown file message.
  1809. //
  1810. } else if (FileObject == NULL
  1811. || (IrpContext->MajorFunction == IRP_MJ_CREATE
  1812. && FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID ))
  1813. || (FileObject->FileName.Length == 0
  1814. && (FileObject->RelatedFileObject == NULL
  1815. || IrpContext->MajorFunction != IRP_MJ_CREATE))) {
  1816. FileName = (PUNICODE_STRING)&(NtfsUnknownFile);
  1817. //
  1818. // If there is a valid name in the file object we use that.
  1819. //
  1820. } else if ((FileObject->FileName.Length != 0) &&
  1821. (FileObject->FileName.Buffer[0] == L'\\')) {
  1822. FileName = &(FileObject->FileName);
  1823. //
  1824. // We have to construct the name from filename + related fileobject.
  1825. //
  1826. } else {
  1827. if (FileObject->FileName.Length != 0) {
  1828. FileName = &(FileObject->FileName);
  1829. }
  1830. if ((FileObject->RelatedFileObject) &&
  1831. (FileObject->RelatedFileObject->FileName.Length != 0)) {
  1832. RelatedFileName = &(FileObject->RelatedFileObject->FileName);
  1833. }
  1834. }
  1835. if (FileName) {
  1836. NameLength += FileName->Length;
  1837. }
  1838. if (RelatedFileName) {
  1839. NameLength += RelatedFileName->Length;
  1840. }
  1841. if (UseLcb) {
  1842. BOOLEAN LeadingBackslash;
  1843. NameLength += NtfsLookupNameLengthViaLcb( Fcb, &LeadingBackslash );
  1844. }
  1845. //
  1846. // Either append what info we found or default to the volume label
  1847. //
  1848. if (NameLength > 0) {
  1849. NewBuffer = NtfsAllocatePool(PagedPool, NameLength );
  1850. Name.Buffer = NewBuffer;
  1851. //
  1852. // For super long names truncate buffer size to 64k.
  1853. // RtlAppendUnicodeString handles the rest of the work
  1854. //
  1855. if (NameLength > 0xFFFF) {
  1856. NameLength = 0xFFFF;
  1857. }
  1858. Name.MaximumLength = (USHORT) NameLength;
  1859. Name.Length = 0;
  1860. if (RelatedFileName) {
  1861. RtlAppendUnicodeStringToString( &Name, RelatedFileName );
  1862. }
  1863. if (FileName) {
  1864. RtlAppendUnicodeStringToString( &Name, FileName );
  1865. }
  1866. if (UseLcb) {
  1867. NtfsFileNameViaLcb( Fcb, NewBuffer, NameLength, NameLength);
  1868. Name.Length = (USHORT) NameLength;
  1869. }
  1870. } else {
  1871. Name.Length = Name.MaximumLength = 0;
  1872. Name.Buffer = NULL;
  1873. }
  1874. //
  1875. // Only allow 1 post to resolve the volume name to occur at a time
  1876. //
  1877. OldCount = InterlockedCompareExchange( &(NtfsData.VolumeNameLookupsInProgress), 1, 0 );
  1878. if (OldCount == 0) {
  1879. VolumeErrorPacket = NtfsAllocatePool( PagedPool, sizeof( VOLUME_ERROR_PACKET ) );
  1880. VolumeErrorPacket->Status = Status;
  1881. VolumeErrorPacket->Thread = Thread;
  1882. RtlCopyMemory( &(VolumeErrorPacket->FileName), &Name, sizeof( UNICODE_STRING ) );
  1883. //
  1884. // Reference the thread to keep it around during the resolveandpost
  1885. //
  1886. if (Thread) {
  1887. ObReferenceObject( Thread );
  1888. }
  1889. //
  1890. // Now post to generate the popup. After posting ResolveVolume will free the newbuffer
  1891. //
  1892. NtfsPostSpecial( IrpContext, IrpContext->Vcb, NtfsResolveVolumeAndRaiseErrorSpecial, VolumeErrorPacket );
  1893. NewBuffer = NULL;
  1894. VolumeErrorPacket = NULL;
  1895. } else {
  1896. //
  1897. // Lets use what we have
  1898. //
  1899. IoRaiseInformationalHardError( Status, &Name, Thread );
  1900. }
  1901. } finally {
  1902. //
  1903. // Cleanup any remaining buffers we still own
  1904. //
  1905. if (NewBuffer) {
  1906. NtfsFreePool( NewBuffer );
  1907. }
  1908. if (VolumeErrorPacket) {
  1909. if (VolumeErrorPacket->Thread) {
  1910. ObDereferenceObject( VolumeErrorPacket->Thread );
  1911. }
  1912. NtfsFreePool( VolumeErrorPacket );
  1913. }
  1914. }
  1915. return;
  1916. }
  1917. VOID
  1918. NtfsResolveVolumeAndRaiseErrorSpecial (
  1919. IN PIRP_CONTEXT IrpContext,
  1920. IN OUT PVOID Context
  1921. )
  1922. /*++
  1923. Routine Description:
  1924. Resolve Vcb's win32 devicename and raise an io hard error. This is done in
  1925. a separate thread in order to have enough stack to re-enter the filesys if necc.
  1926. Also because we may reenter. Starting from here means we own no resources other than
  1927. having inc'ed the close count on the underlying vcb to prevent its going away
  1928. Arguments:
  1929. IrpContext - IrpContext containing vcb we're interested in
  1930. Context - String to append to volume win32 name
  1931. Return Value:
  1932. None.
  1933. --*/
  1934. {
  1935. UNICODE_STRING VolumeName;
  1936. NTSTATUS Status;
  1937. PVOLUME_ERROR_PACKET VolumeErrorPacket;
  1938. UNICODE_STRING FullName;
  1939. WCHAR *NewBuffer = NULL;
  1940. ULONG NameLength;
  1941. ASSERT( Context != NULL );
  1942. ASSERT( IrpContext->Vcb->NodeTypeCode == NTFS_NTC_VCB );
  1943. ASSERT( IrpContext->Vcb->Vpb->RealDevice != NULL );
  1944. VolumeErrorPacket = (PVOLUME_ERROR_PACKET) Context;
  1945. VolumeName.Length = 0;
  1946. VolumeName.Buffer = NULL;
  1947. try {
  1948. //
  1949. // Only use the target device if we haven't stopped it and deref'ed it
  1950. //
  1951. Status = IoVolumeDeviceToDosName( IrpContext->Vcb->TargetDeviceObject, &VolumeName );
  1952. ASSERT( STATUS_SUCCESS == Status );
  1953. NameLength = VolumeName.Length + VolumeErrorPacket->FileName.Length;
  1954. if (NameLength > 0) {
  1955. NewBuffer = NtfsAllocatePool( PagedPool, NameLength );
  1956. FullName.Buffer = NewBuffer;
  1957. //
  1958. // For super long names truncate buffer size to 64k.
  1959. // RtlAppendUnicodeString handles the rest of the work
  1960. //
  1961. if (NameLength > 0xFFFF) {
  1962. NameLength = 0xFFFF;
  1963. }
  1964. FullName.MaximumLength = (USHORT) NameLength;
  1965. FullName.Length = 0;
  1966. if (VolumeName.Length) {
  1967. RtlCopyUnicodeString( &FullName, &VolumeName );
  1968. }
  1969. if (VolumeErrorPacket->FileName.Length) {
  1970. RtlAppendUnicodeStringToString( &FullName, &(VolumeErrorPacket->FileName) );
  1971. }
  1972. } else {
  1973. FullName.MaximumLength = FullName.Length = IrpContext->Vcb->Vpb->VolumeLabelLength;
  1974. FullName.Buffer = (PWCHAR) IrpContext->Vcb->Vpb->VolumeLabel;
  1975. }
  1976. //
  1977. // Now generate a popup.
  1978. //
  1979. IoRaiseInformationalHardError( VolumeErrorPacket->Status, &FullName, VolumeErrorPacket->Thread );
  1980. } finally {
  1981. //
  1982. // Indicate we're done and other lookups can occur
  1983. //
  1984. InterlockedDecrement( &(NtfsData.VolumeNameLookupsInProgress) );
  1985. //
  1986. // deref the thread
  1987. //
  1988. if (VolumeErrorPacket->Thread) {
  1989. ObDereferenceObject( VolumeErrorPacket->Thread );
  1990. }
  1991. if (NewBuffer != NULL) {
  1992. NtfsFreePool( NewBuffer );
  1993. }
  1994. if (VolumeName.Buffer != NULL) {
  1995. NtfsFreePool( VolumeName.Buffer );
  1996. }
  1997. if (VolumeErrorPacket->FileName.Buffer != NULL) {
  1998. NtfsFreePool( VolumeErrorPacket->FileName.Buffer );
  1999. }
  2000. if (Context != NULL) {
  2001. NtfsFreePool( VolumeErrorPacket );
  2002. }
  2003. }
  2004. }
  2005. PTOP_LEVEL_CONTEXT
  2006. NtfsInitializeTopLevelIrp (
  2007. IN PTOP_LEVEL_CONTEXT TopLevelContext,
  2008. IN BOOLEAN ForceTopLevel,
  2009. IN BOOLEAN SetTopLevel
  2010. )
  2011. /*++
  2012. Routine Description:
  2013. This routine is called to initializethe top level context to be used in the
  2014. thread local storage. Ntfs always puts its own context in this location and restores
  2015. the previous value on exit. This routine will determine if this request is
  2016. top level and top level ntfs. It will return a pointer to the top level ntfs
  2017. context which is to be stored in the local storage and associated with the
  2018. IrpContext for this request. The return value may be the existing stack location
  2019. or a new one for a recursive request. If we will use the new one we will initialize
  2020. it but let our caller actually put it on the stack when the IrpContext is initialized.
  2021. The ThreadIrpContext field in the TopLevelContext indicates if this is already on
  2022. the stack. A NULL value indicates that this is not on the stack yet.
  2023. Arguments:
  2024. TopLevelContext - This is the local top level context for our caller.
  2025. ForceTopLevel - Always use the input top level context.
  2026. SetTopLevel - Only applies if the ForceTopLevel value is TRUE. Indicates
  2027. if we should make this look like the top level request.
  2028. Return Value:
  2029. PTOP_LEVEL_CONTEXT - Pointer to the top level ntfs context for this thread.
  2030. It may be the same as passed in by the caller. In that case the fields
  2031. will be initialized except it won't be stored on the stack and wont'
  2032. have an IrpContext field.
  2033. --*/
  2034. {
  2035. PTOP_LEVEL_CONTEXT CurrentTopLevelContext;
  2036. ULONG_PTR StackBottom;
  2037. ULONG_PTR StackTop;
  2038. BOOLEAN TopLevelRequest = TRUE;
  2039. BOOLEAN TopLevelNtfs = TRUE;
  2040. BOOLEAN ValidCurrentTopLevel = FALSE;
  2041. //
  2042. // Get the current value out of the thread local storage. If it is a zero
  2043. // value or not a pointer to a valid ntfs top level context or a valid
  2044. // Fsrtl value then we are the top level request.
  2045. //
  2046. CurrentTopLevelContext = NtfsGetTopLevelContext();
  2047. //
  2048. // Check if this is a valid Ntfs top level context.
  2049. //
  2050. IoGetStackLimits( &StackTop, &StackBottom);
  2051. if (((ULONG_PTR) CurrentTopLevelContext <= StackBottom - sizeof( TOP_LEVEL_CONTEXT )) &&
  2052. ((ULONG_PTR) CurrentTopLevelContext >= StackTop) &&
  2053. !FlagOn( (ULONG_PTR) CurrentTopLevelContext, 0x3 ) &&
  2054. (CurrentTopLevelContext->Ntfs == 0x5346544e)) {
  2055. ValidCurrentTopLevel = TRUE;
  2056. }
  2057. //
  2058. // If we are to force this request to be top level then set the
  2059. // TopLevelRequest flag according to the SetTopLevel input.
  2060. //
  2061. if (ForceTopLevel) {
  2062. TopLevelRequest = SetTopLevel;
  2063. //
  2064. // If the value is NULL then we are top level everything.
  2065. //
  2066. } else if (CurrentTopLevelContext == NULL) {
  2067. NOTHING;
  2068. //
  2069. // If this has one of the Fsrtl magic numbers then we were called from
  2070. // either the fast io path or the mm paging io path.
  2071. //
  2072. } else if ((ULONG_PTR) CurrentTopLevelContext <= FSRTL_MAX_TOP_LEVEL_IRP_FLAG) {
  2073. TopLevelRequest = FALSE;
  2074. } else if (ValidCurrentTopLevel &&
  2075. !FlagOn( CurrentTopLevelContext->ThreadIrpContext->Flags,
  2076. IRP_CONTEXT_FLAG_CALL_SELF )) {
  2077. TopLevelRequest = FALSE;
  2078. TopLevelNtfs = FALSE;
  2079. //
  2080. // Handle the case where we have returned FILE_LOCK_CONFLICT to CC and
  2081. // want to perform a clean checkpoint when releasing the resource.
  2082. //
  2083. } else if ((ULONG_PTR) CurrentTopLevelContext == (0x80000000 | FSRTL_CACHE_TOP_LEVEL_IRP)) {
  2084. TopLevelRequest = FALSE;
  2085. }
  2086. //
  2087. // If we are the top level ntfs then initialize the caller's structure.
  2088. // Leave the Ntfs signature and ThreadIrpContext NULL to indicate this is
  2089. // not in the stack yet.
  2090. //
  2091. if (TopLevelNtfs) {
  2092. TopLevelContext->Ntfs = 0;
  2093. TopLevelContext->SavedTopLevelIrp = (PIRP) CurrentTopLevelContext;
  2094. TopLevelContext->ThreadIrpContext = NULL;
  2095. TopLevelContext->TopLevelRequest = TopLevelRequest;
  2096. if (ValidCurrentTopLevel) {
  2097. TopLevelContext->VboBeingHotFixed = CurrentTopLevelContext->VboBeingHotFixed;
  2098. TopLevelContext->ScbBeingHotFixed = CurrentTopLevelContext->ScbBeingHotFixed;
  2099. TopLevelContext->ValidSavedTopLevel = TRUE;
  2100. TopLevelContext->OverflowReadThread = CurrentTopLevelContext->OverflowReadThread;
  2101. } else {
  2102. TopLevelContext->VboBeingHotFixed = 0;
  2103. TopLevelContext->ScbBeingHotFixed = NULL;
  2104. TopLevelContext->ValidSavedTopLevel = FALSE;
  2105. TopLevelContext->OverflowReadThread = FALSE;
  2106. }
  2107. return TopLevelContext;
  2108. }
  2109. return CurrentTopLevelContext;
  2110. }
  2111. //
  2112. // Non-paged routines to set up and tear down Irps for cancel.
  2113. //
  2114. BOOLEAN
  2115. NtfsSetCancelRoutine (
  2116. IN PIRP Irp,
  2117. IN PDRIVER_CANCEL CancelRoutine,
  2118. IN ULONG_PTR IrpInformation,
  2119. IN ULONG Async
  2120. )
  2121. /*++
  2122. Routine Description:
  2123. This routine is called to set up an Irp for cancel. We will set the cancel routine
  2124. and initialize the Irp information we use during cancel.
  2125. Arguments:
  2126. Irp - This is the Irp we need to set up for cancel.
  2127. CancelRoutine - This is the cancel routine for this irp.
  2128. IrpInformation - This is the context information to store in the irp
  2129. for the cancel routine.
  2130. Async - Indicates if this request is synchronous or asynchronous.
  2131. Return Value:
  2132. BOOLEAN - TRUE if we initialized the Irp, FALSE if the Irp has already
  2133. been marked cancelled. It will be marked cancelled if the user
  2134. has cancelled the irp before we could put it in the queue.
  2135. --*/
  2136. {
  2137. KIRQL Irql;
  2138. //
  2139. // Assume that the Irp has not been cancelled.
  2140. //
  2141. IoAcquireCancelSpinLock( &Irql );
  2142. if (!Irp->Cancel) {
  2143. Irp->IoStatus.Information = (ULONG_PTR) IrpInformation;
  2144. IoSetCancelRoutine( Irp, CancelRoutine );
  2145. IoReleaseCancelSpinLock( Irql );
  2146. if (Async) {
  2147. IoMarkIrpPending( Irp );
  2148. }
  2149. return TRUE;
  2150. } else {
  2151. IoReleaseCancelSpinLock( Irql );
  2152. return FALSE;
  2153. }
  2154. }
  2155. BOOLEAN
  2156. NtfsClearCancelRoutine (
  2157. IN PIRP Irp
  2158. )
  2159. /*++
  2160. Routine Description:
  2161. This routine is called to clear an Irp from cancel. It is called when Ntfs is
  2162. internally ready to continue processing the Irp. We need to know if cancel
  2163. has already been called on this Irp. In that case we allow the cancel routine
  2164. to complete the Irp.
  2165. Arguments:
  2166. Irp - This is the Irp we want to process further.
  2167. Return Value:
  2168. BOOLEAN - TRUE if we can proceed with processing the Irp, FALSE if the cancel
  2169. routine will process the Irp.
  2170. --*/
  2171. {
  2172. KIRQL Irql;
  2173. IoAcquireCancelSpinLock( &Irql );
  2174. //
  2175. // Check if the cancel routine has been called.
  2176. //
  2177. if (IoSetCancelRoutine( Irp, NULL ) == NULL) {
  2178. //
  2179. // Let our cancel routine handle the Irp.
  2180. //
  2181. IoReleaseCancelSpinLock( Irql );
  2182. return FALSE;
  2183. } else {
  2184. IoReleaseCancelSpinLock( Irql );
  2185. Irp->IoStatus.Information = 0;
  2186. return TRUE;
  2187. }
  2188. }
  2189. NTSTATUS
  2190. NtfsFsdDispatchWait (
  2191. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  2192. IN PIRP Irp
  2193. )
  2194. /*++
  2195. Routine Description:
  2196. This is the driver entry to most of the NTFS Fsd dispatch points.
  2197. IrpContext is initialized on the stack and passed from here.
  2198. Arguments:
  2199. VolumeDeviceObject - Supplies the volume device object for this request
  2200. Irp - Supplies the Irp being processed
  2201. Return Value:
  2202. NTSTATUS - The FSD status for the IRP
  2203. --*/
  2204. {
  2205. IRP_CONTEXT LocalIrpContext;
  2206. NTSTATUS Status;
  2207. Status = NtfsFsdDispatchSwitch( &LocalIrpContext, Irp, TRUE );
  2208. //
  2209. // If we ever catch ourselves using an IrpContext of this
  2210. // type, we know we are doing something wrong.
  2211. //
  2212. LocalIrpContext.NodeTypeCode = (NODE_TYPE_CODE)-1;
  2213. return Status;
  2214. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  2215. }
  2216. NTSTATUS
  2217. NtfsFsdDispatch (
  2218. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  2219. IN PIRP Irp
  2220. )
  2221. /*++
  2222. Routine Description:
  2223. This is the driver entry to NTFS Fsd dispatch IRPs that may
  2224. or may not be synchronous.
  2225. Arguments:
  2226. VolumeDeviceObject - Supplies the volume device object for this request
  2227. Irp - Supplies the Irp being processed
  2228. Return Value:
  2229. NTSTATUS - The FSD status for the IRP
  2230. --*/
  2231. {
  2232. //
  2233. // We'd rather create the IrpContext on the stack.
  2234. //
  2235. if (CanFsdWait( Irp )) {
  2236. return NtfsFsdDispatchWait( VolumeDeviceObject, Irp );
  2237. } else {
  2238. return NtfsFsdDispatchSwitch( NULL, Irp, FALSE );
  2239. }
  2240. }
  2241. //
  2242. // Local support routine.
  2243. //
  2244. NTSTATUS
  2245. NtfsFsdDispatchSwitch (
  2246. IN PIRP_CONTEXT StackIrpContext OPTIONAL,
  2247. IN PIRP Irp,
  2248. IN BOOLEAN Wait
  2249. )
  2250. /*++
  2251. Routine Description:
  2252. This is the common switch for all the FsdEntry points
  2253. that don't need special pre-processing. This simply initializes
  2254. the IrpContext and calls the 'Common*' code.
  2255. Arguments:
  2256. VolumeDeviceObject - Supplies the volume device object for this request
  2257. Irp - Supplies the Irp being processed
  2258. Wait - Can this request be posted or not?
  2259. Return Value:
  2260. NTSTATUS - The FSD status for the IRP
  2261. --*/
  2262. {
  2263. TOP_LEVEL_CONTEXT TopLevelContext;
  2264. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  2265. PIRP_CONTEXT IrpContext = NULL;
  2266. NTSTATUS Status = STATUS_SUCCESS;
  2267. ASSERT_IRP( Irp );
  2268. PAGED_CODE();
  2269. DebugTrace( +1, Dbg, ("NtfsFsdDispatch\n") );
  2270. //
  2271. // Call the common query Information routine
  2272. //
  2273. FsRtlEnterFileSystem();
  2274. //
  2275. // Always make these requests look top level.
  2276. //
  2277. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE );
  2278. do {
  2279. try {
  2280. //
  2281. // We are either initiating this request or retrying it.
  2282. //
  2283. if (IrpContext == NULL) {
  2284. //
  2285. // The optional IrpContext could reside on the caller's stack.
  2286. //
  2287. if (ARGUMENT_PRESENT( StackIrpContext )) {
  2288. IrpContext = StackIrpContext;
  2289. }
  2290. NtfsInitializeIrpContext( Irp, Wait, &IrpContext );
  2291. //
  2292. // Initialize the thread top level structure, if needed.
  2293. //
  2294. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  2295. } else if (Status == STATUS_LOG_FILE_FULL) {
  2296. NtfsCheckpointForLogFileFull( IrpContext );
  2297. }
  2298. switch (IrpContext->MajorFunction) {
  2299. case IRP_MJ_QUERY_EA:
  2300. Status = NtfsCommonQueryEa( IrpContext, Irp );
  2301. break;
  2302. case IRP_MJ_SET_EA:
  2303. Status = NtfsCommonSetEa( IrpContext, Irp );
  2304. break;
  2305. case IRP_MJ_QUERY_QUOTA:
  2306. Status = NtfsCommonQueryQuota( IrpContext, Irp );
  2307. break;
  2308. case IRP_MJ_SET_QUOTA:
  2309. Status = NtfsCommonSetQuota( IrpContext, Irp );
  2310. break;
  2311. case IRP_MJ_DEVICE_CONTROL:
  2312. Status = NtfsCommonDeviceControl( IrpContext, Irp );
  2313. break;
  2314. case IRP_MJ_QUERY_INFORMATION:
  2315. Status = NtfsCommonQueryInformation( IrpContext, Irp );
  2316. break;
  2317. case IRP_MJ_QUERY_SECURITY:
  2318. Status = NtfsCommonQuerySecurityInfo( IrpContext, Irp );
  2319. break;
  2320. case IRP_MJ_SET_SECURITY:
  2321. Status = NtfsCommonSetSecurityInfo( IrpContext, Irp );
  2322. break;
  2323. case IRP_MJ_QUERY_VOLUME_INFORMATION:
  2324. Status = NtfsCommonQueryVolumeInfo( IrpContext, Irp );
  2325. break;
  2326. case IRP_MJ_SET_VOLUME_INFORMATION:
  2327. Status = NtfsCommonSetVolumeInfo( IrpContext, Irp );
  2328. break;
  2329. default:
  2330. Status = STATUS_INVALID_DEVICE_REQUEST;
  2331. NtfsCompleteRequest( IrpContext, Irp, Status );
  2332. ASSERT(FALSE);
  2333. break;
  2334. }
  2335. break;
  2336. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  2337. //
  2338. // We had some trouble trying to perform the requested
  2339. // operation, so we'll abort the I/O request with
  2340. // the error status that we get back from the
  2341. // execption code
  2342. //
  2343. Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() );
  2344. }
  2345. } while (Status == STATUS_CANT_WAIT ||
  2346. Status == STATUS_LOG_FILE_FULL);
  2347. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  2348. FsRtlExitFileSystem();
  2349. //
  2350. // And return to our caller
  2351. //
  2352. DebugTrace( -1, Dbg, ("NtfsFsdDispatch -> %08lx\n", Status) );
  2353. return Status;
  2354. }
  2355. #ifdef NTFS_CHECK_BITMAP
  2356. BOOLEAN NtfsForceBitmapBugcheck = FALSE;
  2357. BOOLEAN NtfsDisableBitmapCheck = FALSE;
  2358. VOID
  2359. NtfsBadBitmapCopy (
  2360. IN PIRP_CONTEXT IrpContext,
  2361. IN ULONG BadBit,
  2362. IN ULONG Length
  2363. )
  2364. {
  2365. if (!NtfsDisableBitmapCheck) {
  2366. DbgPrint("%s:%d %s\n",__FILE__,__LINE__,"Invalid bitmap");
  2367. DbgBreakPoint();
  2368. if (!NtfsDisableBitmapCheck && NtfsForceBitmapBugcheck) {
  2369. KeBugCheckEx( NTFS_FILE_SYSTEM, (ULONG) IrpContext, BadBit, Length, 0 );
  2370. }
  2371. }
  2372. return;
  2373. }
  2374. BOOLEAN
  2375. NtfsCheckBitmap (
  2376. IN PVCB Vcb,
  2377. IN ULONG Lcn,
  2378. IN ULONG Count,
  2379. IN BOOLEAN Set
  2380. )
  2381. {
  2382. ULONG BitmapPage;
  2383. ULONG LastBitmapPage;
  2384. ULONG BitOffset;
  2385. ULONG BitsThisPage;
  2386. BOOLEAN Valid = FALSE;
  2387. BitmapPage = Lcn / (PAGE_SIZE * 8);
  2388. LastBitmapPage = (Lcn + Count + (PAGE_SIZE * 8) - 1) / (PAGE_SIZE * 8);
  2389. BitOffset = Lcn & ((PAGE_SIZE * 8) - 1);
  2390. if (LastBitmapPage > Vcb->BitmapPages) {
  2391. return Valid;
  2392. }
  2393. do {
  2394. BitsThisPage = Count;
  2395. if (BitOffset + Count > (PAGE_SIZE * 8)) {
  2396. BitsThisPage = (PAGE_SIZE * 8) - BitOffset;
  2397. }
  2398. if (Set) {
  2399. Valid = RtlAreBitsSet( Vcb->BitmapCopy + BitmapPage,
  2400. BitOffset,
  2401. BitsThisPage );
  2402. } else {
  2403. Valid = RtlAreBitsClear( Vcb->BitmapCopy + BitmapPage,
  2404. BitOffset,
  2405. BitsThisPage );
  2406. }
  2407. BitOffset = 0;
  2408. Count -= BitsThisPage;
  2409. BitmapPage += 1;
  2410. } while (Valid && (BitmapPage < LastBitmapPage));
  2411. if (Count != 0) {
  2412. Valid = FALSE;
  2413. }
  2414. return Valid;
  2415. }
  2416. #endif
  2417. //
  2418. // Debugging support routines used for pool verification. Alas, this works only
  2419. // on checked X86.
  2420. //
  2421. #if DBG && i386 && defined (NTFSPOOLCHECK)
  2422. //
  2423. // Number of backtrace items retrieved on X86
  2424. #define BACKTRACE_DEPTH 9
  2425. typedef struct _BACKTRACE
  2426. {
  2427. ULONG State;
  2428. ULONG Size;
  2429. PVOID Allocate[BACKTRACE_DEPTH];
  2430. PVOID Free[BACKTRACE_DEPTH];
  2431. } BACKTRACE, *PBACKTRACE;
  2432. #define STATE_ALLOCATED 'M'
  2433. #define STATE_FREE 'Z'
  2434. //
  2435. // WARNING! The following depends on pool allocations being either
  2436. // 0 mod PAGE_SIZE (for large blocks)
  2437. // or 8 mod 0x20 (for all other requests)
  2438. //
  2439. #define PAGE_ALIGNED(pv) (((ULONG)(pv) & (PAGE_SIZE - 1)) == 0)
  2440. #define IsKernelPoolBlock(pv) (PAGE_ALIGNED(pv) || (((ULONG)(pv) % 0x20) == 8))
  2441. ULONG NtfsDebugTotalPoolAllocated = 0;
  2442. ULONG NtfsDebugCountAllocated = 0;
  2443. ULONG NtfsDebugSnapshotTotal = 0;
  2444. ULONG NtfsDebugSnapshotCount = 0;
  2445. PVOID
  2446. NtfsDebugAllocatePoolWithTagNoRaise (
  2447. POOL_TYPE Pool,
  2448. ULONG Length,
  2449. ULONG Tag)
  2450. {
  2451. ULONG Ignore;
  2452. PBACKTRACE BackTrace =
  2453. ExAllocatePoolWithTag( Pool, Length + sizeof (BACKTRACE), Tag );
  2454. if (PAGE_ALIGNED(BackTrace))
  2455. {
  2456. return BackTrace;
  2457. }
  2458. RtlZeroMemory( BackTrace, sizeof (BACKTRACE) );
  2459. if (RtlCaptureStackBackTrace( 0, BACKTRACE_DEPTH, BackTrace->Allocate, &Ignore ) == 0)
  2460. BackTrace->Allocate[0] = (PVOID)-1;
  2461. BackTrace->State = STATE_ALLOCATED;
  2462. BackTrace->Size = Length;
  2463. NtfsDebugCountAllocated++;
  2464. NtfsDebugTotalPoolAllocated += Length;
  2465. return BackTrace + 1;
  2466. }
  2467. PVOID
  2468. NtfsDebugAllocatePoolWithTag (
  2469. POOL_TYPE Pool,
  2470. ULONG Length,
  2471. ULONG Tag)
  2472. {
  2473. ULONG Ignore;
  2474. PBACKTRACE BackTrace =
  2475. FsRtlAllocatePoolWithTag( Pool, Length + sizeof (BACKTRACE), Tag );
  2476. if (PAGE_ALIGNED(BackTrace))
  2477. {
  2478. return BackTrace;
  2479. }
  2480. RtlZeroMemory( BackTrace, sizeof (BACKTRACE) );
  2481. if (RtlCaptureStackBackTrace( 0, BACKTRACE_DEPTH, BackTrace->Allocate, &Ignore ) == 0)
  2482. BackTrace->Allocate[0] = (PVOID)-1;
  2483. BackTrace->State = STATE_ALLOCATED;
  2484. BackTrace->Size = Length;
  2485. NtfsDebugCountAllocated++;
  2486. NtfsDebugTotalPoolAllocated += Length;
  2487. return BackTrace + 1;
  2488. }
  2489. VOID
  2490. NtfsDebugFreePool (
  2491. PVOID pv)
  2492. {
  2493. if (IsKernelPoolBlock( pv ))
  2494. {
  2495. ExFreePool( pv );
  2496. }
  2497. else
  2498. {
  2499. ULONG Ignore;
  2500. PBACKTRACE BackTrace = (PBACKTRACE)pv - 1;
  2501. if (BackTrace->State != STATE_ALLOCATED)
  2502. {
  2503. DbgBreakPoint( );
  2504. }
  2505. if (RtlCaptureStackBackTrace( 0, BACKTRACE_DEPTH, BackTrace->Free, &Ignore ) == 0)
  2506. BackTrace->Free[0] = (PVOID)-1;
  2507. BackTrace->State = STATE_FREE;
  2508. NtfsDebugCountAllocated--;
  2509. NtfsDebugTotalPoolAllocated -= BackTrace->Size;
  2510. ExFreePool( BackTrace );
  2511. }
  2512. }
  2513. VOID
  2514. NtfsDebugHeapDump (
  2515. PUNICODE_STRING UnicodeString )
  2516. {
  2517. UNREFERENCED_PARAMETER( UnicodeString );
  2518. DbgPrint( "Cumulative %8x bytes in %8x blocks\n",
  2519. NtfsDebugTotalPoolAllocated, NtfsDebugCountAllocated );
  2520. DbgPrint( "Snapshot %8x bytes in %8x blocks\n",
  2521. NtfsDebugTotalPoolAllocated - NtfsDebugSnapshotTotal,
  2522. NtfsDebugCountAllocated - NtfsDebugSnapshotCount );
  2523. }
  2524. #endif