public AttributeRecord CreateAttributeRecord(AttributeType type, string name)
        {
            AttributeRecord attribute = AttributeRecord.Create(type, name, NextAttributeInstance);

            NextAttributeInstance++;
            FileRecordHelper.InsertSorted(m_immediateAttributes, attribute);
            return(attribute);
        }
Example #2
0
        public AttributeRecord CreateAttributeRecord(AttributeType type, string name)
        {
            AttributeRecord attribute = AttributeRecord.Create(type, name, m_segments[0].NextAttributeInstance);

            m_segments[0].NextAttributeInstance++;
            FileRecordHelper.InsertSorted(this.Attributes, attribute);
            return(attribute);
        }
Example #3
0
        public void Extend(ulong additionalLengthInBytes)
        {
            ulong currentSize = this.Length;

            if (m_attributeRecord is NonResidentAttributeRecord)
            {
                NonResidentAttributeData attributeData = new NonResidentAttributeData(m_volume, m_fileRecord, (NonResidentAttributeRecord)m_attributeRecord);
                attributeData.Extend(additionalLengthInBytes);
            }
            else
            {
                byte[] data              = ((ResidentAttributeRecord)m_attributeRecord).Data;
                ulong  finalDataLength   = (uint)data.Length + additionalLengthInBytes;
                ulong  finalRecordLength = (uint)m_attributeRecord.RecordLength + additionalLengthInBytes;
                if (finalRecordLength >= (ulong)m_volume.AttributeRecordLengthToMakeNonResident &&
                    m_attributeRecord.AttributeType != AttributeType.AttributeList) // We will create an attribute list with the right attribute form in advance.
                {
                    // Convert the attribute to non-resident
                    long clustersToAllocate = (long)Math.Ceiling((double)finalDataLength / m_volume.BytesPerCluster);
                    if (clustersToAllocate > m_volume.NumberOfFreeClusters)
                    {
                        throw new DiskFullException();
                    }
                    NonResidentAttributeRecord attributeRecord = NonResidentAttributeRecord.Create(m_attributeRecord.AttributeType, m_attributeRecord.Name);
                    NonResidentAttributeData   attributeData   = new NonResidentAttributeData(m_volume, null, attributeRecord);
                    attributeData.Extend(finalDataLength);
                    if (data.Length % m_volume.BytesPerCluster > 0)
                    {
                        int fillDataLength = m_volume.BytesPerCluster - (data.Length % m_volume.BytesPerCluster);
                        if ((uint)data.Length + (uint)fillDataLength < finalDataLength)
                        {
                            // Only the last cluster can be partially used, if this is not the last cluster, zero-fill it
                            data = ByteUtils.Concatenate(data, new byte[fillDataLength]);
                        }
                    }
                    attributeData.WriteClusters(0, data);
                    // Note that we overwrite the old attribute only after writing the non-resident data
                    if (m_fileRecord != null)
                    {
                        m_fileRecord.RemoveAttributeRecord(m_attributeRecord.AttributeType, m_attributeRecord.Name);
                        FileRecordHelper.InsertSorted(m_fileRecord.Attributes, attributeRecord);
                    }
                    m_attributeRecord = attributeRecord;
                }
                else
                {
                    int    currentLength = data.Length;
                    byte[] temp          = new byte[currentLength + (int)additionalLengthInBytes];
                    Array.Copy(data, temp, data.Length);
                    ((ResidentAttributeRecord)m_attributeRecord).Data = temp;
                }

                if (m_fileRecord != null)
                {
                    m_volume.UpdateFileRecord(m_fileRecord);
                }
            }
        }
Example #4
0
        internal AttributeRecord CreateAttributeRecord(AttributeType type, string name, bool isResident)
        {
            AttributeRecord attribute = AttributeRecord.Create(type, name, isResident);

            attribute.Instance = NextAttributeInstance;
            NextAttributeInstance++;
            FileRecordHelper.InsertSorted(m_immediateAttributes, attribute);
            return(attribute);
        }
Example #5
0
 private List <AttributeRecord> GetAttributes()
 {
     if (m_segments.Count > 1)
     {
         return(FileRecordHelper.GetAssembledAttributes(m_segments));
     }
     else
     {
         return(new List <AttributeRecord>(m_segments[0].ImmediateAttributes));
     }
 }
Example #6
0
        public AttributeRecord CreateAttributeRecord(AttributeType type, string name)
        {
            if (name.Length > AttributeRecord.MaxAttributeNameLength)
            {
                throw new InvalidNameException();
            }

            bool            isResident = (type != AttributeType.IndexAllocation);
            AttributeRecord attribute  = AttributeRecord.Create(type, name, isResident);

            FileRecordHelper.InsertSorted(this.Attributes, attribute);
            return(attribute);
        }
Example #7
0
 private List <AttributeRecord> GetAttributes()
 {
     if (m_segments.Count > 1)
     {
         return(FileRecordHelper.GetAssembledAttributes(m_segments));
     }
     else
     {
         List <AttributeRecord> result = new List <AttributeRecord>();
         foreach (AttributeRecord attribute in m_segments[0].ImmediateAttributes)
         {
             result.Add(attribute.Clone());
         }
         return(result);
     }
 }
        public AttributeRecord CreateAttributeListRecord(bool isResident)
        {
            AttributeRecord attribute;

            if (isResident)
            {
                attribute = AttributeRecord.Create(AttributeType.AttributeList, String.Empty, NextAttributeInstance);
            }
            else
            {
                attribute = NonResidentAttributeRecord.Create(AttributeType.AttributeList, String.Empty, NextAttributeInstance);
            }
            NextAttributeInstance++;
            FileRecordHelper.InsertSorted(m_immediateAttributes, attribute);
            return(attribute);
        }
Example #9
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);
            }
        }
Example #10
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);
            }
        }
Example #11
0
        public void UpdateFileRecord(FileRecord fileRecord)
        {
            AttributeRecord oldAttributeList = fileRecord.BaseSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty);

            fileRecord.UpdateSegments(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion);
            FileRecordSegment baseSegment = fileRecord.BaseSegment;

            for (int segmentIndex = 1; segmentIndex < fileRecord.Segments.Count; segmentIndex++)
            {
                FileRecordSegment segment = fileRecord.Segments[segmentIndex];
                if (segment.SegmentReference == MftSegmentReference.NullReference)
                {
                    // New segment, we must allocate space for it
                    MftSegmentReference segmentReference;
                    if (baseSegment.SegmentNumber == MasterFileTable.MasterFileTableSegmentNumber)
                    {
                        segmentReference = AllocateReservedFileRecordSegment();
                    }
                    else
                    {
                        segmentReference = AllocateFileRecordSegment();
                    }
                    FileRecordSegment newSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber, baseSegment.SegmentReference);
                    newSegment.IsInUse               = true;
                    newSegment.IsDirectory           = fileRecord.IsDirectory;
                    newSegment.NextAttributeInstance = segment.NextAttributeInstance;
                    newSegment.ImmediateAttributes.AddRange(segment.ImmediateAttributes);
                    fileRecord.Segments[segmentIndex] = newSegment;
                }
                else if (segment.ImmediateAttributes.Count == 0)
                {
                    DeallocateFileRecordSegment(segment);
                    fileRecord.Segments.RemoveAt(segmentIndex);
                    segmentIndex--;
                }
            }

            foreach (FileRecordSegment segment in fileRecord.Segments)
            {
                UpdateFileRecordSegment(segment);
            }

            if (oldAttributeList is NonResidentAttributeRecord)
            {
                new NonResidentAttributeData(m_volume, null, (NonResidentAttributeRecord)oldAttributeList).Truncate(0);
            }

            bool needsAttributeList = (fileRecord.Segments.Count > 1);

            if (needsAttributeList)
            {
                List <AttributeListEntry> entries              = FileRecordHelper.BuildAttributeList(fileRecord.Segments, m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion);
                int             dataLength                     = AttributeList.GetLength(entries);
                int             attributeListRecordLength      = ResidentAttributeRecord.GetRecordLength(0, dataLength);
                int             numberOfBytesFreeInBaseSegment = baseSegment.GetNumberOfBytesFree(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion);
                bool            isResident                     = (attributeListRecordLength <= numberOfBytesFreeInBaseSegment);
                AttributeRecord attributeListRecord            = baseSegment.CreateAttributeListRecord(isResident);
                AttributeList   attributeList                  = new AttributeList(m_volume, attributeListRecord);
                attributeList.WriteEntries(entries);
                UpdateFileRecordSegment(baseSegment);
            }
        }
        public void UpdateFileRecord(FileRecord fileRecord, uint transactionID)
        {
            Dictionary <MftSegmentReference, byte[]> undoDictionary = new Dictionary <MftSegmentReference, byte[]>();

            foreach (FileRecordSegment segment in fileRecord.Segments)
            {
                byte[] segmentBytes = segment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false);
                undoDictionary.Add(segment.SegmentReference, segmentBytes);
            }

            AttributeRecord oldAttributeList = fileRecord.BaseSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty);

            fileRecord.UpdateSegments(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion);
            FileRecordSegment baseSegment = fileRecord.BaseSegment;

            for (int segmentIndex = 1; segmentIndex < fileRecord.Segments.Count; segmentIndex++)
            {
                FileRecordSegment segment = fileRecord.Segments[segmentIndex];
                if (segment.SegmentReference == MftSegmentReference.NullReference)
                {
                    // New segment, we must allocate space for it
                    MftSegmentReference segmentReference;
                    if (baseSegment.SegmentNumber == MasterFileTable.MasterFileTableSegmentNumber)
                    {
                        segmentReference = AllocateReservedFileRecordSegment(transactionID);
                    }
                    else
                    {
                        segmentReference = AllocateFileRecordSegment(transactionID);
                    }
                    FileRecordSegment newSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber, baseSegment.SegmentReference);
                    newSegment.IsInUse               = true;
                    newSegment.IsDirectory           = fileRecord.IsDirectory;
                    newSegment.NextAttributeInstance = segment.NextAttributeInstance;
                    newSegment.ImmediateAttributes.AddRange(segment.ImmediateAttributes);
                    fileRecord.Segments[segmentIndex] = newSegment;
                }
                else if (segment.ImmediateAttributes.Count == 0)
                {
                    byte[] undoData     = undoDictionary[segment.SegmentReference];
                    ulong  streamOffset = (ulong)(segment.SegmentNumber * m_volume.BytesPerFileRecordSegment);
                    m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.DeallocateFileRecordSegment, new byte[0], NTFSLogOperation.InitializeFileRecordSegment, undoData, transactionID);
                    DeallocateFileRecordSegment(segment, transactionID);
                    fileRecord.Segments.RemoveAt(segmentIndex);
                    segmentIndex--;
                }
            }

            for (int segmentIndex = 1; segmentIndex < fileRecord.Segments.Count; segmentIndex++)
            {
                FileRecordSegment segment = fileRecord.Segments[segmentIndex];
                byte[]            undoData;
                byte[]            redoData     = segment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false);
                ulong             streamOffset = (ulong)(segment.SegmentNumber * m_volume.BytesPerFileRecordSegment);
                if (undoDictionary.TryGetValue(segment.SegmentReference, out undoData))
                {
                    m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.InitializeFileRecordSegment, redoData, NTFSLogOperation.InitializeFileRecordSegment, undoData, transactionID);
                }
                else
                {
                    // New segment
                    m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.InitializeFileRecordSegment, redoData, NTFSLogOperation.DeallocateFileRecordSegment, new byte[0], transactionID);
                }
                UpdateFileRecordSegment(segment);
            }

            if (oldAttributeList is NonResidentAttributeRecord)
            {
                new NonResidentAttributeData(m_volume, null, (NonResidentAttributeRecord)oldAttributeList).Truncate(0);
            }

            bool needsAttributeList = (fileRecord.Segments.Count > 1);

            if (needsAttributeList)
            {
                List <AttributeListEntry> entries              = FileRecordHelper.BuildAttributeList(fileRecord.Segments, m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion);
                int             dataLength                     = AttributeList.GetLength(entries);
                int             attributeListRecordLength      = ResidentAttributeRecord.GetRecordLength(0, dataLength);
                int             numberOfBytesFreeInBaseSegment = baseSegment.GetNumberOfBytesFree(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion);
                bool            isResident                     = (attributeListRecordLength <= numberOfBytesFreeInBaseSegment);
                AttributeRecord attributeListRecord            = baseSegment.CreateAttributeListRecord(isResident);
                AttributeList   attributeList                  = new AttributeList(m_volume, attributeListRecord);
                attributeList.WriteEntries(entries);
            }

            byte[] baseRecordUndoData     = undoDictionary[baseSegment.SegmentReference];
            byte[] baseRecordRedoData     = baseSegment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false);
            ulong  baseRecordStreamOffset = (ulong)(baseSegment.SegmentNumber * m_volume.BytesPerFileRecordSegment);

            m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, baseRecordStreamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.InitializeFileRecordSegment, baseRecordRedoData, NTFSLogOperation.InitializeFileRecordSegment, baseRecordUndoData, transactionID);
            UpdateFileRecordSegment(baseSegment);
        }