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

749 lines
19 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. mftfile.hxx
  5. Abstract:
  6. This module contains the member function definitions for the
  7. NTFS_MFT_FILE class.
  8. Author:
  9. Bill McJohn (billmc) 22-June-91
  10. Environment:
  11. ULIB, User Mode
  12. Notes:
  13. The MFT and the Volume Bitmap:
  14. The Master File Table needs the bitmap to extend itself. The
  15. volume bitmap can be passed in upon initialization, or it can
  16. be supplied (using SetVolumeBitmap) at any time. However,
  17. until it is supplied, the Master File Table is unable to grow
  18. itself.
  19. --*/
  20. #include <pch.cxx>
  21. #define _NTAPI_ULIB_
  22. #define _UNTFS_MEMBER_
  23. #include "ulib.hxx"
  24. #include "error.hxx"
  25. #include "untfs.hxx"
  26. #include "drive.hxx"
  27. #include "attrib.hxx"
  28. #include "ntfsbit.hxx"
  29. #include "mftfile.hxx"
  30. #include "clusrun.hxx"
  31. #include "cmem.hxx"
  32. #include "indxtree.hxx"
  33. #define LOGFILE_PLACEMENT_V1 1
  34. DEFINE_EXPORTED_CONSTRUCTOR( NTFS_MFT_FILE, NTFS_FILE_RECORD_SEGMENT, UNTFS_EXPORT );
  35. UNTFS_EXPORT
  36. NTFS_MFT_FILE::~NTFS_MFT_FILE(
  37. )
  38. {
  39. Destroy();
  40. }
  41. VOID
  42. NTFS_MFT_FILE::Construct(
  43. )
  44. /*++
  45. Routine Description:
  46. Worker function for the construtor.
  47. Arguments:
  48. None.
  49. Return Value:
  50. None.
  51. --*/
  52. {
  53. _FirstLcn = 0;
  54. _VolumeBitmap = NULL;
  55. }
  56. VOID
  57. NTFS_MFT_FILE::Destroy(
  58. )
  59. /*++
  60. Routine Description:
  61. Clean up an NTFS_MFT_FILE object in preparation for
  62. destruction or reinitialization.
  63. Arguments:
  64. None.
  65. Return Value:
  66. None.
  67. --*/
  68. {
  69. _FirstLcn = 0;
  70. _VolumeBitmap = NULL;
  71. }
  72. UNTFS_EXPORT
  73. BOOLEAN
  74. NTFS_MFT_FILE::Initialize(
  75. IN OUT PLOG_IO_DP_DRIVE Drive,
  76. IN LCN Lcn,
  77. IN ULONG ClusterFactor,
  78. IN ULONG FrsSize,
  79. IN BIG_INT VolumeSectors,
  80. IN OUT PNTFS_BITMAP VolumeBitmap,
  81. IN PNTFS_UPCASE_TABLE UpcaseTable
  82. )
  83. /*++
  84. Routine Description:
  85. Initialize an NTFS_MFT_FILE object.
  86. Arguments:
  87. Drive -- supplies the Drive on which the file table resides
  88. Lcn -- supplies the logical cluster number of the master
  89. file table entry which describes the master file
  90. table itself.
  91. ClusterFactor -- supplies the number of sectors per cluster.
  92. FrsSize -- supplies the number of bytes per File Record
  93. Segment in this MFT.
  94. VolumeSectors -- supplies the number of volume sectors.
  95. VolumeBitmap -- supplies the bitmap for the volume. This parameter
  96. may be NULL.
  97. Return Value:
  98. TRUE upon successful completion.
  99. --*/
  100. {
  101. ULONG MirroredClusters;
  102. ULONG ClusterSize;
  103. Destroy();
  104. DebugPtrAssert( Drive );
  105. _FirstLcn = Lcn;
  106. _VolumeBitmap = VolumeBitmap;
  107. ClusterSize = Drive->QuerySectorSize() * ClusterFactor;
  108. MirroredClusters = (REFLECTED_MFT_SEGMENTS * FrsSize + (ClusterSize - 1))
  109. / ClusterSize;
  110. if( !_MirrorMem.Initialize() ||
  111. !_MirrorClusterRun.Initialize( &_MirrorMem,
  112. Drive,
  113. 0,
  114. ClusterFactor,
  115. MirroredClusters ) ) {
  116. DebugPrint( "Can't initialize MFT helper cluster run.\n" );
  117. Destroy();
  118. return FALSE;
  119. }
  120. if (!_Mft.Initialize(&_DataAttribute, &_MftBitmap, VolumeBitmap,
  121. UpcaseTable, ClusterFactor, FrsSize,
  122. Drive->QuerySectorSize(), VolumeSectors)) {
  123. return FALSE;
  124. }
  125. _Mft.DisableMethods();
  126. if (!NTFS_FILE_RECORD_SEGMENT::Initialize(Drive,
  127. Lcn,
  128. &_Mft) ) {
  129. Destroy();
  130. return FALSE;
  131. }
  132. return TRUE;
  133. }
  134. BOOLEAN
  135. NTFS_MFT_FILE::Create(
  136. IN ULONG InitialSize,
  137. IN PCSTANDARD_INFORMATION StandardInformation,
  138. IN OUT PNTFS_BITMAP VolumeBitmap
  139. )
  140. /*++
  141. Routine Description:
  142. Create a new Master File Table for the volume.
  143. Arguments:
  144. InitialSize -- supplies the number of clusters to allocate
  145. to the MFT we create.
  146. StandardInformation -- supplies a standard information structure for
  147. the MFT's File Record Segment.
  148. VolumeBitmap -- supplies the bitmap for the volume.
  149. Return Value:
  150. TRUE upon successful completion.
  151. Notes:
  152. The caller must first allocate a run of InitialSize clusters
  153. from the bitmap, and initialize the NTFS_MFT_FILE object
  154. with the starting cluster of that run.
  155. --*/
  156. {
  157. NTFS_EXTENT_LIST Extents;
  158. NTFS_ATTRIBUTE MftBitmapAttribute;
  159. LCN FirstLcnInMftBitmap;
  160. ULONG ClustersInMftBitmap;
  161. ULONG MftBitmapSize;
  162. ULONG ClusterSize;
  163. ULONG MftClusters;
  164. _Mft.DisableMethods();
  165. if( InitialSize < FIRST_USER_FILE_NUMBER ) {
  166. DebugPrint( "MFT Initial Size is too small.\n" );
  167. return FALSE;
  168. }
  169. // Set this object up as a File Record Segment:
  170. if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation ) ) {
  171. return FALSE;
  172. }
  173. // OK, set up the data attribute with the disk space supplied
  174. // by the caller.
  175. ClusterSize = GetDrive()->QuerySectorSize() * QueryClusterFactor();
  176. MftClusters = (InitialSize * QuerySize() + (ClusterSize - 1)) / ClusterSize;
  177. if( !Extents.Initialize( 0, 0 ) ||
  178. !Extents.AddExtent( 0,
  179. _FirstLcn,
  180. MftClusters ) ||
  181. !_DataAttribute.Initialize( GetDrive(),
  182. QueryClusterFactor(),
  183. &Extents,
  184. InitialSize * QuerySize(),
  185. InitialSize * QuerySize(),
  186. $DATA ) ||
  187. !_DataAttribute.Fill(0, 0) ||
  188. !_DataAttribute.InsertIntoFile( this,
  189. VolumeBitmap ) ) {
  190. return FALSE;
  191. }
  192. // Create an MFT Bitmap attribute. Allocate a run on disk to
  193. // hold its initial size, and use that to set up a non-resident
  194. // attribute to hold it. The initial size is at least 8k (to
  195. // allow some space for future growth.)
  196. //
  197. MftBitmapSize = (InitialSize + 7)/ 8;
  198. ClustersInMftBitmap = max((MftBitmapSize + (ClusterSize - 1))/ClusterSize,
  199. /* MFT_BITMAP_INITIAL_SIZE/ClusterSize */, 0);
  200. if( !VolumeBitmap->AllocateClusters(
  201. #if LOGFILE_PLACEMENT_V1 // initial location of MFT Bitmap
  202. _FirstLcn - ClustersInMftBitmap,
  203. #else
  204. 1,
  205. #endif
  206. ClustersInMftBitmap,
  207. &FirstLcnInMftBitmap,
  208. 1 ) ||
  209. !Extents.Initialize( 0, 0 ) ||
  210. !Extents.AddExtent( 0,
  211. FirstLcnInMftBitmap,
  212. ClustersInMftBitmap ) ||
  213. !MftBitmapAttribute.Initialize( GetDrive(),
  214. QueryClusterFactor(),
  215. &Extents,
  216. MftBitmapSize,
  217. /* value length */
  218. /* ClustersInMftBitmap * ClusterSize, */
  219. MftBitmapSize, /* valid length */
  220. $BITMAP ) ||
  221. !MftBitmapAttribute.InsertIntoFile( this,
  222. VolumeBitmap ) ) {
  223. return FALSE;
  224. }
  225. // Create the MFT Bitmap. Note that it is growable.
  226. if( !_MftBitmap.Initialize( InitialSize, TRUE ) ) {
  227. return FALSE;
  228. }
  229. // Mark the system files as in use. Note that we've already
  230. // checked that InitialSize is at least FIRST_USER_FILE_NUMBER.
  231. _MftBitmap.SetAllocated( 0, FIRST_USER_FILE_NUMBER );
  232. _Mft.EnableMethods();
  233. return TRUE;
  234. }
  235. UNTFS_EXPORT
  236. BOOLEAN
  237. NTFS_MFT_FILE::Read(
  238. )
  239. /*++
  240. Routine Description:
  241. This routine reads this FRS for the MFT and then proceeds
  242. to read the MFT bitmap. If all goes well, the internal
  243. data attribute and MFT bitmap will be initialized.
  244. This method will return TRUE if and only if the base FRS for
  245. this MFT is correctly read in. The MFT allocation methods will
  246. be enabled by this method if and only if MFT bitmap and the
  247. MFT data attribute are properly read in and initialized.
  248. Arguments:
  249. None.
  250. Return Value:
  251. FALSE - Failure.
  252. TRUE - Success.
  253. --*/
  254. {
  255. NTFS_ATTRIBUTE MftBitmapAttribute;
  256. BIG_INT DataAttributeWrittenLength;
  257. BIG_INT DataAttributeAllocatedLength;
  258. BIG_INT NumberOfAllocatedFileRecordSegments,
  259. NumberOfWrittenFileRecordSegments;
  260. ULONG RequiredBitsInBitmap, PreferredBitsInBitmap;
  261. BOOLEAN Error;
  262. _Mft.DisableMethods();
  263. if (!NTFS_FILE_RECORD_SEGMENT::Read()) {
  264. return FALSE;
  265. }
  266. _Mft.EnableMethods();
  267. // Make sure that we have the Data Attribute to play with.
  268. if (!QueryAttribute(&_DataAttribute, &Error, $DATA)) {
  269. _Mft.DisableMethods();
  270. return TRUE;
  271. }
  272. // The length of the bitmap depends on the allocated length of
  273. // the data attribute.
  274. _DataAttribute.QueryValueLength( &DataAttributeWrittenLength,
  275. &DataAttributeAllocatedLength );
  276. // A quick sanity check:
  277. //
  278. if( CompareGT(DataAttributeWrittenLength, DataAttributeAllocatedLength) ) {
  279. DebugAbort( "UNTFS: MFT Data attribute is corrupt.\n" );
  280. _Mft.DisableMethods();
  281. return TRUE;
  282. }
  283. NumberOfWrittenFileRecordSegments = DataAttributeWrittenLength / QuerySize();
  284. NumberOfAllocatedFileRecordSegments = DataAttributeAllocatedLength / QuerySize();
  285. DebugAssert( NumberOfWrittenFileRecordSegments.GetHighPart() == 0 );
  286. DebugAssert( NumberOfAllocatedFileRecordSegments.GetHighPart() == 0 );
  287. RequiredBitsInBitmap = NumberOfWrittenFileRecordSegments.GetLowPart();
  288. PreferredBitsInBitmap = NumberOfAllocatedFileRecordSegments.GetLowPart();
  289. // Create a bitmap, and get the MFT bitmap attribute through
  290. // which we read it, and read the bitmap.
  291. if( !_MftBitmap.Initialize( RequiredBitsInBitmap, TRUE ) ||
  292. !QueryAttribute( &MftBitmapAttribute, &Error, $BITMAP ) ||
  293. !_MftBitmap.Read( &MftBitmapAttribute ) ||
  294. !_MftBitmap.Resize( PreferredBitsInBitmap ) ) {
  295. DebugAbort( "Cannot read MFT Bitmap.\n" );
  296. _Mft.DisableMethods();
  297. return TRUE;
  298. }
  299. return TRUE;
  300. }
  301. UNTFS_EXPORT
  302. BOOLEAN
  303. NTFS_MFT_FILE::Flush(
  304. )
  305. /*++
  306. Routine Description:
  307. This method flushes the MFT--re-inserts the DATA attribute (if
  308. necessary); writes the MFT bitmap, and writes the MFT's own
  309. File Record Segment.
  310. Arguments:
  311. None.
  312. Return Value:
  313. TRUE upon successful completion.
  314. Notes:
  315. This method will also write the volume bitmap and the mft mirror.
  316. It will resize the $DATA attributes on the bitmap and mirror files
  317. and write those FRS's, if necessary.
  318. --*/
  319. {
  320. NTFS_BITMAP_FILE BitmapFile;
  321. NTFS_REFLECTED_MASTER_FILE_TABLE MirrorFile;
  322. NTFS_INDEX_TREE RootIndex;
  323. NTFS_FILE_RECORD_SEGMENT RootIndexFrs;
  324. DSTRING FileNameIndexName;
  325. NTFS_ATTRIBUTE MftBitmapAttribute,
  326. MirrorDataAttribute,
  327. VolumeBitmapAttribute;
  328. LCN FirstMirrorLcn;
  329. BIG_INT OldValidLength;
  330. BOOLEAN Error;
  331. if( !_Mft.AreMethodsEnabled() ) {
  332. DebugAbort( "Tried to flush the MFT before enabling it.\n" );
  333. return FALSE;
  334. }
  335. // Ensure that the bitmap file and mirror file's $DATA attributes
  336. // are the correct sizes. This will later allow us to write these
  337. // two constructs without affecting their respective FRS's.
  338. if( !BitmapFile.Initialize( &_Mft ) ||
  339. !BitmapFile.Read() ||
  340. !BitmapFile.QueryAttribute( &VolumeBitmapAttribute,
  341. &Error,
  342. $DATA ) ||
  343. !_VolumeBitmap->CheckAttributeSize( &VolumeBitmapAttribute,
  344. _VolumeBitmap ) ||
  345. !MirrorFile.Initialize( &_Mft ) ||
  346. !MirrorFile.Read() ||
  347. !MirrorFile.QueryAttribute( &MirrorDataAttribute,
  348. &Error,
  349. $DATA ) ||
  350. !CheckMirrorSize( &MirrorDataAttribute,
  351. TRUE,
  352. _VolumeBitmap,
  353. &FirstMirrorLcn ) ) {
  354. DebugPrint( "Cannot check size of bitmap & mirror attributes.\n" );
  355. return FALSE;
  356. }
  357. if( VolumeBitmapAttribute.IsStorageModified() &&
  358. ( !VolumeBitmapAttribute.InsertIntoFile( &BitmapFile,
  359. _VolumeBitmap ) ||
  360. !BitmapFile.Flush( _VolumeBitmap ) ) ) {
  361. DebugPrint( "Cannot save volume bitmap attribute.\n" );
  362. return FALSE;
  363. }
  364. if( MirrorDataAttribute.IsStorageModified() &&
  365. ( !MirrorDataAttribute.InsertIntoFile( &MirrorFile, _VolumeBitmap ) ||
  366. !MirrorFile.Flush( _VolumeBitmap ) ) ) {
  367. DebugPrint( "Cannot save MFT mirror data attribute.\n" );
  368. return FALSE;
  369. }
  370. // Fetch the root index from its FRS.
  371. //
  372. if( !RootIndexFrs.Initialize( ROOT_FILE_NAME_INDEX_NUMBER, this ) ||
  373. !RootIndexFrs.Read() ||
  374. !FileNameIndexName.Initialize( FileNameIndexNameData ) ||
  375. !RootIndex.Initialize( GetDrive(),
  376. QueryClusterFactor(),
  377. _VolumeBitmap,
  378. GetUpcaseTable(),
  379. QuerySize()/2,
  380. &RootIndexFrs,
  381. &FileNameIndexName ) ) {
  382. return FALSE;
  383. }
  384. // Fetch the MFT Bitmap attribute.
  385. //
  386. if( !QueryAttribute( &MftBitmapAttribute, &Error, $BITMAP ) ) {
  387. DebugPrintTrace(( "UNTFS: Cannot fetch MFT bitmap attribute.\n" ));
  388. return FALSE;
  389. }
  390. // Write the bitmap once to make it the right size. If
  391. // it grows while we're saving the MFT, we'll have to
  392. // write it again.
  393. //
  394. if( !_MftBitmap.Write( &MftBitmapAttribute, _VolumeBitmap ) ) {
  395. DebugPrintTrace(( "UNTFS: Cannot write the MFT bitmap.\n" ));
  396. return FALSE;
  397. }
  398. do {
  399. // Note that inserting an attribute into a file resets the
  400. // attribute's StorageModified flag.
  401. //
  402. if( MftBitmapAttribute.IsStorageModified() &&
  403. !MftBitmapAttribute.InsertIntoFile( this, NULL ) ) {
  404. DebugPrint( "UNTFS: Cannot save MFT bitmap attribute.\n" );
  405. return FALSE;
  406. }
  407. // Remember the bitmap size (which is equal to the number
  408. // of FRS's in the MFT).
  409. //
  410. OldValidLength = _DataAttribute.QueryValidDataLength();
  411. // Save the data attribute.
  412. //
  413. if( _DataAttribute.IsStorageModified() &&
  414. !_DataAttribute.InsertIntoFile(this, NULL) ) {
  415. DebugAbort( "UNTFS: Cannot save MFT's data attribute.\n" );
  416. return FALSE;
  417. }
  418. // Flush this FRS.
  419. //
  420. if( !NTFS_FILE_RECORD_SEGMENT::Flush( _VolumeBitmap, &RootIndex) ) {
  421. return FALSE;
  422. }
  423. // Write the bitmap again, in case it changed.
  424. //
  425. if( !_MftBitmap.Write( &MftBitmapAttribute, _VolumeBitmap ) ) {
  426. DebugPrintTrace(( "UNTFS: Cannot write the MFT bitmap.\n" ));
  427. return FALSE;
  428. }
  429. // If the MFT's Valid Data Length changed while we were
  430. // saving the data attribute and bitmap, we have to go
  431. // through this loop again.
  432. } while( OldValidLength != _DataAttribute.QueryValidDataLength() );
  433. // Save the root index:
  434. //
  435. if( !RootIndex.Save( &RootIndexFrs ) ||
  436. !RootIndexFrs.Flush( _VolumeBitmap ) ) {
  437. return FALSE;
  438. }
  439. if( !_VolumeBitmap->Write( &VolumeBitmapAttribute, NULL ) ||
  440. !WriteMirror( &MirrorDataAttribute ) ){
  441. DebugPrint( "Failed write of MFT Mirror or volume bitmap.\n" );
  442. return FALSE;
  443. }
  444. return TRUE;
  445. }
  446. BOOLEAN
  447. NTFS_MFT_FILE::CheckMirrorSize(
  448. IN OUT PNTFS_ATTRIBUTE MirrorDataAttribute,
  449. IN BOOLEAN Fix,
  450. IN OUT PNTFS_BITMAP VolumeBitmap,
  451. OUT PLCN FirstLcn
  452. )
  453. /*++
  454. Routine Description:
  455. This method checks that the MFT Mirror $DATA attribute is the
  456. correct size and contiguous. It can also be used to check these
  457. restrictions.
  458. Arguments:
  459. MirrorDataAttribut -- Supplies the MFT Mirror's $DATA attribute.
  460. Fix -- Supplies a flag which indicates that the
  461. attribute should be reallocated if it is
  462. the wrong size or not contiguous.
  463. VolumeBitmap -- Supplies the volume bitmap (only required
  464. if Fix is TRUE).
  465. FirstLcn -- Receives the starting LCN of the mirror.
  466. Return Value:
  467. TRUE upon successful completion.
  468. --*/
  469. {
  470. BIG_INT RunLength;
  471. LCN NewStartingLcn;
  472. ULONG MirroredClusters;
  473. ULONG ClusterSize;
  474. ClusterSize = QueryClusterFactor() * _Mft.QuerySectorSize();
  475. MirroredClusters = (REFLECTED_MFT_SEGMENTS * QuerySize() + (ClusterSize - 1))
  476. / ClusterSize;
  477. if( MirrorDataAttribute->QueryLcnFromVcn( 0, FirstLcn, &RunLength ) &&
  478. *FirstLcn != 0 &&
  479. *FirstLcn != LCN_NOT_PRESENT &&
  480. RunLength >= MirroredClusters ) {
  481. // Everything is perfect.
  482. return TRUE;
  483. }
  484. // Something is not perfect.
  485. if( Fix &&
  486. VolumeBitmap->AllocateClusters( QueryVolumeSectors()/
  487. QueryClusterFactor()/
  488. 2,
  489. MirroredClusters,
  490. &NewStartingLcn ) &&
  491. MirrorDataAttribute->Resize( 0, VolumeBitmap ) &&
  492. MirrorDataAttribute->AddExtent( 0,
  493. NewStartingLcn,
  494. MirroredClusters ) ) {
  495. // It was broken, but now it's perfect.
  496. *FirstLcn = NewStartingLcn;
  497. return TRUE;
  498. }
  499. return FALSE;
  500. }
  501. BOOLEAN
  502. NTFS_MFT_FILE::WriteMirror(
  503. IN OUT PNTFS_ATTRIBUTE MirrorDataAttribute
  504. )
  505. /*++
  506. Routine Description:
  507. This method writes the MFT Mirror. Note that it will fail if
  508. the mirror's $DATA attribute is not the correct size or is
  509. not contiguous.
  510. Arguments:
  511. MirrorDataAttribute -- Supplies the MFT Mirror's $DATA attribute.
  512. Return Value:
  513. TRUE upon successful completion.
  514. Notes:
  515. This method copies whatever is _on disk_ in the MFT's data attribute
  516. to the mirror's data attribute. Therefore, it should only be called
  517. after the MFT itself has been written.
  518. --*/
  519. {
  520. LCN FirstMirrorLcn;
  521. if( !CheckMirrorSize( MirrorDataAttribute,
  522. FALSE,
  523. NULL,
  524. &FirstMirrorLcn ) ) {
  525. return FALSE;
  526. }
  527. _MirrorClusterRun.Relocate( _FirstLcn );
  528. if( !_MirrorClusterRun.Read() ) {
  529. return FALSE;
  530. }
  531. _MirrorClusterRun.Relocate( FirstMirrorLcn );
  532. if( !_MirrorClusterRun.Write() ) {
  533. return FALSE;
  534. }
  535. return TRUE;
  536. }