summary refs log tree commit diff stats
path: root/lib/std
diff options
context:
space:
mode:
authorAlexander Kernozhitsky <sh200105@mail.ru>2024-05-27 11:01:13 +0200
committerGitHub <noreply@github.com>2024-05-27 11:01:13 +0200
commit3bda5fc840870f6589e4bdbcbbdc811bde599969 (patch)
tree441f1ea48a536c2f2b6fa8c40d23446d0a04c95e /lib/std
parentce85b819ff63b5e9ca57dfe7d4d520851921802e (diff)
downloadNim-3bda5fc840870f6589e4bdbcbbdc811bde599969.tar.gz
Handle arbitrarily long symlink target in `expandSymlinks()` (#23650)
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](https://github.com/golang/go/blob/377646589d5fb0224014683e0d1f1db35e60c3ac/src/os/file_unix.go#L446),
[Rust](https://github.com/rust-lang/rust/blob/785eb65377e5d7f8d8e8b82ede044212bbd2d76e/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.
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/private/ossymlinks.nim18
1 files changed, 10 insertions, 8 deletions
diff --git a/lib/std/private/ossymlinks.nim b/lib/std/private/ossymlinks.nim
index c0774b573..c1760c42e 100644
--- a/lib/std/private/ossymlinks.nim
+++ b/lib/std/private/ossymlinks.nim
@@ -66,11 +66,13 @@ proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} =
   when defined(windows) or defined(nintendoswitch):
     result = symlinkPath
   else:
-    result = newString(maxSymlinkLen)
-    var len = readlink(symlinkPath, result.cstring, maxSymlinkLen)
-    if len < 0:
-      raiseOSError(osLastError(), symlinkPath)
-    if len > maxSymlinkLen:
-      result = newString(len+1)
-      len = readlink(symlinkPath, result.cstring, len)
-    setLen(result, len)
+    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