private Chunk GetChunk(long position, out int chunk, out int block, out int sector) { long chunkSize = (1L << 23) * _metadata.LogicalSectorSize; int chunkRatio = (int)(chunkSize / _metadata.FileParameters.BlockSize); chunk = (int)(position / chunkSize); long chunkOffset = position % chunkSize; block = (int)(chunkOffset / _fileParameters.BlockSize); int blockOffset = (int)(chunkOffset % _fileParameters.BlockSize); sector = (int)(blockOffset / _metadata.LogicalSectorSize); Chunk result = _chunks[chunk]; if (result == null) { result = new Chunk(_batStream, _fileStream, _freeSpaceTable, _fileParameters, chunk, chunkRatio); _chunks[chunk] = result; } return result; }
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 = StreamUtilities.ReadMaximum(_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 = StreamUtilities.ReadMaximum(_fileStream, buffer, offset + totalRead, toRead); } else { _parentStream.Position = _position + totalRead; read = StreamUtilities.ReadMaximum(_parentStream, buffer, offset + totalRead, toRead); } totalRead += read; } else if (blockStatus == PayloadBlockStatus.NotPresent) { _parentStream.Position = _position + totalRead; int read = StreamUtilities.ReadMaximum(_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); }