-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tar, Zip: respect umask when creating files. #71647
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -5,6 +5,7 @@ | |||||
using System.Runtime.InteropServices; | ||||||
using System.Text; | ||||||
using System.Threading.Tasks; | ||||||
using Microsoft.DotNet.RemoteExecutor; | ||||||
using Xunit; | ||||||
|
||||||
namespace System.IO.Compression.Tests | ||||||
|
@@ -56,6 +57,16 @@ void EnsureExternalAttributes(string permissions, ZipArchiveEntry entry) | |||||
} | ||||||
} | ||||||
|
||||||
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] | ||||||
public void UnixCreateSetsPermissionsInExternalAttributesUMaskZero() | ||||||
{ | ||||||
RemoteExecutor.Invoke(() => | ||||||
{ | ||||||
umask(0); | ||||||
new ZipFile_Unix().UnixCreateSetsPermissionsInExternalAttributes(); | ||||||
}).Dispose(); | ||||||
} | ||||||
|
||||||
[Fact] | ||||||
public void UnixExtractSetsFilePermissionsFromExternalAttributes() | ||||||
{ | ||||||
|
@@ -90,6 +101,16 @@ public void UnixExtractSetsFilePermissionsFromExternalAttributes() | |||||
} | ||||||
} | ||||||
|
||||||
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] | ||||||
public void UnixExtractSetsFilePermissionsFromExternalAttributesUMaskZero() | ||||||
{ | ||||||
RemoteExecutor.Invoke(() => | ||||||
{ | ||||||
umask(0); | ||||||
new ZipFile_Unix().UnixExtractSetsFilePermissionsFromExternalAttributes(); | ||||||
}).Dispose(); | ||||||
} | ||||||
|
||||||
private static string[] CreateFiles(string folderPath, string[] testPermissions) | ||||||
{ | ||||||
string[] expectedPermissions = new string[testPermissions.Length]; | ||||||
|
@@ -126,6 +147,8 @@ private static string[] CreateFiles(string folderPath, string[] testPermissions) | |||||
|
||||||
private static void EnsureFilePermissions(string filename, string permissions) | ||||||
{ | ||||||
permissions = GetExpectedPermissions(permissions); | ||||||
|
||||||
Interop.Sys.FileStatus status; | ||||||
Assert.Equal(0, Interop.Sys.Stat(filename, out status)); | ||||||
|
||||||
|
@@ -199,26 +222,28 @@ await Task.WhenAll( | |||||
|
||||||
private static string GetExpectedPermissions(string expectedPermissions) | ||||||
{ | ||||||
if (string.IsNullOrEmpty(expectedPermissions)) | ||||||
using (var tempFolder = new TempDirectory()) | ||||||
{ | ||||||
// Create a new file, and get its permissions to get the current system default permissions | ||||||
|
||||||
using (var tempFolder = new TempDirectory()) | ||||||
string filename = Path.Combine(tempFolder.Path, Path.GetRandomFileName()); | ||||||
FileStreamOptions fileStreamOptions = new() | ||||||
{ | ||||||
string filename = Path.Combine(tempFolder.Path, Path.GetRandomFileName()); | ||||||
File.WriteAllText(filename, "contents"); | ||||||
|
||||||
Interop.Sys.FileStatus status; | ||||||
Assert.Equal(0, Interop.Sys.Stat(filename, out status)); | ||||||
|
||||||
expectedPermissions = Convert.ToString(status.Mode & 0xFFF, 8); | ||||||
Access = FileAccess.Write, | ||||||
Mode = FileMode.CreateNew | ||||||
}; | ||||||
if (expectedPermissions != null) | ||||||
{ | ||||||
fileStreamOptions.UnixCreateMode = (UnixFileMode)Convert.ToInt32(expectedPermissions, 8); | ||||||
} | ||||||
} | ||||||
new FileStream(filename, fileStreamOptions).Dispose(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are the current tests failing without this change? Before we would only create a new file when the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. The current tests require the exact permission. Here we're determining the expected permission that takes into account the umask. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The changes to this test suite are to update the expected permissions so they take into account the umask. @eerhardt is this good for you? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My concern is that we aren't testing that GroupWrite and OtherWrite bits are set correctly anymore. I think we should have tests that respect the umask (what you are fixing here) and tests that clear the umask and ensure the full permissions are kept. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added tests that run with a zero umask. ptal. |
||||||
|
||||||
return expectedPermissions; | ||||||
return Convert.ToString((int)File.GetUnixFileMode(filename), 8); | ||||||
} | ||||||
} | ||||||
|
||||||
[LibraryImport("libc", StringMarshalling = StringMarshalling.Utf8, SetLastError = true)] | ||||||
private static partial int mkfifo(string path, int mode); | ||||||
|
||||||
[LibraryImport("libc", StringMarshalling = StringMarshalling.Utf8)] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
No strings are being marshalled here, so no need. This can be addressed in a different PR, if we don't want to reset CI. |
||||||
private static partial int umask(int umask); | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have some additional members on UnixFileMode that represent common combinations of these flags?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had suggested some as part of the API proposal. They were left out because they'd mess up 'ToString'.
These are common combinations defined in stat.h:
cc @eerhardt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe our internal usage is enough justification to add these common combinations now?
cc @bartonjs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the consts somewhere and having them be values in the enum are two different things.
If
OwnershipPermissions
were defined as-shown in the enum then having the 0777 value would ToString() not asUserRead | UserWrite | ...
but asOwnershipPermissions
, which gets... weird.Putting them somewhere else as a public const doesn't impact the ToString() behavior. The best I can see would be something like
File.UnixOwnershipMask
.