From 9c06ed11f3d98044dc1f6c469ff4bd2020a2d3ab Mon Sep 17 00:00:00 2001 From: carlossanlop Date: Mon, 23 Jan 2023 18:24:24 -0800 Subject: [PATCH 1/8] Do not throw if a unix group is non-existent when creating a TarEntry from a file using TarWriter. --- .../Unix/System.Native/Interop.GetGroupName.cs | 12 +++++++++--- .../src/System/Formats/Tar/TarWriter.Unix.cs | 6 ++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetGroupName.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetGroupName.cs index fadbf314e4d51..3536b1fe02a95 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetGroupName.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetGroupName.cs @@ -7,17 +7,23 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.IO; internal static partial class Interop { internal static partial class Sys { /// - /// Gets the group name associated to the specified group ID. + /// Tries to get the group name associated to the specified group ID. /// /// The group ID. - /// On success, return a string with the group name. On failure, throws an IOException. - internal static string GetGroupName(uint gid) => GetGroupNameInternal(gid) ?? throw GetIOException(GetLastErrorInfo()); + /// When this method returns true, gets the value of the group name associated with the specified id. On failure, it is null. + /// On success, return true. On failure, returns false. + internal static bool TryGetGroupName(uint gid, out string? groupName) + { + groupName = GetGroupNameInternal(gid); + return groupName != null; + } [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetGroupName", StringMarshalling = StringMarshalling.Utf8, SetLastError = true)] private static unsafe partial string? GetGroupNameInternal(uint uid); diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs index 357e4a8a7587f..798ddac5b6d6e 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs @@ -82,8 +82,10 @@ private TarEntry ConstructEntryForWriting(string fullPath, string entryName, Fil entry._header._gid = (int)status.Gid; if (!_groupIdentifiers.TryGetValue(status.Gid, out string? gName)) { - gName = Interop.Sys.GetGroupName(status.Gid); - _groupIdentifiers.Add(status.Gid, gName); + if (Interop.Sys.TryGetGroupName(status.Gid, out gName) && gName != null) + { + _groupIdentifiers.Add(status.Gid, gName); + } } entry._header._gName = gName; From ae50e8f8af26b417645ce122498278b6e8419ed8 Mon Sep 17 00:00:00 2001 From: carlossanlop Date: Mon, 23 Jan 2023 18:24:44 -0800 Subject: [PATCH 2/8] Adjust test that was consuming removed interop method. --- .../tests/TarWriter/TarWriter.File.Base.Unix.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs index 8b613191b0ef8..de159971f504f 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs @@ -20,7 +20,7 @@ protected void VerifyPlatformSpecificMetadata(string filePath, TarEntry entry) if (entry is PosixTarEntry posix) { - string gname = Interop.Sys.GetGroupName(status.Gid); + Interop.Sys.TryGetGroupName(status.Gid, out string gname); string uname = Interop.Sys.GetUserNameFromPasswd(status.Uid); Assert.Equal(gname, posix.GroupName); From 0220d176ada0bb7c82e8c9633faa758d3902fdde Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 23 Jan 2023 21:00:30 -0800 Subject: [PATCH 3/8] Add unit tests to add file entry whose group owner does not exist. --- .../TarWriter/TarWriter.File.Base.Unix.cs | 64 +++++++++++++++++++ .../TarWriter.WriteEntry.File.Tests.Unix.cs | 35 ++++++++++ ...rWriter.WriteEntryAsync.File.Tests.Unix.cs | 35 ++++++++++ 3 files changed, 134 insertions(+) diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs index de159971f504f..2a39ec47403ac 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs @@ -1,6 +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.Diagnostics; using System.IO; using Xunit; @@ -51,5 +52,68 @@ protected void VerifyPlatformSpecificMetadata(string filePath, TarEntry entry) } } } + + protected int CreateGroup(string groupName) + { + int exitCode = Execute("groupadd", groupName, out string standardOutput, out string standardError); + if (exitCode != 0) + { + ThrowOnError(exitCode, "groupadd", groupName, standardError); + } + return GetGroupId(groupName); + } + + protected int GetGroupId(string groupName) + { + int exitCode = Execute("getent", $"group {groupName}", out string standardOutput, out string standardError); + if (exitCode != 0) + { + ThrowOnError(exitCode, "getent", "group", standardError); + } + + string[] values = standardOutput.Split(':', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + + return int.Parse(values[^1]); + } + + protected void SetGroupAsOwnerOfFile(string groupName, string filePath) + { + int exitCode = Execute("chgrp", $"{groupName} {filePath}", out string standardOutput, out string standardError); + if (exitCode != 0) + { + ThrowOnError(exitCode, "chgroup", $"{groupName} {filePath}", standardError); + } + } + + protected void DeleteGroup(string groupName) + { + int exitCode = Execute("groupdel", groupName, out string standardOutput, out string standardError); + if (exitCode != 0) + { + ThrowOnError(exitCode, "groupdel", groupName, standardError); + } + } + + private int Execute(string command, string arguments, out string standardOutput, out string standardError) + { + using Process p = new Process(); + + p.StartInfo.UseShellExecute = false; + p.StartInfo.FileName = command; + p.StartInfo.Arguments = arguments; + p.StartInfo.RedirectStandardOutput = true; + p.StartInfo.RedirectStandardError = true; + p.Start(); + p.WaitForExit(); + + standardOutput = p.StandardOutput.ReadToEnd(); + standardError = p.StandardError.ReadToEnd(); + return p.ExitCode; + } + + private void ThrowOnError(int code, string command, string arguments, string message) + { + throw new IOException($"Error '{code}' when executing '{command} {arguments}'. Message: {message}"); + } } } diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs index 5ca600f992f93..f36d1250046e3 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs @@ -139,5 +139,40 @@ public void Add_CharacterDevice(TarEntryFormat format) }, format.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } + + [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + public void CreateEntryFromFileOwnedByNonExistentGroup() + { + RemoteExecutor.Invoke(() => + { + string groupName = Path.GetRandomFileName()[0..6]; + int groupId = CreateGroup(groupName); + + using TempDirectory root = new TempDirectory(); + + string fileName = "file.txt"; + string filePath = Path.Join(root.Path, fileName); + File.Create(filePath).Dispose(); + + SetGroupAsOwnerOfFile(groupName, filePath); + + DeleteGroup(groupName); + + using MemoryStream archive = new MemoryStream(); + using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) + { + writer.WriteEntry(filePath, fileName); // Should not throw + } + archive.Seek(0, SeekOrigin.Begin); + + using (TarReader reader = new TarReader(archive, leaveOpen: false)) + { + UstarTarEntry entry = reader.GetNextEntry() as UstarTarEntry; + Assert.NotNull(entry); + Assert.Equal(entry.GroupName, string.Empty); + Assert.Equal(groupId, entry.Gid); + } + }, new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); + } } } diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs index ba4a5600ae81d..0c099fc6a5d67 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs @@ -149,5 +149,40 @@ public void Add_CharacterDevice_Async(TarEntryFormat format) } }, format.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } + + [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + public void CreateEntryFromFileOwnedByNonExistentGroup_Async() + { + RemoteExecutor.Invoke(async () => + { + string groupName = Path.GetRandomFileName()[0..6]; + int groupId = CreateGroup(groupName); + + using TempDirectory root = new TempDirectory(); + + string fileName = "file.txt"; + string filePath = Path.Join(root.Path, fileName); + File.Create(filePath).Dispose(); + + SetGroupAsOwnerOfFile(groupName, filePath); + + DeleteGroup(groupName); + + await using MemoryStream archive = new MemoryStream(); + await using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) + { + await writer.WriteEntryAsync(filePath, fileName); // Should not throw + } + archive.Seek(0, SeekOrigin.Begin); + + await using (TarReader reader = new TarReader(archive, leaveOpen: false)) + { + UstarTarEntry entry = await reader.GetNextEntryAsync() as UstarTarEntry; + Assert.NotNull(entry); + Assert.Equal(entry.GroupName, string.Empty); + Assert.Equal(groupId, entry.Gid); + } + }, new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); + } } } From f02aa662a1162b83a04b56138da3f95264f7664b Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:17:48 -0800 Subject: [PATCH 4/8] Address src feedback. --- .../Interop/Unix/System.Native/Interop.GetGroupName.cs | 9 +++++---- .../src/System/Formats/Tar/TarWriter.Unix.cs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetGroupName.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetGroupName.cs index 3536b1fe02a95..f36935ae7f39a 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetGroupName.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetGroupName.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Reflection; using System.IO; +using System.Diagnostics.CodeAnalysis; internal static partial class Interop { @@ -18,14 +19,14 @@ internal static partial class Sys /// /// The group ID. /// When this method returns true, gets the value of the group name associated with the specified id. On failure, it is null. - /// On success, return true. On failure, returns false. - internal static bool TryGetGroupName(uint gid, out string? groupName) + /// On success, returns true. On failure, returns false. + internal static bool TryGetGroupName(uint gid, [NotNullWhen(returnValue: true)] out string? groupName) { - groupName = GetGroupNameInternal(gid); + groupName = GetGroupName(gid); return groupName != null; } [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetGroupName", StringMarshalling = StringMarshalling.Utf8, SetLastError = true)] - private static unsafe partial string? GetGroupNameInternal(uint uid); + private static unsafe partial string? GetGroupName(uint uid); } } diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs index 798ddac5b6d6e..ccdc2b49b017c 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs @@ -82,7 +82,7 @@ private TarEntry ConstructEntryForWriting(string fullPath, string entryName, Fil entry._header._gid = (int)status.Gid; if (!_groupIdentifiers.TryGetValue(status.Gid, out string? gName)) { - if (Interop.Sys.TryGetGroupName(status.Gid, out gName) && gName != null) + if (Interop.Sys.TryGetGroupName(status.Gid, out gName)) { _groupIdentifiers.Add(status.Gid, gName); } From 5a144f609e747081ed144667e18c22c19d017309 Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:29:54 -0800 Subject: [PATCH 5/8] Address test feedback --- .../TarWriter/TarWriter.File.Base.Unix.cs | 55 ++++++------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs index 2a39ec47403ac..4bdb470ce2ae0 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.File.Base.Unix.cs @@ -21,7 +21,7 @@ protected void VerifyPlatformSpecificMetadata(string filePath, TarEntry entry) if (entry is PosixTarEntry posix) { - Interop.Sys.TryGetGroupName(status.Gid, out string gname); + Assert.True(Interop.Sys.TryGetGroupName(status.Gid, out string gname)); string uname = Interop.Sys.GetUserNameFromPasswd(status.Uid); Assert.Equal(gname, posix.GroupName); @@ -55,46 +55,25 @@ protected void VerifyPlatformSpecificMetadata(string filePath, TarEntry entry) protected int CreateGroup(string groupName) { - int exitCode = Execute("groupadd", groupName, out string standardOutput, out string standardError); - if (exitCode != 0) - { - ThrowOnError(exitCode, "groupadd", groupName, standardError); - } + Execute("groupadd", groupName); return GetGroupId(groupName); } protected int GetGroupId(string groupName) { - int exitCode = Execute("getent", $"group {groupName}", out string standardOutput, out string standardError); - if (exitCode != 0) - { - ThrowOnError(exitCode, "getent", "group", standardError); - } - + string standardOutput = Execute("getent", $"group {groupName}"); string[] values = standardOutput.Split(':', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); - return int.Parse(values[^1]); } - protected void SetGroupAsOwnerOfFile(string groupName, string filePath) - { - int exitCode = Execute("chgrp", $"{groupName} {filePath}", out string standardOutput, out string standardError); - if (exitCode != 0) - { - ThrowOnError(exitCode, "chgroup", $"{groupName} {filePath}", standardError); - } - } + protected void SetGroupAsOwnerOfFile(string groupName, string filePath) => + Execute("chgrp", $"{groupName} {filePath}"); - protected void DeleteGroup(string groupName) - { - int exitCode = Execute("groupdel", groupName, out string standardOutput, out string standardError); - if (exitCode != 0) - { - ThrowOnError(exitCode, "groupdel", groupName, standardError); - } - } - private int Execute(string command, string arguments, out string standardOutput, out string standardError) + protected void DeleteGroup(string groupName) => + Execute("groupdel", groupName); + + private string Execute(string command, string arguments) { using Process p = new Process(); @@ -103,17 +82,19 @@ private int Execute(string command, string arguments, out string standardOutput, p.StartInfo.Arguments = arguments; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; + p.Start(); p.WaitForExit(); - standardOutput = p.StandardOutput.ReadToEnd(); - standardError = p.StandardError.ReadToEnd(); - return p.ExitCode; - } + string standardOutput = p.StandardOutput.ReadToEnd(); + string standardError = p.StandardError.ReadToEnd(); + + if (p.ExitCode != 0) + { + throw new IOException($"Error '{p.ExitCode}' when executing '{command} {arguments}'. Message: {standardError}"); + } - private void ThrowOnError(int code, string command, string arguments, string message) - { - throw new IOException($"Error '{code}' when executing '{command} {arguments}'. Message: {message}"); + return standardOutput; } } } From 6ab7e624f1b2bf54fe1130431448f2d523302b66 Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:33:28 -0800 Subject: [PATCH 6/8] Delay creation/deletion of group in test --- .../TarWriter.WriteEntry.File.Tests.Unix.cs | 15 ++++++++++----- .../TarWriter.WriteEntryAsync.File.Tests.Unix.cs | 15 ++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs index f36d1250046e3..2680a59fd6b87 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs @@ -145,18 +145,23 @@ public void CreateEntryFromFileOwnedByNonExistentGroup() { RemoteExecutor.Invoke(() => { - string groupName = Path.GetRandomFileName()[0..6]; - int groupId = CreateGroup(groupName); - using TempDirectory root = new TempDirectory(); string fileName = "file.txt"; string filePath = Path.Join(root.Path, fileName); File.Create(filePath).Dispose(); - SetGroupAsOwnerOfFile(groupName, filePath); + string groupName = Path.GetRandomFileName()[0..6]; + int groupId = CreateGroup(groupName); - DeleteGroup(groupName); + try + { + SetGroupAsOwnerOfFile(groupName, filePath); + } + finally + { + DeleteGroup(groupName); + } using MemoryStream archive = new MemoryStream(); using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs index 0c099fc6a5d67..1dbcfb9651f12 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs @@ -155,18 +155,23 @@ public void CreateEntryFromFileOwnedByNonExistentGroup_Async() { RemoteExecutor.Invoke(async () => { - string groupName = Path.GetRandomFileName()[0..6]; - int groupId = CreateGroup(groupName); - using TempDirectory root = new TempDirectory(); string fileName = "file.txt"; string filePath = Path.Join(root.Path, fileName); File.Create(filePath).Dispose(); - SetGroupAsOwnerOfFile(groupName, filePath); + string groupName = Path.GetRandomFileName()[0..6]; + int groupId = CreateGroup(groupName); - DeleteGroup(groupName); + try + { + SetGroupAsOwnerOfFile(groupName, filePath); + } + finally + { + DeleteGroup(groupName); + } await using MemoryStream archive = new MemoryStream(); await using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) From ee75545d1c4387696a44a3a975649ceeb4b1557b Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:48:46 -0800 Subject: [PATCH 7/8] Test all PosixTarEntry formats --- .../TarWriter.WriteEntry.File.Tests.Unix.cs | 16 ++++++++++------ .../TarWriter.WriteEntryAsync.File.Tests.Unix.cs | 16 ++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs index 2680a59fd6b87..a4c153025b2e0 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs @@ -140,10 +140,13 @@ public void Add_CharacterDevice(TarEntryFormat format) }, format.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } - [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] - public void CreateEntryFromFileOwnedByNonExistentGroup() + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + [InlineData(TarEntryFormat.Ustar)] + [InlineData(TarEntryFormat.Pax)] + [InlineData(TarEntryFormat.Gnu)] + public void CreateEntryFromFileOwnedByNonExistentGroup(TarEntryFormat f) { - RemoteExecutor.Invoke(() => + RemoteExecutor.Invoke((string strFormat) => { using TempDirectory root = new TempDirectory(); @@ -164,7 +167,7 @@ public void CreateEntryFromFileOwnedByNonExistentGroup() } using MemoryStream archive = new MemoryStream(); - using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) + using (TarWriter writer = new TarWriter(archive, Enum.Parse(strFormat), leaveOpen: true)) { writer.WriteEntry(filePath, fileName); // Should not throw } @@ -172,12 +175,13 @@ public void CreateEntryFromFileOwnedByNonExistentGroup() using (TarReader reader = new TarReader(archive, leaveOpen: false)) { - UstarTarEntry entry = reader.GetNextEntry() as UstarTarEntry; + PosixTarEntry entry = reader.GetNextEntry() as PosixTarEntry; Assert.NotNull(entry); Assert.Equal(entry.GroupName, string.Empty); Assert.Equal(groupId, entry.Gid); + Assert.Null(reader.GetNextEntry()); } - }, new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); + }, f.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } } } diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs index 1dbcfb9651f12..7a3d459bc92a7 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs @@ -150,10 +150,13 @@ public void Add_CharacterDevice_Async(TarEntryFormat format) }, format.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } - [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] - public void CreateEntryFromFileOwnedByNonExistentGroup_Async() + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + [InlineData(TarEntryFormat.Ustar)] + [InlineData(TarEntryFormat.Pax)] + [InlineData(TarEntryFormat.Gnu)] + public void CreateEntryFromFileOwnedByNonExistentGroup_Async(TarEntryFormat f) { - RemoteExecutor.Invoke(async () => + RemoteExecutor.Invoke(async (string strFormat) => { using TempDirectory root = new TempDirectory(); @@ -174,7 +177,7 @@ public void CreateEntryFromFileOwnedByNonExistentGroup_Async() } await using MemoryStream archive = new MemoryStream(); - await using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) + await using (TarWriter writer = new TarWriter(archive, Enum.Parse(strFormat), leaveOpen: true)) { await writer.WriteEntryAsync(filePath, fileName); // Should not throw } @@ -182,12 +185,13 @@ public void CreateEntryFromFileOwnedByNonExistentGroup_Async() await using (TarReader reader = new TarReader(archive, leaveOpen: false)) { - UstarTarEntry entry = await reader.GetNextEntryAsync() as UstarTarEntry; + PosixTarEntry entry = await reader.GetNextEntryAsync() as PosixTarEntry; Assert.NotNull(entry); Assert.Equal(entry.GroupName, string.Empty); Assert.Equal(groupId, entry.Gid); + Assert.Null(await reader.GetNextEntryAsync()); } - }, new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); + }, f.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } } } From 9df263c8ca6ff8571f5a8bc975a1f3f4b19617ab Mon Sep 17 00:00:00 2001 From: carlossanlop Date: Wed, 1 Feb 2023 16:30:39 -0800 Subject: [PATCH 8/8] Include not-yet-backported property name change to fix build failure. --- .../TarEntry/TarEntry.ExtractToFile.Tests.Unix.cs | 4 ++-- src/libraries/System.Formats.Tar/tests/TarTestsBase.cs | 5 +++-- .../TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs | 8 ++++---- .../TarWriter.WriteEntryAsync.File.Tests.Unix.cs | 10 +++++----- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Formats.Tar/tests/TarEntry/TarEntry.ExtractToFile.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarEntry/TarEntry.ExtractToFile.Tests.Unix.cs index cee5f6bc7dfd8..d5438928a59dd 100644 --- a/src/libraries/System.Formats.Tar/tests/TarEntry/TarEntry.ExtractToFile.Tests.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarEntry/TarEntry.ExtractToFile.Tests.Unix.cs @@ -23,7 +23,7 @@ public static IEnumerable GetFormatsAndSpecialFiles() } } - [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))] + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] [MemberData(nameof(GetFormatsAndSpecialFiles))] public void Extract_SpecialFiles(TarEntryFormat format, TarEntryType entryType) { @@ -36,7 +36,7 @@ public void Extract_SpecialFiles(TarEntryFormat format, TarEntryType entryType) Verify_Extract_SpecialFiles(destination, entry, entryType); } - [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))] + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] [MemberData(nameof(GetFormatsAndSpecialFiles))] public async Task Extract_SpecialFiles_Async(TarEntryFormat format, TarEntryType entryType) { diff --git a/src/libraries/System.Formats.Tar/tests/TarTestsBase.cs b/src/libraries/System.Formats.Tar/tests/TarTestsBase.cs index 7a4aca955bf32..601fa85c3a23a 100644 --- a/src/libraries/System.Formats.Tar/tests/TarTestsBase.cs +++ b/src/libraries/System.Formats.Tar/tests/TarTestsBase.cs @@ -12,6 +12,8 @@ namespace System.Formats.Tar.Tests { public abstract partial class TarTestsBase : FileCleanupTestBase { + protected static bool IsRemoteExecutorSupportedAndPrivilegedProcess => RemoteExecutor.IsSupported && PlatformDetection.IsUnixAndSuperUser; + protected const string InitialEntryName = "InitialEntryName.ext"; protected readonly string ModifiedEntryName = "ModifiedEntryName.ext"; @@ -208,7 +210,6 @@ public enum TestTarFormat // GNU formatted files. Format used by GNU tar versions up to 1.13.25. gnu } - protected static bool IsRemoteExecutorSupportedAndOnUnixAndSuperUser => RemoteExecutor.IsSupported && PlatformDetection.IsUnixAndSuperUser; protected static bool IsUnixButNotSuperUser => !PlatformDetection.IsWindows && !PlatformDetection.IsSuperUser; @@ -707,7 +708,7 @@ internal static IEnumerable GetNamesNonAsciiTestData(NameCapabilities ma // this is 256 but is supported because prefix is not required to end in separator. yield return Repeat(OneByteCharacter, 155) + Separator + Repeat(OneByteCharacter, 100); - // non-ascii prefix + name + // non-ascii prefix + name yield return Repeat(TwoBytesCharacter, 155 / 2) + Separator + Repeat(OneByteCharacter, 100); yield return Repeat(FourBytesCharacter, 155 / 4) + Separator + Repeat(OneByteCharacter, 100); diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs index a4c153025b2e0..42bcf2c36db21 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs @@ -9,7 +9,7 @@ namespace System.Formats.Tar.Tests { public partial class TarWriter_WriteEntry_File_Tests : TarWriter_File_Base { - [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))] + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] [InlineData(TarEntryFormat.Ustar)] [InlineData(TarEntryFormat.Pax)] [InlineData(TarEntryFormat.Gnu)] @@ -51,7 +51,7 @@ public void Add_Fifo(TarEntryFormat format) }, format.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } - [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))] + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] [InlineData(TarEntryFormat.Ustar)] [InlineData(TarEntryFormat.Pax)] [InlineData(TarEntryFormat.Gnu)] @@ -96,7 +96,7 @@ public void Add_BlockDevice(TarEntryFormat format) }, format.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } - [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))] + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] [InlineData(TarEntryFormat.Ustar)] [InlineData(TarEntryFormat.Pax)] [InlineData(TarEntryFormat.Gnu)] @@ -172,7 +172,7 @@ public void CreateEntryFromFileOwnedByNonExistentGroup(TarEntryFormat f) writer.WriteEntry(filePath, fileName); // Should not throw } archive.Seek(0, SeekOrigin.Begin); - + using (TarReader reader = new TarReader(archive, leaveOpen: false)) { PosixTarEntry entry = reader.GetNextEntry() as PosixTarEntry; diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs index 7a3d459bc92a7..343c4f4e0ca2c 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntryAsync.File.Tests.Unix.cs @@ -10,7 +10,7 @@ namespace System.Formats.Tar.Tests { public partial class TarWriter_WriteEntryAsync_File_Tests : TarWriter_File_Base { - [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))] + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] [InlineData(TarEntryFormat.Ustar)] [InlineData(TarEntryFormat.Pax)] [InlineData(TarEntryFormat.Gnu)] @@ -55,7 +55,7 @@ public void Add_Fifo_Async(TarEntryFormat format) }, format.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } - [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))] + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] [InlineData(TarEntryFormat.Ustar)] [InlineData(TarEntryFormat.Pax)] [InlineData(TarEntryFormat.Gnu)] @@ -103,7 +103,7 @@ public void Add_BlockDevice_Async(TarEntryFormat format) }, format.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } - [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))] + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] [InlineData(TarEntryFormat.Ustar)] [InlineData(TarEntryFormat.Pax)] [InlineData(TarEntryFormat.Gnu)] @@ -149,7 +149,7 @@ public void Add_CharacterDevice_Async(TarEntryFormat format) } }, format.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); } - + [ConditionalTheory(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] [InlineData(TarEntryFormat.Ustar)] [InlineData(TarEntryFormat.Pax)] @@ -182,7 +182,7 @@ public void CreateEntryFromFileOwnedByNonExistentGroup_Async(TarEntryFormat f) await writer.WriteEntryAsync(filePath, fileName); // Should not throw } archive.Seek(0, SeekOrigin.Begin); - + await using (TarReader reader = new TarReader(archive, leaveOpen: false)) { PosixTarEntry entry = await reader.GetNextEntryAsync() as PosixTarEntry;