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