0

I created a couple of symlinks....

The dir command is able to show the target as below


Directory of C:\abc

07/03/2020 04:58 AM link.txt [s:\naveen\ow.bat]

07/03/2020 05:01 AM link1.txt [c:\naveen\ow.bat]


I am trying to get the target value via C code

I am using the GetFinalPathNameByHandleA() API to achieve this.....

Different o/p for different i/p flag

VOLUME_NAME_NT

[C:\abc]a.exe link.txt The final path is: \Device\Mup\den00mce\c$\naveen\ow.bat

[C:\abc]a.exe link1.txt The final path is: \Device\HarddiskVolume5\naveen\ow.bat

VOLUME_NAME_DOS

[C:\abc]a.exe link.txt The final path is: \?\UNC\den00mce\c$\naveen\ow.bat

[C:\abc]a.exe link1.txt The final path is: \?\C:\naveen\ow.bat

VOLUME_NAME_GUID

[C:\abc]a.exe link.txt The final path is: --> this doesn't work, its not resolving for remote file

[C:\abc]a.exe link1.txt The final path is: \?\Volume{ebea43d1-9277-49bb-bb42-57bca6a7fdcc}\naveen\ow.bat

VOLUME_NAME_NONE

[C:]a.exe link.txt The final path is: \den00mce\c$\naveen\ow.bat

[C:]a.exe link1.txt

The final path is: \naveen\ow.bat --> I don't think it will be helpful as it's removing the volume name like c:, d: etc...

Note: s: is a remote drive I mapped using net use * \\abc\def

Do we have any APIs to get the o/p same as the output from dir shown above?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Naveen
  • 91
  • 1
  • 7
  • As you observed, the final path can only return a NT, DOS, or volume GUID canonical device path as known by the system and mountpoint manager. It will not use per-user mapped and subst drive names, which are actually filesystem mountpoints. In contrast, normal DOS drive names are canonical aliases for NT device names (e.g. "C:" -> "\Device\HarddiskVolume5"), and the filesystem mountpoint is the root path (e.g. "C:\"). Also, what if "C:\naveen" is a mountpoint but not the canonical path for the target volume? Clearly, getting the final path is not the way to read the link target. – Eryk Sun Jul 08 '20 at 10:44
  • You need to use `DeviceIoControl`: [`FSCTL_GET_REPARSE_POINT`](https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ni-winioctl-fsctl_get_reparse_point) to get the [`REPARSE_DATA_BUFFER`](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_reparse_data_buffer) of the symlink. If the print path exists (the spec says it SHOULD exist, not MUST exist), prefer it because `CreateSymbolicLinkW` stores the DOS namespace target path in that field. Otherwise use the substitute path, and if it starts with NTAPI "\??\", replace it with WinAPI "\\?\". – Eryk Sun Jul 08 '20 at 10:49
  • The `CreateFileW` call to open "link.txt" needs to use `FILE_FLAG_OPEN_REPARSE_POINT`. Also, only interpret the buffer as a Microsoft `REPARSE_DATA_BUFFER` if the reparse tag is `IO_REPARSE_TAG_SYMLINK` or `IO_REPARSE_TAG_MOUNTPOINT`. For `readlink`, you're only interested in symlinks, which are designed to behave similar to Unix symlinks. If you're being strict to POSIX, `readlink` should not read mountpoints (aka junctions). – Eryk Sun Jul 08 '20 at 11:18
  • A mountpoint (i.e. `IO_REPARSE_TAG_MOUNTPOINT`) behaves like a Unix bind mountpoint. In particular, it's traversed in path parsing as a 'hard' directory link, not as a symlink that collapses to the target, which is especially relevant when relative symlinks traverse parent directories via ".." components, which results in a different final path if the parent is a mountpoint vs. a symlink. Also, a remote mountpoint targets a local device on the remote server, so it's generally useless to read it and impossible to manually evaluate it on the client side. – Eryk Sun Jul 08 '20 at 11:20

0 Answers0