Leaked source code of windows server 2003
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.

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