Getting to the last file in a chain of symlinks

D

Daniel Berger

Hi all,

Here's a little code snippet I thought I'd share. It follows a chain
of symlinks until you get down to the "real" file. Anyone got a better
approach?

# On Solaris 10, Sunblade 150
#
# /dev/fd0 -> fd0c
# /dev/fd0c -> diskette0
# /dev/diskett0 -> ../devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c
#

file = '/dev/fd0'

while true
Dir.chdir(File.dirname(file))
file = File.expand_path(File.readlink(file))
break unless File.symlink?(file)
end

puts file # /devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c

Regards,

Dan
 
D

Daniel Berger

Hi all,

Here's a little code snippet I thought I'd share. It follows a chain
of symlinks until you get down to the "real" file. Anyone got a better
approach?

# On Solaris 10, Sunblade 150
#
# /dev/fd0 -> fd0c
# /dev/fd0c -> diskette0
# /dev/diskett0 -> ../devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c
#

file = '/dev/fd0'

while true
Dir.chdir(File.dirname(file))
file = File.expand_path(File.readlink(file))
break unless File.symlink?(file)
end

puts file # /devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c

Alright, here's a modified File.readlink method. This is an improved
version of the algorithm above in that it uses the block form of
Dir.chdir and handles circular symlinks:

class File
class << self
private

alias readlink_orig readlink

public

# Returns the given symbolic link as a string. If +recursive+ is
set
# to true then it will follow symbolic links until it gets to
the final
# file in the chain. The default is false, i.e. non-recursive.
#
# If circular symlinks are encountered, it will return the last
link
# that it has not already encountered.
#
def readlink(file, recursive=false)
if recursive
visited = {} # Used to avoid circular references
while true
Dir.chdir(File.dirname(file)){
file = File.expand_path(File.readlink(file))
}

if File.symlink?(file) || visited[file]
break
end

visited[file] = true
end
file
else
readlink_orig(file)
end
end
end
end
 
A

AdSR

Hi all,

Here's a little code snippet I thought I'd share. It follows a chain
of symlinks until you get down to the "real" file. Anyone got a better
approach?

# On Solaris 10, Sunblade 150
#
# /dev/fd0 -> fd0c
# /dev/fd0c -> diskette0
# /dev/diskett0 -> ../devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c
#

file = '/dev/fd0'

while true
Dir.chdir(File.dirname(file))
file = File.expand_path(File.readlink(file))
break unless File.symlink?(file)
end

puts file # /devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c

Regards,

Dan

require 'pathname'

puts Pathname.new('/dev/fd0').realpath

I didn't check what would happen for cyclic dependencies.

Regards,
AdSR
 
D

Daniel Berger

require 'pathname'

puts Pathname.new('/dev/fd0').realpath

Oh, dang, forgot about that.
I didn't check what would happen for cyclic dependencies.
lrwxrwxrwx 1 djberge other 5 Mar 9 12:25 link1 -> link2
lrwxrwxrwx 1 djberge other 5 Mar 9 12:23 link2 -> link1
-rw-r--r-- 1 djberge other 57 Mar 9 12:45 test.rb

/usr/local/lib/ruby/1.8/pathname.rb:415:in `realpath_rec': Number of
symbolic links encountered during path name traversal exceeds
MAXSYMLINKS - /export/home/djberge/workspace/ruby_test/lib/test/link2
(Errno::ELOOP)
from /usr/local/lib/ruby/1.8/pathname.rb:425:in `realpath_rec'
from /usr/local/lib/ruby/1.8/pathname.rb:453:in `realpath'
from test.rb:2

Dunno what happens on other platforms.

Regards,

Dan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top