Skip to content

Commit 1d400c2

Browse files
am11jeffhandley
authored andcommitted
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
1 parent 0cee4aa commit 1d400c2

File tree

4 files changed

+33
-3
lines changed

4 files changed

+33
-3
lines changed

src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,12 @@ public string LinkName
138138
/// <remarks>The value in this field has no effect on Windows platforms.</remarks>
139139
public UnixFileMode Mode
140140
{
141-
get => (UnixFileMode)_header._mode;
141+
// Some paths do not use the setter, and we want to return valid UnixFileMode.
142+
// This mask only keeps the least significant 12 bits.
143+
get => (UnixFileMode)(_header._mode & (int)TarHelpers.ValidUnixFileModes);
142144
set
143145
{
144-
if ((int)value is < 0 or > 4095) // 4095 in decimal is 7777 in octal
146+
if ((value & ~TarHelpers.ValidUnixFileModes) != 0) // throw on invalid UnixFileModes
145147
{
146148
throw new ArgumentOutOfRangeException(nameof(value));
147149
}

src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ internal static partial class TarHelpers
2121
internal const int MaxBufferLength = 4096;
2222
internal const long MaxSizeLength = (1L << 33) - 1; // Max value of 11 octal digits = 2^33 - 1 or 8 Gb.
2323

24+
internal const UnixFileMode ValidUnixFileModes =
25+
UnixFileMode.UserRead |
26+
UnixFileMode.UserWrite |
27+
UnixFileMode.UserExecute |
28+
UnixFileMode.GroupRead |
29+
UnixFileMode.GroupWrite |
30+
UnixFileMode.GroupExecute |
31+
UnixFileMode.OtherRead |
32+
UnixFileMode.OtherWrite |
33+
UnixFileMode.OtherExecute |
34+
UnixFileMode.StickyBit |
35+
UnixFileMode.SetGroup |
36+
UnixFileMode.SetUser;
37+
2438
// Default mode for TarEntry created for a file-type.
2539
private const UnixFileMode DefaultFileMode =
2640
UnixFileMode.UserRead | UnixFileMode.UserWrite |

src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ private TarEntry ConstructEntryForWriting(string fullPath, string entryName, Fil
6666
entry._header._aTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(status.ATime);
6767
entry._header._cTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(status.CTime);
6868

69-
entry._header._mode = status.Mode & 4095; // First 12 bits
69+
// This mask only keeps the least significant 12 bits valid for UnixFileModes
70+
entry._header._mode = status.Mode & (int)TarHelpers.ValidUnixFileModes;
7071

7172
// Uid and UName
7273
entry._header._uid = (int)status.Uid;

src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,19 @@ public async Task ExtractEntry_ManySubfolderSegments_NoPrecedingDirectoryEntries
9797
}
9898
}
9999

100+
[Fact]
101+
public async Task ExtractEntry_DockerImageTarWithFileTypeInDirectoriesInMode_SuccessfullyExtracts_Async()
102+
{
103+
using (TempDirectory root = new TempDirectory())
104+
{
105+
await using MemoryStream archiveStream = GetTarMemoryStream(CompressionMethod.Uncompressed, "golang_tar", "docker-hello-world");
106+
await TarFile.ExtractToDirectoryAsync(archiveStream, root.Path, overwriteFiles: true);
107+
108+
Assert.True(File.Exists(Path.Join(root.Path, "manifest.json")));
109+
Assert.True(File.Exists(Path.Join(root.Path, "repositories")));
110+
}
111+
}
112+
100113
[Theory]
101114
[InlineData(TarEntryType.SymbolicLink)]
102115
[InlineData(TarEntryType.HardLink)]

0 commit comments

Comments
 (0)