PSDotFiles icon indicating copy to clipboard operation
PSDotFiles copied to clipboard

Add support for optionally using hardlinks instead of symlinks

Open ralish opened this issue 4 years ago • 4 comments

There are some edge cases where this would be very useful. For example, applications which watch a directory for file changes so they can automatically trigger some processing on file modifications, such as changes to a settings file. This is typically handled via FindFirstChangeNotification.

The catch is this function will only raise an event on changes to the symlink itself and not its target. Implementing watching of the target requires extra support which many applications do not implement. By using a hardlink instead of a symlink this issue is effectively worked-around as the normal filesystem semantics will apply.

ralish avatar May 23 '20 22:05 ralish

Patiently waiting for this.

soredake avatar Jun 29 '22 16:06 soredake

@soredake I'll try and find some time for this but sadly have little time to invest in personal projects at the moment. Out of curiosity, can you provide more details on your use case for this feature? I've got my own scenarios, but would be interested to hear of others.

ralish avatar Jul 06 '22 06:07 ralish

@ralish mainly for having windows terminal hot-reload my config when i change it, that is possible only with hard link

soredake avatar Jul 06 '22 11:07 soredake

I don't believe there's any mechanism available in PowerShell to enumerate all hard links for a file so this would need to be implemented via P/Invoke calls to the Win32 API. We'd need FirstFirstFileNameW, FindNextFileNameW, and FindClose. The GetFinalPathNameByHandleW API may also be needed.

The P/Invoke method signatures are probably something like this (untested):

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetFinalPathNameByHandleW", ExactSpelling = true, SetLastError = true)]
public extern static int GetFinalPathNameByHandle(Microsoft.Win32.SafeHandles.SafeFileHandle hFile,
                                                  System.Text.StringBuilder lpszFilePath,
                                                  int cchFilePath,
                                                  int dwFlags);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "FindFirstFileNameW", ExactSpelling = true, SetLastError = true)]
public extern static Microsoft.Win32.SafeHandles.SafeFileHandle FindFirstFileName(string lpFileName,
                                                                                  int dwFlags,
                                                                                  ref int StringLength,
                                                                                  System.Text.StringBuilder LinkName);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "FindNextFileNameW", ExactSpelling = true, SetLastError = true)]
public extern static bool FindNextFileName(Microsoft.Win32.SafeHandles.SafeFileHandle hFindStream,
                                           ref int StringLength,
                                           System.Text.StringBuilder LinkName);

[DllImport("kernel32.dll", SetLastError = true)]
public extern static bool FindClose(Microsoft.Win32.SafeHandles.SafeFileHandle hFindFile);

ralish avatar Jul 17 '22 20:07 ralish