// The maximum NTFS file size is 2^64 bytes, so total number of file clusters can be represented using long public void AllocateAdditionalClusters(NTFSVolume volume, long clustersToAllocate) { ulong desiredStartLCN = (ulong)DataRunSequence.DataLastLCN; KeyValuePairList <ulong, long> freeClusterRunList = volume.AllocateClusters(desiredStartLCN, clustersToAllocate); for (int index = 0; index < freeClusterRunList.Count; index++) { ulong runStartLCN = freeClusterRunList[index].Key; long runLength = freeClusterRunList[index].Value; bool mergeWithLastRun = (index == 0 && runStartLCN == desiredStartLCN); if (mergeWithLastRun) { // we append this run to the last run DataRun lastRun = DataRunSequence[DataRunSequence.Count - 1]; lastRun.RunLength += (long)runLength; HighestVCN += (long)runLength; } else { DataRun run = new DataRun(); ulong previousLCN = (ulong)DataRunSequence.LastDataRunStartLCN; run.RunOffset = (long)(runStartLCN - previousLCN); run.RunLength = (long)runLength; HighestVCN += runLength; DataRunSequence.Add(run); } } }
public DataRunSequence Clone() { DataRunSequence clone = new DataRunSequence(this.Count); foreach (DataRun run in this) { clone.Add(run.Clone()); } return(clone); }
private static NonResidentAttributeRecord FitMaxNumberOfRuns(NonResidentAttributeRecord record, int runIndex, int availableLength) { // Each attribute record is aligned to 8-byte boundary, we must have enough room for padding availableLength = (int)Math.Floor((double)availableLength / 8) * 8; // Note that we're using the original record Instance instead of using the FileRecordSegment.NextAttributeInstance NonResidentAttributeRecord slice = new NonResidentAttributeRecord(record.AttributeType, record.Name, record.Instance); DataRunSequence dataRuns = record.DataRunSequence; long clusterCount = 0; for (int index = 0; index < runIndex; index++) { clusterCount += dataRuns[index].RunLength; } slice.LowestVCN = clusterCount; slice.DataRunSequence.Add(dataRuns[runIndex]); if (runIndex == 0) { slice.CompressionUnit = record.CompressionUnit; slice.AllocatedLength = record.AllocatedLength; slice.FileSize = record.FileSize; slice.ValidDataLength = record.ValidDataLength; } else { // The DataRunSequence of each NonResidentDataRecord fragment starts at absolute LCN long runLength = dataRuns[runIndex].RunLength; long runStartLCN = dataRuns.GetDataClusterLCN(clusterCount); slice.DataRunSequence[0] = new DataRun(runLength, runStartLCN); } clusterCount += dataRuns[runIndex].RunLength; int sliceRecordLength = NonResidentAttributeRecord.HeaderLength + record.Name.Length * 2 + slice.DataRunSequence.RecordLength; if (sliceRecordLength > availableLength) { return(null); } runIndex++; while (runIndex < dataRuns.Count && sliceRecordLength + dataRuns[runIndex].RecordLength <= availableLength) { slice.DataRunSequence.Add(record.DataRunSequence[runIndex]); sliceRecordLength += dataRuns[runIndex].RecordLength; clusterCount += dataRuns[runIndex].RunLength; runIndex++; } slice.HighestVCN = clusterCount - 1; return(slice); }
public NonResidentAttributeRecord(byte[] buffer, int offset) : base(buffer, offset) { LowestVCN = (long)LittleEndianConverter.ToUInt64(buffer, offset + 0x10); HighestVCN = (long)LittleEndianConverter.ToUInt64(buffer, offset + 0x18); ushort mappingPairsOffset = LittleEndianConverter.ToUInt16(buffer, offset + 0x20); CompressionUnit = ByteReader.ReadByte(buffer, offset + 0x22); AllocatedLength = LittleEndianConverter.ToUInt64(buffer, offset + 0x28); FileSize = LittleEndianConverter.ToUInt64(buffer, offset + 0x30); ValidDataLength = LittleEndianConverter.ToUInt64(buffer, offset + 0x38); m_dataRunSequence = new DataRunSequence(buffer, offset + mappingPairsOffset, (int)this.RecordLengthOnDisk - mappingPairsOffset); if ((HighestVCN - LowestVCN + 1) != m_dataRunSequence.DataClusterCount) { throw new InvalidDataException("Invalid non-resident attribute record"); } }
private void AllocateAdditionalClusters(long clustersToAllocate) { KeyValuePairList <long, long> freeClusterRunList; DataRunSequence dataRuns = m_attributeRecord.DataRunSequence; if (dataRuns.Count == 0) { freeClusterRunList = m_volume.AllocateClusters(clustersToAllocate); } else { long desiredStartLCN = dataRuns.DataLastLCN + 1; freeClusterRunList = m_volume.AllocateClusters(desiredStartLCN, clustersToAllocate); long firstRunStartLCN = freeClusterRunList[0].Key; long firstRunLength = freeClusterRunList[0].Value; if (firstRunStartLCN == desiredStartLCN) { // Merge with last run DataRun lastRun = dataRuns[dataRuns.Count - 1]; lastRun.RunLength += firstRunLength; m_attributeRecord.HighestVCN += (long)firstRunLength; freeClusterRunList.RemoveAt(0); } } for (int index = 0; index < freeClusterRunList.Count; index++) { long runStartLCN = freeClusterRunList[index].Key; long runLength = freeClusterRunList[index].Value; DataRun run = new DataRun(); long previousLCN = m_attributeRecord.DataRunSequence.LastDataRunStartLCN; run.RunOffset = runStartLCN - previousLCN; run.RunLength = runLength; m_attributeRecord.HighestVCN += runLength; m_attributeRecord.DataRunSequence.Add(run); } // Extend() will update the FileRecord m_attributeRecord.AllocatedLength += (ulong)(clustersToAllocate * m_volume.BytesPerCluster); }
public NonResidentAttributeRecord(AttributeType attributeType, string name) : base(attributeType, name, false) { HighestVCN = -1; // This is the value that should be set when the attribute contains no data. m_dataRunSequence = new DataRunSequence(); }