jj icon indicating copy to clipboard operation
jj copied to clipboard

Add support for symlinks on Windows

Open martinvonz opened this issue 4 years ago • 4 comments

We currently don't support symlinks on Windows (in fact, the project doesn't even build on Windows because of that). The advice I got from [email protected] and former hg contributor "bmp" was (please correct me if I'm wrong):

  • Prior to Windows 10: No symlink support
  • Windows 10 without dev mode: No symlink support
  • Windows 10 dev mode: use FFI to call CreateSymbolicLink
  • Don't use the symlink creates, because it creates "junctions", which is not what we want.

Rust's standard library has std::os::windows::fs::symlink_file and std::os::windows::fs::symlink_dir, which both seem to call CreateSymbolicLinkW, only with different flags. Perhaps we can always use the symlink_file version? It's still unclear to me what the effect would be if a "file symbolic link" points to a target that's actually a directory.

martinvonz avatar Jan 08 '21 19:01 martinvonz

Correct enough for government purposes.

To clarify, not to be annoying, but just in case it changes anything: Windows supports symlinks when Developer Mode isn't enabled, and has done so going all the way back to at least Vista. What actually changed was that, prior to Windows 10, you needed to be an admin to create them. The only (albeit major) thing Windows 10 with Developer Mode changes is that normal users can now create symlinks, rather than either needing to run a process as an admin or mucking about with group policy options (GPOs).

For reasons I'm not clear on, the underlying API for this (CreateSymbolicLinkW) still requires you to say whether you're linking a file or a directory. I have absolutely no idea why, but I don't //think// (from two minutes of mucking about) you can cheat, just pass 0x0, and be happy.

bpollack avatar Jan 08 '21 19:01 bpollack

I think 0x0 is what std::os::windows::fs::symlink_file passes, so I guess we'll try to do that whether the target is a file or a directory. I don't have access to a Windows machine, but it sounded like Augie might be able to attempt it later. Thanks!

martinvonz avatar Jan 08 '21 20:01 martinvonz

Based on tests using mklink /D vs mklink, I think symlink_dir is the one to be used. It seems to handle both the directory and file cases, while directory symlink crated by symlink_file won't allow cd into it.

quark-zju avatar Feb 01 '21 23:02 quark-zju

Thanks for checking!

martinvonz avatar Feb 02 '21 07:02 martinvonz