I've a rough implementation here, but it needs testing (in particular, I'd like to ensure that there's no off-by-one errors with buffer lengths):
proc expandSymlink*(symlinkPath: string): string =
## Returns a string representing the path to which the symbolic link points.
##
## On Windows this is a noop, ``symlinkPath`` is simply returned.
const bufsize = 32
when defined(windows):
var handle = openHandle(symlinkPath, false)
when useWinUnicode:
var
buffer = newWideCString("", bufsize)
length = GetFinalPathNameByHandleW(handle, buffer, len(buffer), 0)
while length > len(buffer):
setLen(buffer, length)
length = GetFinalPathNameByHandleW(handle, buffer, len(buffer), 0)
else:
var
result = newWideCString("", bufsize)
length = GetFinalPathNameByHandleA(handle, buffer, len(buffer), 0)
while length > len(buffer):
setLen(buffer, length)
length = GetFinalPathNameByHandleA(handle, buffer, len(buffer), 0)
if length == 0:
raiseOSError(osLastError())
result = $buffer
else:
result = newString(bufsize)
var length = readlink(symlinkPath, result, bufsize)
while length > len(result):
setLen(result, length)
length = readlink(symlinkPath, result, length)
if length < 0:
raiseOSError(osLastError())
setLen(result, length)