Skip to content
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

Fix: Avoid throwing if a symbolic link cycle to itself is detected while enumerating #52749

Merged
merged 9 commits into from
May 24, 2021

Conversation

carlossanlop
Copy link
Member

Fixes #52746

@carlossanlop carlossanlop added this to the 6.0.0 milestone May 14, 2021
@carlossanlop carlossanlop requested review from adamsitnik and jozkee May 14, 2021 08:05
@carlossanlop carlossanlop self-assigned this May 14, 2021
@ghost
Copy link

ghost commented May 14, 2021

Tagging subscribers to this area: @carlossanlop
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #52746

Author: carlossanlop
Assignees: carlossanlop
Labels:

area-System.IO

Milestone: 6.0.0

Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, @carlossanlop thank you for adding the description and a lot of tests, it made the reviewing much easier for me!

DirectoryInfo testDirectory = CreateDirectorySymbolicLinkToItself();

// Windows differentiates between dir symlinks and file symlinks
int expected = PlatformDetection.IsWindows ? 1 : 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very minor nit: since System.IO.FileSystem.Tests does not target older TFMs, you can use OperatingSystem.IsWindows()

Suggested change
int expected = PlatformDetection.IsWindows ? 1 : 0;
int expected = OperatingSystem.IsWindows() ? 1 : 0;

public void EnumerateFileSystemEntries_LinksWithCycles_ShouldNotThrow()
{
DirectoryInfo testDirectory = CreateDirectorySymbolicLinkToItself();
Assert.Equal(1, Directory.EnumerateFileSystemEntries(testDirectory.FullName).Count());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: xUnit analyzer would suggest using Single: https://stackoverflow.com/a/46654308/5852046

Suggested change
Assert.Equal(1, Directory.EnumerateFileSystemEntries(testDirectory.FullName).Count());
Assert.Single(Directory.EnumerateFileSystemEntries(testDirectory.FullName));

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strangely, I did not get the suggestion. But I can change it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only thing I need to confirm is if calling Single will force the creation of the objects, like Count() does, so that the disk hit is performed. If it's some kind of lazy count, it won't work.

// Skipping attributes would force a disk hit which enters the cyclic symlink
new EnumerationOptions(){ AttributesToSkip = 0 });

Assert.Equal(1, enumerable.Count());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Assert.Equal(1, enumerable.Count());
Assert.Single(enumerable);

Copy link
Member

@jozkee jozkee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise LGTM, thanks.

{
public abstract class BaseSymbolicLinks : FileSystemTest
{
protected DirectoryInfo CreateDirectorySymbolicLinkToItself()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Suggested change
protected DirectoryInfo CreateDirectorySymbolicLinkToItself()
protected DirectoryInfo CreateDirectoryContainingSymbolicLinkToItself()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
protected DirectoryInfo CreateDirectorySymbolicLinkToItself()
protected DirectoryInfo CreateDirectoryContainingSelfReferencingSymbolicLink()

Comment on lines +23 to +24
testDirectory.EnumerateDirectories("*", options).Count();
testDirectory.GetDirectories("*", options).Count();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert how many entries this gets.

@jozkee
Copy link
Member

jozkee commented May 14, 2021

@carlossanlop CI issues seem related to the tests you are adding:

[09:34:28] fail: [FAIL] System.IO.Tests.Directory_SymbolicLinks.EnumerateDirectories_LinksWithCycles_ShouldNotThrow
[09:34:28] info: System.PlatformNotSupportedException : System.Diagnostics.Process is not supported on this platform.

https://helixre8s23ayyeko0k025g8.blob.core.windows.net/dotnet-runtime-refs-pull-52749-merge-495ca526023c41e8ab/System.IO.FileSystem.Tests/console.694d2f52.log?sv=2019-07-07&se=2021-06-03T09%3A01%3A35Z&sr=c&sp=rl&sig=%2Bnmb38cHdd1tLVkSo7T8zOvpQGTNIEiMOCkfzWVvZg8%3D

@iSazonov
Copy link
Contributor

Could you please update the PR title to "Avoid throwing if a self symbolic link cycle is detected while enumerating" since the fix is only for symbolic link to itself.

@carlossanlop
Copy link
Member Author

@jozkee thanks for pointing out the CI failure. We cannot create symbolic links in WASM. Any test that attempts to create symbolic links, must run behind the condition CanCreateSymbolicLinks.

@iSazonov I thought about your suggestion to rename the PR, but instead I thought of adding tests that also verify links to the parent directory. There is only one case that I didn't add: recursively enumerate folders inside a symbolic link that points to its parent folder, because that causes an infinite loop. I don't think this is a bug. We can discuss limiting the recursion levels like @jozkee did in System.Text.Json.

@iSazonov
Copy link
Contributor

iSazonov commented May 20, 2021

We can discuss limiting the recursion levels like @jozkee did in System.Text.Json.

This has been mentioned more than once (is there a tracking issue? #52666?) and obviously we will do this - which is why I ask that this PR be renamed to avoid confusion between itself and transition cycles.

@carlossanlop carlossanlop changed the title Fix: Avoid throwing if a symbolic link cycle is detected while enumerating Fix: Avoid throwing if a symbolic link cycle to itself is detected while enumerating May 20, 2021
@carlossanlop carlossanlop merged commit e329c2d into dotnet:main May 24, 2021
@carlossanlop carlossanlop deleted the SymlinkCycle branch May 24, 2021 17:48
@@ -45,15 +45,17 @@ namespace System.IO.Enumeration
if (isUnknown)
{
isSymlink = entry.IsSymbolicLink;
isDirectory = entry._status.IsDirectory(entry.FullPath);
// Need to fail silently in case we are enumerating
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the comment... isn't all of this code about enumerating?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enumeration always goes through this path, yes. I do not know if in the future we will reach FileSystemEntry.Initialize another way.

Next time I touch this code, I can change the comment to // This call needs to fail silently.

@ghost ghost locked as resolved and limited conversation to collaborators Jun 24, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Some filesystem enumeration cases may throw if a symbolic link cycle is detected (link to itself)
6 participants