* 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
This commit is contained in:
akr 2003-10-11 06:42:41 +00:00
parent 79aca9eb60
commit b01f0cab31
2 changed files with 35 additions and 57 deletions

View File

@ -1,7 +1,7 @@
Sat Oct 11 14:35:14 2003 Tanaka Akira <akr@m17n.org> Sat Oct 11 15:41:06 2003 Tanaka Akira <akr@m17n.org>
* lib/pathname.rb (realpath_rec): fix handling of symlink to absolute * lib/pathname.rb (realpath): re-implemented.
path. (realpath_root?, realpath_rec): removed
Sat Oct 11 10:19:39 2003 Shugo Maeda <shugo@ruby-lang.org> Sat Oct 11 10:19:39 2003 Shugo Maeda <shugo@ruby-lang.org>

View File

@ -111,65 +111,43 @@ class Pathname
# it may return relative pathname. # it may return relative pathname.
# Otherwise it returns absolute pathname. # Otherwise it returns absolute pathname.
def realpath(force_absolute=true) def realpath(force_absolute=true)
path = @path top = %r{\A/} =~ @path ? '/' : ''
stats = {} unresolved = @path.scan(%r{[^/]+})
if %r{\A/} =~ path || realpath_root?('.', stats) resolved = []
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: until unresolved.empty?
path_stat = stats[path] ||= File.lstat(path) case unresolved.last
parent = path == '.' ? '..' : File.join(path, '..') when '.'
parent_stat = stats[parent] ||= File.lstat(parent) unresolved.pop
path_stat.dev == parent_stat.dev && path_stat.ino == parent_stat.ino when '..'
end resolved.unshift unresolved.pop
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
else else
path = resolved == '.' ? f : File.join(resolved, f) path = top + unresolved.join('/')
if File.lstat(path).symlink? if FileTest.symlink? path
raise Errno::ELOOP.new(path) if rec.include? path link = File.readlink(path)
link = File.readlink path if %r{\A/} =~ link
resolved = '/' if %r{\A/} =~ link top = '/'
begin unresolved = link.scan(%r{[^/]+})
rec[path] = true else
resolved = realpath_rec(resolved, link, stats, rec) unresolved.pop
ensure unresolved.concat link.scan(%r{[^/]+})
rec.delete path
end end
else else
resolved = path resolved.unshift unresolved.pop
end end
end end
} end
resolved
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 end
# parent method returns parent directory, i.e. ".." is joined at last. # parent method returns parent directory, i.e. ".." is joined at last.