internal bool HigherSequenceThan(LogSequence otherSequence) { ulong other = otherSequence.Count > 0 ? otherSequence.Head.SequenceNumber : 0; ulong self = Count > 0 ? Head.SequenceNumber : 0; return(self > other); }
internal DiskImageFileInfo(FileHeader fileHeader, VhdxHeader vhdxHeader1, VhdxHeader vhdxHeader2, RegionTable regions, Metadata metadata, LogSequence activeLogSequence) { _fileHeader = fileHeader; _vhdxHeader1 = vhdxHeader1; _vhdxHeader2 = vhdxHeader2; _regions = regions; _metadata = metadata; _activeLogSequence = activeLogSequence; }
private LogSequence FindActiveLogSequence() { using ( Stream logStream = new CircularStream(new SubStream(_fileStream, (long)_header.LogOffset, _header.LogLength), Ownership.Dispose)) { LogSequence candidateActiveSequence = new LogSequence(); LogEntry logEntry = null; long oldTail; long currentTail = 0; do { oldTail = currentTail; logStream.Position = currentTail; LogSequence currentSequence = new LogSequence(); while (LogEntry.TryRead(logStream, out logEntry) && logEntry.LogGuid == _header.LogGuid && (currentSequence.Count == 0 || logEntry.SequenceNumber == currentSequence.Head.SequenceNumber + 1)) { currentSequence.Add(logEntry); logEntry = null; } if (currentSequence.Count > 0 && currentSequence.Contains(currentSequence.Head.Tail) && currentSequence.HigherSequenceThan(candidateActiveSequence)) { candidateActiveSequence = currentSequence; } if (currentSequence.Count == 0) { currentTail += LogEntry.LogSectorSize; } else { currentTail = currentSequence.Head.Position + LogEntry.LogSectorSize; } currentTail = currentTail % logStream.Length; } while (currentTail > oldTail); return(candidateActiveSequence); } }
private void ReplayLog() { _freeSpace.Reserve((long)_header.LogOffset, _header.LogLength); _logicalStream = _fileStream; // If log is empty, skip. if (_header.LogGuid == Guid.Empty) { return; } LogSequence activeLogSequence = FindActiveLogSequence(); if (activeLogSequence == null || activeLogSequence.Count == 0) { throw new IOException("Unable to replay VHDX log, suspected corrupt VHDX file"); } if (activeLogSequence.Head.FlushedFileOffset > (ulong)_logicalStream.Length) { throw new IOException("truncated VHDX file found while replaying log"); } if (activeLogSequence.Count > 1 || !activeLogSequence.Head.IsEmpty) { // However, have seen VHDX with a non-empty log with no data to replay. These are // 'safe' to open. if (!_fileStream.CanWrite) { SnapshotStream replayStream = new SnapshotStream(_fileStream, Ownership.None); replayStream.Snapshot(); _logicalStream = replayStream; } foreach (LogEntry logEntry in activeLogSequence) { if (logEntry.LogGuid != _header.LogGuid) { throw new IOException("Invalid log entry in VHDX log, suspected currupt VHDX file"); } if (logEntry.IsEmpty) { continue; } logEntry.Replay(_logicalStream); } _logicalStream.Seek((long)activeLogSequence.Head.LastFileOffset, SeekOrigin.Begin); } }
private void ReplayLog() { _freeSpace.Reserve((long)_header.LogOffset, _header.LogLength); _logicalStream = _fileStream; // If log is empty, skip. if (_header.LogGuid == Guid.Empty) { return; } LogSequence activeLogSequence = FindActiveLogSequence(); if (activeLogSequence == null || activeLogSequence.Count == 0) { throw new IOException("Unable to replay VHDX log, suspected corrupt VHDX file"); } if (activeLogSequence.Count > 1 || !activeLogSequence.Head.IsEmpty) { // TODO - perform actual replay (needs VHDX with real log to replay) // However, have seen VHDX with a non-empty log with no data to replay. These are // 'safe' to open. throw new NotImplementedException("Actual replay of VHDX logs not implemented yet"); //// Have a log to replay, and the base stream is read-only. Use a snapshot stream to //// replay in RAM. ////if (!_fileStream.CanWrite) ////{ //// SnapshotStream replayStream = new SnapshotStream(_fileStream, Ownership.None); //// replayStream.Snapshot(); //// _logicalStream = replayStream; ////} } }