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?
Update: As of July 2019, this has been implemented in the standard library as File.readlink
.
Original answer:
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.