Getting to the last file in a chain of symlinks

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

On Mar 9, 12:44 pm, “AdSR” [email protected] wrote:

On Solaris 10, Sunblade 150

file = File.expand_path(File.readlink(file))

puts Pathname.new(‘/dev/fd0’).realpath

Oh, dang, forgot about that.

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

ls -l
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

On Mar 9, 12:10 pm, “Daniel B.” [email protected] wrote:

/dev/diskett0 → …/devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c

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

On 9 Mar, 20:10, “Daniel B.” [email protected] wrote:

/dev/diskett0 → …/devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c

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