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 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);
        }
        /// <summary>
        /// It's up to the caller to log the changes to the file record segment
        /// </summary>
        private void DeallocateFileRecordSegment(FileRecordSegment segment, uint transactionID)
        {
            ushort            nextSequenceNumber = (ushort)(segment.SequenceNumber + 1);
            FileRecordSegment segmentToWrite     = new FileRecordSegment(segment.SegmentNumber, nextSequenceNumber);

            UpdateFileRecordSegment(segmentToWrite);
            m_mftBitmap.DeallocateRecord(segment.SegmentNumber, transactionID);
        }
Beispiel #4
0
        internal FileRecord(FileRecordSegment segment)
        {
            m_segments = new List <FileRecordSegment>();
            m_segments.Add(segment);

            ReferenceCount = m_segments[0].ReferenceCount;
            IsInUse        = m_segments[0].IsInUse;
            IsDirectory    = m_segments[0].IsDirectory;
        }
        /// <summary>
        /// This method is used to read the record segment of the MFT itself.
        /// Only after strapping the MFT we can use GetFileRecordSegment which relies on the MFT file record.
        /// </summary>
        private FileRecordSegment ReadFileRecordSegment(long mftStartLCN, long segmentNumber)
        {
            long sectorIndex = mftStartLCN * m_volume.SectorsPerCluster + segmentNumber * m_volume.SectorsPerFileRecordSegment;

            byte[]            bytes  = m_volume.ReadSectors(sectorIndex, m_volume.SectorsPerFileRecordSegment);
            FileRecordSegment result = new FileRecordSegment(bytes, 0, segmentNumber);

            return(result);
        }
 private ushort?GetFileRecordSegmentSequenceNumber(long segmentNumber)
 {
     byte[] segmentBytes = GetFileRecordSegmentBytes(segmentNumber);
     if (FileRecordSegment.ContainsFileRecordSegment(segmentBytes))
     {
         return(FileRecordSegment.GetSequenceNumber(segmentBytes));
     }
     return(null);
 }
        private FileRecord ReadMftRecord(bool useMftMirror, bool readMftMirror)
        {
            NTFSBootRecord bootRecord = m_volume.BootRecord;

            if (bootRecord != null)
            {
                long mftStartLCN      = useMftMirror ? (long)bootRecord.MftMirrorStartLCN : (long)bootRecord.MftStartLCN;
                long mftSegmentNumber = readMftMirror ? MftMirrorSegmentNumber : MasterFileTableSegmentNumber;
                FileRecordSegment mftRecordSegment = ReadFileRecordSegment(mftStartLCN, mftSegmentNumber);
                if (!mftRecordSegment.IsBaseFileRecord)
                {
                    throw new InvalidDataException("Invalid MFT record, not a base record");
                }

                AttributeRecord attributeListRecord = mftRecordSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty);
                if (attributeListRecord == null)
                {
                    return(new FileRecord(mftRecordSegment));
                }
                else
                {
                    // I have never personally seen an MFT with an attribute list
                    AttributeList              attributeList = new AttributeList(m_volume, attributeListRecord);
                    List <AttributeListEntry>  entries       = attributeList.ReadEntries();
                    List <MftSegmentReference> references    = AttributeList.GetSegmentReferenceList(entries);
                    int baseSegmentIndex = MftSegmentReference.IndexOfSegmentNumber(references, MasterFileTableSegmentNumber);

                    if (baseSegmentIndex >= 0)
                    {
                        references.RemoveAt(baseSegmentIndex);
                    }

                    List <FileRecordSegment> recordSegments = new List <FileRecordSegment>();
                    // we want the base record segment first
                    recordSegments.Add(mftRecordSegment);

                    foreach (MftSegmentReference reference in references)
                    {
                        FileRecordSegment segment = ReadFileRecordSegment(mftStartLCN, reference);
                        if (segment != null)
                        {
                            recordSegments.Add(segment);
                        }
                        else
                        {
                            throw new InvalidDataException("Invalid MFT record, missing segment");
                        }
                    }
                    return(new FileRecord(recordSegments));
                }
            }
            else
            {
                return(null);
            }
        }
        /// <summary>
        /// This method is used to read the record segment(s) of the MFT itself.
        /// Only after strapping the MFT we can use GetFileRecordSegment which relies on the MFT file record.
        /// </summary>
        private FileRecordSegment ReadMftRecordSegment(long mftStartLCN, long segmentNumber)
        {
            long sectorIndex = mftStartLCN * m_volume.SectorsPerCluster + segmentNumber * m_volume.SectorsPerFileRecordSegment;

            byte[] segmentBytes = m_volume.ReadSectors(sectorIndex, m_volume.SectorsPerFileRecordSegment, ContentType.MftData);
            MultiSectorHelper.RevertUsaProtection(segmentBytes, 0);
            FileRecordSegment result = new FileRecordSegment(segmentBytes, 0, segmentNumber);

            return(result);
        }
        public int GetNumberOfBytesFree(int bytesPerFileRecordSegment, ushort minorNTFSVersion)
        {
            int firstAttributeOffset   = FileRecordSegment.GetFirstAttributeOffset(bytesPerFileRecordSegment, minorNTFSVersion);
            int numberOfBytesAvailable = bytesPerFileRecordSegment - firstAttributeOffset - EndMarkerLength;

            foreach (AttributeRecord attribute in m_immediateAttributes)
            {
                numberOfBytesAvailable -= attribute.RecordLength;
            }
            return(numberOfBytesAvailable);
        }
Beispiel #10
0
        private FileRecordSegment ReadFileRecordSegment(long mftStartLCN, MftSegmentReference reference)
        {
            FileRecordSegment result = ReadFileRecordSegment(mftStartLCN, reference.SegmentNumber);

            if (result.SequenceNumber != reference.SequenceNumber)
            {
                // The file record segment has been freed and reallocated, and an obsolete version is being requested
                return(null);
            }
            return(result);
        }
        private FileRecordSegment GetRecordSegmentOfMasterFileTable(long mftStartLCN, MftSegmentReference reference)
        {
            FileRecordSegment result = GetRecordSegmentOfMasterFileTable(mftStartLCN, reference.SegmentNumber);

            if (result.SequenceNumber != reference.SequenceNumber)
            {
                // The file record segment has been modified, and an older version has been requested
                return(null);
            }
            return(result);
        }
        public FileRecordSegment GetFileRecordSegment(MftSegmentReference reference)
        {
            FileRecordSegment result = GetFileRecordSegment(reference.SegmentNumber);

            if (result.SequenceNumber != reference.SequenceNumber)
            {
                // The file record segment has been modified, and an older version has been requested
                throw new InvalidDataException("MftSegmentReference SequenceNumber does not match FileRecordSegment");
            }
            return(result);
        }
        private FileRecordSegment ReadMftRecordSegment(long mftStartLCN, MftSegmentReference reference)
        {
            FileRecordSegment result = ReadMftRecordSegment(mftStartLCN, reference.SegmentNumber);

            if (result.SequenceNumber != reference.SequenceNumber)
            {
                // The file record segment has been freed and reallocated, and an obsolete version is being requested
                throw new InvalidDataException("MftSegmentReference SequenceNumber does not match FileRecordSegment");
            }
            return(result);
        }
Beispiel #14
0
        public FileRecordSegment GetFileRecordSegment(MftSegmentReference reference)
        {
            FileRecordSegment result = GetFileRecordSegment(reference.SegmentNumber);

            if (result.SequenceNumber != reference.SequenceNumber)
            {
                // The file record segment has been modified, and an older version has been requested
                return(null);
            }
            return(result);
        }
        public void UpdateFileRecordSegment(FileRecordSegment recordSegment)
        {
            long segmentNumber = recordSegment.MftSegmentNumber;

            NTFSBootRecord bootRecord = m_volume.BootRecord;

            long firstSectorIndex = segmentNumber * m_volume.SectorsPerFileRecordSegment;

            byte[] recordSegmentBytes = recordSegment.GetBytes(bootRecord.FileRecordSegmentLength, m_volume.BytesPerCluster, m_volume.MinorVersion);

            m_mftRecord.NonResidentDataRecord.WriteDataSectors(m_volume, firstSectorIndex, recordSegmentBytes);
        }
Beispiel #16
0
        public FileRecord CreateFile(List <FileNameRecord> fileNameRecords, uint transactionID)
        {
            if (fileNameRecords.Count == 0)
            {
                throw new ArgumentException();
            }
            bool isDirectory = fileNameRecords[0].IsDirectory;
            MftSegmentReference segmentReference  = AllocateFileRecordSegment(transactionID);
            FileRecordSegment   fileRecordSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber);

            // UpdateFileRecord() expects the base segment to be present on disk
            byte[] redoData     = fileRecordSegment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false);
            ulong  streamOffset = (ulong)(fileRecordSegment.SegmentNumber * m_volume.BytesPerFileRecordSegment);

            m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, NTFSLogOperation.InitializeFileRecordSegment, redoData, NTFSLogOperation.DeallocateFileRecordSegment, new byte[0], transactionID);
            UpdateFileRecordSegment(fileRecordSegment);

            fileRecordSegment.ReferenceCount = (ushort)fileNameRecords.Count; // Each FileNameRecord is about to be indexed
            fileRecordSegment.IsInUse        = true;
            fileRecordSegment.IsDirectory    = isDirectory;

            FileRecord fileRecord = new FileRecord(fileRecordSegment);
            StandardInformationRecord standardInformation = (StandardInformationRecord)fileRecord.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty);

            standardInformation.CreationTime        = fileNameRecords[0].CreationTime;
            standardInformation.ModificationTime    = fileNameRecords[0].ModificationTime;
            standardInformation.MftModificationTime = fileNameRecords[0].MftModificationTime;
            standardInformation.LastAccessTime      = fileNameRecords[0].LastAccessTime;
            standardInformation.FileAttributes      = 0;
            foreach (FileNameRecord fileNameRecord in fileNameRecords)
            {
                FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)fileRecord.CreateAttributeRecord(AttributeType.FileName, String.Empty);
                fileNameAttribute.IsIndexed = true;
                fileNameAttribute.Record    = fileNameRecord;
            }

            if (isDirectory)
            {
                string          indexName = IndexHelper.GetIndexName(AttributeType.FileName);
                IndexRootRecord indexRoot = (IndexRootRecord)fileRecord.CreateAttributeRecord(AttributeType.IndexRoot, indexName);
                IndexHelper.InitializeIndexRoot(indexRoot, AttributeType.FileName, m_volume.BytesPerIndexRecord, m_volume.BytesPerCluster);
            }
            else
            {
                fileRecord.CreateAttributeRecord(AttributeType.Data, String.Empty);
            }

            UpdateFileRecord(fileRecord, transactionID);

            return(fileRecord);
        }
Beispiel #17
0
        private void DeallocateFileRecordSegment(FileRecordSegment segment)
        {
            BitmapData bitmap = m_mftFile.Bitmap;

            if (bitmap == null)
            {
                throw new InvalidDataException("Invalid MFT Record, missing Bitmap attribute");
            }
            ushort            nextSequenceNumber = (ushort)(segment.SequenceNumber + 1);
            FileRecordSegment segmentToWrite     = new FileRecordSegment(segment.SegmentNumber, nextSequenceNumber);

            UpdateFileRecordSegment(segmentToWrite);
            bitmap.DeallocateRecord(segment.SegmentNumber);
        }
Beispiel #18
0
        public void UpdateFileRecordSegment(FileRecordSegment recordSegment)
        {
            long segmentNumber    = recordSegment.SegmentNumber;
            long firstSectorIndex = segmentNumber * m_volume.SectorsPerFileRecordSegment;

            if (segmentNumber >= FirstReservedSegmentNumber)
            {
                recordSegment.UpdateSequenceNumber++;
            }
            recordSegment.LogFileSequenceNumber = 0;
            byte[] recordSegmentBytes = recordSegment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion);

            m_mftFile.Data.WriteSectors(firstSectorIndex, recordSegmentBytes);
        }
Beispiel #19
0
        public FileRecord GetFileRecord(long baseSegmentNumber)
        {
            FileRecordSegment baseSegment = GetFileRecordSegment(baseSegmentNumber);

            if (baseSegment != null && baseSegment.IsBaseFileRecord)
            {
                AttributeRecord attributeListRecord = baseSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty);
                if (attributeListRecord == null)
                {
                    return(new FileRecord(baseSegment));
                }
                else
                {
                    // The attribute list contains entries for every attribute the record has (excluding the attribute list),
                    // including attributes that reside within the base record segment.
                    AttributeList              attributeList = new AttributeList(m_volume, attributeListRecord);
                    List <AttributeListEntry>  entries       = attributeList.ReadEntries();
                    List <MftSegmentReference> references    = AttributeList.GetSegmentReferenceList(entries);
                    int baseSegmentIndex = MftSegmentReference.IndexOfSegmentNumber(references, baseSegmentNumber);

                    if (baseSegmentIndex >= 0)
                    {
                        references.RemoveAt(baseSegmentIndex);
                    }

                    List <FileRecordSegment> recordSegments = new List <FileRecordSegment>();
                    // we want the base record segment first
                    recordSegments.Add(baseSegment);

                    foreach (MftSegmentReference reference in references)
                    {
                        FileRecordSegment segment = GetFileRecordSegment(reference);
                        if (segment != null)
                        {
                            recordSegments.Add(segment);
                        }
                        else
                        {
                            // record is invalid
                            return(null);
                        }
                    }
                    return(new FileRecord(recordSegments));
                }
            }
            else
            {
                return(null);
            }
        }
Beispiel #20
0
        private static FileRecordSegment CreateSystemReservedSegment(long segmentNumber)
        {
            FileRecordSegment baseRecordSegment = new FileRecordSegment(segmentNumber, (ushort)segmentNumber);

            baseRecordSegment.IsInUse = true;
            baseRecordSegment.UpdateSequenceNumber = 1;
            DateTime creationTime = DateTime.Now;
            StandardInformationRecord standardInformation = (StandardInformationRecord)baseRecordSegment.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty);

            standardInformation.CreationTime        = creationTime;
            standardInformation.ModificationTime    = creationTime;
            standardInformation.MftModificationTime = creationTime;
            standardInformation.LastAccessTime      = creationTime;
            standardInformation.FileAttributes      = FileAttributes.System | FileAttributes.Hidden;
            baseRecordSegment.CreateAttributeRecord(AttributeType.Data, String.Empty);
            return(baseRecordSegment);
        }
Beispiel #21
0
        private static FileRecordSegment CreateBaseRecordSegment(long segmentNumber, ushort sequenceNumber, FileNameRecord fileNameRecord)
        {
            FileRecordSegment baseRecordSegment = new FileRecordSegment(segmentNumber, sequenceNumber);

            baseRecordSegment.IsInUse = true;
            baseRecordSegment.UpdateSequenceNumber = 1;
            StandardInformationRecord standardInformation = (StandardInformationRecord)baseRecordSegment.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty);

            standardInformation.CreationTime        = fileNameRecord.CreationTime;
            standardInformation.ModificationTime    = fileNameRecord.ModificationTime;
            standardInformation.MftModificationTime = fileNameRecord.MftModificationTime;
            standardInformation.LastAccessTime      = fileNameRecord.LastAccessTime;
            standardInformation.FileAttributes      = fileNameRecord.FileAttributes;
            FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)baseRecordSegment.CreateAttributeRecord(AttributeType.FileName, String.Empty);

            fileNameAttribute.IsIndexed = true;
            fileNameAttribute.Record    = fileNameRecord;
            return(baseRecordSegment);
        }
Beispiel #22
0
        public FileRecord CreateFile(List <FileNameRecord> fileNameRecords)
        {
            if (fileNameRecords.Count == 0)
            {
                throw new ArgumentException();
            }
            bool isDirectory = fileNameRecords[0].IsDirectory;
            MftSegmentReference segmentReference  = AllocateFileRecordSegment();
            FileRecordSegment   fileRecordSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber);

            fileRecordSegment.ReferenceCount = (ushort)fileNameRecords.Count; // Each FileNameRecord is about to be indexed
            fileRecordSegment.IsInUse        = true;
            fileRecordSegment.IsDirectory    = isDirectory;
            FileRecord fileRecord = new FileRecord(fileRecordSegment);
            StandardInformationRecord standardInformation = (StandardInformationRecord)fileRecord.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty);

            standardInformation.CreationTime        = fileNameRecords[0].CreationTime;
            standardInformation.ModificationTime    = fileNameRecords[0].ModificationTime;
            standardInformation.MftModificationTime = fileNameRecords[0].MftModificationTime;
            standardInformation.LastAccessTime      = fileNameRecords[0].LastAccessTime;
            standardInformation.FileAttributes      = 0;
            foreach (FileNameRecord fileNameRecord in fileNameRecords)
            {
                FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)fileRecord.CreateAttributeRecord(AttributeType.FileName, String.Empty);
                fileNameAttribute.IsIndexed = true;
                fileNameAttribute.Record    = fileNameRecord;
            }

            if (isDirectory)
            {
                string          indexName = IndexHelper.GetIndexName(AttributeType.FileName);
                IndexRootRecord indexRoot = (IndexRootRecord)fileRecord.CreateAttributeRecord(AttributeType.IndexRoot, indexName);
                IndexHelper.InitializeIndexRoot(indexRoot, AttributeType.FileName, m_volume.BytesPerIndexRecord, m_volume.BytesPerCluster);
            }
            else
            {
                fileRecord.CreateAttributeRecord(AttributeType.Data, String.Empty);
            }

            UpdateFileRecord(fileRecord);

            return(fileRecord);
        }
Beispiel #23
0
        private MftSegmentReference AllocateReservedFileRecordSegment()
        {
            BitmapData bitmap = m_mftFile.Bitmap;

            if (bitmap == null)
            {
                throw new InvalidDataException("Invalid MFT Record, missing Bitmap attribute");
            }
            long?segmentNumber = bitmap.AllocateRecord(FirstReservedSegmentNumber, FirstUserSegmentNumber - 1);

            if (!segmentNumber.HasValue)
            {
                throw new DiskFullException();
            }

            FileRecordSegment previousSegment = GetFileRecordSegment(segmentNumber.Value);
            ushort            sequenceNumber  = (previousSegment == null) ? (ushort)1 : previousSegment.SequenceNumber;

            return(new MftSegmentReference(segmentNumber.Value, sequenceNumber));
        }
Beispiel #24
0
        private FileRecordSegment GetFileRecordSegment(long segmentNumber)
        {
            NTFSBootRecord bootRecord = m_volume.BootRecord;

            // Note: File record always start at the beginning of a sector
            // Note: Record can span multiple clusters, or alternatively, several records can be stored in the same cluster
            long firstSectorIndex = segmentNumber * m_volume.SectorsPerFileRecordSegment;

            byte[] segmentBytes = m_mftFile.Data.ReadSectors(firstSectorIndex, m_volume.SectorsPerFileRecordSegment);

            if (FileRecordSegment.ContainsFileRecordSegment(segmentBytes))
            {
                FileRecordSegment recordSegment = new FileRecordSegment(segmentBytes, 0, segmentNumber);
                return(recordSegment);
            }
            else
            {
                return(null);
            }
        }
Beispiel #25
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);
            }
        }
Beispiel #26
0
        /// <remarks>
        /// https://blogs.technet.microsoft.com/askcore/2009/10/16/the-four-stages-of-ntfs-file-growth/
        /// </remarks>
        public void UpdateSegments(int bytesPerFileRecordSegment, ushort minorNTFSVersion)
        {
            List <AttributeRecord> attributes = this.Attributes;

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

            int segmentLength = FileRecordSegment.GetFirstAttributeOffset(bytesPerFileRecordSegment, minorNTFSVersion);

            segmentLength += FileRecordSegment.EndMarkerLength;

            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].ImmediateAttributes.Add(attribute);
                }

                // 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);
            }
        }
Beispiel #27
0
        public void UpdateSegments(int maximumSegmentLength, int bytesPerSector, ushort minorNTFSVersion)
        {
            foreach (FileRecordSegment segment in m_segments)
            {
                segment.ImmediateAttributes.Clear();
            }

            int segmentLength = FileRecordSegment.GetFirstAttributeOffset(maximumSegmentLength, minorNTFSVersion);

            segmentLength += FileRecordSegment.EndMarkerLength;

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

            if (segmentLength <= maximumSegmentLength)
            {
                // a single record segment is needed
                FileRecordSegment baseRecordSegment = m_segments[0];
                foreach (AttributeRecord attribute in this.Attributes)
                {
                    baseRecordSegment.ImmediateAttributes.Add(attribute);
                }

                // 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 have to check if we can make some data streams non-resident,
                // otherwise we have to use child segments and create an attribute list
                throw new NotImplementedException();
            }
        }
Beispiel #28
0
        private MftSegmentReference AllocateFileRecordSegment()
        {
            BitmapData bitmap = m_mftFile.Bitmap;

            if (bitmap == null)
            {
                throw new InvalidDataException("Invalid MFT Record, missing Bitmap attribute");
            }
            long mftBitmapSearchStartIndex = MasterFileTable.FirstUserSegmentNumber;
            long?segmentNumber             = bitmap.AllocateRecord(mftBitmapSearchStartIndex);

            if (!segmentNumber.HasValue)
            {
                long numberOfUsableBits = bitmap.NumberOfUsableBits;
                Extend();
                segmentNumber = bitmap.AllocateRecord(numberOfUsableBits);
            }

            FileRecordSegment previousSegment = GetFileRecordSegment(segmentNumber.Value);
            ushort            sequenceNumber  = (previousSegment == null) ? (ushort)1 : previousSegment.SequenceNumber;

            return(new MftSegmentReference(segmentNumber.Value, sequenceNumber));
        }
        /// <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);
        }
Beispiel #30
0
 public FileRecord(FileRecordSegment segment)
 {
     m_segments = new List <FileRecordSegment>();
     m_segments.Add(segment);
 }