-
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
Ensure FileStatus and FileSystemEntry Hidden and ReadOnly attributes are retrieved the same way #40641
Conversation
|
||
// Put a period in front to make it hidden on Unix | ||
FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "." + GetTestFileName())); | ||
FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, GetTestFileName())); |
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.
No changes in this test, just organized some lines for easier understanding.
It also helps to show that this test is affected by my PR.
EDIT: I actually ended up making changes in this file, to split the tests into each platform, since the IsHidden property is not supported in Linux.
@iSazonov can you take a look to this PR? I think I still need to add code to throw but I'm not entirely sure exactly where. |
src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs
Show resolved
Hide resolved
src/libraries/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.FileSystem/tests/Enumeration/SkipAttributeTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs
Outdated
Show resolved
Hide resolved
if (PlatformDetection.IsWindows) | ||
fileTwo.Attributes = fileTwo.Attributes | FileAttributes.Hidden; |
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.
Shouldn't this also be performed on other platforms?
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.
You pointed out the documentation says it is supported in Linux, Windows and MacOS. Let me debug this unit test in WIndows, MacOS and Unix to see if it's truly supported there, and if so, then the if should be removed, and maybe a separate test should be added for Linux and MacOS (because of the "." prefix in the name, which already hides the file).
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.
So in Linux, if I remove the code that prepends a "." to the filename, and attempt to set FileAttributes.Hidden to fileTwo, the test fails, because
Interop.Sys.CanSetHiddenFlag
returns false.
The documentation needs to be updated for Linux.
I'll test MacOS and Windows now.
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.
It works on OSX. I actually found a test in FileSystemEntry which would prevent the user from collecting an enumeration of hidden files. I fixed it now.
Next: Windows.
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.
Works on Windows too.
…s PR suggestions.
…Split existing Skip attribute test into different platforms.
@jozkee @iSazonov can you take another look? The new commits include:
|
@@ -143,7 +140,7 @@ public FileAttributes Attributes | |||
public DateTimeOffset LastAccessTimeUtc => _status.GetLastAccessTime(FullPath, continueOnError: true); | |||
public DateTimeOffset LastWriteTimeUtc => _status.GetLastWriteTime(FullPath, continueOnError: true); | |||
public bool IsDirectory => _status.InitiallyDirectory; | |||
public bool IsHidden => _directoryEntry.Name[0] == '.'; | |||
public bool IsHidden => _directoryEntry.Name[0] == '.' || (Attributes & FileAttributes.Hidden) != 0; |
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.
Actually, I think this should be:
public bool IsHidden => _directoryEntry.Name[0] == '.' || (Interop.Sys.CanSetHiddenFlag && (Attributes & FileAttributes.Hidden) != 0);
Otherwise, if the user sets the Hidden flag in Linux, it won't really hide the file, but this will return true.
I'm going to test this on Linux.
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 added this check too, just in case. I noticed that the Hidden flag cannot be set to the file Attributes in Linux, because the property performs some checks to see if it's possible. But just in case, attempting to read the value should be protected.
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.
The public property was introduced here: c603407
But the change that added the case for UF_HIDDEN should've added this check:
dotnet/corefx#34560
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 a conversation with @jozkee about this and the Interop.Sys.CanSetHiddenFlag
check is not necessary, because the Linux P/Invoke will never allow setting it. So I'm reverting the last commit.
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.
Attributes
adds FileAttributes.ReadOnly
which is irrelevant in this operation.
public bool IsHidden => _directoryEntry.Name[0] == '.' || (Attributes & FileAttributes.Hidden) != 0; | |
public bool IsHidden => _directoryEntry.Name[0] == '.' || (_initialAttributes & FileAttributes.Hidden) != 0; |
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.
Can you please also add a comment on top explaining where the attribute is supported?
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.
Suggestion applied, and comment added.
{ | ||
// Put a period in front to make it hidden on Unix | ||
IsHiddenAttributeInternal(useDotPrefix: false, useHiddenFlag: true); |
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.
Can you also add an OSX test that uses the dot prefix?
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.
The test IsHiddenAttribute_Unix
in line 127 runs in OSX too (TestPlatforms.AnyUnix
is true
in OSX).
return IsReadOnly(_fileStatus); | ||
} | ||
|
||
internal static bool IsReadOnly(Interop.Sys.FileStatus fileStatus) |
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.
Private?
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.
No, it needs to be accessed by FileSystemEntry
too, which is in the same assembly.
@@ -39,19 +39,23 @@ internal struct FileStatus | |||
internal bool IsReadOnly(ReadOnlySpan<char> path, bool continueOnError = false) | |||
{ | |||
EnsureStatInitialized(path, continueOnError); | |||
return IsReadOnly(_fileStatus); |
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.
Why do we re-read if we have Refresh() for this.
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'm not sure I understand the question.
The functionality of this code has not been changed. I merely moved the contents of the old IsReadOnly
method into its own internal helper static method that can be accessed by both FileSystemEntry
and FileStatus
, to avoid repeating code.
I don't think we should do a Refresh
call here, that's what EnsureStatInitialized
is for - it will only perform a Refresh
if we haven't called it yet.
{ | ||
// IMPORTANT: Attribute logic must match the logic in FileSystemEntry | ||
return (fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR; |
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.
It is better move p/invokes from FileSystemEntry.Initialize() in the place and exclude re-reading too.
The same for all attributes.
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 talked to @jozkee about this, we can get them moved to a separate helper class, but I would like to do that in a future PR.
Thanks for fixing this! What is Preview we get the fix in? |
@iSazonov .NET RC1 |
Reverts "Ensure FileStatus and FileSystemEntry Hidden and ReadOnly attributes are retrieved the same way" (commit 6ed1e41) which introduced a perf regression.
…0-rc2 [release/5.0-rc2] Revert #40641
Fixes #37301
These two files do very similar tasks, but when it comes to collect the Hidden attribute, the first one is simpler than the second one:
runtime/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs
Lines 59 to 67 in bd6cbe3
runtime/src/libraries/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs
Lines 81 to 82 in bd6cbe3
This change ensures both collect the Hidden attribute the same way, and makes it more obvious that both methods are closely related.
Also, the ReadOnly attribute was not being collected in the first file, so I added code to do it, as well as a unit test.
I ran all the System.IO.FileSystem unit tests in Ubuntu and in MacOS and they passed. Pending yet to see the CI results.
This fix needs to go into 5.0, or later it could become a breaking change, as explained here.