From 1d400c283a1b25eb9910ebd1a49056d8c9e58860 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Thu, 20 Oct 2022 21:51:48 +0300 Subject: [PATCH 1/2] Trim file type bits from mode header (#77151) * Trim file type bits from mode header * Define and use ValidUnixFileModes * Rev System.Formats.Tar.TestData version * Move ValidUnixFileModes to shared helpers --- .../src/System/Formats/Tar/TarEntry.cs | 6 ++++-- .../src/System/Formats/Tar/TarHelpers.cs | 14 ++++++++++++++ .../src/System/Formats/Tar/TarWriter.Unix.cs | 3 ++- ...TarFile.ExtractToDirectoryAsync.Stream.Tests.cs | 13 +++++++++++++ 4 files changed, 33 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 a27df41f4c1c6..5c08ec75f74da 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; + // 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 > 4095) // 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.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs index d5393b45ffc83..45cae1c275904 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 | 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 a691582178df6..357e4a8a7587f 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 & 4095; // First 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; 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 70c6fcbf8049d..82c37fb0dd0a7 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 7cb0085ea51880a6e00a7e2e6b3ef572e547bd8a Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Mon, 31 Oct 2022 11:43:42 -0700 Subject: [PATCH 2/2] Bump package version for TAR test assets --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index bf5ca9e368df6..6a06b30e7d7d5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -126,7 +126,7 @@ 7.0.0-beta.22503.1 7.0.0-beta.22503.1 7.0.0-beta.22503.1 - 7.0.0-beta.22503.1 + 7.0.0-beta.22524.1 7.0.0-beta.22503.1 7.0.0-beta.22503.1 7.0.0-beta.22503.1