Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,12 @@ private static async Task ExtractToDirectoryAsync(string sourceArchiveFileName,
ZipArchive archive = await OpenAsync(sourceArchiveFileName, ZipArchiveMode.Read, entryNameEncoding, cancellationToken).ConfigureAwait(false);
await using (archive.ConfigureAwait(false))
{
string? destinationDirectoryFullPath = null;
foreach (ZipArchiveEntry entry in archive.Entries)
{
cancellationToken.ThrowIfCancellationRequested();
await entry.ExtractRelativeToDirectoryAsync(destinationDirectoryName, overwriteFiles, password, cancellationToken).ConfigureAwait(false);
destinationDirectoryFullPath ??= ZipFileExtensions.GetDestinationDirectoryFullPath(destinationDirectoryName);
await entry.ExtractRelativeToDirectoryAsync(destinationDirectoryFullPath, overwriteFiles, password, cancellationToken).ConfigureAwait(false);
}
}
}
Expand Down Expand Up @@ -488,10 +490,12 @@ private static async Task ExtractToDirectoryAsync(Stream source, string destinat
ZipArchive archive = await ZipArchive.CreateAsync(source, ZipArchiveMode.Read, leaveOpen: true, entryNameEncoding, cancellationToken).ConfigureAwait(false);
await using (archive.ConfigureAwait(false))
{
string? destinationDirectoryFullPath = null;
foreach (ZipArchiveEntry entry in archive.Entries)
{
cancellationToken.ThrowIfCancellationRequested();
await entry.ExtractRelativeToDirectoryAsync(destinationDirectoryName, overwriteFiles, password, cancellationToken).ConfigureAwait(false);
destinationDirectoryFullPath ??= ZipFileExtensions.GetDestinationDirectoryFullPath(destinationDirectoryName);
await entry.ExtractRelativeToDirectoryAsync(destinationDirectoryFullPath, overwriteFiles, password, cancellationToken).ConfigureAwait(false);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,11 @@ private static void ExtractToDirectory(string sourceArchiveFileName, string dest
ArgumentNullException.ThrowIfNull(sourceArchiveFileName);

using ZipArchive archive = Open(sourceArchiveFileName, ZipArchiveMode.Read, entryNameEncoding);
string? destinationDirectoryFullPath = null;
foreach (ZipArchiveEntry entry in archive.Entries)
{
entry.ExtractRelativeToDirectory(destinationDirectoryName, overwriteFiles, password);
destinationDirectoryFullPath ??= ZipFileExtensions.GetDestinationDirectoryFullPath(destinationDirectoryName);
entry.ExtractRelativeToDirectory(destinationDirectoryFullPath, overwriteFiles, password);
}
}

Expand Down Expand Up @@ -438,9 +440,11 @@ private static void ExtractToDirectory(Stream source, string destinationDirector
}

using ZipArchive archive = new ZipArchive(source, ZipArchiveMode.Read, leaveOpen: true, entryNameEncoding);
string? destinationDirectoryFullPath = null;
foreach (ZipArchiveEntry entry in archive.Entries)
{
entry.ExtractRelativeToDirectory(destinationDirectoryName, overwriteFiles, password);
destinationDirectoryFullPath ??= ZipFileExtensions.GetDestinationDirectoryFullPath(destinationDirectoryName);
entry.ExtractRelativeToDirectory(destinationDirectoryFullPath, overwriteFiles, password);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,11 @@ public static async Task ExtractToDirectoryAsync(this ZipArchive source, string
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(destinationDirectoryName);

string? destinationDirectoryFullPath = null;
foreach (ZipArchiveEntry entry in source.Entries)
{
await entry.ExtractRelativeToDirectoryAsync(destinationDirectoryName, overwriteFiles, cancellationToken: cancellationToken).ConfigureAwait(false);
destinationDirectoryFullPath ??= ZipFileExtensions.GetDestinationDirectoryFullPath(destinationDirectoryName);
await entry.ExtractRelativeToDirectoryAsync(destinationDirectoryFullPath, overwriteFiles, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}

Expand All @@ -94,10 +96,12 @@ public static async Task ExtractToDirectoryAsync(this ZipArchive source, string

cancellationToken.ThrowIfCancellationRequested();

string? destinationDirectoryFullPath = null;
foreach (ZipArchiveEntry entry in source.Entries)
{
cancellationToken.ThrowIfCancellationRequested();
await entry.ExtractRelativeToDirectoryAsync(destinationDirectoryName, options.OverwriteFiles, options.Password, cancellationToken).ConfigureAwait(false);
destinationDirectoryFullPath ??= ZipFileExtensions.GetDestinationDirectoryFullPath(destinationDirectoryName);
await entry.ExtractRelativeToDirectoryAsync(destinationDirectoryFullPath, options.OverwriteFiles, options.Password, cancellationToken).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ public static void ExtractToDirectory(this ZipArchive source, string destination
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(destinationDirectoryName);

string? destinationDirectoryFullPath = null;
foreach (ZipArchiveEntry entry in source.Entries)
{
entry.ExtractRelativeToDirectory(destinationDirectoryName, overwriteFiles);
destinationDirectoryFullPath ??= GetDestinationDirectoryFullPath(destinationDirectoryName);
entry.ExtractRelativeToDirectory(destinationDirectoryFullPath, overwriteFiles);
}
}

Expand All @@ -87,9 +89,11 @@ public static void ExtractToDirectory(this ZipArchive source, string destination
ArgumentNullException.ThrowIfNull(destinationDirectoryName);
ArgumentNullException.ThrowIfNull(options);

string? destinationDirectoryFullPath = null;
foreach (ZipArchiveEntry entry in source.Entries)
{
entry.ExtractRelativeToDirectory(destinationDirectoryName, options.OverwriteFiles, options.Password.Span);
destinationDirectoryFullPath ??= GetDestinationDirectoryFullPath(destinationDirectoryName);
entry.ExtractRelativeToDirectory(destinationDirectoryFullPath, options.OverwriteFiles, options.Password.Span);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,11 @@ private static async Task ExtractToFileAsync(ZipArchiveEntry source, string dest
}
}

internal static async Task ExtractRelativeToDirectoryAsync(this ZipArchiveEntry source, string destinationDirectoryName, bool overwrite, ReadOnlyMemory<char> password = default, CancellationToken cancellationToken = default)
internal static async Task ExtractRelativeToDirectoryAsync(this ZipArchiveEntry source, string destinationDirectoryFullPath, bool overwrite, ReadOnlyMemory<char> password = default, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();

if (ExtractRelativeToDirectoryCheckIfFile(source, destinationDirectoryName, out string fileDestinationPath))
if (ExtractRelativeToDirectoryCheckIfFile(source, destinationDirectoryFullPath, out string fileDestinationPath))
{
// If it is a file:
// Create containing directory:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,10 @@ private static void ExtractToFileInitialize(ZipArchiveEntry source, string desti
private static void ExtractToFileFinalize(ZipArchiveEntry source, string destinationFileName) =>
ArchivingUtils.AttemptSetLastWriteTime(destinationFileName, source.LastWriteTime);

private static bool ExtractRelativeToDirectoryCheckIfFile(ZipArchiveEntry source, string destinationDirectoryName, out string fileDestinationPath)
// Computes the normalized destination directory root once per extraction call, so that it can be
// reused across all entries instead of being recomputed for every single one.
internal static string GetDestinationDirectoryFullPath(string destinationDirectoryName)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(destinationDirectoryName);

// Note that this will give us a good DirectoryInfo even if destinationDirectoryName exists:
Expand All @@ -226,6 +227,14 @@ private static bool ExtractRelativeToDirectoryCheckIfFile(ZipArchiveEntry source
destinationDirectoryFullPath = string.Concat(destinationDirectoryFullPath, new ReadOnlySpan<char>(in sep));
}

return destinationDirectoryFullPath;
}

private static bool ExtractRelativeToDirectoryCheckIfFile(ZipArchiveEntry source, string destinationDirectoryFullPath, out string fileDestinationPath)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(destinationDirectoryFullPath);

fileDestinationPath = Path.GetFullPath(Path.Combine(destinationDirectoryFullPath, ArchivingUtils.SanitizeEntryFilePath(source.FullName)));

if (!fileDestinationPath.StartsWith(destinationDirectoryFullPath, PathInternal.StringComparison))
Expand All @@ -248,9 +257,9 @@ private static bool ExtractRelativeToDirectoryCheckIfFile(ZipArchiveEntry source
return true; // It is a file
}

internal static void ExtractRelativeToDirectory(this ZipArchiveEntry source, string destinationDirectoryName, bool overwrite, ReadOnlySpan<char> password = default)
internal static void ExtractRelativeToDirectory(this ZipArchiveEntry source, string destinationDirectoryFullPath, bool overwrite, ReadOnlySpan<char> password = default)
{
if (ExtractRelativeToDirectoryCheckIfFile(source, destinationDirectoryName, out string fileDestinationPath))
if (ExtractRelativeToDirectoryCheckIfFile(source, destinationDirectoryFullPath, out string fileDestinationPath))
{
// If it is a file:
// Create containing directory:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ public async Task ExtractToDirectoryNormal(string file, string folder, bool asyn
await DirsEqual(tempFolder.Path, folderName);
}

[Theory]
[MemberData(nameof(Get_Booleans_Data))]
public async Task ExtractToDirectory_EmptyArchive_DoesNotCreateNonExistentDestinationDirectory(bool async)
{
string zipFileName = zfile("empty.zip");
string destinationDirectoryName = GetTestFilePath();

Assert.False(Directory.Exists(destinationDirectoryName));
await CallZipFileExtractToDirectory(async, zipFileName, destinationDirectoryName);
Assert.False(Directory.Exists(destinationDirectoryName));
}

[Theory]
[MemberData(nameof(Get_Booleans_Data))]
public async Task ExtractToDirectoryNull(bool async)
Expand Down
Loading