From db5f4238d0261919b509428221a21c1964833a94 Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Tue, 18 Oct 2022 09:07:19 +0300 Subject: [PATCH 1/4] Trim file type bits from mode header --- .../src/System/Formats/Tar/TarEntry.cs | 4 ++-- .../src/System/Formats/Tar/TarWriter.Unix.cs | 2 +- .../TarFile.ExtractToDirectoryAsync.Stream.Tests.cs | 13 +++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs index a27df41f4c1c6a..09bb2b39433c49 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs @@ -138,10 +138,10 @@ public string LinkName /// The value in this field has no effect on Windows platforms. public UnixFileMode Mode { - get => (UnixFileMode)_header._mode; + get => (UnixFileMode)(_header._mode & 0xFFF); // mask to only keep least significant 12-bits set { - if ((int)value is < 0 or > 4095) // 4095 in decimal is 7777 in octal + if ((int)value is < 0 or > 0xFFF) // 0xFFF (4095) in decimal is 7777 in octal { throw new ArgumentOutOfRangeException(nameof(value)); } 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 a691582178df6a..7a7f00f89806d6 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 @@ -66,7 +66,7 @@ private TarEntry ConstructEntryForWriting(string fullPath, string entryName, Fil entry._header._aTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(status.ATime); entry._header._cTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(status.CTime); - entry._header._mode = status.Mode & 4095; // First 12 bits + entry._header._mode = status.Mode & 0xFFF; // least significant 12 bits // Uid and UName entry._header._uid = (int)status.Uid; 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 70c6fcbf8049d4..82c37fb0dd0a70 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 @@ -97,6 +97,19 @@ public async Task ExtractEntry_ManySubfolderSegments_NoPrecedingDirectoryEntries } } + [Fact] + public async Task ExtractEntry_DockerImageTarWithFileTypeInDirectoriesInMode_SuccessfullyExtracts_Async() + { + using (TempDirectory root = new TempDirectory()) + { + await using MemoryStream archiveStream = GetTarMemoryStream(CompressionMethod.Uncompressed, "golang_tar", "docker-hello-world"); + await TarFile.ExtractToDirectoryAsync(archiveStream, root.Path, overwriteFiles: true); + + Assert.True(File.Exists(Path.Join(root.Path, "manifest.json"))); + Assert.True(File.Exists(Path.Join(root.Path, "repositories"))); + } + } + [Theory] [InlineData(TarEntryType.SymbolicLink)] [InlineData(TarEntryType.HardLink)] From 04bf3d07173550388f45f5cde7b43af52c4a8299 Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Tue, 18 Oct 2022 09:40:37 +0300 Subject: [PATCH 2/4] Define and use ValidUnixFileModes --- .../src/System/Formats/Tar/TarEntry.cs | 6 ++++-- .../src/System/Formats/Tar/TarHelpers.Unix.cs | 14 ++++++++++++++ .../src/System/Formats/Tar/TarWriter.Unix.cs | 3 ++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs index 09bb2b39433c49..5c08ec75f74da5 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs @@ -138,10 +138,12 @@ public string LinkName /// The value in this field has no effect on Windows platforms. public UnixFileMode Mode { - get => (UnixFileMode)(_header._mode & 0xFFF); // mask to only keep least significant 12-bits + // Some paths do not use the setter, and we want to return valid UnixFileMode. + // This mask only keeps the least significant 12 bits. + get => (UnixFileMode)(_header._mode & (int)TarHelpers.ValidUnixFileModes); set { - if ((int)value is < 0 or > 0xFFF) // 0xFFF (4095) in decimal is 7777 in octal + if ((value & ~TarHelpers.ValidUnixFileModes) != 0) // throw on invalid UnixFileModes { throw new ArgumentOutOfRangeException(nameof(value)); } diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.Unix.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.Unix.cs index 3e0a0b814484d4..b1e2656c3fd951 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.Unix.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.Unix.cs @@ -11,6 +11,20 @@ internal static partial class TarHelpers { private static readonly Lazy s_umask = new Lazy(DetermineUMask); + internal const UnixFileMode ValidUnixFileModes = + UnixFileMode.UserRead | + UnixFileMode.UserWrite | + UnixFileMode.UserExecute | + UnixFileMode.GroupRead | + UnixFileMode.GroupWrite | + UnixFileMode.GroupExecute | + UnixFileMode.OtherRead | + UnixFileMode.OtherWrite | + UnixFileMode.OtherExecute | + UnixFileMode.StickyBit | + UnixFileMode.SetGroup | + UnixFileMode.SetUser; + private static UnixFileMode DetermineUMask() { // To determine the umask, we'll create a file with full permissions and see 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 7a7f00f89806d6..357e4a8a7587f1 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 @@ -66,7 +66,8 @@ private TarEntry ConstructEntryForWriting(string fullPath, string entryName, Fil entry._header._aTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(status.ATime); entry._header._cTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(status.CTime); - entry._header._mode = status.Mode & 0xFFF; // least significant 12 bits + // This mask only keeps the least significant 12 bits valid for UnixFileModes + entry._header._mode = status.Mode & (int)TarHelpers.ValidUnixFileModes; // Uid and UName entry._header._uid = (int)status.Uid; From cec85bfaa072e84312393542324880c6753003a1 Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Tue, 18 Oct 2022 13:03:38 +0300 Subject: [PATCH 3/4] Rev System.Formats.Tar.TestData version --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index cecaf60d795143..cf798fd808027c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -162,9 +162,9 @@ https://github.com/dotnet/runtime-assets 98dccc055b925524dfb77fb9d1b54598475825ac - + https://github.com/dotnet/runtime-assets - 98dccc055b925524dfb77fb9d1b54598475825ac + 6d1bdc7e14a076deb791bf469202bc719a264abd https://github.com/dotnet/runtime-assets diff --git a/eng/Versions.props b/eng/Versions.props index bb65849384cf67..50af6016cbe346 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -141,7 +141,7 @@ 7.0.0-beta.22510.1 7.0.0-beta.22510.1 7.0.0-beta.22510.1 - 7.0.0-beta.22510.1 + 7.0.0-beta.22518.1 7.0.0-beta.22510.1 7.0.0-beta.22510.1 7.0.0-beta.22510.1 From 6af0213e235f05e9c8748f245384864eaf7f004a Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Tue, 18 Oct 2022 13:46:10 +0300 Subject: [PATCH 4/4] Move ValidUnixFileModes to shared helpers --- .../src/System/Formats/Tar/TarHelpers.Unix.cs | 14 -------------- .../src/System/Formats/Tar/TarHelpers.cs | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.Unix.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.Unix.cs index b1e2656c3fd951..3e0a0b814484d4 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.Unix.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.Unix.cs @@ -11,20 +11,6 @@ internal static partial class TarHelpers { private static readonly Lazy s_umask = new Lazy(DetermineUMask); - internal const UnixFileMode ValidUnixFileModes = - UnixFileMode.UserRead | - UnixFileMode.UserWrite | - UnixFileMode.UserExecute | - UnixFileMode.GroupRead | - UnixFileMode.GroupWrite | - UnixFileMode.GroupExecute | - UnixFileMode.OtherRead | - UnixFileMode.OtherWrite | - UnixFileMode.OtherExecute | - UnixFileMode.StickyBit | - UnixFileMode.SetGroup | - UnixFileMode.SetUser; - private static UnixFileMode DetermineUMask() { // To determine the umask, we'll create a file with full permissions and see diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs index d5393b45ffc834..45cae1c2759044 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs @@ -21,6 +21,20 @@ internal static partial class TarHelpers internal const int MaxBufferLength = 4096; internal const long MaxSizeLength = (1L << 33) - 1; // Max value of 11 octal digits = 2^33 - 1 or 8 Gb. + internal const UnixFileMode ValidUnixFileModes = + UnixFileMode.UserRead | + UnixFileMode.UserWrite | + UnixFileMode.UserExecute | + UnixFileMode.GroupRead | + UnixFileMode.GroupWrite | + UnixFileMode.GroupExecute | + UnixFileMode.OtherRead | + UnixFileMode.OtherWrite | + UnixFileMode.OtherExecute | + UnixFileMode.StickyBit | + UnixFileMode.SetGroup | + UnixFileMode.SetUser; + // Default mode for TarEntry created for a file-type. private const UnixFileMode DefaultFileMode = UnixFileMode.UserRead | UnixFileMode.UserWrite |