Beispiel #1
0
        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);
            }
        }
Beispiel #2
0
        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;
        }
Beispiel #4
0
        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);
            }
        }
Beispiel #5
0
 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);
 }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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));
        }
Beispiel #11
0
        public List <TransactionEntry> ReadCurrentTransactionTable()
        {
            NTFSRestartRecord restartRecord = ReadCurrentRestartRecord();

            return(ReadTransactionTable(restartRecord));
        }
Beispiel #12
0
        public List <DirtyPageEntry> ReadCurrentDirtyPageTable()
        {
            NTFSRestartRecord restartRecord = ReadCurrentRestartRecord();

            return(ReadDirtyPageTable(restartRecord));
        }
Beispiel #13
0
        public List <OpenAttributeEntry> ReadCurrentOpenAttributeTable()
        {
            NTFSRestartRecord restartRecord = ReadCurrentRestartRecord();

            return(ReadOpenAttributeTable(restartRecord));
        }
Beispiel #14
0
        public List <AttributeNameEntry> ReadCurrentAttributeNamesTable()
        {
            NTFSRestartRecord restartRecord = ReadCurrentRestartRecord();

            return(ReadAttributeNamesTable(restartRecord));
        }