public override int WriteClusters(long startVcn, int count, byte[] buffer, int offset) { Utilities.AssertBufferParameters(buffer, offset, count * _bytesPerCluster); int runIdx = 0; int totalWritten = 0; while (totalWritten < count) { long focusVcn = startVcn + totalWritten; runIdx = _cookedRuns.FindDataRun(focusVcn, runIdx); CookedDataRun run = _cookedRuns[runIdx]; if (run.IsSparse) { throw new NotImplementedException("Writing to sparse datarun"); } int toWrite = (int)Math.Min(count - totalWritten, run.Length - (focusVcn - run.StartVcn)); long lcn = _cookedRuns[runIdx].StartLcn + (focusVcn - run.StartVcn); _fsStream.Position = lcn * _bytesPerCluster; _fsStream.Write(buffer, offset + (totalWritten * _bytesPerCluster), toWrite * _bytesPerCluster); totalWritten += toWrite; } return(0); }
private void AddDataRun(long startLcn, long length) { var runs = _record.CookedDataRuns; long startVcn = 0; long prevLcn = 0; if (runs.Count > 0) { CookedDataRun tailRun = runs[runs.Count - 1]; startVcn = tailRun.StartVcn + tailRun.Length; prevLcn = tailRun.StartLcn; // Continuation of last run... if (startLcn == prevLcn + tailRun.Length) { tailRun.Length += length; return; } } DataRun newRun = new DataRun(startLcn - prevLcn, length); CookedDataRun newCookedRun = new CookedDataRun(newRun, startVcn, prevLcn); _record.CookedDataRuns.Add(newCookedRun); }
public override void ReadClusters(long startVcn, int count, byte[] buffer, int offset) { StreamUtilities.AssertBufferParameters(buffer, offset, count * _bytesPerCluster); int runIdx = 0; int totalRead = 0; while (totalRead < count) { long focusVcn = startVcn + totalRead; runIdx = _cookedRuns.FindDataRun(focusVcn, runIdx); CookedDataRun run = _cookedRuns[runIdx]; int toRead = (int)Math.Min(count - totalRead, run.Length - (focusVcn - run.StartVcn)); if (run.IsSparse) { Array.Clear(buffer, offset + totalRead * _bytesPerCluster, toRead * _bytesPerCluster); } else { long lcn = _cookedRuns[runIdx].StartLcn + (focusVcn - run.StartVcn); _fsStream.Position = lcn * _bytesPerCluster; StreamUtilities.ReadExact(_fsStream, buffer, offset + totalRead * _bytesPerCluster, toRead * _bytesPerCluster); } totalRead += toRead; } }
public void MakeSparse(int index) { if (index < _firstDirty) { _firstDirty = index; } if (index > _lastDirty) { _lastDirty = index; } long prevLcn = index == 0 ? 0 : _runs[index - 1].StartLcn; CookedDataRun run = _runs[index]; if (run.IsSparse) { throw new ArgumentException("Run is already sparse", "index"); } _runs[index] = new CookedDataRun(new DataRun(0, run.Length, true), run.StartVcn, prevLcn, run.AttributeExtent); run.AttributeExtent.ReplaceRun(run.DataRun, _runs[index].DataRun); for (int i = index + 1; i < _runs.Count; ++i) { if (!_runs[i].IsSparse) { _runs[i].DataRun.RunOffset += run.StartLcn - prevLcn; break; } } }
public override void ReadClusters(long startVcn, int count, byte[] buffer, int offset) { Utilities.AssertBufferParameters(buffer, offset, count * _bytesPerCluster); int runIdx = 0; int totalRead = 0; while (totalRead < count) { long focusVcn = startVcn + totalRead; runIdx = _cookedRuns.FindDataRun(focusVcn, runIdx); CookedDataRun run = _cookedRuns[runIdx]; int toRead = (int)Math.Min(count - totalRead, run.Length - (focusVcn - run.StartVcn)); if (run.IsSparse) { Array.Clear(buffer, offset + (totalRead * _bytesPerCluster), toRead * _bytesPerCluster); } else { long lcn = _cookedRuns[runIdx].StartLcn + (focusVcn - run.StartVcn); _fsStream.Position = lcn * _bytesPerCluster; int numRead = Utilities.ReadFully(_fsStream, buffer, offset + (totalRead * _bytesPerCluster), toRead * _bytesPerCluster); if (numRead != toRead * _bytesPerCluster) { throw new IOException(string.Format(CultureInfo.InvariantCulture, "Short read, reading {0} clusters starting at LCN {1}", toRead, lcn)); } } totalRead += toRead; } }
public int FindDataRun(long vcn, int startIdx) { int numRuns = _runs.Count; if (numRuns > 0) { CookedDataRun run = _runs[numRuns - 1]; if (vcn >= run.StartVcn) { if (run.StartVcn + run.Length > vcn) { return(numRuns - 1); } else { throw new IOException("Looking for VCN outside of data runs"); } } for (int i = startIdx; i < numRuns; ++i) { run = _runs[i]; if (run.StartVcn + run.Length > vcn) { return(i); } } } throw new IOException("Looking for VCN outside of data runs"); }
public void MakeNonSparse(int index, IEnumerable <DataRun> rawRuns) { if (index < _firstDirty) { _firstDirty = index; } if (index > _lastDirty) { _lastDirty = index; } long prevLcn = index == 0 ? 0 : _runs[index - 1].StartLcn; CookedDataRun run = _runs[index]; if (!run.IsSparse) { throw new ArgumentException("Run is already non-sparse", "index"); } _runs.RemoveAt(index); int insertIdx = run.AttributeExtent.RemoveRun(run.DataRun); CookedDataRun lastNewRun = null; long lcn = prevLcn; long vcn = run.StartVcn; foreach (var rawRun in rawRuns) { CookedDataRun newRun = new CookedDataRun(rawRun, vcn, lcn, run.AttributeExtent); _runs.Insert(index, newRun); run.AttributeExtent.InsertRun(insertIdx, rawRun); vcn += rawRun.RunLength; lcn += rawRun.RunOffset; lastNewRun = newRun; insertIdx++; index++; } for (int i = index; i < _runs.Count; ++i) { if (_runs[i].IsSparse) { _runs[i].StartLcn = lastNewRun.StartLcn; } else { _runs[i].DataRun.RunOffset = _runs[i].StartLcn - lastNewRun.StartLcn; break; } } }
public NonResidentAttributeRecord(AttributeType type, string name, ushort id, AttributeFlags flags, List <CookedDataRun> dataRuns) : base(type, name, id, flags) { base._nonResidentFlag = 1; _cookedDataRuns = dataRuns; if (dataRuns != null && dataRuns.Count != 0) { CookedDataRun lastRun = dataRuns[dataRuns.Count - 1]; _startingVCN = (ulong)dataRuns[0].StartVcn; _lastVCN = (ulong)(lastRun.StartVcn + lastRun.Length - 1); } }
public int ReleaseClusters(long startVcn, int count) { int runIdx = 0; int totalReleased = 0; long focus = startVcn; while (focus < startVcn + count) { runIdx = _cookedRuns.FindDataRun(focus, runIdx); CookedDataRun run = _cookedRuns[runIdx]; if (run.IsSparse) { focus += run.Length; } else { if (focus != run.StartVcn) { _cookedRuns.SplitRun(runIdx, focus); runIdx++; run = _cookedRuns[runIdx]; } long numClusters = Math.Min((startVcn + count) - focus, run.Length); if (numClusters != run.Length) { _cookedRuns.SplitRun(runIdx, focus + numClusters); run = _cookedRuns[runIdx]; } _context.ClusterBitmap.FreeClusters(new Range <long, long>(run.StartLcn, run.Length)); _cookedRuns.MakeSparse(runIdx); totalReleased += (int)run.Length; focus += numClusters; } } return(totalReleased); }
public override AttributeRecord Split(FileRecord fileRecord) { int splitIdx = _cookedDataRuns.Count / 2; List <CookedDataRun> newRecordRuns = new List <CookedDataRun>(); while (_cookedDataRuns.Count > splitIdx) { newRecordRuns.Add(_cookedDataRuns[splitIdx]); _cookedDataRuns.RemoveAt(splitIdx); } newRecordRuns[0].DataRun.RunOffset = newRecordRuns[0].StartLcn; CookedDataRun lastRemRun = _cookedDataRuns[_cookedDataRuns.Count - 1]; _lastVCN = (ulong)(lastRemRun.StartVcn + lastRemRun.Length - 1); return(new NonResidentAttributeRecord(_type, _name, 0, _flags, newRecordRuns)); }
public void SplitRun(int runIdx, long vcn) { if (runIdx < _firstDirty) { _firstDirty = runIdx; } if (runIdx > _lastDirty) { _lastDirty = runIdx; } CookedDataRun run = _runs[runIdx]; if (run.StartVcn >= vcn || run.StartVcn + run.Length <= vcn) { throw new ArgumentException("Attempt to split run outside of it's range", nameof(vcn)); } long distance = vcn - run.StartVcn; long offset = run.IsSparse ? 0 : distance; CookedDataRun newRun = new CookedDataRun(new DataRun(offset, run.Length - distance, run.IsSparse), vcn, run.StartLcn, run.AttributeExtent); run.Length = distance; _runs.Insert(runIdx + 1, newRun); run.AttributeExtent.InsertRun(run.DataRun, newRun.DataRun); for (int i = runIdx + 2; i < _runs.Count; ++i) { if (_runs[i].IsSparse) { _runs[i].StartLcn += offset; } else { _runs[i].DataRun.RunOffset -= offset; break; } } }
public bool AreAllClustersStored(long vcn, int count) { int runIdx = 0; long focusVcn = vcn; while (focusVcn < vcn + count) { runIdx = _cookedRuns.FindDataRun(focusVcn, runIdx); CookedDataRun run = _cookedRuns[runIdx]; if (run.IsSparse) { return(false); } focusVcn = run.StartVcn + run.Length; } return(true); }
protected override void Read(byte[] buffer, int offset, out int length) { _cookedDataRuns = null; base.Read(buffer, offset, out length); _startingVCN = Utilities.ToUInt64LittleEndian(buffer, offset + 0x10); _lastVCN = Utilities.ToUInt64LittleEndian(buffer, offset + 0x18); _dataRunsOffset = Utilities.ToUInt16LittleEndian(buffer, offset + 0x20); _compressionUnitSize = Utilities.ToUInt16LittleEndian(buffer, offset + 0x22); _dataAllocatedSize = Utilities.ToUInt64LittleEndian(buffer, offset + 0x28); _dataRealSize = Utilities.ToUInt64LittleEndian(buffer, offset + 0x30); _initializedDataSize = Utilities.ToUInt64LittleEndian(buffer, offset + 0x38); if ((Flags & AttributeFlags.Compressed) != 0) { _compressedSize = Utilities.ToUInt64LittleEndian(buffer, offset + 0x40); } var dataRuns = new List <DataRun>(); int pos = _dataRunsOffset; while (pos < length) { DataRun run = new DataRun(); int len = run.Read(buffer, offset + pos); // Length 1 means there was only a header byte (i.e. terminator) if (len == 1) { break; } dataRuns.Add(run); pos += len; } _cookedDataRuns = CookedDataRun.Cook(dataRuns); }
public int AllocateClusters(long startVcn, int count) { if (startVcn + count > _cookedRuns.NextVirtualCluster) { throw new IOException("Attempt to allocate unknown clusters"); } int totalAllocated = 0; int runIdx = 0; long focus = startVcn; while (focus < startVcn + count) { runIdx = _cookedRuns.FindDataRun(focus, runIdx); CookedDataRun run = _cookedRuns[runIdx]; if (run.IsSparse) { if (focus != run.StartVcn) { _cookedRuns.SplitRun(runIdx, focus); runIdx++; run = _cookedRuns[runIdx]; } long numClusters = Math.Min((startVcn + count) - focus, run.Length); if (numClusters != run.Length) { _cookedRuns.SplitRun(runIdx, focus + numClusters); run = _cookedRuns[runIdx]; } long nextCluster = -1; for (int i = runIdx - 1; i >= 0; --i) { if (!_cookedRuns[i].IsSparse) { nextCluster = _cookedRuns[i].StartLcn + _cookedRuns[i].Length; break; } } var alloced = _context.ClusterBitmap.AllocateClusters(numClusters, nextCluster, _isMft, AllocatedClusterCount); List <DataRun> runs = new List <DataRun>(); long lcn = runIdx == 0 ? 0 : _cookedRuns[runIdx - 1].StartLcn; foreach (var allocation in alloced) { runs.Add(new DataRun(allocation.First - lcn, allocation.Second, false)); lcn = allocation.First; } _cookedRuns.MakeNonSparse(runIdx, runs); totalAllocated += (int)numClusters; focus += numClusters; } else { focus = run.StartVcn + run.Length; } } return(totalAllocated); }
public void SplitRun(int runIdx, long vcn) { if (runIdx < _firstDirty) { _firstDirty = runIdx; } if (runIdx > _lastDirty) { _lastDirty = runIdx; } CookedDataRun run = _runs[runIdx]; if (run.StartVcn >= vcn || run.StartVcn + run.Length <= vcn) { throw new ArgumentException("Attempt to split run outside of it's range", "vcn"); } long distance = vcn - run.StartVcn; long offset = run.IsSparse ? 0 : distance; CookedDataRun newRun = new CookedDataRun(new DataRun(offset, run.Length - distance, run.IsSparse), vcn, run.StartLcn, run.AttributeExtent); run.Length = distance; _runs.Insert(runIdx + 1, newRun); run.AttributeExtent.InsertRun(run.DataRun, newRun.DataRun); for (int i = runIdx + 2; i < _runs.Count; ++i) { if (_runs[i].IsSparse) { _runs[i].StartLcn += offset; } else { _runs[i].DataRun.RunOffset -= offset; break; } } }
public void MakeSparse(int index) { if (index < _firstDirty) { _firstDirty = index; } if (index > _lastDirty) { _lastDirty = index; } long prevLcn = index == 0 ? 0 : _runs[index - 1].StartLcn; CookedDataRun run = _runs[index]; if (run.IsSparse) { throw new ArgumentException("Run is already sparse", "index"); } _runs[index] = new CookedDataRun(new DataRun(0, run.Length, true), run.StartVcn, prevLcn, run.AttributeExtent); run.AttributeExtent.ReplaceRun(run.DataRun, _runs[index].DataRun); for (int i = index + 1; i < _runs.Count; ++i) { if (!_runs[i].IsSparse) { _runs[i].DataRun.RunOffset += run.StartLcn - prevLcn; break; } } }
public void MakeNonSparse(int index, IEnumerable<DataRun> rawRuns) { if (index < _firstDirty) { _firstDirty = index; } if (index > _lastDirty) { _lastDirty = index; } long prevLcn = index == 0 ? 0 : _runs[index - 1].StartLcn; CookedDataRun run = _runs[index]; if (!run.IsSparse) { throw new ArgumentException("Run is already non-sparse", "index"); } _runs.RemoveAt(index); int insertIdx = run.AttributeExtent.RemoveRun(run.DataRun); CookedDataRun lastNewRun = null; long lcn = prevLcn; long vcn = run.StartVcn; foreach (var rawRun in rawRuns) { CookedDataRun newRun = new CookedDataRun(rawRun, vcn, lcn, run.AttributeExtent); _runs.Insert(index, newRun); run.AttributeExtent.InsertRun(insertIdx, rawRun); vcn += rawRun.RunLength; lcn += rawRun.RunOffset; lastNewRun = newRun; insertIdx++; index++; } for (int i = index; i < _runs.Count; ++i) { if (_runs[i].IsSparse) { _runs[i].StartLcn = lastNewRun.StartLcn; } else { _runs[i].DataRun.RunOffset = _runs[i].StartLcn - lastNewRun.StartLcn; break; } } }
private void AddDataRun(long startLcn, long length) { var runs = _record.CookedDataRuns; long startVcn = 0; long prevLcn = 0; if (runs.Count > 0) { CookedDataRun tailRun = runs[runs.Count - 1]; startVcn = tailRun.StartVcn + tailRun.Length; prevLcn = tailRun.StartLcn; // Continuation of last run... if (startLcn == prevLcn + tailRun.Length) { tailRun.Length += length; return; } } DataRun newRun = new DataRun(startLcn - prevLcn, length); CookedDataRun newCookedRun = new CookedDataRun(newRun, startVcn, prevLcn); _record.CookedDataRuns.Add(newCookedRun); }
public void Append(DataRun rawRun, NonResidentAttributeRecord attributeExtent) { CookedDataRun last = Last; _runs.Add(new CookedDataRun(rawRun, NextVirtualCluster, last == null ? 0 : last.StartLcn, attributeExtent)); }