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

Incorrect cwd() inside subfolders of Windows directory symlinks or junctions #34866

Closed
silverwind opened this issue Aug 21, 2020 · 10 comments
Closed
Labels
libuv Issues and PRs related to the libuv dependency or the uv binding. path Issues and PRs related to the path subsystem. process Issues and PRs related to the process subsystem. windows Issues and PRs related to the Windows platform.

Comments

@silverwind
Copy link
Contributor

silverwind commented Aug 21, 2020

  • 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: babel/babel#10232

@silverwind silverwind added windows Issues and PRs related to the Windows platform. path Issues and PRs related to the path subsystem. process Issues and PRs related to the process subsystem. labels Aug 21, 2020
@silverwind silverwind added path Issues and PRs related to the path subsystem. and removed path Issues and PRs related to the path subsystem. labels Aug 21, 2020
@bzoz
Copy link
Contributor

bzoz commented Aug 24, 2020

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

@silverwind
Copy link
Contributor Author

silverwind commented Aug 24, 2020

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.

@silverwind silverwind added the libuv Issues and PRs related to the libuv dependency or the uv binding. label Aug 24, 2020
@bzoz
Copy link
Contributor

bzoz commented Aug 24, 2020

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

@silverwind
Copy link
Contributor Author

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.

@bzoz
Copy link
Contributor

bzoz commented Aug 24, 2020

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

@jahudka
Copy link

jahudka commented Jun 24, 2021

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.

@Trott
Copy link
Member

Trott commented Nov 24, 2022

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.

@davidnaumann-bastian
Copy link

davidnaumann-bastian commented Mar 4, 2024

Still relevant found in LTS (v20.11.1) and latest (v21.6.2).

@huseyinacacak-janea
Copy link
Contributor

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.

@StefanStojanovic
Copy link
Contributor

Since there have been no objections after the last comment, which was left a long time ago, I'll close this now. Please reopen if needed.

@StefanStojanovic StefanStojanovic closed this as not planned Won't fix, can't repro, duplicate, stale Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libuv Issues and PRs related to the libuv dependency or the uv binding. path Issues and PRs related to the path subsystem. process Issues and PRs related to the process subsystem. windows Issues and PRs related to the Windows platform.
Projects
None yet
Development

No branches or pull requests

7 participants