Skip to content

Commit ae4ba7f

Browse files
authored
Fix PAX extended attribute reading logic to treat '=' character as valid in the value strings. (#82810)
* Move PaxExtendedAttribute_Roundtrips test to correct source code file. It is not handling any filesystem entries. * Bug fix: Do not fail when reading an extended attribute when the value contains an '=' character., * Add unit tests that verify extended attribute and global extended attribute roundtripping when the value contains an '=' character. Also add a null check for a subsequent GetNextEntry. * Convert duplicate InlineData to single shared MemberData method. * Apply suggestion --------- Co-authored-by: carlossanlop <carlossanlop@users.noreply.github.com>
1 parent 1b2eb12 commit ae4ba7f

File tree

5 files changed

+38
-36
lines changed

5 files changed

+38
-36
lines changed

src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Read.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -733,12 +733,6 @@ private static bool TryGetNextExtendedAttribute(
733733
ReadOnlySpan<byte> keySlice = line.Slice(0, equalPos);
734734
ReadOnlySpan<byte> valueSlice = line.Slice(equalPos + 1);
735735

736-
// If the value contains an =, it's malformed.
737-
if (valueSlice.IndexOf((byte)'=') >= 0)
738-
{
739-
return false;
740-
}
741-
742736
// Return the parsed key and value.
743737
key = Encoding.UTF8.GetString(keySlice);
744738
value = Encoding.UTF8.GetString(valueSlice);

src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.GlobalExtendedAttributes.Tests.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,7 @@ public void ExtractGlobalExtendedAttributesEntry_Throws()
8484
}
8585

8686
[Theory]
87-
[InlineData("key", "value")]
88-
[InlineData("key ", "value ")]
89-
[InlineData(" key", " value")]
90-
[InlineData(" key ", " value ")]
91-
[InlineData(" key spaced ", " value spaced ")]
92-
[InlineData("many sla/s\\hes", "/////////////\\\\\\///////////")]
87+
[MemberData(nameof(GetPaxExtendedAttributesRoundtripTestData))]
9388
public void GlobalExtendedAttribute_Roundtrips(string key, string value)
9489
{
9590
var stream = new MemoryStream();
@@ -104,6 +99,7 @@ public void GlobalExtendedAttribute_Roundtrips(string key, string value)
10499
PaxGlobalExtendedAttributesTarEntry entry = Assert.IsType<PaxGlobalExtendedAttributesTarEntry>(reader.GetNextEntry());
105100
Assert.Equal(1, entry.GlobalExtendedAttributes.Count);
106101
Assert.Equal(KeyValuePair.Create(key, value), entry.GlobalExtendedAttributes.First());
102+
Assert.Null(reader.GetNextEntry());
107103
}
108104
}
109105
}

src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -333,30 +333,6 @@ public void PaxSizeLargerThanMaxAllowedByStream()
333333
Assert.Throws<ArgumentOutOfRangeException>(() => reader.GetNextEntry());
334334
}
335335

336-
[Theory]
337-
[InlineData("key", "value")]
338-
[InlineData("key ", "value ")]
339-
[InlineData(" key", " value")]
340-
[InlineData(" key ", " value ")]
341-
[InlineData(" key spaced ", " value spaced ")]
342-
[InlineData("many sla/s\\hes", "/////////////\\\\\\///////////")]
343-
public void PaxExtendedAttribute_Roundtrips(string key, string value)
344-
{
345-
var stream = new MemoryStream();
346-
using (var writer = new TarWriter(stream, leaveOpen: true))
347-
{
348-
writer.WriteEntry(new PaxTarEntry(TarEntryType.Directory, "entryName", new Dictionary<string, string>() { { key, value } }));
349-
}
350-
351-
stream.Position = 0;
352-
using (var reader = new TarReader(stream))
353-
{
354-
PaxTarEntry entry = Assert.IsType<PaxTarEntry>(reader.GetNextEntry());
355-
Assert.Equal(5, entry.ExtendedAttributes.Count);
356-
Assert.Contains(KeyValuePair.Create(key, value), entry.ExtendedAttributes);
357-
}
358-
}
359-
360336
private static void VerifyDataStreamOfTarUncompressedInternal(string testFolderName, string testCaseName, bool copyData)
361337
{
362338
using MemoryStream archiveStream = GetTarMemoryStream(CompressionMethod.Uncompressed, testFolderName, testCaseName);

src/libraries/System.Formats.Tar/tests/TarReader/TarReader.Tests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,25 @@ public void TarReader_LeaveOpen_False_CopiedDataNotDisposed()
9898
ds.Dispose();
9999
}
100100
}
101+
102+
[Theory]
103+
[MemberData(nameof(GetPaxExtendedAttributesRoundtripTestData))]
104+
public void PaxExtendedAttribute_Roundtrips(string key, string value)
105+
{
106+
var stream = new MemoryStream();
107+
using (var writer = new TarWriter(stream, leaveOpen: true))
108+
{
109+
writer.WriteEntry(new PaxTarEntry(TarEntryType.Directory, "entryName", new Dictionary<string, string>() { { key, value } }));
110+
}
111+
112+
stream.Position = 0;
113+
using (var reader = new TarReader(stream))
114+
{
115+
PaxTarEntry entry = Assert.IsType<PaxTarEntry>(reader.GetNextEntry());
116+
Assert.Equal(5, entry.ExtendedAttributes.Count);
117+
Assert.Contains(KeyValuePair.Create(key, value), entry.ExtendedAttributes);
118+
Assert.Null(reader.GetNextEntry());
119+
}
120+
}
101121
}
102122
}

src/libraries/System.Formats.Tar/tests/TarTestsBase.Pax.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,21 @@ protected void VerifyExtendedAttributeTimestamps(PaxTarEntry pax)
124124
VerifyExtendedAttributeTimestamp(pax, PaxEaATime, MinimumTime);
125125
VerifyExtendedAttributeTimestamp(pax, PaxEaCTime, MinimumTime);
126126
}
127+
128+
public static IEnumerable<object[]> GetPaxExtendedAttributesRoundtripTestData()
129+
{
130+
yield return new object[] { "key", "value" };
131+
yield return new object[] { "key ", "value " };
132+
yield return new object[] { " key", " value" };
133+
yield return new object[] { " key ", " value " };
134+
yield return new object[] { " key spaced ", " value spaced " };
135+
yield return new object[] { "many sla/s\\hes", "/////////////\\\\\\///////////" };
136+
yield return new object[] { "key", "=" };
137+
yield return new object[] { "key", "=value" };
138+
yield return new object[] { "key", "va=lue" };
139+
yield return new object[] { "key", "value=" };
140+
// real world scenario
141+
yield return new object[] { "MSWINDOWS.rawsd", "AQAAgBQAAAAkAAAAAAAAAAAAAAABAgAAAAAABSAAAAAhAgAAAQIAAAAAAAUgAAAAIQIAAA==" };
142+
}
127143
}
128144
}

0 commit comments

Comments
 (0)