diff --git a/src/SharpCompress/Archives/AbstractArchive.cs b/src/SharpCompress/Archives/AbstractArchive.cs index 587e0f04..c84bd41a 100644 --- a/src/SharpCompress/Archives/AbstractArchive.cs +++ b/src/SharpCompress/Archives/AbstractArchive.cs @@ -173,8 +173,7 @@ public abstract class AbstractArchive : IArchive, IArchiveExtra } } - public virtual bool IsMultiVolume => - Volumes.Count > 1 || _sourceStream?.Files.Count > 1 || _sourceStream?.Streams.Count > 1; + public virtual bool IsMultiVolume =>_sourceStream?.Files.Count > 1 || _sourceStream?.Streams.Count > 1; public virtual bool SupportsMultiThreading => false; } diff --git a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs index 1d524cd9..ee9e8dba 100644 --- a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs @@ -124,10 +124,10 @@ public static class IArchiveEntryExtensions entry, destinationFileName, options, - async (x, fm) => + async (x, fm, ct) => { using var fs = File.Open(destinationFileName, fm); - await entry.WriteToAsync(fs, cancellationToken).ConfigureAwait(false); + await entry.WriteToAsync(fs, ct).ConfigureAwait(false); }, cancellationToken ); diff --git a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs b/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs deleted file mode 100644 index 65f31d01..00000000 --- a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.IO; -using SharpCompress.Readers; - -namespace SharpCompress.Archives.Rar; - -/// -/// A rar part based on a FileInfo object -/// -internal class FileInfoRarArchiveVolume : RarVolume -{ - internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options, int index) - : base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options), index) - { - FileInfo = fileInfo; - FileParts = GetVolumeFileParts().ToArray().ToReadOnly(); - } - - private static ReaderOptions FixOptions(ReaderOptions options) - { - //make sure we're closing streams with fileinfo - options.LeaveStreamOpen = false; - return options; - } - - internal ReadOnlyCollection FileParts { get; } - - internal FileInfo FileInfo { get; } - - internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) => - new FileInfoRarFilePart(this, ReaderOptions.Password, markHeader, fileHeader, FileInfo); - - internal override IEnumerable ReadFileParts() => FileParts; -} diff --git a/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs b/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs deleted file mode 100644 index 02d2f769..00000000 --- a/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.IO; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Archives.Rar; - -internal sealed class FileInfoRarFilePart : SeekableFilePart -{ - internal FileInfoRarFilePart( - FileInfoRarArchiveVolume volume, - string? password, - MarkHeader mh, - FileHeader fh, - FileInfo fi - ) - : base(mh, fh, volume.Index, volume.Stream, password) => FileInfo = fi; - - internal FileInfo FileInfo { get; } - - internal override string FilePartName => - "Rar File: " + FileInfo.FullName + " File Entry: " + FileHeader.FileName; -} diff --git a/src/SharpCompress/Archives/Rar/RarArchive.cs b/src/SharpCompress/Archives/Rar/RarArchive.cs index b3689a9f..5354de15 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.cs @@ -47,9 +47,9 @@ public class RarArchive : AbstractArchive { sourceStream.LoadAllParts(); //request all streams var streams = sourceStream.Streams.ToArray(); - var i = 0; if (streams.Length > 1 && IsRarFile(streams[1], ReaderOptions)) //test part 2 - true = multipart not split { + var i = 0; sourceStream.IsVolumes = true; streams[1].Position = 0; sourceStream.Position = 0; @@ -57,12 +57,12 @@ public class RarArchive : AbstractArchive return sourceStream.Streams.Select(a => new StreamRarArchiveVolume( a, ReaderOptions, - i++ + i++, IsMultiVolume )); } //split mode or single file - return new StreamRarArchiveVolume(sourceStream, ReaderOptions, i++).AsEnumerable(); + return new StreamRarArchiveVolume(sourceStream, ReaderOptions, 0, IsMultiVolume).AsEnumerable(); } protected override IReader CreateReaderForSolidExtraction() @@ -83,6 +83,7 @@ public class RarArchive : AbstractArchive } public override bool IsSolid => Volumes.First().IsSolidArchive; + public override bool SupportsMultiThreading => !IsMultiVolume && !IsSolid; public virtual int MinVersion => Volumes.First().MinVersion; public virtual int MaxVersion => Volumes.First().MaxVersion; diff --git a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs index aaba6d1e..48b384e3 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs @@ -134,4 +134,7 @@ public class RarArchiveEntry : RarEntry, IArchiveEntry ); } } + + + public override bool SupportsMultiThreading => Parts.Single().SupportsMultiThreading; } diff --git a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs b/src/SharpCompress/Archives/Rar/SeekableRarFilePart.cs similarity index 73% rename from src/SharpCompress/Archives/Rar/SeekableFilePart.cs rename to src/SharpCompress/Archives/Rar/SeekableRarFilePart.cs index 97822d90..9e3f960c 100644 --- a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs +++ b/src/SharpCompress/Archives/Rar/SeekableRarFilePart.cs @@ -1,25 +1,28 @@ using System.IO; using SharpCompress.Common.Rar; using SharpCompress.Common.Rar.Headers; +using SharpCompress.IO; namespace SharpCompress.Archives.Rar; -internal class SeekableFilePart : RarFilePart +internal class SeekableRarFilePart : RarFilePart { private readonly Stream _stream; private readonly string? _password; + private readonly bool _isMultiVolume; - internal SeekableFilePart( + internal SeekableRarFilePart( MarkHeader mh, FileHeader fh, int index, Stream stream, - string? password - ) + string? password, + bool isMultiVolume) : base(mh, fh, index) { _stream = stream; _password = password; + _isMultiVolume = isMultiVolume; } internal override Stream GetCompressedStream() @@ -42,4 +45,7 @@ internal class SeekableFilePart : RarFilePart } internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName; + + public override bool SupportsMultiThreading => + !_isMultiVolume && _stream is SourceStream ss && ss.IsFileMode && ss.Files.Count == 1; } diff --git a/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs b/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs index 60cbab9a..d504dae4 100644 --- a/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs +++ b/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs @@ -9,11 +9,15 @@ namespace SharpCompress.Archives.Rar; internal class StreamRarArchiveVolume : RarVolume { - internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index) - : base(StreamingMode.Seekable, stream, options, index) { } + private readonly bool _isMultiVolume; + internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index, bool isMultiVolume) + : base(StreamingMode.Seekable, stream, options, index) + { + _isMultiVolume = isMultiVolume; + } internal override IEnumerable ReadFileParts() => GetVolumeFileParts(); internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) => - new SeekableFilePart(markHeader, fileHeader, Index, Stream, ReaderOptions.Password); + new SeekableRarFilePart(markHeader, fileHeader, Index, Stream, ReaderOptions.Password, _isMultiVolume); } diff --git a/src/SharpCompress/Common/ExtractionMethods.cs b/src/SharpCompress/Common/ExtractionMethods.cs index 2b5640e0..1fafe48b 100644 --- a/src/SharpCompress/Common/ExtractionMethods.cs +++ b/src/SharpCompress/Common/ExtractionMethods.cs @@ -201,7 +201,7 @@ internal static class ExtractionMethods IEntry entry, string destinationFileName, ExtractionOptions? options, - Func openAndWriteAsync, + Func openAndWriteAsync, CancellationToken cancellationToken = default ) { @@ -225,7 +225,7 @@ internal static class ExtractionMethods fm = FileMode.CreateNew; } - await openAndWriteAsync(destinationFileName, fm).ConfigureAwait(false); + await openAndWriteAsync(destinationFileName, fm, cancellationToken).ConfigureAwait(false); entry.PreserveExtractionOptions(destinationFileName, options); } } diff --git a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs index d20fecd0..daaa2886 100644 --- a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs +++ b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs @@ -62,10 +62,6 @@ internal sealed class MultiVolumeReadOnlyStream : Stream, IStreamStack base.Dispose(disposing); if (disposing) { -#if DEBUG_STREAMS - this.DebugDispose(typeof(MultiVolumeReadOnlyStream)); -#endif - if (filePartEnumerator != null) { filePartEnumerator.Dispose(); diff --git a/src/SharpCompress/Compressors/Rar/RarStream.cs b/src/SharpCompress/Compressors/Rar/RarStream.cs index ca718d61..0611c0c4 100644 --- a/src/SharpCompress/Compressors/Rar/RarStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarStream.cs @@ -82,9 +82,6 @@ internal class RarStream : Stream, IStreamStack { if (disposing) { -#if DEBUG_STREAMS - this.DebugDispose(typeof(RarStream)); -#endif ArrayPool.Shared.Return(this.tmpBuffer); this.tmpBuffer = null; } diff --git a/src/SharpCompress/Readers/IReaderExtensions.cs b/src/SharpCompress/Readers/IReaderExtensions.cs index 329e8def..652269bc 100644 --- a/src/SharpCompress/Readers/IReaderExtensions.cs +++ b/src/SharpCompress/Readers/IReaderExtensions.cs @@ -101,10 +101,10 @@ public static class IReaderExtensions reader.Entry, destinationFileName, options, - async (x, fm) => + async (x, fm, ct) => { using var fs = File.Open(destinationFileName, fm); - await reader.WriteEntryToAsync(fs, cancellationToken).ConfigureAwait(false); + await reader.WriteEntryToAsync(fs, ct).ConfigureAwait(false); }, cancellationToken ) diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index e685bb73..5946a967 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -277,13 +277,10 @@ public class ArchiveTests : ReaderTests var tasks = new List(); using (var archive = archiveFactory.Open(new FileInfo(testArchive), readerOptions)) { + Assert.True(archive.SupportsMultiThreading); foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - if (archive.SupportsMultiThreading) - { Assert.True(entry.SupportsMultiThreading); - } - var t = entry.WriteToDirectoryAsync( SCRATCH_FILES_PATH, new ExtractionOptions { ExtractFullPath = true, Overwrite = true } @@ -306,11 +303,6 @@ public class ArchiveTests : ReaderTests { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - if (archive.SupportsMultiThreading) - { - Assert.True(entry.SupportsMultiThreading); - } - entry.WriteToDirectory( SCRATCH_FILES_PATH, new ExtractionOptions { ExtractFullPath = true, Overwrite = true } diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs index 1aca13dd..ce2a4231 100644 --- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs +++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs @@ -1,5 +1,6 @@ using System.IO; using System.Linq; +using System.Threading.Tasks; using SharpCompress.Archives; using SharpCompress.Archives.Rar; using SharpCompress.Common; @@ -291,9 +292,13 @@ public class RarArchiveTests : ArchiveTests [Fact] public void Rar_ArchiveFileRead() => ArchiveFileRead("Rar.rar"); + [Fact] + public Task Rar_ArchiveFileRead_Multithreaded() => ArchiveFileRead_Multithreaded("Rar.rar"); [Fact] public void Rar5_ArchiveFileRead() => ArchiveFileRead("Rar5.rar"); + [Fact] + public Task Rar5_ArchiveFileRead_Multithreaded() => ArchiveFileRead_Multithreaded("Rar5.rar"); [Fact] public void Rar_ArchiveFileRead_HasDirectories() => @@ -358,6 +363,8 @@ public class RarArchiveTests : ArchiveTests [Fact] public void Rar2_ArchiveFileRead() => ArchiveFileRead("Rar2.rar"); + [Fact] + public Task Rar2_ArchiveFileRead_Multithreaded() => ArchiveFileRead_Multithreaded("Rar2.rar"); [Fact] public void Rar15_ArchiveFileRead()