public override void Write(byte[] buffer, int offset, int count) { CheckDisposed(); if (!CanWrite) { throw new InvalidOperationException("Attempt to write to read-only VHDX"); } if (_position % _metadata.LogicalSectorSize != 0 || count % _metadata.LogicalSectorSize != 0) { throw new IOException("Unaligned read"); } int totalWritten = 0; while (totalWritten < count) { int chunkIndex; int blockIndex; int sectorIndex; Chunk chunk = GetChunk(_position + totalWritten, out chunkIndex, out blockIndex, out sectorIndex); int blockOffset = (int)(sectorIndex * _metadata.LogicalSectorSize); int blockBytesRemaining = (int)(_fileParameters.BlockSize - blockOffset); PayloadBlockStatus blockStatus = chunk.GetBlockStatus(blockIndex); if (blockStatus != PayloadBlockStatus.FullyPresent && blockStatus != PayloadBlockStatus.PartiallyPresent) { blockStatus = chunk.AllocateSpaceForBlock(blockIndex); } int toWrite = Math.Min(blockBytesRemaining, count - totalWritten); _fileStream.Position = chunk.GetBlockPosition(blockIndex) + blockOffset; _fileStream.Write(buffer, offset + totalWritten, toWrite); if (blockStatus == PayloadBlockStatus.PartiallyPresent) { BlockBitmap bitmap = chunk.GetBlockBitmap(blockIndex); bool changed = bitmap.MarkSectorsPresent(sectorIndex, (int)(toWrite / _metadata.LogicalSectorSize)); if (changed) { chunk.WriteBlockBitmap(blockIndex); } } totalWritten += toWrite; } _position += totalWritten; }
public override int Read(byte[] buffer, int offset, int count) { CheckDisposed(); if (_atEof || _position > _length) { _atEof = true; throw new IOException("Attempt to read beyond end of file"); } if (_position == _length) { _atEof = true; return(0); } if (_position % _metadata.LogicalSectorSize != 0 || count % _metadata.LogicalSectorSize != 0) { throw new IOException("Unaligned read"); } int totalToRead = (int)Math.Min(_length - _position, count); int totalRead = 0; while (totalRead < totalToRead) { int chunkIndex; int blockIndex; int sectorIndex; Chunk chunk = GetChunk(_position + totalRead, out chunkIndex, out blockIndex, out sectorIndex); int blockOffset = (int)(sectorIndex * _metadata.LogicalSectorSize); int blockBytesRemaining = (int)(_fileParameters.BlockSize - blockOffset); PayloadBlockStatus blockStatus = chunk.GetBlockStatus(blockIndex); if (blockStatus == PayloadBlockStatus.FullyPresent) { _fileStream.Position = chunk.GetBlockPosition(blockIndex) + blockOffset; int read = Utilities.ReadFully(_fileStream, buffer, offset + totalRead, Math.Min(blockBytesRemaining, totalToRead - totalRead)); totalRead += read; } else if (blockStatus == PayloadBlockStatus.PartiallyPresent) { BlockBitmap bitmap = chunk.GetBlockBitmap(blockIndex); bool present; int numSectors = bitmap.ContiguousSectors(sectorIndex, out present); int toRead = (int)Math.Min(numSectors * _metadata.LogicalSectorSize, totalToRead - totalRead); int read; if (present) { _fileStream.Position = chunk.GetBlockPosition(blockIndex) + blockOffset; read = Utilities.ReadFully(_fileStream, buffer, offset + totalRead, toRead); } else { _parentStream.Position = _position + totalRead; read = Utilities.ReadFully(_parentStream, buffer, offset + totalRead, toRead); } totalRead += read; } else if (blockStatus == PayloadBlockStatus.NotPresent) { _parentStream.Position = _position + totalRead; int read = Utilities.ReadFully(_parentStream, buffer, offset + totalRead, Math.Min(blockBytesRemaining, totalToRead - totalRead)); totalRead += read; } else { int zeroed = Math.Min(blockBytesRemaining, totalToRead - totalRead); Array.Clear(buffer, offset + totalRead, zeroed); totalRead += zeroed; } } _position += totalRead; return(totalRead); }