-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Preview 7 inconsistent FileSystemInfo LinkTarget and ResolveLinkTarget results when using virtual drives #57582
Comments
Tagging subscribers to this area: @dotnet/area-system-io Issue DetailsOriginally reported by @fitdev in #57575 On Windows, there is an inconsistency of final targets returned depending on which APIs are used, and whether or not virtual drives created with subst command are used in the path (both the link and the target residing on such virtual drives): The So, given a structure like this:
Calling While calling Even though, logically, and for consistency results should be the same.
|
I manually tested this and was able to reproduce it. Here are my findings: A) runtime/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs Line 605 in 27059fb
We currently pass the
Interestingly, I tested passing the Now, on the other hand, runtime/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs Line 474 in 27059fb
The example of this issue happens to only have one symlink (no chain of 2 or more), so passing If you call runtime/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs Line 435 in 27059fb
I do not think this is a bug. This seems to be expected behavior coming from Windows: When retrieving the final target of a symlink, we want to resolve all the path segments (especially because symlinks can be relative). As part of the normalization, Windows happens to also resolve a virtual drive to its real path. I'd like to leave this issue open in case @fitdev or the community have some additional thoughts. |
@carlossanlop Thank you for looking into this. When looking through your code I saw that you indeed use 2 different Windows APIs to resolve targets, and I did suspect that the inconsistency comes from the way The problem being that you would expect the final targets obtained both ways to be the same, and currently nowhere in the API names or the docs / comments it is suggested that it may not be so. Furthermore, on Linux or other platforms, these 2 ways of getting final target may actually produce the same result (Windows being the exception), which again would be inconsistent. You may ask why would anyone be using It may also be important in addressing somewhat niche questions like finding all symlinks whose targets are on the same logical drive. But I guess my biggest concern is just inconsistency. Perhaps you could address that with another bool/enum flag for the An enum may be (names are just an example): public enum LinkTargetType {
Immediate = 0,
Final,
FinalNormalized
} |
Also, I have not yet tested a case without Virtual Disks, but where a symlink's target is set throgh another symlink:
I suspect that in this case, once again results will be inconsistent, and the Which is quite serious discrepancy, because this way the resulting paths may look totally different between the two methods. |
And one last thought: somehow a distinction between 2 concepts in the API should be surfaced or at least noted either in API names, comments, or docs (later perhaps even specific APIs for the 2 concepts could be made available):
And so the trouble is that the So in my opinion, it is not ideal that the current API effectively mixes these 2 related, but slightly different concepts. |
IIRC, virtual drives are another kind of Reparse Point (Mount Point I think), so it's understandable that With that said, we should improve the API |
If you do not fully support junctions / mount points (at least in as far as "reading" them), it does not make sense to partially support them through a single, presumably new API - "ResolveFinalTarget" (while the other APIs like So my take on this, either you support these 2 kinds of reparse points in all your "read" APIs consistently, or not at all, i.e. treat them as regular directories. Writing support for these is another matter which is not part of this issue.
So, today I did this test:
Note, there are no junctions or virtual drives involved - only symlinks. And, just as I thought results are very different for
Whereas And this is the issue! It's confusing and inconsistent, currently seen on Windows only, though perhaps a similar thing happens on Linux, but I don't know. And the reason it happens is because the 2 APIs It's a subtle but an important issue and should somehow be addressed to avoid confusion. As I suggested the distinction in the behavior, perhaps, can be surfaced though another flag or an enum that tells what kind of final target should be returned - merely the one so that the last path segment is not a link (consistent with public enum LinkTargetType {
// Immediate target of the link as it was set
Immediate = 0,
// Final target of the link, so that the last path segment is not a link, consistent with calling LinkTarget repeatedly until it is null
Final,
// The ultimate, fully resolved, target path without any links in the path. NOT consistent with calling LinkTarget repeatedly until it is null, and may produce completely different paths (depending on specific cases)
FinalResolved
} |
I meant
Exactly, you are trying to get the same result from two different APIs. One is for resolution and the other, |
Right. It does make sense. However I still think that at the very least in the comments, and in the docs it should be explained that in general: Also note that the way |
Yes, we can fix Junctions returning null LinkTarget, that will be tracked in #57575. And for the noted discrepancy, we can document the behavior in the API remarks. Thanks for reporting your experience with the new API, very valuable! |
Just wanted to clarify though, with respect to Junctions. The current behavior of |
Originally reported by @fitdev in #57575
On Windows, there is an inconsistency of final targets returned depending on which APIs are used, and whether or not virtual drives created with subst command are used in the path (both the link and the target residing on such virtual drives):
The
DirectoryInfo.ResolveLinkTarget(returnFinalTarget: true)
API (and other APIs you added that resolve final target) resolve the final target to non-virtual drives, while theDirectoryInfo.LinkTarget
(and other similar APIs that resolve the immediate target), when called repeatedly while LinkTarget != null stop at the virtual drive level.So, given a structure like this:
Calling
DirectoryInfo.ResolveLinkTarget(returnFinalTarget: true)
onX:\SymlinkToRealFolderOnX
will result in:C:\RootDirectoryForVirtualDriveX\SomeRealFolder
While calling
DirectoryInfo.LinkTarget
(repeatedly while the result is non-null) onX:\SymlinkToRealFolderOnX
will result in:X:\SomeRealFolder
Even though, logically, and for consistency results should be the same.
The text was updated successfully, but these errors were encountered: