node
node copied to clipboard
Incorrect cwd() inside subfolders of Windows directory symlinks or junctions
- Version: v14.8.0
- Platform: Windows 10 1809
- Subsystem: process, path
What steps will reproduce the bug?
cd c:
mkdir folder
mklink /D link folder
cd link
node -p 'process.cwd()'
# C:\folder
mkdir sub
cd sub
node -p 'process.cwd()'
# C:\link\sub
Same behaviour with /J
(junction) instead of /D
(directory symlink).
What is the expected behavior?
It should resolve the path to C:\folder\sub
, similar to how it works for symlinks on Unix:
cd /
mkdir folder
ln -s folder link
cd link
node -p 'process.cwd()'
# /folder
mkdir sub
cd sub
node -p 'process.cwd()'
# /folder/sub
Additional information
__filename
, __dirname
and fs.realpath(".")
correctly resolve, process.cwd()
and path.resolve(".")
don't.
Related issue: https://github.com/babel/babel/issues/10232
Deep, deep inside process.cwd()
is just a GetCurrentDirectoryW
. As such this is probably unfixable.
For babel, this probably can be worked around. Cwd is defined by the caller, so maybe adding fs.realpath.native call might help? Also, the cwd printed by Node depends on how you entered the folder.
Basically, I cant reproduce. If I do cd link
I get link
in process.cwd()
. If I fo cd folder
, only then I get folder
:
C:\...\test>cd link
C:\...\test\link>node -p process.cwd()
C:\...\test\link
C:\...\test\link>cd ..\folder
C:\...\test\folder>node -p process.cwd()
C:\...\test\folder
C:\...\test\folder>cd ssub
C:\...\test\folder\sub>node -p process.cwd()
C:\...\test\folder\sub
C:\...\test\f\s>cd ..\..\link\sub
C:\...\test\link\sub>node -p process.cwd()
C:\...\test\link\sub
Yes, I think ultimately the bug is in win32 GetCurrentDirectoryW
and if we attempt a fix, it should probably be done as close to the source as possible, e.g. in libuv. I've been testing on Windows 10 1809, maybe that behaviour has changed in recent versions.
If I interpret your results correctly, they already show the bug as link
should never appear in any cwd()
output to match Unix behaviour.
I don't think this is something we can fix. Forcing process.cwd()
to always return a realpath will probably break a lot of users setups. In the end the calling process decides what is the working directory of the child process.
Running this script in the C:\...\test\link
folder:
const path = require('path')
const fs = require('fs')
const cwd = path.join(fs.realpathSync(process.cwd()), 'sub');
require('child_process').spawnSync(
process.execPath,
['-p', 'process.cwd()'],
{ stdio: 'inherit',
cwd
}
);
produces:
C:\...\test\link>node t.js
C:\...\test\folder\sub
Forcing process.cwd() to always return a realpath will probably break a lot of users
It should probably be a semver-major change to be safe but I think it's the right thing to so it works the same on Unix (which already seems to return realpath in all cases) and Windows.
For the record, subst would work if we would do a realpath on all child cwd:
C:\...\test\>subst z: C:\...\test
C:\...\test\>z:
Z:\>cd link
Z:\link>node t.js
Z:\folder\sub
Bringing Windows and Unix closer together is always a good thing, but I would expect something somewhere to break horribly. We should probably do both a realpath on CWD when starting and when doing process.chdir
.
/cc @nodejs/platform-windows
Hi, just stumbled across this and I'm confused:
In Linux shell:
# setup
$> cd && pwd
/home/jahudka
$> mkdir folder
$> ln -s $(pwd)/folder link
# test
$> cd ~/folder && pwd
/home/jahudka/folder
$> node -e 'console.log(process.cwd());'
/home/jahudka/folder
$> cd ~/link1 && pwd
/home/jahudka/link
$> node -e 'console.log(process.cwd());'
/home/jahudka/folder
As you can see, in Linux the symlink in pwd
is not resolved, whereas in Node it is resolved. In fact, the same happens even if the symlink is not the CWD itself, but somewhere higher in the fs tree:
# setup
$> cd && pwd
/home/jahudka
$> mkdir -p folder1/folder2/folder3
$> ln -s $(pwd)/folder1/folder2 link
# test
$> cd ~/link/folder3 && pwd
/home/jahudka/link/folder3
$> node -e 'console.log(process.cwd());'
/home/jahudka/folder1/folder2/folder3
So it seems NodeJS is already doing what you guys want it to do (ie. resolving symlinks in CWD always).. and there appears to be no way to convince it to do what I want (which is the exact opposite, ie. never resolve symlinks in CWD).. sux for me 😂 I've tested this on Node 12 and 14 on Debian and macOS and it behaves exactly the same everywhere.
As you can see, in Linux the symlink in
pwd
is not resolved, whereas in Node it is resolved.
pwd
is similar to cwd
but it is not the same thing. In Linux, the pwd
command defaults to -L
(logical path) which will not resolve symlinks. You can force it to resolve symlinks with -P
(physical path). However, the return value of the system call getcwd()
will never contain a symlink. And that's what's relevant here. On Windows, the equivalent-ish system call does not have the same guarantee, apparently.
Still relevant found in LTS (v20.11.1) and latest (v21.6.2).
I have locally implemented a draft to assess the impact of this fix. The tests ran on both libuv and Node and a significant number of tests failed. This inconsistency originates from the Windows API, which has evolved into a feature over time. Therefore, it appears infeasible to fix this issue without affecting a lot of users. With all this considered, I propose closing this issue.