path/filepath: fix EvalSymLinks documentation #40180
path/filepath: fix EvalSymLinks documentation #40180
Jul 13, 2020
The background to this is that Docker misuses EvalSymlinks, so produces confusing logs and/or errors on common Windows configurations.
The Windows bugs are #39786 & #40176. See also kubernetes/utils#172
Jul 13, 2020
It would be beneficial to be able to suggest against using this API on Windows and once there are alternatives which are truly portable and provide solutions to the other issues with this API, against use of this API altogether.
Jul 20, 2020
Here is a list of results for
It shows it may be fixing issues for many more people than introduce breaking changes having this API stop trying to resolve links on Windows and instead return one of
Correct useful results are also results with errors 53 and 67 which are the result of correctly establishing that the path does not exist. Other errors are all wrong. 2 for being the wrong error code - a persistent problem accross go's
The error code -111 means that there was any go error without an error code.
The paths have the following meaning:
This list is far from complete, since these tests
Nov 8, 2020
I closed #40095 on grounds that there is agreement that
Feb 17, 2021
is there any progress on this? Is there on going work on replacing EvalSymlinks? Thanks!
Feb 18, 2021
I think this is still an important issue which is very hard to solve today. But there are lots of great discussion here and the other thread. So the plan is to document some of the conclusions somewhere?
Feb 18, 2021
AFAIK, there is no plan. Feel free to submit a change to the docs. It should indicate that ppl who need EvalSymlinks on Windows should use the WinAPI via x/sys/windows. And perhaps reference this issue and the one I mentioned above.
What version of Go are you using (
What operating system and processor architecture are you using (
What did you do?
Read the docs.
What did you expect to see?
Documentation to the effect that most applications on all operating systems should not use this API, unless they write complex additional logic to resolve just those links that they are interested in (e.g. searching through one volume only, although this API cannot reliably enable this specific scenario) or responsible for (e.g. system administration software).
What did you see instead?
EvalSymLinksintending to resolve all links in the path that it receives as argument, without any hint in the documentation that this might introduce issues due to system reconfigurations, amongst others.
What do you propose to fix this?
I propose documentation changes as the best solution for
EvalSymLinksshort of deleting this API altogether, which is not possible today since deleting or no-op'ing this API as proposed in #40104 violates go policies.
EvalSymLinkviolates what Wikipedia calls the Fundamental Theorem of Software Engineering
EvalSymLinks is not suitable for most applications on any operating system because it unconditionally undoes all indirections for a given path. This is a violation of the principle mentioned which states (in my wording more applicable here):
EvalSymLinksalways resolves all indirections, even those that might have been introduced to fix operational issues affecting the particular application using this API, or which might have been introduced to solve administrative problems on a system that applications should generally remain unaware of - such as disk full situations.
I quote from Microsoft documentation:
Mounted Folders - Win32 apps | Microsoft Docs
This API gives software no options to pick and choose to remove only those indirections that they are aware of, are designed to resolve, or have responsibility for.
Practical reasons for most developers not to use
Certainly on Windows, the practical usefulness and applicability of this API for most applications is severely limited by the following four facts:
On the contrary, especially those users that might in some situations want to see resolved paths may configure links for the specific purpose of abbreviating paths that they frequently use, in which case resolving links and showing them to the user is a severe and annoying usability issue beyond what it in most situations normally already is. Applications should hence always remember the path they were configured or started with and generally only ever show that to the user. I champion that this point stands firmly on any operating system besides Windows.
No reboot is necessary to create, change or delete junctions or links. Such events might hence invalidate results of
EvalSymLinksat any time. No notification is given about such changes, unless the application specifically registers for them. But this is an advanced feature which is nontrivial to implement and test, even though go has/if go would have first-class support for this scenario.
The path through which files or directories on a volume are accessible might hence change at a moments notice, even while the application is using files or directories whose access path(s) changed and the application might continue to open handles to the access path(s) it was configured with on another volume, while the application remains unaware, if it does not use the
EvalSymLinksAPI, or if it takes care not to cache the result of
EvalSymLinksin any way.
And if they do, they do not need to point at the root of the drive with that letter (
Z:\). This might be surprising to any developer that is not intimately aware of Windows internals and will produce issues as soon as they do not consistently use API that is itself properly aware of and tested thoroughly to work on Windows.
Similar expectations and issues may arise about paths that require the use of the
\\?\prefix, which complicates all operations with paths further, including long paths and volume GUID paths which
EvalSymLinksmay also introduce in any application on any machine. It is fair to note that
EvalSymLinksis not the only source of such paths and Windows applications should be prepared to deal with them regardless of whether they use
EvalSymLinks- such paths might even be introduced by user input directly, or through the operating system working directory at application start, or be intermittently visible while the system is being reconfigured.
EvalSymLinkscannot be used to identify volumes in applicable advanced scenario's
Finally, this API by design and as documented can on Windows not identify the volume on which a file or directory resides. Besides resolving UNC mappings, again only in advanced scenario's, this is - for as far as I have been able to identify - about the only situation where the above arguments against the use of
EvalSymLinksmay not always apply for all applications.
Paths with a drive letter never identify volumes. Drive letters may in some trivial system configurations happen to correspond to identifiable volumes, but this can not and must never be relied upon.
EvalSymLinkdefinition, documentation and behavior on Windows reinforces this wrong assumption.
EvalSymLinksis of very limited use on Windows is strikingly evidenced by the configuration provided to reproduce issue #40176. This configuration is of particular interest, since
EvalSymLinksprovides here exactly zero information to the caller. Any path the application requests to be resolved will result in the exact path provided to
EvalSymLinks, since the reparse point resolves to the exact same path as that of the directory that points to it. (before making the path relative and cleaning it, perhaps against statements in the documentation if the fact that an absolute link was resolved might have been lost - and a conforming result might confuse anyone)
In fact, until #40095 is part of go,
EvalSymLinksis completely unable to identify volumes on 64-bit Windows and other Windows installations that use GPT partitioning at all. With this fix, it is only able to do so if the volume happens to have its volume GUID path as its only access path. However now this is merely accidental, due to a fortunate side effect of Windows system architecture.
On Windows systems that do not use GPT partitioning, or on (external) disks that do not use GPT, identifying volumes is simply not possible with a path alone, neither before nor after calling
How concretely do you propose to fix this?
Change the documentation of
The text was updated successfully, but these errors were encountered: