public List <TransactionEntry> ReadTransactionTable(NTFSRestartRecord restartRecord) { ulong transactionTableLsn = restartRecord.TransactionTableLsn; if (transactionTableLsn != 0) { NTFSLogRecord record = ReadLogRecord(transactionTableLsn); if (record.RedoOperation != NTFSLogOperation.TransactionTableDump) { string message = String.Format("Restart record TransactionTableLsn points to a record with RedoOperation {0}", record.RedoOperation); throw new InvalidDataException(message); } if (restartRecord.TransactionTableLength != record.RedoData.Length) { throw new InvalidDataException("Transcation table length does not match restart record"); } return(RestartTableHelper.ReadTable <TransactionEntry>(record.RedoData, restartRecord.MajorVersion)); } else { return(null); } }
private LfsRecord WriteRestartRecord(ulong usnJournalUnknown1, ulong previousRestartRecordLsn, MftSegmentReference usnJournal, ulong usnJournalUnknown2, bool isClean) { NTFSRestartRecord restartRecord = new NTFSRestartRecord(m_majorVersion, m_minorVersion); restartRecord.StartOfCheckpointLsn = m_lastClientLsn; restartRecord.UsnJournalUnknown1 = usnJournalUnknown1; restartRecord.PreviousRestartRecordLsn = previousRestartRecordLsn; restartRecord.BytesPerCluster = (uint)Volume.BytesPerCluster; restartRecord.UsnJournal = usnJournal; restartRecord.UsnJournalUnknown2 = usnJournalUnknown2; if (isClean) { if (m_transactions.Count > 0) { throw new InvalidOperationException("All TransactionIDs must be deallocated before writing a clean restart record"); } } else { foreach (Transaction transaction in m_transactions) { if (transaction.OldestLsn != 0 && transaction.OldestLsn < restartRecord.StartOfCheckpointLsn) { restartRecord.StartOfCheckpointLsn = transaction.OldestLsn; } } 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, 0, 0, 0, NTFSLogOperation.OpenAttributeTableDump, openAttributeTableBytes, NTFSLogOperation.Noop, new byte[0], transactionID, false); restartRecord.OpenAttributeTableLsn = openAttributeTableRecord.ThisLsn; restartRecord.OpenAttributeTableLength = (uint)openAttributeTableBytes.Length; if (attributeNameTableBytes != null) { LfsRecord attributeNameTableRecord = WriteLogRecord(null, null, 0, 0, 0, 0, NTFSLogOperation.AttributeNamesDump, attributeNameTableBytes, NTFSLogOperation.Noop, new byte[0], transactionID, false); restartRecord.AttributeNamesLsn = attributeNameTableRecord.ThisLsn; restartRecord.AttributeNamesLength = (uint)attributeNameTableBytes.Length; } DeallocateTransactionID(transactionID); } } byte[] clientData = restartRecord.GetBytes(Volume.MajorVersion); LfsRecord result = m_logFile.WriteRecord(m_clientIndex, LfsRecordType.ClientRestart, 0, 0, 0, clientData, true); m_lastClientLsn = result.ThisLsn; LfsClientRecord clientRecord = m_logFile.GetClientRecord(m_clientIndex); clientRecord.OldestLsn = restartRecord.StartOfCheckpointLsn; clientRecord.ClientRestartLsn = result.ThisLsn; // Note that writing a client restart record without also updating ClientRestartLsn has no effect. // During the analysis pass, the NTFS v5.1 driver will use ClientRestartLsn in the most recent restart page to determine // the StartOfCheckpointLsn that the scan should start from, any client restart record that is found during the scan will be ignored. m_logFile.WriteRestartPage(isClean); m_currentRestartRecord = restartRecord; return(result); }
public NTFSLogClient(LogFile logFile) { m_logFile = logFile; m_clientIndex = m_logFile.FindClientIndex(ClientName); if (m_clientIndex == -1) { throw new InvalidDataException("NTFS Client was not found"); } bool isClientInUse = m_logFile.IsClientInUse(m_clientIndex); if (!isClientInUse) { throw new NotSupportedException("NTFS Client is not in use"); } ulong lastClientRestartLsn = m_logFile.GetClientRecord(m_clientIndex).ClientRestartLsn; m_lastClientLsn = lastClientRestartLsn; if (lastClientRestartLsn == 0) // Freshly formatted disk { m_currentRestartRecord = new NTFSRestartRecord(1, 0); if (!Volume.IsReadOnly) { // An initial restart record must be present for any subsequent log operations to be found during analysis and redone / undone WriteRestartRecord(true); } } else { m_currentRestartRecord = ReadRestartRecord(lastClientRestartLsn); } m_majorVersion = m_currentRestartRecord.MajorVersion; m_minorVersion = m_currentRestartRecord.MinorVersion; }
public List <AttributeNameEntry> ReadAttributeNamesTable(NTFSRestartRecord restartRecord) { ulong attributeNamesLsn = restartRecord.AttributeNamesLsn; if (attributeNamesLsn != 0) { NTFSLogRecord record = ReadLogRecord(attributeNamesLsn); if (record.RedoOperation != NTFSLogOperation.AttributeNamesDump) { string message = String.Format("Restart record AttributeNamesLsn points to a record with RedoOperation {0}", record.RedoOperation); throw new InvalidDataException(message); } if (restartRecord.AttributeNamesLength != record.RedoData.Length) { throw new InvalidDataException("Open attribute table length does not match restart record"); } return(AttributeNameEntry.ReadTable(record.RedoData)); } else { return(null); } }
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); }
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 NTFSLogClient(LogFile logFile) { m_logFile = logFile; m_clientIndex = m_logFile.FindClientIndex(ClientName); if (m_clientIndex == -1) { throw new InvalidDataException("NTFS Client was not found"); } ulong lastClientRestartLsn = m_logFile.GetClientRecord(m_clientIndex).ClientRestartLsn; m_lastClientLsn = lastClientRestartLsn; NTFSRestartRecord currentRestartRecord = ReadRestartRecord(lastClientRestartLsn); m_majorVersion = currentRestartRecord.MajorVersion; m_minorVersion = currentRestartRecord.MinorVersion; }
public List <NTFSLogRecord> FindRecordsToRedo() { NTFSRestartRecord restartRecord = ReadCurrentRestartRecord(); List <DirtyPageEntry> dirtyPageTable = ReadDirtyPageTable(restartRecord); ulong redoLsn = FindRedoLsn(dirtyPageTable); LfsRecord firstRecord = m_logFile.ReadRecord(redoLsn); List <LfsRecord> records = m_logFile.FindNextRecords(redoLsn, m_clientIndex); records.Insert(0, firstRecord); List <NTFSLogRecord> result = new List <NTFSLogRecord>(); foreach (LfsRecord record in records) { if (record.RecordType == LfsRecordType.ClientRecord) { NTFSLogRecord clientRecord = new NTFSLogRecord(record.Data); switch (clientRecord.RedoOperation) { case NTFSLogOperation.Noop: case NTFSLogOperation.OpenAttributeTableDump: case NTFSLogOperation.AttributeNamesDump: case NTFSLogOperation.DirtyPageTableDump: case NTFSLogOperation.TransactionTableDump: { continue; } default: { result.Add(clientRecord); break; } } } } return(result); }
public List <LfsRecord> FindRecordsFollowingCheckpoint(NTFSRestartRecord restartRecord) { return(m_logFile.FindNextRecords(restartRecord.StartOfCheckpointLsn, m_clientIndex)); }
public List <LfsRecord> FindRecordsFollowingCurrentCheckpoint() { NTFSRestartRecord restartRecord = ReadCurrentRestartRecord(); return(FindRecordsFollowingCheckpoint(restartRecord)); }
public List <TransactionEntry> ReadCurrentTransactionTable() { NTFSRestartRecord restartRecord = ReadCurrentRestartRecord(); return(ReadTransactionTable(restartRecord)); }
public List <DirtyPageEntry> ReadCurrentDirtyPageTable() { NTFSRestartRecord restartRecord = ReadCurrentRestartRecord(); return(ReadDirtyPageTable(restartRecord)); }
public List <OpenAttributeEntry> ReadCurrentOpenAttributeTable() { NTFSRestartRecord restartRecord = ReadCurrentRestartRecord(); return(ReadOpenAttributeTable(restartRecord)); }
public List <AttributeNameEntry> ReadCurrentAttributeNamesTable() { NTFSRestartRecord restartRecord = ReadCurrentRestartRecord(); return(ReadAttributeNamesTable(restartRecord)); }