// 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);
        }
示例#3
0
        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();
 }