public void Extend(ulong additionalLengthInBytes) { ulong currentSize = this.Length; if (m_attributeRecord is NonResidentAttributeRecord) { NonResidentAttributeData attributeData = new NonResidentAttributeData(m_volume, m_fileRecord, (NonResidentAttributeRecord)m_attributeRecord); attributeData.Extend(additionalLengthInBytes); } else { byte[] data = ((ResidentAttributeRecord)m_attributeRecord).Data; ulong finalDataLength = (uint)data.Length + additionalLengthInBytes; ulong finalRecordLength = (uint)m_attributeRecord.RecordLength + additionalLengthInBytes; if (finalRecordLength >= (ulong)m_volume.AttributeRecordLengthToMakeNonResident && m_attributeRecord.AttributeType != AttributeType.AttributeList) // We will create an attribute list with the right attribute form in advance. { // Convert the attribute to non-resident long clustersToAllocate = (long)Math.Ceiling((double)finalDataLength / m_volume.BytesPerCluster); if (clustersToAllocate > m_volume.NumberOfFreeClusters) { throw new DiskFullException(); } NonResidentAttributeRecord attributeRecord = NonResidentAttributeRecord.Create(m_attributeRecord.AttributeType, m_attributeRecord.Name); NonResidentAttributeData attributeData = new NonResidentAttributeData(m_volume, null, attributeRecord); attributeData.Extend(finalDataLength); if (data.Length % m_volume.BytesPerCluster > 0) { int fillDataLength = m_volume.BytesPerCluster - (data.Length % m_volume.BytesPerCluster); if ((uint)data.Length + (uint)fillDataLength < finalDataLength) { // Only the last cluster can be partially used, if this is not the last cluster, zero-fill it data = ByteUtils.Concatenate(data, new byte[fillDataLength]); } } attributeData.WriteClusters(0, data); // Note that we overwrite the old attribute only after writing the non-resident data if (m_fileRecord != null) { m_fileRecord.RemoveAttributeRecord(m_attributeRecord.AttributeType, m_attributeRecord.Name); FileRecordHelper.InsertSorted(m_fileRecord.Attributes, attributeRecord); } m_attributeRecord = attributeRecord; } else { int currentLength = data.Length; byte[] temp = new byte[currentLength + (int)additionalLengthInBytes]; Array.Copy(data, temp, data.Length); ((ResidentAttributeRecord)m_attributeRecord).Data = temp; } if (m_fileRecord != null) { m_volume.UpdateFileRecord(m_fileRecord); } } }
public static AttributeRecord Create(AttributeType type, string name, bool isResident) { if (isResident) { return(ResidentAttributeRecord.Create(type, name)); } else { return(NonResidentAttributeRecord.Create(type, name)); } }
public AttributeRecord CreateAttributeListRecord(bool isResident) { AttributeRecord attribute; if (isResident) { attribute = AttributeRecord.Create(AttributeType.AttributeList, String.Empty, NextAttributeInstance); } else { attribute = NonResidentAttributeRecord.Create(AttributeType.AttributeList, String.Empty, NextAttributeInstance); } NextAttributeInstance++; FileRecordHelper.InsertSorted(m_immediateAttributes, attribute); return(attribute); }
private static NonResidentAttributeRecord AssembleFragments(List <NonResidentAttributeRecord> attributeFragments, ushort nextAttributeInstance) { // Attribute fragments are written to disk sorted by LowestVCN NonResidentAttributeRecord firstFragment = attributeFragments[0]; if (firstFragment.LowestVCN != 0) { string message = String.Format("Attribute fragments must be sorted. Attribute type: {0}", firstFragment.AttributeType); throw new InvalidDataException(message); } NonResidentAttributeRecord attribute = NonResidentAttributeRecord.Create(firstFragment.AttributeType, firstFragment.Name, nextAttributeInstance); attribute.Flags = firstFragment.Flags; attribute.LowestVCN = 0; attribute.HighestVCN = -1; attribute.CompressionUnit = firstFragment.CompressionUnit; attribute.AllocatedLength = firstFragment.AllocatedLength; attribute.FileSize = firstFragment.FileSize; attribute.ValidDataLength = firstFragment.ValidDataLength; foreach (NonResidentAttributeRecord attributeFragment in attributeFragments) { if (attributeFragment.LowestVCN == attribute.HighestVCN + 1) { // The DataRunSequence of each NonResidentDataRecord fragment starts at absolute LCN, // We need to convert it to relative offset before adding it to the base DataRunSequence long runLength = attributeFragment.DataRunSequence[0].RunLength; long absoluteOffset = attributeFragment.DataRunSequence[0].RunOffset; long previousLCN = attribute.DataRunSequence.LastDataRunStartLCN; long relativeOffset = absoluteOffset - previousLCN; int runIndex = attribute.DataRunSequence.Count; attribute.DataRunSequence.AddRange(attributeFragment.DataRunSequence); attribute.DataRunSequence[runIndex] = new DataRun(runLength, relativeOffset); attribute.HighestVCN = attributeFragment.HighestVCN; } else { throw new InvalidDataException("Invalid attribute fragments order"); } } return(attribute); }