Skip to content
Merged
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 @@ -4,7 +4,7 @@ Author="Microsoft Corporation"
CompanyName="Microsoft Corporation"
Copyright="© Microsoft Corporation. All rights reserved."
Description='PowerShell module for working with ZIP archives.'
ModuleVersion="1.2.2.0"
ModuleVersion="1.2.3.0"
PowerShellVersion="3.0"
FunctionsToExport = @('Compress-Archive', 'Expand-Archive')
DotNetFrameworkVersion = 4.5
Expand Down
55 changes: 51 additions & 4 deletions Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
data LocalizedData
data LocalizedData
{
# culture="en-US"
ConvertFrom-StringData @'
Expand Down Expand Up @@ -779,7 +779,7 @@ function ZipArchiveHelper

foreach($currentArchiveEntry in $zipArchive.Entries)
{
if($currentArchiveEntry.FullName -eq $relativeFilePath)
if(ArchivePathCompareHelper $currentArchiveEntry.FullName $relativeFilePath)
{
$entryToBeUpdated = $currentArchiveEntry
break
Expand Down Expand Up @@ -824,7 +824,8 @@ function ZipArchiveHelper
{
$srcStream = New-Object System.IO.BinaryReader $currentFileStream

$currentArchiveEntry = $zipArchive.CreateEntry($relativeFilePath, $compression)
$entryPath = DirectorySeparatorNormalizeHelper $relativeFilePath
$currentArchiveEntry = $zipArchive.CreateEntry($entryPath, $compression)

# Updating the File Creation time so that the same timestamp would be retained after expanding the compressed file.
# At this point we are sure that Get-ChildItem would succeed.
Expand Down Expand Up @@ -867,7 +868,8 @@ function ZipArchiveHelper
}
else
{
$currentArchiveEntry = $zipArchive.CreateEntry("$relativeFilePath", $compression)
$entryPath = DirectorySeparatorNormalizeHelper $relativeFilePath
$currentArchiveEntry = $zipArchive.CreateEntry($entryPath, $compression)
$numberOfItemsArchived += 1
$addItemtoArchiveFileMessage = ($LocalizedData.AddItemtoArchiveFile -f $currentFilePath)
}
Expand Down Expand Up @@ -988,6 +990,7 @@ function ExpandArchiveHelper
# The archive entries can either be empty directories or files.
foreach($currentArchiveEntry in $zipArchive.Entries)
{
# Windows filesystem provider will internally convert from `/` to `\`
$currentArchiveEntryPath = Join-Path -Path $expandedDir -ChildPath $currentArchiveEntry.FullName

# Remove possible relative segments from target
Expand Down Expand Up @@ -1263,3 +1266,47 @@ function CreateErrorRecordHelper
$errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $targetObject
return $errorRecord
}

<############################################################################################
# DirectorySeparatorNormalizeHelper: This is a helper function used to normalize separators
# when compressing archives, creating cross platform archives.
#
# The approach taken is leveraging the fact that .net on Windows all the way back to
# Framework 1.1 specifies `\` as DirectoryPathSeparatorChar and `/` as
# AltDirectoryPathSeparatorChar, while other platforms in .net Core use `/` for
# DirectoryPathSeparatorChar and AltDirectoryPathSeparatorChar. When using a *nix platform,
# the replacements will be no-ops, while Windows will convert all `\` to `/` for the
# purposes of the ZipEntry FullName.
############################################################################################>
function DirectorySeparatorNormalizeHelper
{
param
(
[string] $archivePath
)

if($null -eq $archivePath)
{
return $archivePath
}

return $archivePath.replace([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)
}

<############################################################################################
# ArchivePathCompareHelper: This is a helper function used to compare with normalized
# separators.
############################################################################################>
function ArchivePathCompareHelper
{
param
(
[string] $pathArgA,
[string] $pathArgB
)

$normalizedPathArgA = DirectorySeparatorNormalizeHelper $pathArgA
$normalizedPathArgB = DirectorySeparatorNormalizeHelper $pathArgB

return $normalizedPathArgA -eq $normalizedPathArgB
}
53 changes: 52 additions & 1 deletion Tests/Pester.Commands.Cmdlets.Archive.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Describe "Test suite for Microsoft.PowerShell.Archive module" -Tags "BVT" {
$zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false)
$zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs

$entryToBeUpdated = $zipArchive.Entries | ? {$_.FullName -eq $entryFileName}
$entryToBeUpdated = $zipArchive.Entries | ? {$_.FullName -eq $entryFileName.replace([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)}

if($entryToBeUpdated -ne $null)
{
Expand Down Expand Up @@ -209,6 +209,40 @@ Describe "Test suite for Microsoft.PowerShell.Archive module" -Tags "BVT" {
}
}

function ArchiveFileEntrySeparatorValidator {
param
(
[string] $path
)

Add-CompressionAssemblies
try
{
$destFile = "$TestDrive$($DS)ExpandedFile"+([System.Guid]::NewGuid().ToString())+".txt"

$archiveFileStreamArgs = @($path, [System.IO.FileMode]::Open)
$archiveFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $archiveFileStreamArgs

$zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false)
$zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs

$badEntries = $zipArchive.Entries | Where-Object {$_.FullName.Contains('\')}

$badEntries.Count | Should Be 0
}
finally
{
if ($zipArchive)
{
$zipArchive.Dispose()
}
if ($archiveFileStream)
{
$archiveFileStream.Dispose()
}
}
}

function ExpandArchiveInvalidParameterValidator {
param
(
Expand Down Expand Up @@ -630,6 +664,23 @@ Describe "Test suite for Microsoft.PowerShell.Archive module" -Tags "BVT" {
ArchiveFileEntryContentValidator "$destinationPath" "SourceDir$($DS)ChildDir-1$($DS)Sample-3.txt" $modifiedContent
}

It "Validate that only / separators are used as archive directory separators" {
$filePath = "$TestDrive$($DS)SourceDir$($DS)ChildDir-1$($DS)Sample-3.txt"

$initialContent = "Initial Content"
$modifiedContent = "Modified Content"

$initialContent | Set-Content $filePath

$sourcePath = "$TestDrive$($DS)SourceDir"
$destinationPath = "$TestDrive$($DS)VerifyingSeparators.zip"

Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $True

ArchiveFileEntrySeparatorValidator "$destinationPath"
}

It "Validate Compress-Archive cmdlet in pipleline scenario" {
$destinationPath = "$TestDrive$($DS)CompressArchiveFromPipeline.zip"

Expand Down