mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 09:24:36 +00:00
For now, `expandSymlinks()` can handle only symlinks with lengths up to 1024. We can improve this logic and retry inside a loop with increasing lengths until we succeed. The same approach is used in [Go](377646589d/src/os/file_unix.go (L446)), [Rust](785eb65377/library/std/src/sys/pal/unix/fs.rs (L1700)) and [Nim's `getCurrentDir()`](https://github.com/nim-lang/Nim/blob/devel/lib/std/private/ospaths2.nim#L877), so maybe it's a good idea to use the same logic in `expandSymlinks()` also.
79 lines
2.3 KiB
Nim
79 lines
2.3 KiB
Nim
include system/inclrtl
|
|
import std/oserrors
|
|
|
|
import oscommon
|
|
export symlinkExists
|
|
|
|
when defined(nimPreviewSlimSystem):
|
|
import std/[syncio, assertions, widestrs]
|
|
|
|
when weirdTarget:
|
|
discard
|
|
elif defined(windows):
|
|
import std/[winlean, times]
|
|
elif defined(posix):
|
|
import std/posix
|
|
else:
|
|
{.error: "OS module not ported to your operating system!".}
|
|
|
|
|
|
when weirdTarget:
|
|
{.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".}
|
|
else:
|
|
{.pragma: noWeirdTarget.}
|
|
|
|
|
|
when defined(nimscript):
|
|
# for procs already defined in scriptconfig.nim
|
|
template noNimJs(body): untyped = discard
|
|
elif defined(js):
|
|
{.pragma: noNimJs, error: "this proc is not available on the js target".}
|
|
else:
|
|
{.pragma: noNimJs.}
|
|
|
|
## .. importdoc:: os.nim
|
|
|
|
proc createSymlink*(src, dest: string) {.noWeirdTarget.} =
|
|
## Create a symbolic link at `dest` which points to the item specified
|
|
## by `src`. On most operating systems, will fail if a link already exists.
|
|
##
|
|
## .. warning:: Some OS's (such as Microsoft Windows) restrict the creation
|
|
## of symlinks to root users (administrators) or users with developer mode enabled.
|
|
##
|
|
## See also:
|
|
## * `createHardlink proc`_
|
|
## * `expandSymlink proc`_
|
|
|
|
when defined(windows):
|
|
const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 2
|
|
# allows anyone with developer mode on to create a link
|
|
let flag = dirExists(src).int32 or SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
|
|
var wSrc = newWideCString(src)
|
|
var wDst = newWideCString(dest)
|
|
if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0:
|
|
raiseOSError(osLastError(), $(src, dest))
|
|
else:
|
|
if symlink(src, dest) != 0:
|
|
raiseOSError(osLastError(), $(src, dest))
|
|
|
|
proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} =
|
|
## Returns a string representing the path to which the symbolic link points.
|
|
##
|
|
## On Windows this is a noop, `symlinkPath` is simply returned.
|
|
##
|
|
## See also:
|
|
## * `createSymlink proc`_
|
|
when defined(windows) or defined(nintendoswitch):
|
|
result = symlinkPath
|
|
else:
|
|
var bufLen = 1024
|
|
while true:
|
|
result = newString(bufLen)
|
|
let len = readlink(symlinkPath.cstring, result.cstring, bufLen)
|
|
if len < 0:
|
|
raiseOSError(osLastError(), symlinkPath)
|
|
if len < bufLen:
|
|
result.setLen(len)
|
|
break
|
|
bufLen = bufLen shl 1
|