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)); } }
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); } } }
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"); } }
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); }
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(); }
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); } } }
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); } }
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)); } }
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); } } }
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); } } }
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); } }