diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs index b62196bb5c5d6..ab90f0043bc7d 100644 --- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs @@ -177,5 +177,32 @@ public void Extract_UnseekableStream_BlockAlignmentPadding_DoesNotAffectNextEntr Assert.Equal(2, Directory.GetFileSystemEntries(destination.Path, "*", SearchOption.AllDirectories).Count()); } + + [Fact] + public void PaxNameCollision_DedupInExtendedAttributes() + { + using TempDirectory root = new(); + + string sharedRootFolders = Path.Join(root.Path, "folder with spaces", new string('a', 100)); + string path1 = Path.Join(sharedRootFolders, "entry 1 with spaces.txt"); + string path2 = Path.Join(sharedRootFolders, "entry 2 with spaces.txt"); + + using MemoryStream stream = new(); + using (TarWriter writer = new(stream, TarEntryFormat.Pax, leaveOpen: true)) + { + // Paths don't fit in the standard 'name' field, but they differ in the filename, + // which is fully stored as an extended attribute + PaxTarEntry entry1 = new(TarEntryType.RegularFile, path1); + writer.WriteEntry(entry1); + PaxTarEntry entry2 = new(TarEntryType.RegularFile, path2); + writer.WriteEntry(entry2); + } + stream.Position = 0; + + TarFile.ExtractToDirectory(stream, root.Path, overwriteFiles: true); + + Assert.True(File.Exists(path1)); + Assert.True(Path.Exists(path2)); + } } } 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 cde32d3f97916..d7502d940e94e 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 @@ -242,5 +242,32 @@ public async Task Extract_UnseekableStream_BlockAlignmentPadding_DoesNotAffectNe Assert.Equal(2, Directory.GetFileSystemEntries(destination.Path, "*", SearchOption.AllDirectories).Count()); } + + [Fact] + public async Task PaxNameCollision_DedupInExtendedAttributesAsync() + { + using TempDirectory root = new(); + + string sharedRootFolders = Path.Join(root.Path, "folder with spaces", new string('a', 100)); + string path1 = Path.Join(sharedRootFolders, "entry 1 with spaces.txt"); + string path2 = Path.Join(sharedRootFolders, "entry 2 with spaces.txt"); + + await using MemoryStream stream = new(); + await using (TarWriter writer = new(stream, TarEntryFormat.Pax, leaveOpen: true)) + { + // Paths don't fit in the standard 'name' field, but they differ in the filename, + // which is fully stored as an extended attribute + PaxTarEntry entry1 = new(TarEntryType.RegularFile, path1); + await writer.WriteEntryAsync(entry1); + PaxTarEntry entry2 = new(TarEntryType.RegularFile, path2); + await writer.WriteEntryAsync(entry2); + } + stream.Position = 0; + + await TarFile.ExtractToDirectoryAsync(stream, root.Path, overwriteFiles: true); + + Assert.True(File.Exists(path1)); + Assert.True(Path.Exists(path2)); + } } }