private void Truncate(long value)
        {
            long endVcn = Utilities.Ceil(value, _bytesPerCluster);

            // Release the clusters
            _activeStream.TruncateToClusters(endVcn);

            // First, remove any extents that are now redundant.
            Dictionary <AttributeReference, AttributeRecord> extentCache = new Dictionary <AttributeReference, AttributeRecord>(_attribute.Extents);

            foreach (var extent in extentCache)
            {
                if (extent.Value.StartVcn >= endVcn)
                {
                    NonResidentAttributeRecord record = (NonResidentAttributeRecord)extent.Value;
                    _file.RemoveAttributeExtent(extent.Key);
                    _attribute.RemoveExtentCacheSafe(extent.Key);
                }
            }

            PrimaryAttributeRecord.LastVcn               = Math.Max(0, endVcn - 1);
            PrimaryAttributeRecord.AllocatedLength       = endVcn * _bytesPerCluster;
            PrimaryAttributeRecord.DataLength            = value;
            PrimaryAttributeRecord.InitializedDataLength = Math.Min(PrimaryAttributeRecord.InitializedDataLength, value);

            _file.MarkMftRecordDirty();
        }
 public NonResidentAttributeBuffer(File file, NonResidentAttributeRecord record)
 {
     _file            = file;
     _fsStream        = _file.Context.RawStream;
     _bytesPerCluster = file.Context.BiosParameterBlock.BytesPerCluster;
     _record          = record;
 }
 public NonResidentAttributeBuffer(File file, NonResidentAttributeRecord record)
 {
     _file = file;
     _fsStream = _file.Context.RawStream;
     _bytesPerCluster = file.Context.BiosParameterBlock.BytesPerCluster;
     _record = record;
 }
Example #4
0
        public void Append(IEnumerable <DataRun> rawRuns, NonResidentAttributeRecord attributeExtent)
        {
            long vcn = NextVirtualCluster;
            long lcn = 0;

            foreach (var run in rawRuns)
            {
                _runs.Add(new CookedDataRun(run, vcn, lcn, attributeExtent));
                vcn += run.RunLength;
                lcn += run.RunOffset;
            }
        }
Example #5
0
        public CookedDataRun(DataRun raw, long startVcn, long prevLcn, NonResidentAttributeRecord attributeExtent)
        {
            _raw = raw;
            _startVcn = startVcn;
            _startLcn = prevLcn + raw.RunOffset;
            _attributeExtent = attributeExtent;

            if (startVcn < 0)
            {
                throw new ArgumentOutOfRangeException("startVcn", startVcn, "VCN must be >= 0");
            }

            if (_startLcn < 0)
            {
                throw new ArgumentOutOfRangeException("prevLcn", prevLcn, "LCN must be >= 0");
            }
        }
        public CookedDataRun(DataRun raw, long startVcn, long prevLcn, NonResidentAttributeRecord attributeExtent)
        {
            _raw             = raw;
            _startVcn        = startVcn;
            _startLcn        = prevLcn + raw.RunOffset;
            _attributeExtent = attributeExtent;

            if (startVcn < 0)
            {
                throw new ArgumentOutOfRangeException("startVcn", startVcn, "VCN must be >= 0");
            }

            if (_startLcn < 0)
            {
                throw new ArgumentOutOfRangeException("prevLcn", prevLcn, "LCN must be >= 0");
            }
        }
Example #7
0
        public CookedDataRun(DataRun raw, long startVcn, long prevLcn, NonResidentAttributeRecord attributeExtent)
        {
            DataRun         = raw;
            StartVcn        = startVcn;
            StartLcn        = prevLcn + raw.RunOffset;
            AttributeExtent = attributeExtent;

            if (startVcn < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(startVcn), startVcn, "VCN must be >= 0");
            }

            if (StartLcn < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(prevLcn), prevLcn, "LCN must be >= 0");
            }
        }
Example #8
0
        public NonResidentAttributeRecord GetNonResidentExtent(long targetVcn)
        {
            foreach (var extent in _extents)
            {
                NonResidentAttributeRecord nonResident = extent.Value as NonResidentAttributeRecord;
                if (nonResident == null)
                {
                    throw new IOException("Attempt to get non-resident extent from resident attribute");
                }

                if (nonResident.StartVcn <= targetVcn && nonResident.LastVcn >= targetVcn)
                {
                    return(nonResident);
                }
            }

            throw new IOException("Attempt to access position outside of a known extent");
        }
Example #9
0
        private IBuffer GetExtentBuffer(long targetPos, out long streamStartPos)
        {
            AttributeRecord rec = null;

            if (_attribute.Extents.Count == 1)
            {
                // Handled as a special case, because sometimes _file can be null (for diagnostics)
                rec            = _attribute.LastExtent;
                streamStartPos = 0;
            }
            else
            {
                long bytesPerCluster = _file.Context.BiosParameterBlock.BytesPerCluster;
                long vcn             = targetPos / bytesPerCluster;

                NonResidentAttributeRecord nonResident = _attribute.GetNonResidentExtent(vcn);
                streamStartPos = nonResident.StartVcn * bytesPerCluster;
                rec            = nonResident;
            }

            return(rec.GetDataBuffer(_file));
        }
        public override void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate)
        {
            long totalVirtualClusters = _cookedRuns.NextVirtualCluster;

            if (totalVirtualClusters < numVirtualClusters)
            {
                NonResidentAttributeRecord realExtent = extent;
                if (realExtent == null)
                {
                    realExtent = _cookedRuns.Last.AttributeExtent;
                }

                DataRun newRun = new DataRun(0, numVirtualClusters - totalVirtualClusters, true);
                realExtent.DataRuns.Add(newRun);
                _cookedRuns.Append(newRun, extent);
                realExtent.LastVcn = numVirtualClusters - 1;
            }

            if (allocate)
            {
                AllocateClusters(totalVirtualClusters, (int)(numVirtualClusters - totalVirtualClusters));
            }
        }
Example #11
0
        public override void Write(long pos, byte[] buffer, int offset, int count)
        {
            var record = _attribute.Record;

            if (!CanWrite)
            {
                throw new IOException("Attempt to write to file not opened for write");
            }

            if (record.Flags != AttributeFlags.None)
            {
                throw new NotImplementedException("Writing to compressed / sparse attributes");
            }

            if (count == 0)
            {
                return;
            }


            if (!record.IsNonResident)
            {
                record.GetDataBuffer(_file).Write(pos, buffer, offset, count);
                _file.MarkMftRecordDirty();
            }
            else
            {
                NonResidentAttributeRecord lastExtent = (NonResidentAttributeRecord)_attribute.LastExtent;
                IBuffer lastExtentBuffer = lastExtent.GetDataBuffer(_file);

                long bytesPerCluster = _file.Context.BiosParameterBlock.BytesPerCluster;

                if (pos + count > record.AllocatedLength)
                {
                    _file.MarkMftRecordDirty();

                    long clusterLength = Utilities.RoundUp(pos + count, bytesPerCluster);
                    lastExtentBuffer.SetCapacity(clusterLength - (lastExtent.StartVcn * bytesPerCluster));
                    record.AllocatedLength = clusterLength;
                }

                // Write zeros from end of current initialized data to the start of the new write
                if (pos > record.InitializedDataLength + 1)
                {
                    _file.MarkMftRecordDirty();

                    byte[] wipeBuffer = new byte[bytesPerCluster * 4];

                    long wipePos = record.InitializedDataLength;
                    while (wipePos < pos)
                    {
                        long    extentStartPos;
                        IBuffer extentBuffer = GetExtentBuffer(wipePos, out extentStartPos);

                        long writePos   = wipePos - extentStartPos;
                        int  numToWrite = (int)Math.Min(Math.Min(extentBuffer.Capacity - writePos, pos - wipePos), wipeBuffer.Length);
                        extentBuffer.Write(writePos, wipeBuffer, 0, numToWrite);
                        wipePos += numToWrite;
                    }
                }

                long focusPos     = pos;
                int  bytesWritten = 0;
                while (bytesWritten < count)
                {
                    long    extentStartPos;
                    IBuffer extentBuffer = GetExtentBuffer(focusPos, out extentStartPos);

                    long writePos   = focusPos - extentStartPos;
                    int  numToWrite = (int)Math.Min(extentBuffer.Capacity - writePos, count - bytesWritten);
                    extentBuffer.Write(writePos, buffer, offset + bytesWritten, numToWrite);
                    focusPos     += numToWrite;
                    bytesWritten += numToWrite;
                }

                if (pos + count > record.InitializedDataLength)
                {
                    _file.MarkMftRecordDirty();

                    record.InitializedDataLength = pos + count;
                }

                if (pos + count > record.DataLength)
                {
                    _file.MarkMftRecordDirty();

                    record.DataLength = pos + count;
                }
            }
        }
Example #12
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 (FileRecord 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 (NtfsAttribute attr in _attributes)
            {
                foreach (KeyValuePair <AttributeReference, AttributeRecord> 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);
        }
Example #13
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;
        }
 public CookedDataRuns(IEnumerable<DataRun> rawRuns, NonResidentAttributeRecord attributeExtent)
 {
     _runs = new List<CookedDataRun>();
     Append(rawRuns, attributeExtent);
 }
Example #15
0
 public override void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate)
 {
     _rawStream.ExpandToClusters(CompressionStart(numVirtualClusters), extent, false);
 }
 public NonResidentDataBuffer(INtfsContext context, NonResidentAttributeRecord record)
     : this(context, new CookedDataRuns(record.DataRuns, record), false)
 {
 }
 public void Append(IEnumerable<DataRun> rawRuns, NonResidentAttributeRecord attributeExtent)
 {
     long vcn = NextVirtualCluster;
     long lcn = 0;
     foreach (var run in rawRuns)
     {
         _runs.Add(new CookedDataRun(run, vcn, lcn, attributeExtent));
         vcn += run.RunLength;
         lcn += run.RunOffset;
     }
 }
 public NonResidentDataBuffer(INtfsContext context, NonResidentAttributeRecord record)
     : this(context, new CookedDataRuns(record.DataRuns, record), false)
 {
 }
Example #19
0
 public CookedDataRuns(IEnumerable <DataRun> rawRuns, NonResidentAttributeRecord attributeExtent)
 {
     _runs = new List <CookedDataRun>();
     Append(rawRuns, attributeExtent);
 }
Example #20
0
        public override void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate)
        {
            long totalVirtualClusters = _cookedRuns.NextVirtualCluster;
            if (totalVirtualClusters < numVirtualClusters)
            {
                NonResidentAttributeRecord realExtent = extent;
                if (realExtent == null)
                {
                    realExtent = _cookedRuns.Last.AttributeExtent;
                }

                DataRun newRun = new DataRun(0, numVirtualClusters - totalVirtualClusters, true);
                realExtent.DataRuns.Add(newRun);
                _cookedRuns.Append(newRun, extent);
                realExtent.LastVcn = numVirtualClusters - 1;
            }

            if (allocate)
            {
                AllocateClusters(totalVirtualClusters, (int)(numVirtualClusters - totalVirtualClusters));
            }
        }
Example #21
0
        public void Append(DataRun rawRun, NonResidentAttributeRecord attributeExtent)
        {
            CookedDataRun last = Last;

            _runs.Add(new CookedDataRun(rawRun, NextVirtualCluster, last == null ? 0 : last.StartLcn, attributeExtent));
        }
Example #22
0
 public override void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate)
 {
     _rawStream.ExpandToClusters(Utilities.RoundUp(numVirtualClusters, _attr.CompressionUnitSize), extent, false);
 }
Example #23
0
 public abstract void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate);
Example #24
0
 public override void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate)
 {
     _rawStream.ExpandToClusters(CompressionStart(numVirtualClusters), extent, false);
 }
 public override void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate)
 {
     _rawStream.ExpandToClusters(Utilities.RoundUp(numVirtualClusters, _attr.CompressionUnitSize), extent, false);
 }
 public void Append(DataRun rawRun, NonResidentAttributeRecord attributeExtent)
 {
     CookedDataRun last = Last;
     _runs.Add(new CookedDataRun(rawRun, NextVirtualCluster, last == null ? 0 : last.StartLcn, attributeExtent));
 }
        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);
        }
 public abstract void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate);