Example #1
0
        public byte[] ReadSectors(long firstSectorIndex, int count)
        {
            if (m_attributeRecord is NonResidentAttributeRecord)
            {
                NonResidentAttributeData attributeData = new NonResidentAttributeData(m_volume, m_fileRecord, (NonResidentAttributeRecord)m_attributeRecord);
                return(attributeData.ReadSectors(firstSectorIndex, count));
            }
            else
            {
                byte[] data               = ((ResidentAttributeRecord)m_attributeRecord).Data;
                long   totalSectors       = (long)Math.Ceiling((double)data.Length / m_volume.BytesPerSector);
                long   highestSectorIndex = Math.Max(totalSectors - 1, 0);
                if (firstSectorIndex < 0 || firstSectorIndex > highestSectorIndex)
                {
                    throw new ArgumentOutOfRangeException("firstSectorIndex is not within the valid range");
                }

                int offset = (int)firstSectorIndex * m_volume.BytesPerSector;
                int bytesToRead;
                if (offset + count * m_volume.BytesPerSector <= data.Length)
                {
                    bytesToRead = count * m_volume.BytesPerCluster;
                }
                else
                {
                    bytesToRead = data.Length - offset;
                }
                return(ByteReader.ReadBytes(data, offset, bytesToRead));
            }
        }
Example #2
0
        public void WriteSectors(long firstSectorIndex, byte[] data)
        {
            if (m_attributeRecord is NonResidentAttributeRecord)
            {
                NonResidentAttributeData attributeData = new NonResidentAttributeData(m_volume, m_fileRecord, (NonResidentAttributeRecord)m_attributeRecord);
                attributeData.WriteSectors(firstSectorIndex, data);
            }
            else
            {
                byte[] recordData         = ((ResidentAttributeRecord)m_attributeRecord).Data;
                long   totalSectors       = (long)Math.Ceiling((double)recordData.Length / m_volume.BytesPerSector);
                long   highestSectorIndex = Math.Max(totalSectors - 1, 0);
                if (firstSectorIndex < 0 || firstSectorIndex > highestSectorIndex)
                {
                    throw new ArgumentOutOfRangeException("firstSectorIndex is not within the valid range");
                }

                int offset = (int)firstSectorIndex * m_volume.BytesPerSector;
                int bytesToWrite;
                if (offset + data.Length <= recordData.Length)
                {
                    bytesToWrite = data.Length;
                }
                else
                {
                    bytesToWrite = recordData.Length - offset;
                }
                ByteWriter.WriteBytes(recordData, offset, data, bytesToWrite);
                if (m_fileRecord != null)
                {
                    m_volume.UpdateFileRecord(m_fileRecord);
                }
            }
        }
Example #3
0
 public IndexData(NTFSVolume volume, FileRecord fileRecord, AttributeType indexedAttributeType)
 {
     m_volume               = volume;
     m_fileRecord           = fileRecord;
     m_indexedAttributeType = indexedAttributeType;
     m_indexName            = IndexHelper.GetIndexName(indexedAttributeType);
     m_rootRecord           = (IndexRootRecord)m_fileRecord.GetAttributeRecord(AttributeType.IndexRoot, m_indexName);
     // I have observed the NTFS v5.1 driver keeping the IndexAllocation and associated Bitmap attributes after deleting files from the directory even though m_rootRecord.IsParentNode is set to false.
     m_indexAllocationRecord = (IndexAllocationRecord)m_fileRecord.GetAttributeRecord(AttributeType.IndexAllocation, m_indexName);
     m_bitmapRecord          = m_fileRecord.GetAttributeRecord(AttributeType.Bitmap, m_indexName);
     if (m_indexAllocationRecord != null && m_bitmapRecord != null)
     {
         m_indexAllocationData = new NonResidentAttributeData(m_volume, m_fileRecord, m_indexAllocationRecord);
         long numberOfUsableBits = (long)(m_indexAllocationRecord.DataLength / m_rootRecord.BytesPerIndexRecord);
         m_bitmapData = new BitmapData(m_volume, m_fileRecord, m_bitmapRecord, numberOfUsableBits);
     }
     else if (m_rootRecord.IsParentNode && m_indexAllocationRecord == null)
     {
         throw new InvalidDataException("Missing Index Allocation Record");
     }
     else if (m_rootRecord.IsParentNode && m_bitmapRecord == null)
     {
         throw new InvalidDataException("Missing Index Bitmap Record");
     }
 }
Example #4
0
        public virtual void DeleteFile(FileRecord fileRecord)
        {
            MftSegmentReference parentDirectory       = fileRecord.ParentDirectoryReference;
            FileRecord          parentDirectoryRecord = GetFileRecord(parentDirectory);
            IndexData           parentDirectoryIndex  = new IndexData(this, parentDirectoryRecord, AttributeType.FileName);

            // Update parent directory index
            List <FileNameRecord> fileNameRecords = fileRecord.FileNameRecords;

            foreach (FileNameRecord fileNameRecord in fileNameRecords)
            {
                parentDirectoryIndex.RemoveEntry(fileNameRecord.GetBytes());
            }

            // Deallocate all data clusters
            foreach (AttributeRecord atttributeRecord in fileRecord.Attributes)
            {
                if (atttributeRecord is NonResidentAttributeRecord)
                {
                    NonResidentAttributeData attributeData = new NonResidentAttributeData(this, fileRecord, (NonResidentAttributeRecord)atttributeRecord);
                    attributeData.Truncate(0);
                }
            }

            m_mft.DeleteFile(fileRecord);
        }
Example #5
0
        public virtual void DeleteFile(FileRecord fileRecord)
        {
            MftSegmentReference parentDirectory       = fileRecord.ParentDirectoryReference;
            FileRecord          parentDirectoryRecord = GetFileRecord(parentDirectory);

            m_mftLock.AcquireWriterLock(Timeout.Infinite);
            IndexData parentDirectoryIndex = new IndexData(this, parentDirectoryRecord, AttributeType.FileName);

            uint transactionID = m_logClient.AllocateTransactionID();
            // Update parent directory index
            List <FileNameRecord> fileNameRecords = fileRecord.FileNameRecords;

            foreach (FileNameRecord fileNameRecord in fileNameRecords)
            {
                parentDirectoryIndex.RemoveEntry(fileNameRecord.GetBytes());
            }

            // Deallocate all data clusters
            foreach (AttributeRecord atttributeRecord in fileRecord.Attributes)
            {
                if (atttributeRecord is NonResidentAttributeRecord)
                {
                    NonResidentAttributeData attributeData = new NonResidentAttributeData(this, fileRecord, (NonResidentAttributeRecord)atttributeRecord);
                    attributeData.Truncate(0);
                }
            }

            m_mft.DeleteFile(fileRecord, transactionID);
            m_logClient.WriteForgetTransactionRecord(transactionID);
            m_logClient.WriteRestartRecord(this.MajorVersion, true);
            m_mftLock.ReleaseWriterLock();
        }
Example #6
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 #7
0
 public void WriteClusters(long firstClusterVCN, byte[] data)
 {
     if (m_attributeRecord is NonResidentAttributeRecord)
     {
         NonResidentAttributeData attributeData = new NonResidentAttributeData(m_volume, m_fileRecord, (NonResidentAttributeRecord)m_attributeRecord);
         attributeData.WriteClusters(firstClusterVCN, data);
     }
     else
     {
         long firstSectorIndex = firstClusterVCN * m_volume.SectorsPerCluster;
         WriteSectors(firstClusterVCN, data);
     }
 }
Example #8
0
 public byte[] ReadClusters(long firstClusterVCN, int count)
 {
     if (m_attributeRecord is NonResidentAttributeRecord)
     {
         NonResidentAttributeData attributeData = new NonResidentAttributeData(m_volume, m_fileRecord, (NonResidentAttributeRecord)m_attributeRecord);
         return(attributeData.ReadClusters(firstClusterVCN, count));
     }
     else
     {
         int  sectorsPerCluster = m_volume.SectorsPerCluster;
         long firstSectorIndex  = firstClusterVCN * sectorsPerCluster;
         int  sectorCount       = count * sectorsPerCluster;
         return(ReadSectors(firstSectorIndex, sectorCount));
     }
 }
Example #9
0
        public void AddEntry(MftSegmentReference fileReference, byte[] key)
        {
            IndexEntry entry = new IndexEntry();

            entry.FileReference = fileReference;
            entry.Key           = key;
            if (!m_rootRecord.IsParentNode)
            {
                int insertIndex = CollationHelper.FindIndexForSortedInsert(m_rootRecord.IndexEntries, key, m_rootRecord.CollationRule);
                m_rootRecord.IndexEntries.Insert(insertIndex, entry);
                if (m_rootRecord.RecordLength >= m_volume.AttributeRecordLengthToMakeNonResident)
                {
                    if (m_indexAllocationRecord == null)
                    {
                        m_indexAllocationRecord = (IndexAllocationRecord)m_fileRecord.CreateAttributeRecord(AttributeType.IndexAllocation, m_indexName);
                        m_indexAllocationData   = new NonResidentAttributeData(m_volume, m_fileRecord, m_indexAllocationRecord);
                        m_bitmapRecord          = m_fileRecord.CreateAttributeRecord(AttributeType.Bitmap, m_indexName);
                        m_bitmapData            = new BitmapData(m_volume, m_fileRecord, m_bitmapRecord, 0);
                    }
                    SplitRootIndexRecord();
                }
                else
                {
                    m_volume.UpdateFileRecord(m_fileRecord);
                }
            }
            else
            {
                KeyValuePairList <int, IndexRecord> path = FindInsertPath(key);
                IndexRecord leafRecord    = path[path.Count - 1].Value;
                long        leafRecordVBN = leafRecord.RecordVBN;
                int         insertIndex   = CollationHelper.FindIndexForSortedInsert(leafRecord.IndexEntries, key, m_rootRecord.CollationRule);
                leafRecord.IndexEntries.Insert(insertIndex, entry);
                long leafRecordIndex = ConvertToRecordIndex(leafRecordVBN);
                if (leafRecord.DoesFit((int)m_rootRecord.BytesPerIndexRecord))
                {
                    WriteIndexRecord(leafRecordIndex, leafRecord);
                }
                else
                {
                    // Split index record
                    SplitIndexRecord(path);
                }
            }
        }
Example #10
0
        public void Truncate(ulong newLengthInBytes)
        {
            ulong currentSize = this.Length;

            if (m_attributeRecord is NonResidentAttributeRecord)
            {
                NonResidentAttributeData attributeData = new NonResidentAttributeData(m_volume, m_fileRecord, (NonResidentAttributeRecord)m_attributeRecord);
                attributeData.Truncate(newLengthInBytes);
            }
            else
            {
                byte[] data = ((ResidentAttributeRecord)m_attributeRecord).Data;
                byte[] temp = new byte[newLengthInBytes];
                Array.Copy(data, temp, temp.Length);
                ((ResidentAttributeRecord)m_attributeRecord).Data = temp;
                if (m_fileRecord != null)
                {
                    m_volume.UpdateFileRecord(m_fileRecord);
                }
            }
        }
Example #11
0
        public virtual void DeleteFile(FileRecord fileRecord)
        {
            lock (m_mftLock)
            {
                MftSegmentReference parentDirectory       = fileRecord.ParentDirectoryReference;
                FileRecord          parentDirectoryRecord = GetFileRecord(parentDirectory);
                IndexData           parentDirectoryIndex  = new IndexData(this, parentDirectoryRecord, AttributeType.FileName);

                if (fileRecord.IsDirectory)
                {
                    IndexData directoryIndex = new IndexData(this, fileRecord, AttributeType.FileName);
                    if (!directoryIndex.IsEmpty)
                    {
                        throw new DirectoryNotEmptyException();
                    }
                }

                uint transactionID = m_logClient.AllocateTransactionID();
                // Update parent directory index
                List <FileNameRecord> fileNameRecords = fileRecord.FileNameRecords;
                foreach (FileNameRecord fileNameRecord in fileNameRecords)
                {
                    parentDirectoryIndex.RemoveEntry(fileNameRecord.GetBytes());
                }

                // Deallocate all data clusters
                foreach (AttributeRecord atttributeRecord in fileRecord.Attributes)
                {
                    if (atttributeRecord is NonResidentAttributeRecord)
                    {
                        NonResidentAttributeData attributeData = new NonResidentAttributeData(this, fileRecord, (NonResidentAttributeRecord)atttributeRecord);
                        attributeData.Truncate(0);
                    }
                }

                m_mft.DeleteFile(fileRecord, transactionID);
                m_logClient.WriteForgetTransactionRecord(transactionID);
                m_logClient.WriteRestartRecord(true);
            }
        }