3

I've been unable to find a way to get the target path of a broken symbolic link in Crystal:

Dir.cd "/tmp"
`ln -s a b`
puts File.exists?(b)  # false
puts File.symlink?(b) # true

Is there anything in the standard library to get the address the broken link points to?

dgo.a
  • 2,634
  • 23
  • 35

1 Answers1

5

This is done on Linux/MacOS via readlink, which unfortunately hasn't been implemented in the standard library yet. This is tracked in issue #3284 on GitHub, and kostya has posted a version that seems to work in that issue.

Using his code:

lib LibC
  fun readlink(pathname : Char*, buf : Char*, bufsiz : SizeT) : SizeT
end

def File.readlink(path)
  buf = uninitialized UInt8[1024]
  size = LibC.readlink(path.to_unsafe, buf.to_unsafe, 1024).to_i32

  if size == -1
    raise Errno.new("readlink")
  elsif size > 1024
    raise "buffer too small"
  else
    return String.new(buf.to_unsafe, size)
  end
end

and then calling that function:

File.symlink("a", "b")
puts File.readlink("b") # => a

Note however that you'll probably need to do some work to get an absolute path. It might just be more feasible to use the command line version directly, since you can pass the -f flag which gives an absolute path:

File.symlink("a", "b")
puts `readlink -f b` # => /path/to/a

The -f-flag isn't available on MacOS though.

Sven
  • 5,155
  • 29
  • 53