Symbolic link is a very convenient facility to organize your files. When using Bash on Windows, there are multiple options that simulate the native symlink as on Linux. This post records my experience with them and also some other useful tips.

Due to some limitations of MobaXterm MobaXterm notably lacks proper tty setup, but cmder has its own problems as well., I started to use cmder for some tasks again. One thing I noticed is that the ln bundled together in the Git4Win is merely a cp, essentially making ln not usable at all. Why they (Msys2) would ship such a version in the first place is still a mystery to me. Since MobaXterm by default would create a special file, recognized also by Bash in MSys2, I took this chance looking into the whole symbolic link thing on Windows. As a departure from my previous practice, i.e. conduct thorough research first and only write after I feel I know enough in a systematic way. I’ll write what I’ve researched so far, what I decided to use and leave the rest with a note for potential future research. In a nut shell, I’ll do it in an note-taking fashion.

The Four Types

According to Symbolic links in the Cygwin website, there are four types of symlinks on Windows:

As I decided later to only use this one, I’ll quote the whole passage:

The default symlinks are plain files containing a magic cookie followed by the path to which the link points. They are marked with the DOS SYSTEM attribute so that only files with that attribute have to be read to determine whether or not the file is a symbolic link.

Very Linux-ish: plain text file for everything. Just open the file with an external editor and you can to see everything written inside. External to the Bash in use. After all, all commands bundled with the Bash are built to treat these plain files as real symlinks ;P

The Windows .lnk shortcut

Plus some special header and DOS READONLY attribute.

This one sounds quite appealing from the beginning. However, first there is no native way to create .lnk from command line (other then the cygwin’s ln), second you need to set CYGWIN to winsymlinks, an extra trouble that gains nothing anyway.

This has been around for quite a while now and requires file system support, like NTFS. Are there much use for FAT32 still? Linux’s support for NTFS is quite stable now.

This type of symlink is more a equivalence of Linux symlink than any other option, however it has some weird restrictions and behaviors.

Never used these, and thus I will not explore them here. NFS is really convenient in a Linux-centric environment. However since I’ve migrated to work on Windows, the combination of vboxsf share folder and Samba is good enough. vboxsf is way easier to setup and Samba has sufficient performance for now.

Create fake symlink from script

As stated above, this one is the easiest to understand, the below is the core part of a script I’m using to create such a link in MSys2 environment:

echo -n -e "!<symlink>$target\\x0\\xd" > "$link"

attrib.exe +S "$link"
  1. -e toggle asks echo to interpret \xHH form as a byte with hexical value of HH. You need double slashes in the double quotes. In this case, the two special chars at the end is NULL and carriage return (aka. \n, CR, Return).
  2. attrib is an Windows utility since the DOS era. Here we need to set System attribute as Cygwin mandates. The attrib allows the user to change the attribute of a file, like Read-only, Hidden, System, Archived. Atrributes you would see in the file/directory Properties Dialog.

Eventually I choose this one mainly for two reasons:

  1. I use symlinks mostly from within the Bash, and thus interoperability with Windows host is a lesser concern.
  2. This is so easy to understand and proved to work with MSys2.

Create shortcut from CLI

Windows shortcuts are useful for Windows Explorer only. The .lnk file is a binary blob that evades manual editing. What’s worse there is no native CLI tool to create such shortcuts.

During my search, I encountered a very interesting collection: NirCmd. It seems to be a treasure trove of CLI utilities for various Windows tasks, including .lnk creation from command prompt. I am sure to explore it later, for now it’s sufficient to point out it’s not good enough to persuade me to use .lnk: though well documented, nircmd doesn’t have proper error message if a command fails. Also it’s not open source. For the record, I usually do not hold grudges against non-open software. It’s just that for daily tools, I prefer to know the inner workings to be able to tweak them to my satisfaction. Though granted, the tweaking is not done that often ;P

Native symlink on NTFS

The Cygwin documentation stated:

Due to to their weird restrictions and behaviour, they are only created if the user explicitly requests creating them.

Yes, this, I couldn’t agree more.

First, it needs SeCreateSymbolicLinkPrivilege that is only granted to administrator by default (sure, you can grant a user with this right simply by … well, I can’t remember those multi-step GUI-driven instructions as in this SO answer).

Second, it has extra confusing options, as stated here:

You can create a hardlink (mklink /H) without admin privileges, and that will be executable. Hardlinks are for files, junctions are for directories, symlinks are for both (and /D is used to indicate that a symlink is for a directory)

With above said, this type of symlink is still the only true symlink on Windows.

Ending

Recently I find that I like to add these mumbling at the end of a post. It’s usually some supposedly deeper thoughts about the topic just covered. Anyway, it’s my idiosyncratic reflections that matter more to future me rather than anyone else reading the post ;P

Symbolic link is conceptually simple: a location/file pointer implemented as a file that is understood by applications. However, as demonstrated by my own decision to use only the cygwin fake symlink, this understanding of applications lies at the very root of its complexity. Understood by what applications? By all or only some of them? What if the developers behind some applications simply disagree with others, either due to a philosophical difference or mere convenience? Adding all these up through a long history, together with kept, broken or semi-kept compatibility is a snapshot of any non-trivial engineering.


Comment: Github Issue