6

My application is writing logs to a directory, which is hardcoded "Logs" and is present under the runtime directory of my application.
Today, a customer asked me if it was possible to have those logs on another place (on another computer).

As a first test, I tried to create a symlink:

  1. I stopped the application.
  2. I removed the "Logs" directory.
  3. Using a WSL on my computer, I created a symlink, something like ln -s /mnt/c/Temp_Folder/TestLog/ /mnt/c/<Application>/Logs.
  4. I started up my application.

I did not see any logs appearing in the directory C:\Temp_Folder\TestLog\.

I see different reasons:

  • Either it's a complete stupid idea to try to use Linux technology on a Windows computer.
  • Either it might work, but some extra things need to be taken into account.

I hope it's the second choice, but in that case, what things do I need to take into account?

Edit after Harry's answer:
Why use WSL's ln -s if you can use Windows technology, like mklink? :-)

I like the idea, but unfortunately it seems not to be working, as you can see from the following experiments:

C:\<Runtime_Dir>mklink /D Logs E:\TestLog\
=> result:
29/03/2024  08:21    <SYMLINKD>     Logs [E:\TestLog\]

=> So, indeed, the Logs directory symlink is created, but when I launch my application, it seems not to write any logs anymore (I see them being created in a console window, but they are not written down in a file).

Some other experiments: (I remember something about a junction from before, but the details have slipped my mind)

C:\<Runtime_Dir>mklink /D /J Logs E:\TestLog\
Local volumes are required to complete the operation.
C:\<Runtime_Dir>mklink /D /H Logs E:\TestLog\
The system cannot find the path specified.
C:\<Runtime_Dir>mklink /J Logs E:\TestLog\
Local volumes are required to complete the operation.

Edit2 after some more experiments:
It seems not to work, while referring to another drive, but it does seem to work when I refer to another directory on the same computer, as you can see here:

C:\<Runtime_Dir>mklink /D Logs C:\Temp_Folder\TestLog\
symbolic link created for Logs <<===>> C:\Temp_Folder\TestLog\

C:&lt;Runtime_Dir>mklink /D /J Logs C:\Temp_Folder\TestLog
Junction created for Logs <<===>> C:\Temp_Folder\TestLog

I can confirm that, in both cases, the logs are being created!

In other words, the problem is not that the Windows symlink/junction is not working: the problem is with the fact that the symlink/junction is referring to another drive.
I remember that there are two, even three ways to create a drive in Windows (a drive mapping, a subst (?) and another one(???), this is all very blurry in my head), and I'm wondering whether the symlink/junction story might be working on one kind of drive, but not the other, and if there is a way to work around this.

Edit3 after the answer of u1686_gravity:
Even when using UNC path and having the "correct" configured behaviour, it still seems not to work:

fsutil behavior query symlinkEvaluation
Local to local symbolic links are enabled.
Local to remote symbolic links are enabled. => That's the one, isn't it?
Remote to local symbolic links are disabled.
Remote to remote symbolic links are disabled.
C:\<Runtime_Dir>mklink /D Logs \\petrvs01\Log\TestLog\
symbolic link created for Logs <<===>> \\petrvs01\Log\TestLog\

The link gets created, but no logfiles are being created over there.

So, as I think I'm the right track here, I decided to perform another test: use the Windows explorer to enter the Logs directory/symlink/junction and create a simple text file, using the explorer's context menu. This does not work because of the following error message:

enter image description here

I have learned three things up to now:

  1. For creating a symlink on Windows, use mklink instead of WSL's ln -s. Open a command prompt as an administrator for this.
  2. For creating a symlink/junction to a remote directory, you need to use the UNC path, not the drive letter.
  3. Permission for creating symlinks/junctions from and to remote directories is checked, using the fsutil command fsutil behavior query symlinkEvaluation.

Next thing I need to learn: where to check for the symlink/junction destination permissions? Does anybody have an idea?

Dominique
  • 2,373

2 Answers2

5

Symlinks on Linux are implemented differently than on Windows:

  • On Windows a symlink is a file-table entry that's implemented and manipulated by kernel calls
  • On Linux, a symlink is simply a text file with a special flag, whose content is a path to the destination. (The path doesn’t even have to be valid.)

This means that symbolic links (or symlinks) created through the Windows Subsystem for Linux (WSL) can’t be followed by Windows.

Windows creates symlinks using the mklink command.

For more information see the article
The Complete Guide to Creating Symbolic Links (aka Symlinks) on Windows.


For the problem of "Access Denied", I quote from the post creating symbolic links on networked drive part of the answer by GambleNerd:

Access Denied Fix

If you run the mklink /D command as administrator and the Link part of the command is a UNC network path and you get Access Denied error message, then follow the below to potentially resolve this issue.

  1. On there server where (and/or on the Windows client PC you're getting the Access Denied error message when you run the command) the Link part of the command is located, run this command as administrator on the server: fsutil behavior query SymlinkEvaluation
  2. If you see Remote to remote symbolic links are disabled. then run this command: fsutil behavior set SymlinkEvaluation R2R:1
  • You can run this from the location where you're running the MKLINK command and getting access denied whether on the Windows Server itself or the Windows client PC
  1. Now try running your command again and hopefully it works successfully now.

Link Reference: Access is denied on mklink

harrymc
  • 498,455
3

Is there a way to use Linux-like symlinks on a Windows computer, referring to a location on another computer?

It's possible, but you need to use UNC paths rather than drive letters, as the latter are not nec­es­sar­i­ly global – while physical volumes have global assignments, each logon session can have its own private mappings on top of that (e.g. user 1 can have Y:\ representing one location and user 2 can have it representing another). Think of it a bit like each user having their own "mount name­space" on Linux (pam_namespace).

Specifically, all "mapped network share" drive letters are private to your logon session and will not be understood in the kernel context when the symlink is followed. So if the target is on another machine, you need to use the raw UNC path for it:

cmd /c mklink /d Logs \\FileServer\Trash\Logs

You should also make sure that local-to-remote symlink evaluation hasn't been disabled through fsutil behavior query symlinkEvaluation.

where to check for the symlink/junction destination permissions? Does anybody have an idea?

Run icacls on the target – or right-click it in Explorer and go "Properties > Security".

icacls \\FileServer\Trash\Logs

Also, symlinks and junctions on Windows can have their own permissions, which can be checked using icacls Logs /l. I doubt that would be the problem, as the link would initially inherit the same permissions as a normal directory would – but it might be worth checking.

So first make sure file/folder creation works without symlinks being involved, i.e. directly through the UNC path (or a mapped drive, no difference), and only after you have that working, attempt to do the same through a symlink.

Don't forget that if your application is running as a service, with its own credentials (service account), then permissions must be granted to that account; if it's running as "NetworkService", then permissions must be granted to the machine account (FOOBAR$). (And if it's running as "LocalService", it will never have network share access.)

grawity
  • 501,077