diff --git a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs index 5ceba087..8ce891f9 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Buffers.Binary; using System.IO; using System.Security.Cryptography; @@ -18,15 +19,17 @@ internal partial class WinzipAesCryptoStream : Stream private bool _isFinalBlock; private long _totalBytesLeftToRead; private bool _isDisposed; + private bool _useSyncOverAsyncDispose; internal WinzipAesCryptoStream( Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, - long length - ) + long length, + bool useSyncOverAsyncDispose) { _stream = stream; _totalBytesLeftToRead = length; + _useSyncOverAsyncDispose = useSyncOverAsyncDispose; #if DEBUG_STREAMS this.DebugConstruct(typeof(WinzipAesCryptoStream)); @@ -75,20 +78,30 @@ internal partial class WinzipAesCryptoStream : Stream if (disposing) { // Read out last 10 auth bytes - catch exceptions for async-only streams - try - { - Span ten = stackalloc byte[10]; - _stream.ReadFully(ten); - } - catch (NotSupportedException) - { - // Stream may be async-only, auth bytes will be skipped - // This is acceptable when the entire stream has been read - } + if (_useSyncOverAsyncDispose) + { + var ten = ArrayPool.Shared.Rent(10); + try { + _stream.ReadFullyAsync(ten, 0, 10).GetAwaiter().GetResult(); + } finally { + ArrayPool.Shared.Return(ten); + } + } + else + { + Span ten = stackalloc byte[10]; + _stream.ReadFully(ten); + } _stream.Dispose(); } } + private async Task ReadAuthBytesAsync() + { + byte[] authBytes = new byte[10]; + await _stream.ReadFullyAsync(authBytes, 0, 10).ConfigureAwait(false); + } + public override void Flush() { } public override int Read(byte[] buffer, int offset, int count) diff --git a/src/SharpCompress/Common/Zip/ZipFilePart.Async.cs b/src/SharpCompress/Common/Zip/ZipFilePart.Async.cs index 61c6e8e2..dbb9b322 100644 --- a/src/SharpCompress/Common/Zip/ZipFilePart.Async.cs +++ b/src/SharpCompress/Common/Zip/ZipFilePart.Async.cs @@ -99,10 +99,15 @@ internal abstract partial class ZipFilePart { if (Header.WinzipAesEncryptionData != null) { + var useSyncOverAsync = false; +#if LEGACY_DOTNET + useSyncOverAsync = true; +#endif return new WinzipAesCryptoStream( plainStream, Header.WinzipAesEncryptionData, - Header.CompressedSize - 10 + Header.CompressedSize - 10, + useSyncOverAsync ); } return plainStream; diff --git a/src/SharpCompress/Common/Zip/ZipFilePart.cs b/src/SharpCompress/Common/Zip/ZipFilePart.cs index 88822249..43eac529 100644 --- a/src/SharpCompress/Common/Zip/ZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/ZipFilePart.cs @@ -270,7 +270,8 @@ internal abstract partial class ZipFilePart : FilePart return new WinzipAesCryptoStream( plainStream, Header.WinzipAesEncryptionData, - Header.CompressedSize - 10 + Header.CompressedSize - 10, + false ); } return plainStream; diff --git a/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs index c93552cf..ece913bf 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; +using SharpCompress.Archives; using SharpCompress.Common; using SharpCompress.IO; using SharpCompress.Readers; @@ -252,14 +253,14 @@ public class ZipReaderAsyncTests : ReaderTests File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip")) ) ) - using ( - IReader baseReader = ZipReader.OpenReader( + + await using ( + var reader = await ReaderFactory.OpenAsyncReader( stream, new ReaderOptions { Password = "test" } ) ) { - IAsyncReader reader = (IAsyncReader)baseReader; while (await reader.MoveToNextEntryAsync()) { if (!reader.Entry.IsDirectory) @@ -284,14 +285,13 @@ public class ZipReaderAsyncTests : ReaderTests File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "zipcrypto.zip")) ) ) - using ( - IReader baseReader = ZipReader.OpenReader( + await using ( + var reader = await ReaderFactory.OpenAsyncReader( stream, new ReaderOptions { Password = "test" } ) ) { - IAsyncReader reader = (IAsyncReader)baseReader; while (await reader.MoveToNextEntryAsync()) { if (!reader.Entry.IsDirectory)