Skip to content

Commit

Permalink
[release/7.0] Tar: Remove invalidation of whitespace in PAX extended …
Browse files Browse the repository at this point in the history
…attributes (#78785)

* Remove invalidation of whitespace in TryGetNextExtendedAttribute (#78465)

* Remove invalidation of whitespace in TryGetNextExtendedAttribute

* Add requested test

* Remove TrimStart in PAX extended attributes (#78707)

* Remove TrimStart in PAX extended attributes

* Adjust existing tests with two extra inline datas.

Co-authored-by: carlossanlop <[email protected]>

* Tar: Extra tests to confirm extra long paths are not treated as duplicate entries when the full path is in the extended attributes. (#78744)

Co-authored-by: carlossanlop <[email protected]>

Co-authored-by: Stephen Toub <[email protected]>
Co-authored-by: carlossanlop <[email protected]>
  • Loading branch information
3 people committed Nov 29, 2022
1 parent 7d81963 commit 64ddf49
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -723,13 +723,7 @@ private static bool TryGetNextExtendedAttribute(
{
return false;
}
line = line.Slice(spacePos + 1).TrimStart((byte)' ');

// If there are any more spaces, it's malformed.
if (line.IndexOf((byte)' ') >= 0)
{
return false;
}
line = line.Slice(spacePos + 1);

// Find the equal separator.
int equalPos = line.IndexOf((byte)'=');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,29 @@ public void ExtractGlobalExtendedAttributesEntry_Throws()
Assert.Throws<InvalidOperationException>(() => entry.ExtractToFile(Path.Join(root.Path, "file"), overwrite: true));
}
}

[Theory]
[InlineData("key", "value")]
[InlineData("key ", "value ")]
[InlineData(" key", " value")]
[InlineData(" key ", " value ")]
[InlineData(" key spaced ", " value spaced ")]
[InlineData("many sla/s\\hes", "/////////////\\\\\\///////////")]
public void GlobalExtendedAttribute_Roundtrips(string key, string value)
{
var stream = new MemoryStream();
using (var writer = new TarWriter(stream, leaveOpen: true))
{
writer.WriteEntry(new PaxGlobalExtendedAttributesTarEntry(new Dictionary<string, string>() { { key, value } }));
}

stream.Position = 0;
using (var reader = new TarReader(stream))
{
PaxGlobalExtendedAttributesTarEntry entry = Assert.IsType<PaxGlobalExtendedAttributesTarEntry>(reader.GetNextEntry());
Assert.Equal(1, entry.GlobalExtendedAttributes.Count);
Assert.Equal(KeyValuePair.Create(key, value), entry.GlobalExtendedAttributes.First());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,30 @@ public void PaxSizeLargerThanMaxAllowedByStream()
Assert.Throws<ArgumentOutOfRangeException>(() => reader.GetNextEntry());
}

[Theory]
[InlineData("key", "value")]
[InlineData("key ", "value ")]
[InlineData(" key", " value")]
[InlineData(" key ", " value ")]
[InlineData(" key spaced ", " value spaced ")]
[InlineData("many sla/s\\hes", "/////////////\\\\\\///////////")]
public void PaxExtendedAttribute_Roundtrips(string key, string value)
{
var stream = new MemoryStream();
using (var writer = new TarWriter(stream, leaveOpen: true))
{
writer.WriteEntry(new PaxTarEntry(TarEntryType.Directory, "entryName", new Dictionary<string, string>() { { key, value } }));
}

stream.Position = 0;
using (var reader = new TarReader(stream))
{
PaxTarEntry entry = Assert.IsType<PaxTarEntry>(reader.GetNextEntry());
Assert.Equal(5, entry.ExtendedAttributes.Count);
Assert.Contains(KeyValuePair.Create(key, value), entry.ExtendedAttributes);
}
}

private static void VerifyDataStreamOfTarUncompressedInternal(string testFolderName, string testCaseName, bool copyData)
{
using MemoryStream archiveStream = GetTarMemoryStream(CompressionMethod.Uncompressed, testFolderName, testCaseName);
Expand Down

0 comments on commit 64ddf49

Please sign in to comment.