public void Extend() { ulong additionalDataLength = (ulong)(m_volume.BytesPerFileRecordSegment * ExtendGranularity); ulong additionalBitmapLength = ExtendGranularity / 8; // We calculate the maximum possible number of free cluster required long numberOfClustersRequiredForData = (long)Math.Ceiling((double)additionalDataLength / m_volume.BytesPerCluster); long numberOfClustersRequiredForBitmap = (long)Math.Ceiling((double)additionalBitmapLength / m_volume.BytesPerCluster); if (numberOfClustersRequiredForData + numberOfClustersRequiredForBitmap > m_volume.NumberOfFreeClusters) { throw new DiskFullException(); } // We have to extend the bitmap first because one of the constructor parameters is the size of the data. // MFT Bitmap: ValidDataLength could be smaller than FileSize, however, we will later copy the value of ValidDataLength. // to the MFT mirror, we have to make sure that the copy will not become stale after writing beyond the current ValidDataLength. m_mftFile.Bitmap.ExtendBitmap(ExtendGranularity, true); // MFT Data: ValidDataLength must be equal to FileSize. // This will take care of the FileNameRecord and RootDirectory index as well. // Note: The NTFS v5.1 driver does not bother updating the FileNameRecord. m_mftFile.WriteData(m_mftFile.Data.Length, new byte[additionalDataLength]); // Update the MFT mirror MasterFileTable mftMirror = new MasterFileTable(m_volume, false, true); // When the MFT has an attribute list, CHKDSK expects the mirror to contain the segment references from the MFT as-is. FileRecordSegment mftRecordSegmentFromMirror = mftMirror.GetFileRecordSegment(MasterFileTableSegmentNumber); mftRecordSegmentFromMirror.ImmediateAttributes.Clear(); mftRecordSegmentFromMirror.ImmediateAttributes.AddRange(m_mftFile.FileRecord.BaseSegment.ImmediateAttributes); // CHKDSK seems to expect the mirror's NextAttributeInstance to be the same as the MFT. mftRecordSegmentFromMirror.NextAttributeInstance = m_mftFile.FileRecord.BaseSegment.NextAttributeInstance; mftMirror.UpdateFileRecordSegment(mftRecordSegmentFromMirror); }
public void Extend() { if (NumberOfClustersRequiredToExtend > m_volume.NumberOfFreeClusters) { throw new DiskFullException(); } int additionalDataLength = m_volume.BytesPerFileRecordSegment * ExtendGranularity; // MFT Bitmap: ValidDataLength could be smaller than FileSize, however, we will later copy the value of ValidDataLength. // to the MFT mirror, we have to make sure that the copy will not become stale after writing beyond the current ValidDataLength. m_mftBitmap.ExtendBitmap(ExtendGranularity, true); // MFT Data: ValidDataLength must be equal to FileSize. // We are opting to skip updating the FileNameRecord and RootDirectory index. // Note: The NTFS v5.1 driver does not bother updating the FileNameRecord. while (additionalDataLength > 0) { int transferSize = Math.Min(Settings.MaximumTransferSizeLBA * m_volume.BytesPerSector, additionalDataLength); m_mftData.WriteBytes(m_mftData.Length, new byte[transferSize]); additionalDataLength -= transferSize; } // Update the MFT mirror MasterFileTable mftMirror = new MasterFileTable(m_volume, false, true); // When the MFT has an attribute list, CHKDSK expects the mirror to contain the segment references from the MFT as-is. FileRecordSegment mftRecordSegmentFromMirror = mftMirror.GetFileRecordSegment(MasterFileTableSegmentNumber); mftRecordSegmentFromMirror.ImmediateAttributes.Clear(); mftRecordSegmentFromMirror.ImmediateAttributes.AddRange(m_mftRecord.BaseSegment.ImmediateAttributes); // CHKDSK seems to expect the mirror's NextAttributeInstance to be the same as the MFT. mftRecordSegmentFromMirror.NextAttributeInstance = m_mftRecord.BaseSegment.NextAttributeInstance; mftMirror.UpdateFileRecordSegment(mftRecordSegmentFromMirror); }