Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdeel Mujahid <3840695+am11@users.noreply.github.com>2022-11-12 00:46:06 +0300
committerGitHub <noreply@github.com>2022-11-12 00:46:06 +0300
commit493574ee470daf8a353203ce7e933f931f986159 (patch)
tree93b6885bdf339e37f4fda0e63c8459f68a80a89c
parent486682a719e064ed30dd4c6db94f5c34a05ad5f2 (diff)
Fix relative symlink support in TarFile (#77338)
* Fix relative symlink support in TarFile * Update src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectory.File.Roundtrip.cs Co-authored-by: David Cantú <dacantu@microsoft.com> Co-authored-by: David Cantú <dacantu@microsoft.com>
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs8
-rw-r--r--src/libraries/System.Formats.Tar/tests/System.Formats.Tar.Tests.csproj3
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectory.File.Roundtrip.cs79
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs23
4 files changed, 111 insertions, 2 deletions
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs
index 61368173b0d..e7d6761c592 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs
@@ -349,11 +349,17 @@ namespace System.Formats.Tar
throw new InvalidDataException(SR.TarEntryHardLinkOrSymlinkLinkNameEmpty);
}
- linkTargetPath = GetSanitizedFullPath(destinationDirectoryPath, LinkName);
+ linkTargetPath = GetSanitizedFullPath(destinationDirectoryPath,
+ Path.IsPathFullyQualified(LinkName) ? LinkName : Path.Join(Path.GetDirectoryName(fileDestinationPath), LinkName));
+
if (linkTargetPath == null)
{
throw new IOException(SR.Format(SR.TarExtractingResultsLinkOutside, LinkName, destinationDirectoryPath));
}
+
+ // after TarExtractingResultsLinkOutside validation, preserve the original
+ // symlink target path (to match behavior of other utilities).
+ linkTargetPath = LinkName;
}
return (fileDestinationPath, linkTargetPath);
diff --git a/src/libraries/System.Formats.Tar/tests/System.Formats.Tar.Tests.csproj b/src/libraries/System.Formats.Tar/tests/System.Formats.Tar.Tests.csproj
index ca1b4d99e50..1d30aa09d0f 100644
--- a/src/libraries/System.Formats.Tar/tests/System.Formats.Tar.Tests.csproj
+++ b/src/libraries/System.Formats.Tar/tests/System.Formats.Tar.Tests.csproj
@@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <StringResourcesPath>$(LibrariesProjectRoot)/Common/tests/Resources/Strings.resx</StringResourcesPath>
+ <StringResourcesPath>$(MSBuildProjectDirectory)\..\src\Resources\Strings.resx</StringResourcesPath>
<EnableLibraryImportGenerator>true</EnableLibraryImportGenerator>
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
</PropertyGroup>
@@ -17,6 +17,7 @@
<Compile Include="TarFile\TarFile.ExtractToDirectoryAsync.File.Tests.cs" />
<Compile Include="TarFile\TarFile.CreateFromDirectoryAsync.Stream.Tests.cs" />
<Compile Include="TarFile\TarFile.CreateFromDirectoryAsync.File.Tests.cs" />
+ <Compile Include="TarFile\TarFile.CreateFromDirectory.File.Roundtrip.cs" />
<Compile Include="TarEntry\TarEntry.Conversion.Tests.Base.cs" />
<Compile Include="TarEntry\GnuTarEntry.Conversion.Tests.cs" />
<Compile Include="TarEntry\PaxTarEntry.Conversion.Tests.cs" />
diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectory.File.Roundtrip.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectory.File.Roundtrip.cs
new file mode 100644
index 00000000000..460dec75780
--- /dev/null
+++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectory.File.Roundtrip.cs
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.IO;
+using Xunit;
+
+namespace System.Formats.Tar.Tests
+{
+ public class TarFile_CreateFromDirectory_Roundtrip_Tests : TarTestsBase
+ {
+ [ConditionalTheory(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))]
+ [InlineData("./file.txt", "subDirectory")]
+ [InlineData("../file.txt", "subDirectory")]
+ [InlineData("../file.txt", "subDirectory1/subDirectory1.1")]
+ [InlineData("./file.txt", "subDirectory1/subDirectory1.1")]
+ [InlineData("./file.txt", null)]
+ public void SymlinkRelativeTargets_InsideTheArchive_RoundtripsSuccessfully(string symlinkTargetPath, string subDirectory)
+ {
+ using TempDirectory root = new TempDirectory();
+
+ string destinationArchive = Path.Join(root.Path, "destination.tar");
+
+ string sourceDirectoryName = Path.Join(root.Path, "baseDirectory");
+ Directory.CreateDirectory(sourceDirectoryName);
+
+ string destinationDirectoryName = Path.Join(root.Path, "destinationDirectory");
+ Directory.CreateDirectory(destinationDirectoryName);
+
+ string sourceSubDirectory = Path.Join(sourceDirectoryName, subDirectory);
+ if(subDirectory != null) Directory.CreateDirectory(sourceSubDirectory);
+
+ File.Create(Path.Join(sourceDirectoryName, subDirectory, symlinkTargetPath)).Dispose();
+ File.CreateSymbolicLink(Path.Join(sourceSubDirectory, "linkToFile"), symlinkTargetPath);
+
+ TarFile.CreateFromDirectory(sourceDirectoryName, destinationArchive, includeBaseDirectory: false);
+
+ using FileStream archiveStream = File.OpenRead(destinationArchive);
+ TarFile.ExtractToDirectory(archiveStream, destinationDirectoryName, overwriteFiles: true);
+
+ string destinationSubDirectory = Path.Join(destinationDirectoryName, subDirectory);
+ string symlinkPath = Path.Join(destinationSubDirectory, "linkToFile");
+ Assert.True(File.Exists(symlinkPath));
+
+ FileInfo? fileInfo = new(symlinkPath);
+ Assert.Equal(symlinkTargetPath, fileInfo.LinkTarget);
+
+ FileSystemInfo? symlinkTarget = File.ResolveLinkTarget(symlinkPath, returnFinalTarget: true);
+ Assert.True(File.Exists(symlinkTarget.FullName));
+ }
+
+ [ConditionalTheory(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))]
+ [InlineData("../file.txt", null)]
+ [InlineData("../../file.txt", "subDirectory")]
+ public void SymlinkRelativeTargets_OutsideTheArchive_Fails(string symlinkTargetPath, string subDirectory)
+ {
+ using TempDirectory root = new TempDirectory();
+
+ string destinationArchive = Path.Join(root.Path, "destination.tar");
+
+ string sourceDirectoryName = Path.Join(root.Path, "baseDirectory");
+ Directory.CreateDirectory(sourceDirectoryName);
+
+ string destinationDirectoryName = Path.Join(root.Path, "destinationDirectory");
+ Directory.CreateDirectory(destinationDirectoryName);
+
+ string sourceSubDirectory = Path.Join(sourceDirectoryName, subDirectory);
+ if(subDirectory != null) Directory.CreateDirectory(sourceSubDirectory);
+
+ File.CreateSymbolicLink(Path.Join(sourceSubDirectory, "linkToFile"), symlinkTargetPath);
+
+ TarFile.CreateFromDirectory(sourceDirectoryName, destinationArchive, includeBaseDirectory: false);
+
+ using FileStream archiveStream = File.OpenRead(destinationArchive);
+ Exception exception = Assert.Throws<IOException>(() => TarFile.ExtractToDirectory(archiveStream, destinationDirectoryName, overwriteFiles: true));
+
+ Assert.Equal(SR.Format(SR.TarExtractingResultsLinkOutside, symlinkTargetPath, destinationDirectoryName), exception.Message);
+ }
+ }
+}
diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs
index ec32ab1ab81..cde32d3f979 100644
--- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs
@@ -110,6 +110,29 @@ namespace System.Formats.Tar.Tests
}
}
+ [ConditionalFact(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))]
+ public async Task ExtractEntry_PodmanImageTarWithRelativeSymlinksPointingInExtractDirectory_SuccessfullyExtracts_Async()
+ {
+ using (TempDirectory root = new TempDirectory())
+ {
+ await using MemoryStream archiveStream = GetTarMemoryStream(CompressionMethod.Uncompressed, "misc", "podman-hello-world");
+ await TarFile.ExtractToDirectoryAsync(archiveStream, root.Path, overwriteFiles: true);
+
+ Assert.True(File.Exists(Path.Join(root.Path, "manifest.json")));
+ Assert.True(File.Exists(Path.Join(root.Path, "repositories")));
+ Assert.True(File.Exists(Path.Join(root.Path, "efb53921da3394806160641b72a2cbd34ca1a9a8345ac670a85a04ad3d0e3507.tar")));
+
+ string symlinkPath = Path.Join(root.Path, "e7fc2b397c1ab5af9938f18cc9a80d526cccd1910e4678390157d8cc6c94410d/layer.tar");
+ Assert.True(File.Exists(symlinkPath));
+
+ FileInfo? fileInfo = new(symlinkPath);
+ Assert.Equal("../efb53921da3394806160641b72a2cbd34ca1a9a8345ac670a85a04ad3d0e3507.tar", fileInfo.LinkTarget);
+
+ FileSystemInfo? symlinkTarget = File.ResolveLinkTarget(symlinkPath, returnFinalTarget: true);
+ Assert.True(File.Exists(symlinkTarget.FullName));
+ }
+ }
+
[Theory]
[InlineData(TarEntryType.SymbolicLink)]
[InlineData(TarEntryType.HardLink)]