Skip to content

Commit 249a17b

Browse files
Add branching and specific SharpCompress calls for solid vs non-solid archives in order to extract solid archives properly. (#375)
* Add branching for solid vs non-solid archives in order to extract solid archives properly. * Change comments on sevenzip, reuse archive-level solid flag for rar * Fully simplify identifying if archive is solid. * Finish implementing first round of feedback. * Fix second round of formatting issues. * Final formatting fixes.
1 parent dff15ef commit 249a17b

File tree

2 files changed

+144
-60
lines changed

2 files changed

+144
-60
lines changed

BinaryObjectScanner/FileType/RAR.cs

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#if NET462_OR_GREATER || NETCOREAPP
55
using SharpCompress.Archives;
66
using SharpCompress.Archives.Rar;
7+
using SharpCompress.Common;
78
using SharpCompress.Readers;
89
#endif
910

@@ -51,36 +52,11 @@ public bool Extract(Stream? stream, string file, string outDir, bool lookForHead
5152
if (!rarFile.IsComplete)
5253
return false;
5354

54-
foreach (var entry in rarFile.Entries)
55-
{
56-
try
57-
{
58-
// If the entry is a directory
59-
if (entry.IsDirectory)
60-
continue;
61-
62-
// If the entry has an invalid key
63-
if (entry.Key == null)
64-
continue;
65-
66-
// If we have a partial entry due to an incomplete multi-part archive, skip it
67-
if (!entry.IsComplete)
68-
continue;
69-
70-
string tempFile = Path.Combine(outDir, entry.Key);
71-
var directoryName = Path.GetDirectoryName(tempFile);
72-
if (directoryName != null && !Directory.Exists(directoryName))
73-
Directory.CreateDirectory(directoryName);
74-
75-
entry.WriteToFile(tempFile);
76-
}
77-
catch (Exception ex)
78-
{
79-
if (includeDebug) Console.WriteLine(ex);
80-
}
81-
}
55+
if (rarFile.IsSolid)
56+
return ExtractSolid(rarFile, outDir, includeDebug);
57+
else
58+
return ExtractNonSolid(rarFile, outDir, includeDebug);
8259

83-
return true;
8460
}
8561
catch (Exception ex)
8662
{
@@ -91,5 +67,71 @@ public bool Extract(Stream? stream, string file, string outDir, bool lookForHead
9167
return false;
9268
#endif
9369
}
70+
71+
#if NET462_OR_GREATER || NETCOREAPP
72+
73+
/// <summary>
74+
/// Extraction method for non-solid archives. This iterates over each entry in the archive to extract every
75+
/// file individually, in order to extract all valid files from the archive.
76+
/// </summary>
77+
private bool ExtractNonSolid(RarArchive rarFile, string outDir, bool includeDebug)
78+
{
79+
foreach (var entry in rarFile.Entries)
80+
{
81+
try
82+
{
83+
// If the entry is a directory
84+
if (entry.IsDirectory)
85+
continue;
86+
87+
// If the entry has an invalid key
88+
if (entry.Key == null)
89+
continue;
90+
91+
// If we have a partial entry due to an incomplete multi-part archive, skip it
92+
if (!entry.IsComplete)
93+
continue;
94+
95+
string tempFile = Path.Combine(outDir, entry.Key);
96+
var directoryName = Path.GetDirectoryName(tempFile);
97+
if (directoryName != null && !Directory.Exists(directoryName))
98+
Directory.CreateDirectory(directoryName);
99+
100+
entry.WriteToFile(tempFile);
101+
}
102+
catch (Exception ex)
103+
{
104+
if (includeDebug) Console.WriteLine(ex);
105+
}
106+
}
107+
return true;
108+
}
109+
110+
/// <summary>
111+
/// Extraction method for solid archives. Uses ExtractAllEntries because extraction for solid archives must be
112+
/// done sequentially, and files beyond a corrupted point in a solid archive will be unreadable anyways.
113+
/// </summary>
114+
private bool ExtractSolid(RarArchive rarFile, string outDir, bool includeDebug)
115+
{
116+
try
117+
{
118+
if (!Directory.Exists(outDir))
119+
Directory.CreateDirectory(outDir);
120+
121+
rarFile.WriteToDirectory(outDir, new ExtractionOptions()
122+
{
123+
ExtractFullPath = true,
124+
Overwrite = true,
125+
});
126+
127+
}
128+
catch (Exception ex)
129+
{
130+
if (includeDebug) Console.WriteLine(ex);
131+
}
132+
133+
return true;
134+
}
135+
#endif
94136
}
95-
}
137+
}

BinaryObjectScanner/FileType/SevenZip.cs

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#if NET462_OR_GREATER || NETCOREAPP
55
using SharpCompress.Archives;
66
using SharpCompress.Archives.SevenZip;
7+
using SharpCompress.Common;
78
using SharpCompress.Readers;
89
#endif
910

@@ -43,50 +44,91 @@ public bool Extract(Stream? stream, string file, string outDir, bool lookForHead
4344
{
4445
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
4546
var sevenZip = SevenZipArchive.Open(stream, readerOptions);
46-
4747
// Try to read the file path if no entries are found
4848
if (sevenZip.Entries.Count == 0 && !string.IsNullOrEmpty(file) && File.Exists(file))
4949
sevenZip = SevenZipArchive.Open(file, readerOptions);
5050

51-
foreach (var entry in sevenZip.Entries)
51+
// Currently doesn't flag solid 7z archives with only 1 solid block as solid, but practically speaking
52+
// this is not much of a concern.
53+
if (sevenZip.IsSolid)
54+
return ExtractSolid(sevenZip, outDir, includeDebug);
55+
else
56+
return ExtractNonSolid(sevenZip, outDir, includeDebug);
57+
58+
}
59+
catch (Exception ex)
60+
{
61+
if (includeDebug) Console.WriteLine(ex);
62+
return false;
63+
}
64+
#else
65+
return false;
66+
#endif
67+
}
68+
69+
#if NET462_OR_GREATER || NETCOREAPP
70+
/// <summary>
71+
/// Extraction method for non-solid archives. This iterates over each entry in the archive to extract every
72+
/// file individually, in order to extract all valid files from the archive.
73+
/// </summary>
74+
private bool ExtractNonSolid(SevenZipArchive sevenZip, string outDir, bool includeDebug)
75+
{
76+
foreach (var entry in sevenZip.Entries)
77+
{
78+
try
5279
{
53-
try
54-
{
55-
// If the entry is a directory
56-
if (entry.IsDirectory)
57-
continue;
80+
// If the entry is a directory
81+
if (entry.IsDirectory)
82+
continue;
5883

59-
// If the entry has an invalid key
60-
if (entry.Key == null)
61-
continue;
84+
// If the entry has an invalid key
85+
if (entry.Key == null)
86+
continue;
6287

63-
// If we have a partial entry due to an incomplete multi-part archive, skip it
64-
if (!entry.IsComplete)
65-
continue;
88+
// If we have a partial entry due to an incomplete multi-part archive, skip it
89+
if (!entry.IsComplete)
90+
continue;
6691

67-
string tempFile = Path.Combine(outDir, entry.Key);
68-
var directoryName = Path.GetDirectoryName(tempFile);
69-
if (directoryName != null && !Directory.Exists(directoryName))
70-
Directory.CreateDirectory(directoryName);
92+
string tempFile = Path.Combine(outDir, entry.Key);
93+
var directoryName = Path.GetDirectoryName(tempFile);
94+
if (directoryName != null && !Directory.Exists(directoryName))
95+
Directory.CreateDirectory(directoryName);
7196

72-
entry.WriteToFile(tempFile);
73-
}
74-
catch (Exception ex)
75-
{
76-
if (includeDebug) Console.WriteLine(ex);
77-
}
97+
entry.WriteToFile(tempFile);
98+
}
99+
catch (Exception ex)
100+
{
101+
if (includeDebug) Console.WriteLine(ex);
78102
}
79-
80-
return true;
103+
}
104+
return true;
105+
}
106+
107+
/// <summary>
108+
/// Extraction method for solid archives. Uses ExtractAllEntries because extraction for solid archives must be
109+
/// done sequentially, and files beyond a corrupted point in a solid archive will be unreadable anyways.
110+
/// </summary>
111+
private bool ExtractSolid(SevenZipArchive sevenZip, string outDir, bool includeDebug)
112+
{
113+
try
114+
{
115+
if (!Directory.Exists(outDir))
116+
Directory.CreateDirectory(outDir);
117+
118+
sevenZip.WriteToDirectory(outDir, new ExtractionOptions()
119+
{
120+
ExtractFullPath = true,
121+
Overwrite = true,
122+
});
123+
81124
}
82125
catch (Exception ex)
83126
{
84127
if (includeDebug) Console.WriteLine(ex);
85-
return false;
86128
}
87-
#else
88-
return false;
89-
#endif
129+
130+
return true;
90131
}
132+
#endif
91133
}
92-
}
134+
}

0 commit comments

Comments
 (0)