On Mar 9, 12:10 pm, "Daniel Berger" <djber... / gmail.com> wrote:
> 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