private byte[] GetOpenAttributeTableBytes(out byte[] attributeNameTableBytes) { List <OpenAttributeEntry> openAttributeTable = new List <OpenAttributeEntry>(); List <AttributeNameEntry> attributeNameTable = new List <AttributeNameEntry>(); for (int index = 0; index < m_openAttributes.Count; index++) { OpenAttribute openAttribute = m_openAttributes[index]; OpenAttributeEntry entry = new OpenAttributeEntry(m_majorVersion); entry.AllocatedOrNextFree = RestartTableEntry.RestartEntryAllocated; // Note: NTFS v5.1 driver calulates AttributeOffset using entry length of 0x28, the reason is unclear but we're immitating this. entry.AttributeOffset = (uint)(RestartTableHeader.Length + index * OpenAttributeEntry.LengthV1); entry.FileReference = openAttribute.FileReference; entry.LsnOfOpenRecord = openAttribute.LsnOfOpenRecord; entry.AttributeTypeCode = openAttribute.AttributeType; openAttributeTable.Add(entry); if (openAttribute.AttributeName != String.Empty) { int openAttributeOffset = OpenAttributeIndexToOffset(index); AttributeNameEntry nameEntry = new AttributeNameEntry(); nameEntry.OpenAttributeOffset = (ushort)openAttributeOffset; nameEntry.Name = openAttribute.AttributeName; attributeNameTable.Add(nameEntry); } } attributeNameTableBytes = null; if (attributeNameTable.Count > 0) { attributeNameTableBytes = AttributeNameEntry.GetTableBytes(attributeNameTable); } return(RestartTableHelper.GetTableBytes <OpenAttributeEntry>(openAttributeTable)); }
public LfsRecord WriteLogRecord(MftSegmentReference fileReference, AttributeRecord attributeRecord, ulong streamOffset, int structureLength, int recordOffset, int attributeOffset, NTFSLogOperation redoOperation, byte[] redoData, NTFSLogOperation undoOperation, byte[] undoData, uint transactionID, bool flushToDisk) { int openAttributeOffset = 0; if (fileReference != null) { int openAttributeIndex = IndexOfOpenAttribute(fileReference, attributeRecord.AttributeType, attributeRecord.Name); if (openAttributeIndex == -1) { openAttributeIndex = AddToOpenAttributeTable(fileReference, attributeRecord.AttributeType, attributeRecord.Name, m_lastClientLsn); m_openAttributes[openAttributeIndex].AssociatedTransactions.Add(transactionID); openAttributeOffset = OpenAttributeIndexToOffset(openAttributeIndex); OpenAttributeEntry entry = new OpenAttributeEntry(m_majorVersion); entry.AllocatedOrNextFree = RestartTableEntry.RestartEntryAllocated; // Note: NTFS v5.1 driver calulates AttributeOffset using entry length of 0x28, the reason is unclear but we're immitating this. entry.AttributeOffset = (uint)(RestartTableHeader.Length + openAttributeIndex * OpenAttributeEntry.LengthV1); entry.FileReference = fileReference; entry.LsnOfOpenRecord = m_lastClientLsn; entry.AttributeTypeCode = attributeRecord.AttributeType; if (attributeRecord.AttributeType == AttributeType.IndexAllocation) { entry.BytesPerIndexBuffer = (uint)Volume.BytesPerIndexRecord; } byte[] openAttributeBytes = entry.GetBytes(); byte[] attributeNameBytes = System.Text.Encoding.Unicode.GetBytes(attributeRecord.Name); LfsRecord openAttributeRecord = WriteLogRecord(openAttributeOffset, 0, 0, 0, new List <long>(), NTFSLogOperation.OpenNonResidentAttribute, openAttributeBytes, NTFSLogOperation.Noop, attributeNameBytes, transactionID, false); } else { openAttributeOffset = OpenAttributeIndexToOffset(openAttributeIndex); if (!m_openAttributes[openAttributeIndex].AssociatedTransactions.Contains(transactionID)) { m_openAttributes[openAttributeIndex].AssociatedTransactions.Add(transactionID); } } } List <long> lcnList = new List <long>(); if (attributeRecord is NonResidentAttributeRecord) { long startVCN = (long)(streamOffset / (uint)Volume.BytesPerCluster); int clusterCount = (int)Math.Ceiling((double)structureLength / Volume.BytesPerCluster); for (long vcn = startVCN; vcn < startVCN + clusterCount; vcn++) { long lcn = ((NonResidentAttributeRecord)attributeRecord).DataRunSequence.GetDataClusterLCN(vcn); lcnList.Add(lcn); } } return(WriteLogRecord(openAttributeOffset, streamOffset, recordOffset, attributeOffset, lcnList, redoOperation, redoData, undoOperation, undoData, transactionID, flushToDisk)); }