Exemple #1
0
        /// <remarks>
        /// https://blogs.technet.microsoft.com/askcore/2009/10/16/the-four-stages-of-ntfs-file-growth/
        /// </remarks>
        public void UpdateSegments(int bytesPerFileRecordSegment, byte minorNTFSVersion)
        {
            m_segments[0].ReferenceCount = ReferenceCount;
            m_segments[0].IsInUse        = IsInUse;
            m_segments[0].IsDirectory    = IsDirectory;
            List <AttributeRecord> attributes = this.Attributes;

            foreach (FileRecordSegment segment in m_segments)
            {
                segment.ImmediateAttributes.Clear();
                segment.NextAttributeInstance = 0;
            }

            int segmentLength = bytesPerFileRecordSegment - FileRecordSegment.GetNumberOfBytesAvailable(bytesPerFileRecordSegment, minorNTFSVersion);

            foreach (AttributeRecord attribute in attributes)
            {
                segmentLength += (int)attribute.RecordLength;
            }

            if (segmentLength <= bytesPerFileRecordSegment)
            {
                // A single record segment is needed
                foreach (AttributeRecord attribute in attributes)
                {
                    m_segments[0].AddAttributeRecord(attribute.Clone());
                }

                // Free the rest of the segments, if there are any
                for (int index = 1; index < m_segments.Count; index++)
                {
                    m_segments[index].IsInUse = false;
                }
            }
            else
            {
                // We slice the attributes and put them in segments, the attribute list will be built by the caller after the new segments will be allocated
                FileRecordHelper.SliceAttributes(m_segments, attributes, bytesPerFileRecordSegment, minorNTFSVersion);
            }
        }
        /// <remarks>
        /// An attribute list MUST be sorted by AttributeType with a secondary sort by AttributeName.
        /// </remarks>
        public static List <AttributeListEntry> BuildAttributeList(List <FileRecordSegment> segments, int bytesPerFileRecordSegment, ushort minorNTFSVersion)
        {
            int bytesAvailableInSegment = FileRecordSegment.GetNumberOfBytesAvailable(bytesPerFileRecordSegment, minorNTFSVersion);

            List <AttributeListEntry> result = new List <AttributeListEntry>();

            foreach (FileRecordSegment segment in segments)
            {
                foreach (AttributeRecord attribute in segment.ImmediateAttributes)
                {
                    AttributeListEntry entry = new AttributeListEntry();
                    entry.AttributeType = attribute.AttributeType;
                    if (attribute is NonResidentAttributeRecord)
                    {
                        entry.LowestVCN = ((NonResidentAttributeRecord)attribute).LowestVCN;
                    }
                    entry.SegmentReference = segment.SegmentReference;
                    entry.Instance         = attribute.Instance;
                    entry.AttributeName    = attribute.Name;
                    result.Add(entry);
                }
            }
            return(result);
        }
        public static void SliceAttributes(List <FileRecordSegment> segments, List <AttributeRecord> attributes, int bytesPerFileRecordSegment, ushort minorNTFSVersion)
        {
            int bytesAvailableInSegment = FileRecordSegment.GetNumberOfBytesAvailable(bytesPerFileRecordSegment, minorNTFSVersion);
            LinkedList <KeyValuePair <AttributeRecord, bool> > remainingAttributes = new LinkedList <KeyValuePair <AttributeRecord, bool> >();
            FileRecordSegment baseFileRecordSegment = segments[0];
            long segmentNumber   = baseFileRecordSegment.SegmentNumber;
            bool isMftFileRecord = (segmentNumber == MasterFileTable.MasterFileTableSegmentNumber || segmentNumber == MasterFileTable.MftMirrorSegmentNumber);

            foreach (AttributeRecord attribute in attributes)
            {
                if (attribute.AttributeType == AttributeType.StandardInformation ||
                    attribute.AttributeType == AttributeType.FileName)
                {
                    baseFileRecordSegment.ImmediateAttributes.Add(attribute);
                }
                else if (isMftFileRecord && attribute.AttributeType == AttributeType.Data)
                {
                    List <NonResidentAttributeRecord> slices = SliceAttributeRecord((NonResidentAttributeRecord)attribute, bytesPerFileRecordSegment / 2, bytesAvailableInSegment);
                    baseFileRecordSegment.ImmediateAttributes.Add(slices[0]);
                    slices.RemoveAt(0);
                    foreach (NonResidentAttributeRecord slice in slices)
                    {
                        remainingAttributes.AddLast(new KeyValuePair <AttributeRecord, bool>(slice, true));
                    }
                }
                else
                {
                    remainingAttributes.AddLast(new KeyValuePair <AttributeRecord, bool>(attribute, false));
                }
            }

            int segmentIndex = 1;
            int remainingLengthInCurrentSegment = bytesAvailableInSegment;

            while (remainingAttributes.Count > 0)
            {
                AttributeRecord attribute = remainingAttributes.First.Value.Key;
                bool            isSlice   = remainingAttributes.First.Value.Value;

                if (segmentIndex == segments.Count)
                {
                    MftSegmentReference newSegmentReference  = MftSegmentReference.NullReference;
                    FileRecordSegment   newFileRecordSegment = new FileRecordSegment(newSegmentReference.SegmentNumber, newSegmentReference.SequenceNumber, baseFileRecordSegment.SegmentReference);
                    newFileRecordSegment.IsInUse = true;
                    segments.Add(newFileRecordSegment);
                }

                if (attribute.RecordLength <= remainingLengthInCurrentSegment)
                {
                    remainingLengthInCurrentSegment -= (int)attribute.RecordLength;
                    segments[segmentIndex].ImmediateAttributes.Add(attribute);
                    remainingAttributes.RemoveFirst();
                    // Instead of renumbering each attribute slice in the new FileRecordSegment, we use the original Instance number.
                    if (segments[segmentIndex].NextAttributeInstance <= attribute.Instance)
                    {
                        segments[segmentIndex].NextAttributeInstance = (ushort)(attribute.Instance + 1);
                    }
                }
                else
                {
                    if (attribute is ResidentAttributeRecord || isSlice)
                    {
                        segmentIndex++;
                        remainingLengthInCurrentSegment = bytesAvailableInSegment;
                    }
                    else
                    {
                        NonResidentAttributeRecord        nonResidentAttribute = ((NonResidentAttributeRecord)attribute);
                        List <NonResidentAttributeRecord> slices = SliceAttributeRecord((NonResidentAttributeRecord)attribute, remainingLengthInCurrentSegment, bytesAvailableInSegment);
                        remainingAttributes.RemoveFirst();
                        slices.Reverse();
                        foreach (NonResidentAttributeRecord slice in slices)
                        {
                            remainingAttributes.AddFirst(new KeyValuePair <AttributeRecord, bool>(slice, true));
                        }
                    }
                }
            }
        }