Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 7 additions & 1 deletion src/libraries/System.Formats.Tar/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,10 @@
<data name="TarSizeFieldTooLargeForEntryFormat" xml:space="preserve">
<value>The value of the size field for the current entry of format '{0}' is greater than the format allows.</value>
</data>
</root>
<data name="TarExtAttrDisallowedKeyChar" xml:space="preserve">
<value>The extended attribute key '{0}' contains a disallowed '{1}' character.</value>
</data>
<data name="TarExtAttrDisallowedValueChar" xml:space="preserve">
<value>The value of the extended attribute key '{0}' contains a disallowed '{1}' character.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,27 @@ internal TarHeader(TarEntryFormat format, TarEntryType typeFlag, TarHeader other
internal void InitializeExtendedAttributesWithExisting(IEnumerable<KeyValuePair<string, string>> existing)
{
Debug.Assert(_ea == null);
_ea = new Dictionary<string, string>(existing);
Debug.Assert(existing != null);

using IEnumerator<KeyValuePair<string, string>> enumerator = existing.GetEnumerator();
while (enumerator.MoveNext())
{
KeyValuePair<string, string> kvp = enumerator.Current;

int index = kvp.Key.IndexOfAny(new char[] { '=', '\n' });
if (index >= 0)
{
throw new ArgumentException(SR.Format(SR.TarExtAttrDisallowedKeyChar, kvp.Key, kvp.Key[index] == '\n' ? "\\n" : kvp.Key[index]));
}
if (kvp.Value.IndexOf('\n') != -1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readability:

Suggested change
if (kvp.Value.IndexOf('\n') != -1)
if (kvp.Value.Contains('\n'))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it's more readable, but I am unsure if Contains is more or less performant compared to IndexOf. Let me find out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contains is strictly better in this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually have an analyzer for this:

# CA2249: Consider using 'string.Contains' instead of 'string.IndexOf'
dotnet_diagnostic.CA2249.severity = warning

Do we know why it's not firing?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea. @carlossanlop can you please check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The analyzer has a bug: it only runs when using == or >=. My code is using !=.

I opened an issue: dotnet/roslyn-analyzers#6587

{
throw new ArgumentException(SR.Format(SR.TarExtAttrDisallowedValueChar, kvp.Key, "\\n"));
}

_ea ??= new Dictionary<string, string>();

_ea.Add(kvp.Key, kvp.Value);
}
}

private static string GetMagicForFormat(TarEntryFormat format) => format switch
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// 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 System.Linq;
using System.Collections.Generic;
using Xunit;

namespace System.Formats.Tar.Tests
Expand Down Expand Up @@ -36,6 +35,30 @@ public void Constructor_UnsupportedEntryTypes()
Assert.Throws<ArgumentException>(() => new PaxTarEntry(TarEntryType.GlobalExtendedAttributes, InitialEntryName));
}


[Theory]
[InlineData("\n", "value")]
[InlineData("=", "value")]
[InlineData("key", "\n")]
[InlineData("\nkey", "value")]
[InlineData("k\ney", "value")]
[InlineData("key\n", "value")]
[InlineData("=key", "value")]
[InlineData("ke=y", "value")]
[InlineData("key=", "value")]
[InlineData("key", "\nvalue")]
[InlineData("key", "val\nue")]
[InlineData("key", "value\n")]
[InlineData("key=", "value\n")]
[InlineData("key\n", "value\n")]
public void Disallowed_ExtendedAttributes_SeparatorCharacters(string key, string value)
{
Dictionary<string, string> extendedAttribute = new Dictionary<string, string>() { { key, value } };

Assert.Throws<ArgumentException>(() => new PaxTarEntry(TarEntryType.RegularFile, InitialEntryName, extendedAttribute));
Assert.Throws<ArgumentException>(() => new PaxGlobalExtendedAttributesTarEntry(extendedAttribute));
}

[Fact]
public void SupportedEntryType_RegularFile()
{
Expand Down