Пример #1
0
        public File(INtfsContext context, FileRecord baseRecord)
        {
            _context = context;
            _mft = _context.Mft;
            _records = new List<FileRecord>();
            _records.Add(baseRecord);
            _indexCache = new ObjectCache<string, Index>();
            _attributes = new List<NtfsAttribute>();

            LoadAttributes();
        }
Пример #2
0
        public File InitializeNew(INtfsContext context, long firstBitmapCluster, ulong numBitmapClusters, long firstRecordsCluster, ulong numRecordsClusters)
        {
            BiosParameterBlock bpb = context.BiosParameterBlock;

            FileRecord fileRec = new FileRecord(bpb.BytesPerSector, bpb.MftRecordSize, (uint)MftIndex);
            fileRec.Flags = FileRecordFlags.InUse;
            fileRec.SequenceNumber = 1;
            _recordCache[MftIndex] = fileRec;

            _self = new File(context, fileRec);

            StandardInformation.InitializeNewFile(_self, FileAttributeFlags.Hidden | FileAttributeFlags.System);

            NtfsStream recordsStream = _self.CreateStream(AttributeType.Data, null, firstRecordsCluster, numRecordsClusters, (uint)bpb.BytesPerCluster);
            _recordStream = recordsStream.Open(FileAccess.ReadWrite);
            Wipe(_recordStream);

            NtfsStream bitmapStream = _self.CreateStream(AttributeType.Bitmap, null, firstBitmapCluster, numBitmapClusters, (uint)bpb.BytesPerCluster);
            using (Stream s = bitmapStream.Open(FileAccess.ReadWrite))
            {
                Wipe(s);
                s.SetLength(8);
                _bitmap = new Bitmap(s, long.MaxValue);
            }

            _recordLength = context.BiosParameterBlock.MftRecordSize;
            _bytesPerSector = context.BiosParameterBlock.BytesPerSector;

            _bitmap.MarkPresentRange(0, 1);

            // Write the MFT's own record to itself
            byte[] buffer = new byte[_recordLength];
            fileRec.ToBytes(buffer, 0);
            _recordStream.Position = 0;
            _recordStream.Write(buffer, 0, _recordLength);
            _recordStream.Flush();

            return _self;
        }
Пример #3
0
        public FileRecord GetRecord(long index, bool ignoreMagic, bool ignoreBitmap)
        {
            if (ignoreBitmap || _bitmap == null || _bitmap.IsPresent(index))
            {
                FileRecord result = _recordCache[index];
                if (result != null)
                {
                    return result;
                }

                if ((index + 1) * _recordLength <= _recordStream.Length)
                {
                    _recordStream.Position = index * _recordLength;
                    byte[] recordBuffer = Utilities.ReadFully(_recordStream, _recordLength);

                    result = new FileRecord(_bytesPerSector);
                    result.FromBytes(recordBuffer, 0, ignoreMagic);
                    result.LoadedIndex = (uint)index;
                }
                else
                {
                    result = new FileRecord(_bytesPerSector, _recordLength, (uint)index);
                }

                _recordCache[index] = result;
                return result;
            }

            return null;
        }
Пример #4
0
 public FileRecord GetBootstrapRecord()
 {
     _recordStream.Position = 0;
     byte[] mftSelfRecordData = Utilities.ReadFully(_recordStream, _recordLength);
     FileRecord mftSelfRecord = new FileRecord(_bytesPerSector);
     mftSelfRecord.FromBytes(mftSelfRecordData, 0);
     _recordCache[MftIndex] = mftSelfRecord;
     return mftSelfRecord;
 }
Пример #5
0
        public FileRecord AllocateRecord(long index, FileRecordFlags flags)
        {
            _bitmap.MarkPresent(index);

            FileRecord newRecord = new FileRecord(_bytesPerSector, _recordLength, (uint)index);
            _recordCache[index] = newRecord;
            newRecord.Flags = FileRecordFlags.InUse | flags;

            WriteRecord(newRecord);
            _self.UpdateRecordInMft();
            return newRecord;
        }
Пример #6
0
        private bool ExpelAttribute(FileRecord record)
        {
            List<AttributeRecord> attrs = record.Attributes;
            for(int i = attrs.Count - 1; i >= 0; --i)
            {
                AttributeRecord attr = attrs[i];
                if (attr.AttributeType > AttributeType.AttributeList)
                {
                    foreach (var targetRecord in _records)
                    {
                        if (_mft.RecordSize - targetRecord.Size >= attr.Size)
                        {
                            MoveAttribute(record, attr, targetRecord);
                            return true;
                        }
                    }

                    FileRecord newFileRecord = _mft.AllocateRecord(FileRecordFlags.None);
                    newFileRecord.BaseFile = record.Reference;
                    _records.Add(newFileRecord);
                    MoveAttribute(record, attr, newFileRecord);
                    return true;
                }
            }

            return false;
        }
Пример #7
0
        private bool ExpelAttribute(FileRecord record)
        {
            if (record.MasterFileTableIndex == MasterFileTable.MftIndex)
            {
                // Special case for MFT - can't fully expel attributes, instead split most of the data runs off.
                List<AttributeRecord> attrs = record.Attributes;
                for (int i = attrs.Count - 1; i >= 0; --i)
                {
                    AttributeRecord attr = attrs[i];
                    if (attr.AttributeType == AttributeType.Data)
                    {
                        if (SplitAttribute(record, (NonResidentAttributeRecord)attr, true))
                        {
                            return true;
                        }
                    }
                }
            }
            else
            {
                List<AttributeRecord> attrs = record.Attributes;
                for (int i = attrs.Count - 1; i >= 0; --i)
                {
                    AttributeRecord attr = attrs[i];
                    if (attr.AttributeType > AttributeType.AttributeList)
                    {
                        foreach (var targetRecord in _records)
                        {
                            if (_mft.RecordSize - targetRecord.Size >= attr.Size)
                            {
                                MoveAttribute(record, attr, targetRecord);
                                return true;
                            }
                        }

                        FileRecord newFileRecord = _mft.AllocateRecord(FileRecordFlags.None, record.IsMftRecord);
                        newFileRecord.BaseFile = record.Reference;
                        _records.Add(newFileRecord);
                        MoveAttribute(record, attr, newFileRecord);
                        return true;
                    }
                }
            }

            return false;
        }
Пример #8
0
        private bool SplitAttribute(FileRecord record)
        {
            if (record.Attributes.Count != 1)
            {
                throw new InvalidOperationException("Attempting to split attribute in MFT record containing multiple attributes");
            }

            return SplitAttribute(record, (NonResidentAttributeRecord)record.FirstAttribute, false);
        }
        private bool VerifyMftRecord(byte[] recordData, bool presentInBitmap, int bytesPerSector)
        {
            bool ok = true;

            //
            // Verify the attributes seem OK...
            //
            byte[] tempBuffer = new byte[recordData.Length];
            Array.Copy(recordData, tempBuffer, tempBuffer.Length);
            GenericFixupRecord genericRecord = new GenericFixupRecord(bytesPerSector);

            genericRecord.FromBytes(tempBuffer, 0);

            int pos = Utilities.ToUInt16LittleEndian(genericRecord.Content, 0x14);

            while (Utilities.ToUInt32LittleEndian(genericRecord.Content, pos) != 0xFFFFFFFF)
            {
                int attrLen;
                try
                {
                    AttributeRecord ar = AttributeRecord.FromBytes(genericRecord.Content, pos, out attrLen);
                    if (attrLen != ar.Size)
                    {
                        ReportError("Attribute size is different to calculated size.  AttrId={0}", ar.AttributeId);
                        ok = false;
                    }

                    if (ar.IsNonResident)
                    {
                        NonResidentAttributeRecord nrr = (NonResidentAttributeRecord)ar;
                        if (nrr.DataRuns.Count > 0)
                        {
                            long totalVcn = 0;
                            foreach (var run in nrr.DataRuns)
                            {
                                totalVcn += run.RunLength;
                            }

                            if (totalVcn != nrr.LastVcn - nrr.StartVcn + 1)
                            {
                                ReportError("Declared VCNs doesn't match data runs.  AttrId={0}", ar.AttributeId);
                                ok = false;
                            }
                        }
                    }
                }
                catch
                {
                    ReportError("Failure parsing attribute at pos={0}", pos);
                    return(false);
                }

                pos += attrLen;
            }

            //
            // Now consider record as a whole
            //
            FileRecord record = new FileRecord(bytesPerSector);

            record.FromBytes(recordData, 0);

            bool inUse = (record.Flags & FileRecordFlags.InUse) != 0;

            if (inUse != presentInBitmap)
            {
                ReportError("MFT bitmap and record in-use flag don't agree.  Mft={0}, Record={1}", presentInBitmap ? "InUse" : "Free", inUse ? "InUse" : "Free");
                ok = false;
            }

            if (record.Size != record.RealSize)
            {
                ReportError("MFT record real size is different to calculated size.  Stored in MFT={0}, Calculated={1}", record.RealSize, record.Size);
                ok = false;
            }

            if (Utilities.ToUInt32LittleEndian(recordData, (int)record.RealSize - 8) != uint.MaxValue)
            {
                ReportError("MFT record is not correctly terminated with 0xFFFFFFFF");
                ok = false;
            }

            return(ok);
        }
Пример #10
0
 public Directory(INtfsContext context, FileRecord baseRecord)
     : base(context, baseRecord)
 {
 }
Пример #11
0
        private bool SplitAttribute(FileRecord record, NonResidentAttributeRecord targetAttr, bool atStart)
        {
            if (targetAttr.DataRuns.Count <= 1)
            {
                return(false);
            }

            int splitIndex = 1;

            if (!atStart)
            {
                List <DataRun> runs = targetAttr.DataRuns;

                splitIndex = runs.Count - 1;
                int saved = runs[splitIndex].Size;
                while (splitIndex > 1 && record.Size - saved > record.AllocatedSize)
                {
                    --splitIndex;
                    saved += runs[splitIndex].Size;
                }
            }

            AttributeRecord newAttr = targetAttr.Split(splitIndex);

            // Find a home for the new attribute record
            FileRecord newAttrHome = null;

            foreach (var targetRecord in _records)
            {
                if (!targetRecord.IsMftRecord && _mft.RecordSize - targetRecord.Size >= newAttr.Size)
                {
                    targetRecord.AddAttribute(newAttr);
                    newAttrHome = targetRecord;
                }
            }

            if (newAttrHome == null)
            {
                newAttrHome          = _mft.AllocateRecord(_records[0].Flags & (~FileRecordFlags.InUse), record.IsMftRecord);
                newAttrHome.BaseFile = record.BaseFile.IsNull ? record.Reference : record.BaseFile;
                _records.Add(newAttrHome);
                newAttrHome.AddAttribute(newAttr);
            }

            // Add the new attribute record as an extent on the attribute it split from
            bool added = false;

            foreach (var attr in _attributes)
            {
                foreach (var existingRecord in attr.Extents)
                {
                    if (existingRecord.Key.File == record.Reference && existingRecord.Key.AttributeId == targetAttr.AttributeId)
                    {
                        attr.AddExtent(newAttrHome.Reference, newAttr);
                        added = true;
                        break;
                    }
                }

                if (added)
                {
                    break;
                }
            }

            UpdateAttributeList();

            return(true);
        }
Пример #12
0
        private void LoadAttributes()
        {
            Dictionary <long, FileRecord> extraFileRecords = new Dictionary <long, FileRecord>();

            AttributeRecord attrListRec = _records[0].GetAttribute(AttributeType.AttributeList);

            if (attrListRec != null)
            {
                NtfsAttribute lastAttr = null;

                StructuredNtfsAttribute <AttributeList> attrListAttr = (StructuredNtfsAttribute <AttributeList>)NtfsAttribute.FromRecord(this, MftReference, attrListRec);
                var attrList = attrListAttr.Content;
                _attributes.Add(attrListAttr);

                foreach (var record in attrList)
                {
                    FileRecord attrFileRecord = _records[0];
                    if (record.BaseFileReference.MftIndex != _records[0].MasterFileTableIndex)
                    {
                        if (!extraFileRecords.TryGetValue(record.BaseFileReference.MftIndex, out attrFileRecord))
                        {
                            attrFileRecord = _context.Mft.GetRecord(record.BaseFileReference);
                            if (attrFileRecord != null)
                            {
                                extraFileRecords[attrFileRecord.MasterFileTableIndex] = attrFileRecord;
                            }
                        }
                    }

                    if (attrFileRecord != null)
                    {
                        AttributeRecord attrRec = attrFileRecord.GetAttribute(record.AttributeId);

                        if (attrRec != null)
                        {
                            if (record.StartVcn == 0)
                            {
                                lastAttr = NtfsAttribute.FromRecord(this, record.BaseFileReference, attrRec);
                                _attributes.Add(lastAttr);
                            }
                            else
                            {
                                lastAttr.AddExtent(record.BaseFileReference, attrRec);
                            }
                        }
                    }
                }

                foreach (var extraFileRecord in extraFileRecords)
                {
                    _records.Add(extraFileRecord.Value);
                }
            }
            else
            {
                foreach (var record in _records[0].Attributes)
                {
                    _attributes.Add(NtfsAttribute.FromRecord(this, MftReference, record));
                }
            }
        }
Пример #13
0
        public void UpdateRecordInMft()
        {
            if (MftRecordIsDirty)
            {
                if (NtfsTransaction.Current != null)
                {
                    NtfsStream          stream = GetStream(AttributeType.StandardInformation, null);
                    StandardInformation si     = stream.GetContent <StandardInformation>();
                    si.MftChangedTime = NtfsTransaction.Current.Timestamp;
                    stream.SetContent(si);
                }

                bool fixesApplied = true;
                while (fixesApplied)
                {
                    fixesApplied = false;

                    for (int i = 0; i < _records.Count; ++i)
                    {
                        FileRecord record = _records[i];

                        bool fixedAttribute = true;
                        while (record.Size > _mft.RecordSize && fixedAttribute)
                        {
                            fixedAttribute = false;

                            if (!fixedAttribute && !record.IsMftRecord)
                            {
                                foreach (AttributeRecord attr in record.Attributes)
                                {
                                    if (!attr.IsNonResident &&
                                        !_context.AttributeDefinitions.MustBeResident(attr.AttributeType))
                                    {
                                        MakeAttributeNonResident(
                                            new AttributeReference(record.Reference, attr.AttributeId),
                                            (int)attr.DataLength);
                                        fixedAttribute = true;
                                        break;
                                    }
                                }
                            }

                            if (!fixedAttribute)
                            {
                                foreach (AttributeRecord attr in record.Attributes)
                                {
                                    if (attr.AttributeType == AttributeType.IndexRoot &&
                                        ShrinkIndexRoot(attr.Name))
                                    {
                                        fixedAttribute = true;
                                        break;
                                    }
                                }
                            }

                            if (!fixedAttribute)
                            {
                                if (record.Attributes.Count == 1)
                                {
                                    fixedAttribute = SplitAttribute(record);
                                }
                                else
                                {
                                    if (_records.Count == 1)
                                    {
                                        CreateAttributeList();
                                    }

                                    fixedAttribute = ExpelAttribute(record);
                                }
                            }

                            fixesApplied |= fixedAttribute;
                        }
                    }
                }

                MftRecordIsDirty = false;
                foreach (FileRecord record in _records)
                {
                    _mft.WriteRecord(record);
                }
            }
        }
Пример #14
0
        internal static File CreateNew(INtfsContext context, FileRecordFlags flags)
        {
            DateTime now = DateTime.UtcNow;

            File newFile = context.AllocateFile(flags);

            StandardInformation.InitializeNewFile(newFile, FileAttributeFlags.Archive | FileRecord.ConvertFlags(flags));

            if (context.ObjectIds != null)
            {
                Guid       newId  = CreateNewGuid(context);
                NtfsStream stream = newFile.CreateStream(AttributeType.ObjectId, null);
                ObjectId   objId  = new ObjectId();
                objId.Id = newId;
                stream.SetContent(objId);
                context.ObjectIds.Add(newId, newFile.MftReference, newId, Guid.Empty, Guid.Empty);
            }

            newFile.CreateAttribute(AttributeType.Data, AttributeFlags.None);

            newFile.UpdateRecordInMft();

            return(newFile);
        }
Пример #15
0
        public FileRecord AllocateRecord(FileRecordFlags flags)
        {
            long index = _bitmap.AllocateFirstAvailable(FirstAvailableMftIndex);

            if (index * _recordLength >= _recordStream.Length)
            {
                // Note: 64 is significant, since bitmap extends by 8 bytes (=64 bits) at a time.
                long newEndIndex = Utilities.RoundUp(index + 1, 64);
                for (long i = index; i < newEndIndex; ++i)
                {
                    FileRecord record = new FileRecord(_bytesPerSector, _recordLength, (uint)i);
                    WriteRecord(record);
                }
            }

            FileRecord newRecord = GetRecord(index, true);
            newRecord.ReInitialize(_bytesPerSector, _recordLength, (uint)index);

            _recordCache[index] = newRecord;

            newRecord.Flags = FileRecordFlags.InUse | flags;

            WriteRecord(newRecord);
            _self.UpdateRecordInMft();
            return newRecord;
        }
Пример #16
0
        public void WriteRecord(FileRecord record)
        {
            int recordSize = record.Size;
            if (recordSize > _recordLength)
            {
                throw new IOException("Attempting to write over-sized MFT record");
            }

            byte[] buffer = new byte[_recordLength];
            record.ToBytes(buffer, 0);

            _recordStream.Position = record.MasterFileTableIndex * (long)_recordLength;
            _recordStream.Write(buffer, 0, _recordLength);
            _recordStream.Flush();

            // We may have modified our own meta-data by extending the data stream, so
            // make sure our records are up-to-date.
            if (_self.MftRecordIsDirty)
            {
                DirectoryEntry dirEntry = _self.DirectoryEntry;
                if (dirEntry != null)
                {
                    dirEntry.UpdateFrom(_self);
                }

                _self.UpdateRecordInMft();
            }

            // Need to update Mirror.  OpenRaw is OK because this is short duration, and we don't
            // extend or otherwise modify any meta-data, just the content of the Data stream.
            if (record.MasterFileTableIndex < 4 && _self.Context.GetFileByIndex != null)
            {
                File mftMirror = _self.Context.GetFileByIndex(MftMirrorIndex);
                if (mftMirror != null)
                {
                    using (Stream s = mftMirror.OpenStream(AttributeType.Data, null, FileAccess.ReadWrite))
                    {
                        s.Position = record.MasterFileTableIndex * (long)_recordLength;
                        s.Write(buffer, 0, _recordLength);
                    }
                }
            }
        }
Пример #17
0
        private File CreateSystemFile(long mftIndex, FileRecordFlags flags)
        {
            FileRecord fileRec = _context.Mft.AllocateRecord((uint)mftIndex, flags);

            fileRec.SequenceNumber = (ushort)mftIndex;

            File file = new File(_context, fileRec);

            StandardInformation.InitializeNewFile(file,
                                                  FileAttributeFlags.Hidden | FileAttributeFlags.System | FileRecord.ConvertFlags(flags));

            file.CreateStream(AttributeType.Data, null);

            file.UpdateRecordInMft();

            return(file);
        }
        private bool VerifyMftRecord(byte[] recordData, bool presentInBitmap, int bytesPerSector)
        {
            bool ok = true;

            //
            // Verify the attributes seem OK...
            //
            byte[] tempBuffer = new byte[recordData.Length];
            Array.Copy(recordData, tempBuffer, tempBuffer.Length);
            GenericFixupRecord genericRecord = new GenericFixupRecord(bytesPerSector);
            genericRecord.FromBytes(tempBuffer, 0);

            int pos = Utilities.ToUInt16LittleEndian(genericRecord.Content, 0x14);
            while (Utilities.ToUInt32LittleEndian(genericRecord.Content, pos) != 0xFFFFFFFF)
            {
                int attrLen;
                try
                {
                    AttributeRecord ar = AttributeRecord.FromBytes(genericRecord.Content, pos, out attrLen);
                    if (attrLen != ar.Size)
                    {
                        ReportError("Attribute size is different to calculated size.  AttrId={0}", ar.AttributeId);
                        ok = false;
                    }

                    if (ar.IsNonResident)
                    {
                        NonResidentAttributeRecord nrr = (NonResidentAttributeRecord)ar;
                        if (nrr.DataRuns.Count > 0)
                        {
                            long totalVcn = 0;
                            foreach (var run in nrr.DataRuns)
                            {
                                totalVcn += run.RunLength;
                            }

                            if (totalVcn != nrr.LastVcn - nrr.StartVcn + 1)
                            {
                                ReportError("Declared VCNs doesn't match data runs.  AttrId={0}", ar.AttributeId);
                                ok = false;
                            }
                        }
                    }
                }
                catch
                {
                    ReportError("Failure parsing attribute at pos={0}", pos);
                    return false;
                }

                pos += attrLen;
            }

            //
            // Now consider record as a whole
            //
            FileRecord record = new FileRecord(bytesPerSector);
            record.FromBytes(recordData, 0);

            bool inUse = (record.Flags & FileRecordFlags.InUse) != 0;
            if (inUse != presentInBitmap)
            {
                ReportError("MFT bitmap and record in-use flag don't agree.  Mft={0}, Record={1}", presentInBitmap ? "InUse" : "Free", inUse ? "InUse" : "Free");
                ok = false;
            }

            if (record.Size != record.RealSize)
            {
                ReportError("MFT record real size is different to calculated size.  Stored in MFT={0}, Calculated={1}", record.RealSize, record.Size);
                ok = false;
            }

            if (Utilities.ToUInt32LittleEndian(recordData, (int)record.RealSize - 8) != uint.MaxValue)
            {
                ReportError("MFT record is not correctly terminated with 0xFFFFFFFF");
                ok = false;
            }

            return ok;
        }
Пример #19
0
        private bool SplitAttribute(FileRecord record, NonResidentAttributeRecord targetAttr, bool atStart)
        {
            if (targetAttr.DataRuns.Count <= 1)
            {
                return false;
            }

            int splitIndex = 1;
            if (!atStart)
            {
                List<DataRun> runs = targetAttr.DataRuns;

                splitIndex = runs.Count - 1;
                int saved = runs[splitIndex].Size;
                while (splitIndex > 1 && record.Size - saved > record.AllocatedSize)
                {
                    --splitIndex;
                    saved += runs[splitIndex].Size;
                }
            }

            AttributeRecord newAttr = targetAttr.Split(splitIndex);

            // Find a home for the new attribute record
            FileRecord newAttrHome = null;
            foreach (var targetRecord in _records)
            {
                if (!targetRecord.IsMftRecord && _mft.RecordSize - targetRecord.Size >= newAttr.Size)
                {
                    targetRecord.AddAttribute(newAttr);
                    newAttrHome = targetRecord;
                }
            }

            if (newAttrHome == null)
            {
                newAttrHome = _mft.AllocateRecord(_records[0].Flags & (~FileRecordFlags.InUse), record.IsMftRecord);
                newAttrHome.BaseFile = record.BaseFile.IsNull ? record.Reference : record.BaseFile;
                _records.Add(newAttrHome);
                newAttrHome.AddAttribute(newAttr);
            }

            // Add the new attribute record as an extent on the attribute it split from
            bool added = false;
            foreach (var attr in _attributes)
            {
                foreach (var existingRecord in attr.Extents)
                {
                    if (existingRecord.Key.File == record.Reference && existingRecord.Key.AttributeId == targetAttr.AttributeId)
                    {
                        attr.AddExtent(newAttrHome.Reference, newAttr);
                        added = true;
                        break;
                    }
                }

                if (added)
                {
                    break;
                }
            }

            UpdateAttributeList();

            return true;
        }
Пример #20
0
        public FileRecord AllocateRecord(FileRecordFlags flags, bool isMft)
        {
            long index;
            if (isMft)
            {
                // Have to take a lot of care extending the MFT itself, to ensure we never end up unable to
                // bootstrap the file system via the MFT itself - hence why special records are reserved
                // for MFT's own MFT record overflow.
                for (int i = 15; i > 11; --i)
                {
                    FileRecord r = GetRecord(i, false);
                    if (r.BaseFile.SequenceNumber == 0)
                    {
                        r.Reset();
                        r.Flags |= FileRecordFlags.InUse;
                        WriteRecord(r);
                        return r;
                    }
                }

                throw new IOException("MFT too fragmented - unable to allocate MFT overflow record");
            }
            else
            {
                index = _bitmap.AllocateFirstAvailable(FirstAvailableMftIndex);
            }

            if (index * _recordLength >= _recordStream.Length)
            {
                // Note: 64 is significant, since bitmap extends by 8 bytes (=64 bits) at a time.
                long newEndIndex = Utilities.RoundUp(index + 1, 64);
                _recordStream.SetLength(newEndIndex * _recordLength);
                for (long i = index; i < newEndIndex; ++i)
                {
                    FileRecord record = new FileRecord(_bytesPerSector, _recordLength, (uint)i);
                    WriteRecord(record);
                }
            }

            FileRecord newRecord = GetRecord(index, true);
            newRecord.ReInitialize(_bytesPerSector, _recordLength, (uint)index);

            _recordCache[index] = newRecord;

            newRecord.Flags = FileRecordFlags.InUse | flags;

            WriteRecord(newRecord);
            _self.UpdateRecordInMft();

            return newRecord;
        }
Пример #21
0
        private void MoveAttribute(FileRecord record, AttributeRecord attrRec, FileRecord targetRecord)
        {
            AttributeReference oldRef = new AttributeReference(record.Reference, attrRec.AttributeId);

            record.RemoveAttribute(attrRec.AttributeId);
            targetRecord.AddAttribute(attrRec);

            AttributeReference newRef = new AttributeReference(targetRecord.Reference, attrRec.AttributeId);

            foreach (var attr in _attributes)
            {
                attr.ReplaceExtent(oldRef, newRef, attrRec);
            }

            UpdateAttributeList();
        }
Пример #22
0
        private bool SplitAttribute(FileRecord record)
        {
            if (record.Attributes.Count != 1)
            {
                throw new InvalidOperationException("Attempting to split attribute in MFT record containing multiple attributes");
            }

            AttributeRecord targetAttr = record.FirstAttribute;
            if (targetAttr.AttributeType != AttributeType.Data)
            {
                throw new InvalidOperationException("Attempting to split non-Data attribute");
            }

            AttributeRecord newAttr = targetAttr.Split(record);

            // Find a home for the new attribute record
            FileRecord newAttrHome = null;
            foreach (var targetRecord in _records)
            {
                if (_mft.RecordSize - targetRecord.Size >= newAttr.Size)
                {
                    targetRecord.AddAttribute(newAttr);
                    newAttrHome = targetRecord;
                }
            }
            if (newAttrHome == null)
            {
                newAttrHome = _mft.AllocateRecord(FileRecordFlags.None);
                newAttrHome.BaseFile = record.BaseFile;
                _records.Add(newAttrHome);
                newAttrHome.AddAttribute(newAttr);
           }

            // Add the new attribute record as an extent on the attribute it split from
            bool added = false;
            foreach (var attr in _attributes)
            {
                foreach (var existingRecord in attr.Extents)
                {
                    if (existingRecord.Key.File == record.Reference && existingRecord.Key.AttributeId == targetAttr.AttributeId)
                    {
                        attr.AddExtent(newAttrHome.Reference, newAttr);
                        added = true;
                        break;
                    }
                }

                if (added)
                {
                    break;
                }
            }

            UpdateAttributeList();

            return true;
        }