-
Notifications
You must be signed in to change notification settings - Fork 29.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
win, fs: fix realpath behavior on substed drives #7559
Conversation
This is a partial revert of nodejs@b488b19 It restores old javascript implementation of realpath and realpathSync. The names have been changed: added JS and not exported in fs module.
Before v6 on drives created with subst and network mapped drives realpath used to return filename on the mapped drive. With v6 it now returns filename on the original device or on the network share. This restores the old behavior by using old javascript implementation when path returned by new implementation is on a different device than the original path. Fixes: 7294
#7548 Should make this unnecessary? |
No, #7294 is different beast than ELOOP. |
@@ -1562,6 +1562,8 @@ fs.unwatchFile = function(filename, listener) { | |||
} | |||
}; | |||
|
|||
// Cache for JS real path | |||
var realpathCache = {}; |
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.
One global realpath
cache without some kind of cache validation is probably a no-go?
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.
That's a thing that needs to be solved. One global cache is probably not a good idea. But some caching is needed for performance reasons.
I would guess user could add cache object to options. It could be also used on Linux, to cache realpath results (not the partial ones as in JS implementation)
It seems like this could be handled better in C++ instead of resorting to reinstating the js realpath implementation? |
Labelling as |
Would definitely prefer to see if there's a fix that can be made in libuv before bringing back the js realpath impl. |
@mscdex, @jasnell: old JS implementation didn't check if the drive itself was not a "link" - e.g. subst or mapped network location. It just assumed its a hard drive, only checking if it exists. I don't think there is a workaround for this in uv - it calls GetFinalPathNameByHandle, and that will always return original drive/network share name and not the mapped one. One thing that could be done, is to port old js implementation to C++, as a fallback for this corner case, but that would not be an easy task. |
@bzoz What I had in mind was to check if the drive is mapped when the input path starts with a drive letter that is different than that of the output path. If it is, then simply replace the beginning, common portion of the input and output paths with the drive letter from the input path. |
I think the other Windows issues that were arising from the v6 realpath change are a lot easier to fix when building upon this, likely by simple additions to I’d also be +1 on moving the entire old implementation to C++, but as @bzoz said, that’s something for a different time scale. |
@mscdex: that would unfortunately not work:
Old JS would follow the link to C drive, returning |
@bzoz I'm confused now. I thought you said the C++ realpath and js realpath were returning different paths, so why would both return |
Maybe to clarify: return value of
If we would use only uv version and try to replace the beginning, we would have a bug in case |
This does step on my
even though this PR only addresses Windows specific behavior. Would it not be possible to resolve the path normally then pass it to a function for fixup afterwards, instead of adding the entire JS implementation again? |
@trevnorris #6861 #7044 #7192 #7294 are a couple of Windows issues that were arising from the libuv-based realpath implementation, and I think your PR is orthogonal to fixing them? |
I think this can be addressed in C++ land by passing the original drive letter to |
@trevnorris: JS realpath implementation is copy/pasted from before the change to uv. I didn't want to change it so it would be easier to review rest of the changes. But yes, I'll clean it up, remove those What I try to do here is pretty much resolving the path normally using the new native realpath, and then running "fixup" if needed ( @addaleax: From the issues you mentioned my PR will only fix #7294, but as you noticed earlier we could extend this fix for the other issues that you mentioned. @mscdex: Sorry, I just don't see how it could work. As I understand your idea, with
|
@bzoz Normal junctions can be detected as well. |
@mscdex I just cannot see how it could be done other than reimplementing JS code in C++. We would have to check every path segment to see if it is not a link. |
It is, but also I don't believe re-adding the entire JS implementation is necessary to solve this issue. @bzoz In my initial implementation I actually was implementing a way of resolving arbitrarily long nested symlinks using |
I'll try to elaborate on 3: If the Case 3 is when We could add some conditions to make it work. For example if we take But when Now, we have As for performance - isn't disk access the bottleneck anyway? Would it really be faster in C++? Also, here we have a working implementation, with caching etc. Sure, we could reimplement it in C++, but I don't think it would be easy to do so. |
const uvResult = binding.realpath(pathModule._makeLong(resolvedPath), | ||
options.encoding); | ||
if (realpathJSNeeded(resolvedPath, uvResult)) | ||
{ |
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.
Does make lint
not catch this?
IMHO "fixing" case 3 is not correct. It might be how pre-v6 behave, but that doesn't make it correct. I guess it boils down to how we want to interpret drive subst-ing. In my mind it's like a symlink from /c/xthing to /x/ so since symlinks should be resolved by realpath, we shouldn't put the substed drive letter, but keep the resolved one. As a general note: it might be better to have a meta-issue with the realpath edge cases that need fixing, there are other reasons why might want / need to go back to the JS implementation than this specific one: ELOOP, ramdisks, etc. |
I also think that "case 3" was pretty much a bug in pre-v6, but from discussion at #7175 I understand, that v6 change didn't suppose to change the way realpath work. |
Please see #7726. Saúl Ibarra Corretgé |
This will be addressed when #7899 lands. |
Checklist
make -j4 test
(UNIX), orvcbuild test nosign
(Windows) passesAffected core subsystem(s)
fs, win
Description of change
Work in progress for issues related to new realpath implementation (#7175).
Before v6 on drives created with subst and network mapped drives realpath used to return filename on the mapped drive. With v6 (b488b19) it now returns filename on the original device or on the network share. This restores the old behavior by:
This PR addresses only issues related to the filename resolved being different on v6 and v4 (e.g. #7294). There are other issues, for example related to permissions on Windows like #7192 and other on Linux as described in #7175. Some of those are to be addressed in different patch (comment).
@trevnorris this fixes some of the Windows issues. Can you review to make sure it's compatible with your changes?