public LfsRestartArea(byte[] buffer, int offset) { CurrentLsn = LittleEndianConverter.ToUInt64(buffer, offset + 0x00); ushort logClients = LittleEndianConverter.ToUInt16(buffer, offset + 0x08); ClientFreeList = LittleEndianConverter.ToUInt16(buffer, offset + 0x0A); ClientInUseList = LittleEndianConverter.ToUInt16(buffer, offset + 0x0C); Flags = (LfsRestartFlags)LittleEndianConverter.ToUInt16(buffer, offset + 0x0E); SeqNumberBits = LittleEndianConverter.ToUInt32(buffer, offset + 0x10); RestartAreaLength = LittleEndianConverter.ToUInt16(buffer, offset + 0x14); ushort clientArrayOffset = LittleEndianConverter.ToUInt16(buffer, offset + 0x16); FileSize = LittleEndianConverter.ToUInt32(buffer, offset + 0x18); LastLsnDataLength = LittleEndianConverter.ToUInt32(buffer, offset + 0x20); RecordHeaderLength = LittleEndianConverter.ToUInt16(buffer, offset + 0x24); LogPageDataOffset = LittleEndianConverter.ToUInt16(buffer, offset + 0x26); if (clientArrayOffset >= 0x30) { RevisionNumber = LittleEndianConverter.ToUInt32(buffer, offset + 0x28); } int position = offset + clientArrayOffset; for (int index = 0; index < logClients; index++) { LfsClientRecord clientRecord = new LfsClientRecord(buffer, position); LogClientArray.Add(clientRecord); position += clientRecord.Length; } }
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); }
private LfsRecord WriteLogRecord(NTFSLogRecord ntfsLogRecord, uint transactionID, bool flushToDisk) { LfsClientRecord clientRecord = m_logFile.GetClientRecord(m_clientIndex); byte[] clientData = ntfsLogRecord.GetBytes(); int transactionIndex = IndexOfTransaction(transactionID); ulong lastLsnToUndo = m_transactions[transactionIndex].LastLsnToUndo; LfsRecord result = m_logFile.WriteRecord(m_clientIndex, LfsRecordType.ClientRecord, m_lastClientLsn, lastLsnToUndo, transactionID, clientData, flushToDisk); m_lastClientLsn = result.ThisLsn; m_transactions[transactionIndex].LastLsnToUndo = result.ThisLsn; if (m_transactions[transactionIndex].OldestLsn == 0) { m_transactions[transactionIndex].OldestLsn = result.ThisLsn; } return(result); }
private static void WriteLogFile(Volume volume, long logFileStartSector, long logFileSize, int bytesPerLogPage) { const int BytesPerSystemPage = 4096; LfsClientRecord ntfsClientRecord = new LfsClientRecord(NTFSLogClient.ClientName); LfsRestartPage restartPage = LfsRestartPage.Create(logFileSize, BytesPerSystemPage, bytesPerLogPage, ntfsClientRecord); long secondRestartPageStartSector = logFileStartSector + BytesPerSystemPage / volume.BytesPerSector; long firstRecordPageStartSector = logFileStartSector + 2 * BytesPerSystemPage / volume.BytesPerSector; byte[] restartPageBytes = restartPage.GetBytes(BytesPerSystemPage, true); volume.WriteSectors(logFileStartSector, restartPageBytes); volume.WriteSectors(secondRestartPageStartSector, restartPageBytes); byte[] recordPagesBytes = new byte[logFileSize - 2 * BytesPerSystemPage]; for (int index = 0; index < recordPagesBytes.Length; index += 4) { LittleEndianWriter.WriteUInt32(recordPagesBytes, index, LfsRecordPage.UninitializedPageSignature); } volume.WriteSectors(firstRecordPageStartSector, recordPagesBytes); }