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); }
public NTFSVolume(Volume volume, bool useMftMirror) { m_volume = volume; byte[] bootSector = m_volume.ReadSector(0); m_bootRecord = NTFSBootRecord.ReadRecord(bootSector); if (m_bootRecord == null) { throw new InvalidDataException("The volume does not contain a valid NTFS boot record"); } m_mft = new MasterFileTable(this, useMftMirror); m_volumeInformation = GetVolumeInformationRecord(); if (m_volumeInformation.IsDirty) { throw new NotSupportedException("The volume is marked dirty, please run CHKDSK to repair the volume"); } // Note: We could support NTFS v1.2 with minimal effort, but there isn't really any point. if (!(m_volumeInformation.MajorVersion == 3 && m_volumeInformation.MinorVersion == 0) && !(m_volumeInformation.MajorVersion == 3 && m_volumeInformation.MinorVersion == 1)) { throw new NotSupportedException(String.Format("NTFS v{0}.{1} is not supported", m_volumeInformation.MajorVersion, m_volumeInformation.MinorVersion)); } m_logFile = new LogFile(this); m_logClient = new NTFSLogClient(m_logFile); m_bitmap = new VolumeBitmap(this); NumberOfClustersRequiredToExtendIndex = (int)Math.Ceiling((double)(IndexData.ExtendGranularity * m_bootRecord.BytesPerIndexRecord) / m_bootRecord.BytesPerCluster); }
public NTFSVolume(Volume volume, bool useMftMirror) { m_volume = volume; byte[] bootSector = m_volume.ReadSector(0); m_bootRecord = NTFSBootRecord.ReadRecord(bootSector); if (m_bootRecord != null) { m_mft = new MasterFileTable(this, useMftMirror); m_bitmap = new ClusterUsageBitmap(this); } }