private void WriteAnyUnwrittenData() { if (currentWritingBlock != null) { underlyingStream.WriteBlock(currentWritingBlock, currentWritingBlockUsage); currentWritingBlock = null; currentReadingBlock = null; } }
public override int Read(byte[] buffer, int bufferOffset, int count) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (bufferOffset + count > buffer.LongLength) { throw new ArgumentOutOfRangeException("bufferOffset"); } if (count == 0) { return(0); } lock (locker) { // If the stream is used for both reading and writing, make sure we're reading everything that was written WriteAnyUnwrittenData(); if (Position >= underlyingStream.Footer.TotalLength) { return(0); } long startingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position); long blockOffset = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Position); if (currentReadingBlock == null || currentReadingBlock.BlockNumber != startingBlock) { currentReadingBlock = underlyingStream.ReadBlock(startingBlock); } int blockRead = (int)Math.Min(currentReadingBlock.TotalStreamLength - Position, currentBlockSize - bufferOffset); int actualRead = Math.Min(count, blockRead); Array.Copy(currentReadingBlock.Data, blockOffset, buffer, bufferOffset, actualRead); // We use the fact that a stream doesn't have to read all data in one go to avoid a loop here. Position += actualRead; return(actualRead); } }
/// <summary> /// Writes a block to its correct place in the file. /// The block's TotalStreamLength is saved as the total length of the stream IF AND ONLY IF the written block is the last block in the stream. /// </summary> public void WriteBlock(EncryptedFile.Block block, long size) { if (isReadonly) { throw new InvalidOperationException("The current stream is read-only."); } lock (locker) { if (block == null) { throw new ArgumentNullException("block"); } if (block.BlockNumber < 0) { throw new ArgumentOutOfRangeException("block", "Block number be non negative."); } if (block.Data == null || block.Data.Length != header.DecryptedBlockSize) { throw new ArgumentException("Block must have data with length == " + header.DecryptedBlockSize); } long position = header.GetPhysicalPositionFromBlockNumber(block.BlockNumber); if (stream.Length - EncryptedFile.Footer.FooterSize < position) { throw new InvalidOperationException("Write past end of file."); } stream.Position = position; var encrypted = settings.Codec.EncodeBlock(key, block.Data); Debug.Assert(encrypted.Data.Length == header.EncryptedBlockSize); stream.Write(encrypted.IV, 0, encrypted.IV.Length); stream.Write(encrypted.Data, 0, encrypted.Data.Length); totalUnencryptedSize += size; if (stream.Length <= stream.Position + EncryptedFile.Footer.FooterSize) { footer.TotalLength = block.TotalEncryptedStreamLength; WriteFooterInCurrentPosition(footer); } } }
public override int Read(byte[] buffer, int bufferOffset, int count) { //precaution, should never be true if (underlyingStream.Header.MagicNumber != EncryptedFile.WithTotalSizeMagicNumber && underlyingStream.Header.MagicNumber != EncryptedFile.DefaultMagicNumber) throw new ApplicationException("Invalid magic number in the encrypted file. Cannot proceed with reading."); if (buffer == null) throw new ArgumentNullException("buffer"); if (count < 0) throw new ArgumentOutOfRangeException("count"); if (bufferOffset + count > buffer.LongLength) throw new ArgumentOutOfRangeException("bufferOffset"); if (count == 0) return 0; lock (locker) { // If the stream is used for both reading and writing, make sure we're reading everything that was written WriteAnyUnwrittenData(); if (Position >= underlyingStream.Footer.TotalLength && underlyingStream.Header.MagicNumber == EncryptedFile.DefaultMagicNumber) return 0; if (Position >= underlyingStream.Header.TotalUnencryptedSize && underlyingStream.Header.MagicNumber == EncryptedFile.WithTotalSizeMagicNumber) return 0; if (underlyingStream.Header.MagicNumber != EncryptedFile.WithTotalSizeMagicNumber && underlyingStream.Header.MagicNumber != EncryptedFile.DefaultMagicNumber) throw new ApplicationException("Invalid magic number in the encrypted file. Cannot proceed with reading."); var startingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position); var blockOffset = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Position); if (currentReadingBlock == null || currentReadingBlock.BlockNumber != startingBlock) { currentReadingBlock = underlyingStream.ReadBlock(startingBlock); } int blockRead; if (underlyingStream.Header.MagicNumber == EncryptedFile.DefaultMagicNumber) { blockRead = (int) Math.Min(currentReadingBlock.TotalEncryptedStreamLength - Position, currentBlockSize - blockOffset); } else { blockRead = (int) Math.Min(underlyingStream.Header.TotalUnencryptedSize - Position, currentBlockSize - blockOffset); } var actualRead = Math.Min(count, blockRead); Array.Copy(currentReadingBlock.Data, blockOffset, buffer, bufferOffset, actualRead); // We use the fact that a stream doesn't have to read all data in one go to avoid a loop here. Position += actualRead; return actualRead; } }
public override void Write(byte[] buffer, int bufferOffset, int count) { if (isReadonly) throw new InvalidOperationException("The current stream is read-only."); if (buffer == null) throw new ArgumentNullException("buffer"); if (count < 0) throw new ArgumentOutOfRangeException("count"); if (bufferOffset + count > buffer.LongLength) throw new ArgumentOutOfRangeException("bufferOffset"); if (count == 0) return; lock (locker) { while (true) { long startingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position); long endingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position + count - 1); long blockOffset = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Position); if (currentWritingBlock == null || currentWritingBlock.BlockNumber != startingBlock) // If we're writing into a different block than the one that's currently in memory { WriteAnyUnwrittenData(); if (blockOffset != 0 || count < currentBlockSize) { // Read the existing block from the underlying stream, as we're only changing part of it currentWritingBlock = underlyingStream.ReadBlock(startingBlock); var lastBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Length); if (lastBlock == startingBlock) { // this is the last block, it may not be a full one, so we need to make sure that it // the actual size reflect that currentWritingBlockUsage = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Length); } else { currentWritingBlockUsage = currentWritingBlock.Data.Length;// full size } } else { // We're writing the entire block in one go currentWritingBlock = new EncryptedFile.Block { BlockNumber = startingBlock, Data = new byte[currentBlockSize], TotalEncryptedStreamLength = underlyingStream.Footer.TotalLength }; currentWritingBlockUsage = 0; } } if (startingBlock == endingBlock) // If the entire write is done to the same block { currentWritingBlockUsage = Math.Max(currentWritingBlockUsage, blockOffset + count); Array.Copy(buffer, bufferOffset, currentWritingBlock.Data, blockOffset, count); Position += count; break; } var countInCurrentBlock = currentBlockSize - (int)blockOffset; currentWritingBlockUsage = Math.Max(currentWritingBlockUsage, blockOffset + countInCurrentBlock); Array.Copy(buffer, bufferOffset, currentWritingBlock.Data, blockOffset, countInCurrentBlock); Position += countInCurrentBlock; // Write the next block from the same buffer bufferOffset += countInCurrentBlock; count -= countInCurrentBlock; } } }
public override int Read(byte[] buffer, int bufferOffset, int count) { //precaution, should never be true if (underlyingStream.Header.MagicNumber != EncryptedFile.WithTotalSizeMagicNumber && underlyingStream.Header.MagicNumber != EncryptedFile.DefaultMagicNumber) { throw new ApplicationException("Invalid magic number in the encrypted file. Cannot proceed with reading."); } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (bufferOffset + count > buffer.LongLength) { throw new ArgumentOutOfRangeException("bufferOffset"); } if (count == 0) { return(0); } lock (locker) { // If the stream is used for both reading and writing, make sure we're reading everything that was written WriteAnyUnwrittenData(); if (Position >= underlyingStream.Footer.TotalLength && underlyingStream.Header.MagicNumber == EncryptedFile.DefaultMagicNumber) { return(0); } if (Position >= underlyingStream.Header.TotalUnencryptedSize && underlyingStream.Header.MagicNumber == EncryptedFile.WithTotalSizeMagicNumber) { return(0); } if (underlyingStream.Header.MagicNumber != EncryptedFile.WithTotalSizeMagicNumber && underlyingStream.Header.MagicNumber != EncryptedFile.DefaultMagicNumber) { throw new ApplicationException("Invalid magic number in the encrypted file. Cannot proceed with reading."); } var startingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position); var blockOffset = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Position); if (currentReadingBlock == null || currentReadingBlock.BlockNumber != startingBlock) { currentReadingBlock = underlyingStream.ReadBlock(startingBlock); } var blockRead = (int)Math.Min(underlyingStream.Header.TotalUnencryptedSize - Position, currentBlockSize - blockOffset); var actualRead = Math.Min(count, blockRead); Array.Copy(currentReadingBlock.Data, blockOffset, buffer, bufferOffset, actualRead); // We use the fact that a stream doesn't have to read all data in one go to avoid a loop here. Position += actualRead; return(actualRead); } }
public override void Write(byte[] buffer, int bufferOffset, int count) { if (isReadonly) { throw new InvalidOperationException("The current stream is read-only."); } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (bufferOffset + count > buffer.LongLength) { throw new ArgumentOutOfRangeException("bufferOffset"); } if (count == 0) { return; } lock (locker) { while (true) { long startingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position); long endingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position + count - 1); long blockOffset = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Position); if (currentWritingBlock == null || currentWritingBlock.BlockNumber != startingBlock) // If we're writing into a different block than the one that's currently in memory { WriteAnyUnwrittenData(); if (blockOffset != 0 || count < currentBlockSize) { // Read the existing block from the underlying stream, as we're only changing part of it currentWritingBlock = underlyingStream.ReadBlock(startingBlock); var lastBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Length); if (lastBlock == startingBlock) { // this is the last block, it may not be a full one, so we need to make sure that it // the actual size reflect that currentWritingBlockUsage = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Length); } else { currentWritingBlockUsage = currentWritingBlock.Data.Length; // full size } } else { // We're writing the entire block in one go currentWritingBlock = new EncryptedFile.Block { BlockNumber = startingBlock, Data = new byte[currentBlockSize], TotalEncryptedStreamLength = underlyingStream.Footer.TotalLength }; currentWritingBlockUsage = 0; } } if (startingBlock == endingBlock) // If the entire write is done to the same block { currentWritingBlockUsage = Math.Max(currentWritingBlockUsage, blockOffset + count); Array.Copy(buffer, bufferOffset, currentWritingBlock.Data, blockOffset, count); Position += count; break; } var countInCurrentBlock = currentBlockSize - (int)blockOffset; currentWritingBlockUsage = Math.Max(currentWritingBlockUsage, blockOffset + countInCurrentBlock); Array.Copy(buffer, bufferOffset, currentWritingBlock.Data, blockOffset, countInCurrentBlock); Position += countInCurrentBlock; // Write the next block from the same buffer bufferOffset += countInCurrentBlock; count -= countInCurrentBlock; } } }
public override void Write(byte[] buffer, int bufferOffset, int count) { if (isReadonly) { throw new InvalidOperationException("The current stream is read-only."); } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (bufferOffset + count > buffer.LongLength) { throw new ArgumentOutOfRangeException("bufferOffset"); } if (count == 0) { return; } lock (locker) { writeStart: long startingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position); long endingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position + count - 1); long blockOffset = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Position); if (currentWritingBlock == null || currentWritingBlock.BlockNumber != startingBlock) // If we're writing into a different block than the one that's currently in memory { WriteAnyUnwrittenData(); if (blockOffset != 0 || count < currentBlockSize) { // Read the existing block from the underlying stream, as we're only changing part of it currentWritingBlock = underlyingStream.ReadBlock(startingBlock); } else { // We're writing the entire block in one go currentWritingBlock = new EncryptedFile.Block { BlockNumber = startingBlock, Data = new byte[currentBlockSize], TotalStreamLength = underlyingStream.Footer.TotalLength }; } } if (startingBlock == endingBlock) // If the entire write is done to the same block { Array.Copy(buffer, bufferOffset, currentWritingBlock.Data, blockOffset, count); Position += count; } else { var countInCurrentBlock = currentBlockSize - bufferOffset; Array.Copy(buffer, bufferOffset, currentWritingBlock.Data, blockOffset, countInCurrentBlock); Position += countInCurrentBlock; // Write the next block from the same buffer bufferOffset += countInCurrentBlock; count -= countInCurrentBlock; goto writeStart; } } }
public override int Read(byte[] buffer, int bufferOffset, int count) { if (buffer == null) throw new ArgumentNullException("buffer"); if (count < 0) throw new ArgumentOutOfRangeException("count"); if (bufferOffset + count > buffer.LongLength) throw new ArgumentOutOfRangeException("bufferOffset"); if (count == 0) return 0; lock (locker) { // If the stream is used for both reading and writing, make sure we're reading everything that was written WriteAnyUnwrittenData(); if (Position >= underlyingStream.Footer.TotalLength) return 0; long startingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position); long blockOffset = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Position); if (currentReadingBlock == null || currentReadingBlock.BlockNumber != startingBlock) { currentReadingBlock = underlyingStream.ReadBlock(startingBlock); } int blockRead = (int)Math.Min(currentReadingBlock.TotalStreamLength - Position, currentBlockSize - blockOffset); int actualRead = Math.Min(count, blockRead); Array.Copy(currentReadingBlock.Data, blockOffset, buffer, bufferOffset, actualRead); // We use the fact that a stream doesn't have to read all data in one go to avoid a loop here. Position += actualRead; return actualRead; } }
public override void Write(byte[] buffer, int bufferOffset, int count) { if (isReadonly) throw new InvalidOperationException("The current stream is read-only."); if (buffer == null) throw new ArgumentNullException("buffer"); if (count < 0) throw new ArgumentOutOfRangeException("count"); if (bufferOffset + count > buffer.LongLength) throw new ArgumentOutOfRangeException("bufferOffset"); if (count == 0) return; lock (locker) { writeStart: long startingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position); long endingBlock = underlyingStream.Header.GetBlockNumberFromLogicalPosition(Position + count - 1); long blockOffset = underlyingStream.Header.GetBlockOffsetFromLogicalPosition(Position); if (currentWritingBlock == null || currentWritingBlock.BlockNumber != startingBlock) // If we're writing into a different block than the one that's currently in memory { WriteAnyUnwrittenData(); if (blockOffset != 0 || count < currentBlockSize) { // Read the existing block from the underlying stream, as we're only changing part of it currentWritingBlock = underlyingStream.ReadBlock(startingBlock); } else { // We're writing the entire block in one go currentWritingBlock = new EncryptedFile.Block { BlockNumber = startingBlock, Data = new byte[currentBlockSize], TotalStreamLength = underlyingStream.Footer.TotalLength }; } } if (startingBlock == endingBlock) // If the entire write is done to the same block { Array.Copy(buffer, bufferOffset, currentWritingBlock.Data, blockOffset, count); Position += count; } else { var countInCurrentBlock = currentBlockSize - bufferOffset; Array.Copy(buffer, bufferOffset, currentWritingBlock.Data, blockOffset, countInCurrentBlock); Position += countInCurrentBlock; // Write the next block from the same buffer bufferOffset += countInCurrentBlock; count -= countInCurrentBlock; goto writeStart; } } }