/// <summary> /// Will remove the pointer while preserving the entry (if present) /// </summary> private void RemovePointerFromRoot(int indexOfEntryToRemove) { IndexEntry pointer = m_rootRecord.IndexEntries[indexOfEntryToRemove]; if (pointer.IsLastEntry) { if (m_rootRecord.IndexEntries.Count == 1) { m_rootRecord.IndexEntries.RemoveAt(indexOfEntryToRemove); m_rootRecord.IsParentNode = false; } else { MftSegmentReference fileReferenceToReinsert = m_rootRecord.IndexEntries[indexOfEntryToRemove - 1].FileReference; byte[] keyToReinsert = m_rootRecord.IndexEntries[indexOfEntryToRemove - 1].Key; m_rootRecord.IndexEntries.RemoveAt(indexOfEntryToRemove); m_rootRecord.IndexEntries[indexOfEntryToRemove - 1].FileReference = MftSegmentReference.NullReference; m_rootRecord.IndexEntries[indexOfEntryToRemove - 1].Key = new byte[0]; AddEntry(fileReferenceToReinsert, keyToReinsert); } } else { MftSegmentReference fileReferenceToReinsert = pointer.FileReference; byte[] keyToReinsert = pointer.Key; m_rootRecord.IndexEntries.RemoveAt(indexOfEntryToRemove); AddEntry(fileReferenceToReinsert, keyToReinsert); } m_volume.UpdateFileRecord(m_fileRecord); }
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); }
private FileRecord ReadMftRecord(bool useMftMirror, bool readMftMirror) { NTFSBootRecord bootRecord = m_volume.BootRecord; long mftStartLCN = useMftMirror ? (long)bootRecord.MftMirrorStartLCN : (long)bootRecord.MftStartLCN; long mftSegmentNumber = readMftMirror ? MftMirrorSegmentNumber : MasterFileTableSegmentNumber; FileRecordSegment mftRecordSegment; try { mftRecordSegment = ReadMftRecordSegment(mftStartLCN, mftSegmentNumber); } catch (InvalidDataException) { throw new InvalidDataException("Invalid MFT base record segment"); } if (!mftRecordSegment.IsBaseFileRecord) { throw new InvalidDataException("Invalid MFT file record, MFT segment number did not correspond to a base file record segment"); } AttributeRecord attributeListRecord = mftRecordSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty); if (attributeListRecord == null) { return(new FileRecord(mftRecordSegment)); } else { 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; try { segment = ReadMftRecordSegment(mftStartLCN, reference); } catch (InvalidDataException) { throw new InvalidDataException("Invalid MFT file record, referenced segment is invalid"); } recordSegments.Add(segment); } return(new FileRecord(recordSegments)); } }
public NTFSRestartRecord(byte[] recordBytes) { MajorVersion = LittleEndianConverter.ToUInt32(recordBytes, 0x00); MinorVersion = LittleEndianConverter.ToUInt32(recordBytes, 0x04); StartOfCheckpointLsn = LittleEndianConverter.ToUInt64(recordBytes, 0x08); OpenAttributeTableLsn = LittleEndianConverter.ToUInt64(recordBytes, 0x10); AttributeNamesLsn = LittleEndianConverter.ToUInt64(recordBytes, 0x18); DirtyPageTableLsn = LittleEndianConverter.ToUInt64(recordBytes, 0x20); TransactionTableLsn = LittleEndianConverter.ToUInt64(recordBytes, 0x28); OpenAttributeTableLength = LittleEndianConverter.ToUInt32(recordBytes, 0x30); AttributeNamesLength = LittleEndianConverter.ToUInt32(recordBytes, 0x34); DirtyPageTableLength = LittleEndianConverter.ToUInt32(recordBytes, 0x38); TransactionTableLength = LittleEndianConverter.ToUInt32(recordBytes, 0x3C); if (recordBytes.Length >= LengthNTFS30) { Unknown1 = LittleEndianConverter.ToUInt64(recordBytes, 0x40); PreviousRestartRecordLsn = LittleEndianConverter.ToUInt64(recordBytes, 0x48); BytesPerCluster = LittleEndianConverter.ToUInt32(recordBytes, 0x50); UsnJournal = new MftSegmentReference(recordBytes, 0x58); Unknown2 = LittleEndianConverter.ToUInt64(recordBytes, 0x60); if (recordBytes.Length >= LengthVista) { UnknownLsn = LittleEndianConverter.ToUInt64(recordBytes, 0x68); } } }
/// <returns>Index in open attribute table</returns> private int AddToOpenAttributeTable(MftSegmentReference fileReference, AttributeType attributeType, string attributeName, ulong lsnOfOpenRecord) { int openAttributeIndex = m_openAttributes.Count; m_openAttributes.Add(new OpenAttribute(fileReference, attributeType, attributeName, lsnOfOpenRecord)); return(openAttributeIndex); }
public OpenAttributeEntry(byte[] buffer, int offset, uint majorVersion) { m_majorVersion = majorVersion; int fileReferenceOffset = (m_majorVersion == 0) ? FileReferenceOffsetV0 : FileReferenceOffsetV1; int lsnOfOpenRecordOffset = (m_majorVersion == 0) ? LsnOfOpenRecordOffsetV0 : LsnOfOpenRecordOffsetV1; int dirtyPagesSeenOffset = (m_majorVersion == 0) ? DirtyPagesSeenOffsetV0 : DirtyPagesSeenOffsetV1; int attributeTypeCodeOffset = (m_majorVersion == 0) ? AttributeTypeCodeOffsetV0 : AttributeTypeCodeOffsetV1; int bytesPerIndexBufferOffset = (m_majorVersion == 0) ? BytesPerIndexBufferOffsetV0 : BytesPerIndexBufferOffsetV1; AllocatedOrNextFree = LittleEndianConverter.ToUInt32(buffer, offset + 0x00); if (majorVersion == 0) { AttributeOffset = LittleEndianConverter.ToUInt32(buffer, offset + 0x04); } FileReference = new MftSegmentReference(buffer, offset + fileReferenceOffset); LsnOfOpenRecord = LittleEndianConverter.ToUInt64(buffer, offset + lsnOfOpenRecordOffset); DirtyPagesSeen = Convert.ToBoolean(ByteReader.ReadByte(buffer, offset + dirtyPagesSeenOffset)); if (m_majorVersion == 0) { // This field exists in NTFS v1.2, will be false in NTFS v3.0+ AttributeNamePresent = Convert.ToBoolean(ByteReader.ReadByte(buffer, offset + 0x19)); } AttributeTypeCode = (AttributeType)LittleEndianConverter.ToUInt32(buffer, offset + attributeTypeCodeOffset); PointerToAttributeName = LittleEndianConverter.ToUInt64(buffer, offset + 0x20); if (AttributeTypeCode == AttributeType.IndexAllocation) { BytesPerIndexBuffer = LittleEndianConverter.ToUInt32(buffer, offset + bytesPerIndexBufferOffset); } }
protected internal virtual FileRecord GetFileRecord(MftSegmentReference fileReference) { lock (m_mftLock) { return(m_mft.GetFileRecord(fileReference)); } }
public virtual FileRecord CreateFile(MftSegmentReference parentDirectory, string fileName, bool isDirectory) { // Worst case scenrario: the MFT might be full and the parent directory index requires multiple splits if (NumberOfFreeClusters < 24) { throw new DiskFullException(); } FileRecord parentDirectoryRecord = GetFileRecord(parentDirectory); m_mftLock.AcquireWriterLock(Timeout.Infinite); IndexData parentDirectoryIndex = new IndexData(this, parentDirectoryRecord, AttributeType.FileName); if (parentDirectoryIndex.ContainsFileName(fileName)) { m_mftLock.ReleaseWriterLock(); throw new AlreadyExistsException(); } List <FileNameRecord> fileNameRecords = IndexHelper.GenerateFileNameRecords(parentDirectory, fileName, isDirectory, m_generateDosNames, parentDirectoryIndex); uint transactionID = m_logClient.AllocateTransactionID(); FileRecord fileRecord = m_mft.CreateFile(fileNameRecords, transactionID); // Update parent directory index foreach (FileNameRecord fileNameRecord in fileNameRecords) { parentDirectoryIndex.AddEntry(fileRecord.BaseSegmentReference, fileNameRecord.GetBytes()); } m_logClient.WriteForgetTransactionRecord(transactionID); m_logClient.WriteRestartRecord(this.MajorVersion, true); m_mftLock.ReleaseWriterLock(); return(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 WriteRestartRecord(ushort majorNTFSVersion, bool isClean) { NTFSRestartRecord previousRestartRecord = ReadCurrentRestartRecord(); MftSegmentReference usnJournal = previousRestartRecord.UsnJournal; ulong previousRestartRecordLsn = previousRestartRecord.PreviousRestartRecordLsn; LfsRecord restartRecord = WriteRestartRecord(previousRestartRecordLsn, usnJournal, majorNTFSVersion, isClean); }
public List <uint> AssociatedTransactions = new List <uint>(); // List of transactions using this open attribute public OpenAttribute(MftSegmentReference fileReference, AttributeType attributeType, string attributeName, ulong lsnOfOpenRecord) { FileReference = fileReference; AttributeType = attributeType; AttributeName = attributeName; LsnOfOpenRecord = lsnOfOpenRecord; }
public virtual FileRecord CreateFile(MftSegmentReference parentDirectory, string fileName, bool isDirectory) { // Worst case scenrario: the MFT might be full and the parent directory index requires multiple splits if (NumberOfFreeClusters < 24) { throw new DiskFullException(); } FileRecord parentDirectoryRecord = GetFileRecord(parentDirectory); IndexData parentDirectoryIndex = new IndexData(this, parentDirectoryRecord, AttributeType.FileName); if (parentDirectoryIndex.ContainsFileName(fileName)) { throw new AlreadyExistsException(); } List <FileNameRecord> fileNameRecords = IndexHelper.GenerateFileNameRecords(parentDirectory, fileName, isDirectory, m_generateDosNames, parentDirectoryIndex); FileRecord fileRecord = m_mft.CreateFile(fileNameRecords); // Update parent directory index foreach (FileNameRecord fileNameRecord in fileNameRecords) { parentDirectoryIndex.AddEntry(fileRecord.BaseSegmentReference, fileNameRecord.GetBytes()); } return(fileRecord); }
public void WriteRestartRecord(bool isClean) { ulong usnJournalUnknown1 = m_currentRestartRecord.UsnJournalUnknown1; ulong previousRestartRecordLsn = m_currentRestartRecord.PreviousRestartRecordLsn; MftSegmentReference usnJournal = m_currentRestartRecord.UsnJournal; ulong usnJournalUnknown2 = m_currentRestartRecord.UsnJournalUnknown2; LfsRecord restartRecord = WriteRestartRecord(usnJournalUnknown1, previousRestartRecordLsn, usnJournal, usnJournalUnknown2, isClean); }
protected internal virtual FileRecord GetFileRecord(MftSegmentReference fileReference) { m_mftLock.AcquireReaderLock(Timeout.Infinite); FileRecord fileRecord = m_mft.GetFileRecord(fileReference); m_mftLock.ReleaseReaderLock(); return(fileRecord); }
private LfsRecord WriteRestartRecord(ulong previousRestartRecordLsn, MftSegmentReference usnJournal, ushort majorNTFSVersion, bool isClean) { NTFSRestartRecord restartRecord = new NTFSRestartRecord(m_majorVersion, m_minorVersion); restartRecord.StartOfCheckpointLsn = m_lastClientLsn; restartRecord.PreviousRestartRecordLsn = previousRestartRecordLsn; if (isClean) { if (m_transactions.Count > 0) { throw new InvalidOperationException("All TransactionIDs must be deallocated before writing a clean restart record"); } } else if (m_openAttributes.Count > 0) { byte[] attributeNameTableBytes; byte[] openAttributeTableBytes = GetOpenAttributeTableBytes(out attributeNameTableBytes); m_lastClientLsn = 0; uint transactionID = AllocateTransactionID(); // These records must have a valid transactionID LfsRecord openAttributeTableRecord = WriteLogRecord(null, null, 0, NTFSLogOperation.OpenAttributeTableDump, openAttributeTableBytes, NTFSLogOperation.Noop, new byte[0], transactionID); restartRecord.OpenAttributeTableLsn = openAttributeTableRecord.ThisLsn; restartRecord.OpenAttributeTableLength = (uint)openAttributeTableBytes.Length; if (attributeNameTableBytes != null) { LfsRecord attributeNameTableRecord = WriteLogRecord(null, null, 0, NTFSLogOperation.AttributeNamesDump, openAttributeTableBytes, NTFSLogOperation.Noop, new byte[0], transactionID); restartRecord.AttributeNamesLsn = attributeNameTableRecord.ThisLsn; restartRecord.AttributeNamesLength = (uint)attributeNameTableBytes.Length; } DeallocateTransactionID(transactionID); } restartRecord.BytesPerCluster = (uint)Volume.BytesPerCluster; restartRecord.UsnJournal = usnJournal; byte[] clientData = restartRecord.GetBytes(majorNTFSVersion); LfsRecord result = m_logFile.WriteRecord(m_clientIndex, LfsRecordType.ClientRestart, 0, 0, 0, clientData); m_lastClientLsn = result.ThisLsn; LfsClientRecord clientRecord = m_logFile.GetClientRecord(m_clientIndex); if (isClean) { clientRecord.OldestLsn = restartRecord.StartOfCheckpointLsn; } else { ulong oldestLsn = restartRecord.StartOfCheckpointLsn; foreach (Transaction transaction in m_transactions) { if (transaction.OldestLsn != 0 && transaction.OldestLsn < oldestLsn) { oldestLsn = transaction.OldestLsn; } } clientRecord.OldestLsn = oldestLsn; } clientRecord.ClientRestartLsn = result.ThisLsn; m_logFile.WriteRestartPage(isClean); return(result); }
public virtual void MoveFile(FileRecord fileRecord, MftSegmentReference newParentDirectory, string newFileName) { // Worst case scenrario: the new parent directory index requires multiple splits if (NumberOfFreeClusters < 4) { throw new DiskFullException(); } FileRecord oldParentDirectoryRecord = GetFileRecord(fileRecord.ParentDirectoryReference); IndexData oldParentDirectoryIndex = new IndexData(this, oldParentDirectoryRecord, AttributeType.FileName); IndexData newParentDirectoryIndex; if (fileRecord.ParentDirectoryReference == newParentDirectory) { newParentDirectoryIndex = oldParentDirectoryIndex; } else { FileRecord newParentDirectoryRecord = GetFileRecord(newParentDirectory); newParentDirectoryIndex = new IndexData(this, newParentDirectoryRecord, AttributeType.FileName); if (newParentDirectoryIndex.ContainsFileName(newFileName)) { throw new AlreadyExistsException(); } } List <FileNameRecord> fileNameRecords = fileRecord.FileNameRecords; foreach (FileNameRecord fileNameRecord in fileNameRecords) { oldParentDirectoryIndex.RemoveEntry(fileNameRecord.GetBytes()); } DateTime creationTime = fileRecord.FileNameRecord.CreationTime; DateTime modificationTime = fileRecord.FileNameRecord.ModificationTime; DateTime mftModificationTime = fileRecord.FileNameRecord.MftModificationTime; DateTime lastAccessTime = fileRecord.FileNameRecord.LastAccessTime; ulong allocatedLength = fileRecord.FileNameRecord.AllocatedLength; ulong fileSize = fileRecord.FileNameRecord.FileSize; FileAttributes fileAttributes = fileRecord.FileNameRecord.FileAttributes; ushort packedEASize = fileRecord.FileNameRecord.PackedEASize; fileNameRecords = IndexHelper.GenerateFileNameRecords(newParentDirectory, newFileName, fileRecord.IsDirectory, m_generateDosNames, newParentDirectoryIndex, creationTime, modificationTime, mftModificationTime, lastAccessTime, allocatedLength, fileSize, fileAttributes, packedEASize); fileRecord.RemoveAttributeRecords(AttributeType.FileName, String.Empty); foreach (FileNameRecord fileNameRecord in fileNameRecords) { FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)fileRecord.CreateAttributeRecord(AttributeType.FileName, String.Empty); fileNameAttribute.IsIndexed = true; fileNameAttribute.Record = fileNameRecord; } UpdateFileRecord(fileRecord); foreach (FileNameRecord fileNameRecord in fileNameRecords) { newParentDirectoryIndex.AddEntry(fileRecord.BaseSegmentReference, fileNameRecord.GetBytes()); } }
public virtual FileRecord GetFileRecord(string path) { if (path != String.Empty && !path.StartsWith(@"\")) { throw new InvalidPathException(String.Format("The path '{0}' is invalid", path)); } if (path.EndsWith(@"\")) { path = path.Substring(0, path.Length - 1); } if (path == String.Empty) { return(GetFileRecord(MasterFileTable.RootDirSegmentReference)); } string[] components = path.Substring(1).Split('\\'); MftSegmentReference directoryReference = MasterFileTable.RootDirSegmentReference; lock (m_mftLock) { for (int index = 0; index < components.Length; index++) { FileRecord directoryRecord = GetFileRecord(directoryReference); if (index < components.Length - 1) { if (!directoryRecord.IsDirectory) { throw new InvalidPathException(String.Format("The path '{0}' is invalid", path)); } IndexData indexData = new IndexData(this, directoryRecord, AttributeType.FileName); directoryReference = indexData.FindFileNameRecordSegmentReference(components[index]); if (directoryReference == null) { throw new DirectoryNotFoundException(String.Format("Could not find part of the path '{0}'", path)); } } else // Last component { IndexData indexData = new IndexData(this, directoryRecord, AttributeType.FileName); MftSegmentReference fileReference = indexData.FindFileNameRecordSegmentReference(components[index]); if (fileReference == null) { throw new FileNotFoundException(String.Format("Could not find file '{0}'", path)); } FileRecord fileRecord = GetFileRecord(fileReference); if (!fileRecord.IsMetaFile) { return(fileRecord); } } } } // We should never get here throw new InvalidPathException(); }
public override bool Equals(object obj) { if (obj is MftSegmentReference) { MftSegmentReference reference = (MftSegmentReference)obj; return((SegmentNumber == reference.SegmentNumber) && (SequenceNumber == reference.SequenceNumber)); } return(false); }
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); } }
public FileNameRecord(MftSegmentReference parentDirectory, string fileName, bool isDirectory, DateTime creationTime) { ParentDirectory = parentDirectory; CreationTime = creationTime; ModificationTime = creationTime; MftModificationTime = creationTime; LastAccessTime = creationTime; IsDirectory = isDirectory; FileName = fileName; }
public FileRecord GetFileRecord(MftSegmentReference fileReference) { FileRecord fileRecord = GetFileRecord(fileReference.SegmentNumber); if (fileRecord.BaseSequenceNumber != fileReference.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 BaseFileRecordSegment"); } return(fileRecord); }
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); }
public virtual FileRecord GetFileRecord(string path) { if (path != String.Empty && !path.StartsWith(@"\")) { throw new ArgumentException("Invalid path"); } if (path.EndsWith(@"\")) { path = path.Substring(0, path.Length - 1); } if (path == String.Empty) { return(GetFileRecord(MasterFileTable.RootDirSegmentReference)); } string[] components = path.Substring(1).Split('\\'); MftSegmentReference directoryReference = MasterFileTable.RootDirSegmentReference; for (int index = 0; index < components.Length; index++) { FileRecord directoryRecord = GetFileRecord(directoryReference); if (index < components.Length - 1) { if (!directoryRecord.IsDirectory) { return(null); } IndexData indexData = new IndexData(this, directoryRecord, AttributeType.FileName); directoryReference = indexData.FindFileNameRecordSegmentReference(components[index]); if (directoryReference == null) { return(null); } } else // Last component { IndexData indexData = new IndexData(this, directoryRecord, AttributeType.FileName); MftSegmentReference fileReference = indexData.FindFileNameRecordSegmentReference(components[index]); if (fileReference == null) { return(null); } FileRecord fileRecord = GetFileRecord(fileReference); if (fileRecord != null && !fileRecord.IsMetaFile) { return(fileRecord); } } } return(null); }
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); }
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 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); }
public FileNameIndexEntry(byte[] buffer, int offset) { FileReference = new MftSegmentReference(buffer, offset + 0x00); RecordLength = LittleEndianConverter.ToUInt16(buffer, offset + 0x08); FileNameOffset = LittleEndianConverter.ToUInt16(buffer, offset + 0x0A); IndexFlags = (IndexEntryFlags)LittleEndianConverter.ToUInt16(buffer, offset + 0x0C); if (RecordLength > 16)// otherwise it's the last record { Record = new FileNameRecord(buffer, offset + 0x10); } }
internal void UpdateDirectoryIndex(MftSegmentReference parentDirectory, List <FileNameRecord> fileNameRecords) { lock (m_mftLock) { FileRecord parentDirectoryRecord = GetFileRecord(parentDirectory); IndexData parentDirectoryIndex = new IndexData(this, parentDirectoryRecord, AttributeType.FileName); foreach (FileNameRecord fileNameRecord in fileNameRecords) { parentDirectoryIndex.UpdateFileNameRecord(fileNameRecord); } } }
public LfsRecord WriteLogRecord(MftSegmentReference fileReference, AttributeRecord attributeRecord, ulong streamOffset, int structureLength, int recordOffset, int attributeOffset, NTFSLogOperation redoOperation, byte[] redoData, NTFSLogOperation undoOperation, byte[] undoData, uint transactionID, bool flushToDisk) { int openAttributeOffset = 0; if (fileReference != null) { int openAttributeIndex = IndexOfOpenAttribute(fileReference, attributeRecord.AttributeType, attributeRecord.Name); if (openAttributeIndex == -1) { openAttributeIndex = AddToOpenAttributeTable(fileReference, attributeRecord.AttributeType, attributeRecord.Name, m_lastClientLsn); m_openAttributes[openAttributeIndex].AssociatedTransactions.Add(transactionID); openAttributeOffset = OpenAttributeIndexToOffset(openAttributeIndex); OpenAttributeEntry entry = new OpenAttributeEntry(m_majorVersion); entry.AllocatedOrNextFree = RestartTableEntry.RestartEntryAllocated; // Note: NTFS v5.1 driver calulates AttributeOffset using entry length of 0x28, the reason is unclear but we're immitating this. entry.AttributeOffset = (uint)(RestartTableHeader.Length + openAttributeIndex * OpenAttributeEntry.LengthV1); entry.FileReference = fileReference; entry.LsnOfOpenRecord = m_lastClientLsn; entry.AttributeTypeCode = attributeRecord.AttributeType; if (attributeRecord.AttributeType == AttributeType.IndexAllocation) { entry.BytesPerIndexBuffer = (uint)Volume.BytesPerIndexRecord; } byte[] openAttributeBytes = entry.GetBytes(); byte[] attributeNameBytes = System.Text.Encoding.Unicode.GetBytes(attributeRecord.Name); LfsRecord openAttributeRecord = WriteLogRecord(openAttributeOffset, 0, 0, 0, new List <long>(), NTFSLogOperation.OpenNonResidentAttribute, openAttributeBytes, NTFSLogOperation.Noop, attributeNameBytes, transactionID, false); } else { openAttributeOffset = OpenAttributeIndexToOffset(openAttributeIndex); if (!m_openAttributes[openAttributeIndex].AssociatedTransactions.Contains(transactionID)) { m_openAttributes[openAttributeIndex].AssociatedTransactions.Add(transactionID); } } } List <long> lcnList = new List <long>(); if (attributeRecord is NonResidentAttributeRecord) { long startVCN = (long)(streamOffset / (uint)Volume.BytesPerCluster); int clusterCount = (int)Math.Ceiling((double)structureLength / Volume.BytesPerCluster); for (long vcn = startVCN; vcn < startVCN + clusterCount; vcn++) { long lcn = ((NonResidentAttributeRecord)attributeRecord).DataRunSequence.GetDataClusterLCN(vcn); lcnList.Add(lcn); } } return(WriteLogRecord(openAttributeOffset, streamOffset, recordOffset, attributeOffset, lcnList, redoOperation, redoData, undoOperation, undoData, transactionID, flushToDisk)); }
private int IndexOfOpenAttribute(MftSegmentReference fileReference, AttributeType attributeType, string attributeName) { for (int index = 0; index < m_openAttributes.Count; index++) { if (m_openAttributes[index].FileReference == fileReference && m_openAttributes[index].AttributeType == attributeType && String.Equals(m_openAttributes[index].AttributeName, attributeName, StringComparison.OrdinalIgnoreCase)) { return(index); } } return(-1); }