From b01f0cab31d34451d00f1ee1ecffb79a7e11851b Mon Sep 17 00:00:00 2001 From: akr Date: Sat, 11 Oct 2003 06:42:41 +0000 Subject: [PATCH] * lib/pathname.rb (realpath): re-implemented. (realpath_root?, realpath_rec): removed git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4743 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++-- lib/pathname.rb | 86 ++++++++++++++++++------------------------------- 2 files changed, 35 insertions(+), 57 deletions(-) diff --git a/ChangeLog b/ChangeLog index aa59c423a4..772776f184 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ -Sat Oct 11 14:35:14 2003 Tanaka Akira +Sat Oct 11 15:41:06 2003 Tanaka Akira - * lib/pathname.rb (realpath_rec): fix handling of symlink to absolute - path. + * lib/pathname.rb (realpath): re-implemented. + (realpath_root?, realpath_rec): removed Sat Oct 11 10:19:39 2003 Shugo Maeda diff --git a/lib/pathname.rb b/lib/pathname.rb index eff3b6cd15..7bd007a2c8 100644 --- a/lib/pathname.rb +++ b/lib/pathname.rb @@ -111,65 +111,43 @@ class Pathname # it may return relative pathname. # Otherwise it returns absolute pathname. def realpath(force_absolute=true) - path = @path - stats = {} - if %r{\A/} =~ path || realpath_root?('.', stats) - resolved = '/' - else - resolved = '.' - end - resolved = realpath_rec(resolved, path, stats) - if %r{\A/} !~ resolved && force_absolute - # Note that Dir.pwd and resolved has no symlinks. - Pathname.new(File.join(Dir.pwd, resolved)).cleanpath - else - Pathname.new(resolved) - end - end - - def realpath_root?(path, stats) # :nodoc: - path_stat = stats[path] ||= File.lstat(path) - parent = path == '.' ? '..' : File.join(path, '..') - parent_stat = stats[parent] ||= File.lstat(parent) - path_stat.dev == parent_stat.dev && path_stat.ino == parent_stat.ino - end - - def realpath_rec(resolved, unresolved, stats, rec={}) # :nodoc: - unresolved.scan(%r{[^/]+}) {|f| - next if f == '.' - if f == '..' - case resolved - when '/' - # Since the parent directory of '/' is '/', do nothing. - when '.' - resolved = '..' - resolved = '/' if realpath_root?(resolved, stats) - when %r{(\A|/)\.\.\z} - resolved << '/..' - resolved = '/' if realpath_root?(resolved, stats) - when %r{/} - resolved = File.dirname(resolved) - else - resolved = '.' - end + top = %r{\A/} =~ @path ? '/' : '' + unresolved = @path.scan(%r{[^/]+}) + resolved = [] + + until unresolved.empty? + case unresolved.last + when '.' + unresolved.pop + when '..' + resolved.unshift unresolved.pop else - path = resolved == '.' ? f : File.join(resolved, f) - if File.lstat(path).symlink? - raise Errno::ELOOP.new(path) if rec.include? path - link = File.readlink path - resolved = '/' if %r{\A/} =~ link - begin - rec[path] = true - resolved = realpath_rec(resolved, link, stats, rec) - ensure - rec.delete path + path = top + unresolved.join('/') + if FileTest.symlink? path + link = File.readlink(path) + if %r{\A/} =~ link + top = '/' + unresolved = link.scan(%r{[^/]+}) + else + unresolved.pop + unresolved.concat link.scan(%r{[^/]+}) end else - resolved = path + resolved.unshift unresolved.pop end end - } - resolved + end + + if resolved.empty? + path = top.empty? ? '.' : top + else + path = top + resolved.join('/') + end + + # Note that Dir.pwd has no symlinks. + path = File.join(Dir.pwd, path) if %r{\A/} !~ path && force_absolute + + Pathname.new(path).cleanpath end # parent method returns parent directory, i.e. ".." is joined at last.