/// <summary> /// Used to check/adjust data before we begin to interpret it /// </summary> private unsafe void FixupRawMftdata(byte *buffer, UInt64 len) { FileRecordHeader *ntfsFileRecordHeader = (FileRecordHeader *)buffer; if (ntfsFileRecordHeader->RecordHeader.Type != RecordType.File) { return; } UInt16 *wordBuffer = (UInt16 *)buffer; UInt16 *UpdateSequenceArray = (UInt16 *)(buffer + ntfsFileRecordHeader->RecordHeader.UsaOffset); UInt32 increment = (UInt32)_diskInfo.BytesPerSector / sizeof(UInt16); UInt32 Index = increment - 1; for (int i = 1; i < ntfsFileRecordHeader->RecordHeader.UsaCount; i++) { /* Check if we are inside the buffer. */ if (Index * sizeof(UInt16) >= len) { throw new Exception("USA data indicates that data is missing, the MFT may be corrupt."); } // Check if the last 2 bytes of the sector contain the Update Sequence Number. if (wordBuffer[Index] != UpdateSequenceArray[0]) { throw new Exception("USA fixup word is not equal to the Update Sequence Number, the MFT may be corrupt."); } /* Replace the last 2 bytes in the sector with the value from the Usa array. */ wordBuffer[Index] = UpdateSequenceArray[i]; Index = Index + increment; } }
/// <summary> /// Process an actual MFT record from the buffer /// </summary> private unsafe bool ProcessMftRecord(byte *buffer, UInt64 length, UInt32 nodeIndex, out Node node, List <Stream> streams, bool isMftNode) { node = new Node(); FileRecordHeader *ntfsFileRecordHeader = (FileRecordHeader *)buffer; node.MFTRecordNumber = ntfsFileRecordHeader->MFTRecordNumber; node.SequenceNumber = ntfsFileRecordHeader->BaseFileRecord.SequenceNumber; if (ntfsFileRecordHeader->RecordHeader.Type != RecordType.File) { return(false); } //the inode is not in use if ((ntfsFileRecordHeader->Flags & 1) != 1) { return(false); } UInt64 baseInode = ((UInt64)ntfsFileRecordHeader->BaseFileRecord.InodeNumberHighPart << 32) + ntfsFileRecordHeader->BaseFileRecord.InodeNumberLowPart; //This is an inode extension used in an AttributeAttributeList of another inode, don't parse it if (baseInode != 0) { return(false); } if (ntfsFileRecordHeader->AttributeOffset >= length) { throw new Exception("Error: attributes in Inode %I64u are outside the FILE record, the MFT may be corrupt."); } if (ntfsFileRecordHeader->BytesInUse > length) { throw new Exception("Error: in Inode %I64u the record is bigger than the size of the buffer, the MFT may be corrupt."); } //make the file appear in the rootdirectory by default node.ParentNodeIndex = ROOTDIRECTORY; if ((ntfsFileRecordHeader->Flags & 2) == 2) { node.Attributes |= Attributes.Directory; } ProcessAttributes(ref node, nodeIndex, buffer + ntfsFileRecordHeader->AttributeOffset, length - ntfsFileRecordHeader->AttributeOffset, 65535, 0, streams, isMftNode); return(true); }