* file.c: add optional basedir argument for realpath/realdirpath.

(realpath_internal): handle basedir.
  (rb_file_s_realpath): extract basedir from argument list.
  (rb_file_s_realdirpath): extract basedir from argument list.

* lib/pathname.rb (realpath): pass basedir.
  (realdirpath): ditto.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26841 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2010-03-07 04:55:34 +00:00
Родитель 8a144fdedc
Коммит 785b31bed4
5 изменённых файлов: 103 добавлений и 31 удалений

Просмотреть файл

@ -1,3 +1,13 @@
Sun Mar 7 13:49:49 2010 Tanaka Akira <akr@fsij.org>
* file.c: add optional basedir argument for realpath/realdirpath.
(realpath_internal): handle basedir.
(rb_file_s_realpath): extract basedir from argument list.
(rb_file_s_realdirpath): extract basedir from argument list.
* lib/pathname.rb (realpath): pass basedir.
(realdirpath): ditto.
Sun Mar 7 02:05:38 2010 NARUSE, Yui <naruse@ruby-lang.org>
* encoding.c (enc_set_filesystem_encoding):

90
file.c
Просмотреть файл

@ -3166,65 +3166,105 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, char *unresolved, VALUE loopche
}
static VALUE
realpath_internal(VALUE path, int strict)
realpath_internal(VALUE basedir, VALUE path, int strict)
{
long prefixlen;
VALUE resolved;
volatile VALUE unresolved_path;
char *unresolved_names;
VALUE loopcheck;
volatile VALUE curdir = Qnil;
char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
char *ptr;
rb_secure(2);
FilePathValue(path);
unresolved_path = rb_str_dup_frozen(path);
unresolved_names = skiproot(RSTRING_PTR(unresolved_path));
prefixlen = unresolved_names - RSTRING_PTR(unresolved_path);
if (!NIL_P(basedir)) {
FilePathValue(basedir);
basedir = rb_str_dup_frozen(basedir);
}
ptr = RSTRING_PTR(unresolved_path);
path_names = skiproot(ptr);
if (ptr != path_names) {
resolved = rb_str_new(ptr, path_names - ptr);
goto root_found;
}
if (!NIL_P(basedir)) {
ptr = RSTRING_PTR(basedir);
basedir_names = skiproot(ptr);
if (ptr != basedir_names) {
resolved = rb_str_new(ptr, basedir_names - ptr);
goto root_found;
}
}
curdir = rb_dir_getwd();
ptr = RSTRING_PTR(curdir);
curdir_names = skiproot(ptr);
resolved = rb_str_new(ptr, curdir_names - ptr);
root_found:
ptr = chompdirsep(RSTRING_PTR(resolved));
if (*ptr) {
rb_str_set_len(resolved, ptr - RSTRING_PTR(resolved) + 1);
}
prefixlen = RSTRING_LEN(resolved);
loopcheck = rb_hash_new();
if (prefixlen == 0) {
volatile VALUE curdir = rb_dir_getwd();
char *unresolved_curdir_names = skiproot(RSTRING_PTR(curdir));
prefixlen = unresolved_curdir_names - RSTRING_PTR(curdir);
resolved = rb_str_new(RSTRING_PTR(curdir), prefixlen);
realpath_rec(&prefixlen, &resolved, unresolved_curdir_names, loopcheck, 1, 0);
}
else {
resolved = rb_str_new(RSTRING_PTR(unresolved_path), prefixlen);
}
realpath_rec(&prefixlen, &resolved, unresolved_names, loopcheck, strict, 1);
if (curdir_names)
realpath_rec(&prefixlen, &resolved, curdir_names, loopcheck, 1, 0);
if (basedir_names)
realpath_rec(&prefixlen, &resolved, basedir_names, loopcheck, 1, 0);
realpath_rec(&prefixlen, &resolved, path_names, loopcheck, strict, 1);
OBJ_TAINT(resolved);
return resolved;
}
/*
* call-seq:
* File.realpath(pathname) -> real_pathname
* File.realpath(pathname [, dir_string]) -> real_pathname
*
* Returns the real (absolute) pathname of +pathname+ in the actual
* Returns the real (absolute) pathname of _pathname_ in the actual
* filesystem not containing symlinks or useless dots.
*
* If _dir_string_ is given, it is used as a base directory
* for interpreting relative pathname instead of the current directory.
*
* All components of the pathname must exist when this method is
* called.
*/
static VALUE
rb_file_s_realpath(VALUE klass, VALUE path)
rb_file_s_realpath(int argc, VALUE *argv, VALUE klass)
{
return realpath_internal(path, 1);
VALUE path, basedir;
rb_scan_args(argc, argv, "11", &path, &basedir);
return realpath_internal(basedir, path, 1);
}
/*
* call-seq:
* File.realdirpath(pathname) -> real_pathname
* File.realdirpath(pathname [, dir_string]) -> real_pathname
*
* Returns the real (absolute) pathname of +pathname+ in the actual filesystem.
* Returns the real (absolute) pathname of _pathname_ in the actual filesystem.
* The real pathname doesn't contain symlinks or useless dots.
*
* If _dir_string_ is given, it is used as a base directory
* for interpreting relative pathname instead of the current directory.
*
* The last component of the real pathname can be nonexistent.
*/
static VALUE
rb_file_s_realdirpath(VALUE klass, VALUE path)
rb_file_s_realdirpath(int argc, VALUE *argv, VALUE klass)
{
return realpath_internal(path, 0);
VALUE path, basedir;
rb_scan_args(argc, argv, "11", &path, &basedir);
return realpath_internal(basedir, path, 0);
}
static size_t
@ -5041,8 +5081,8 @@ Init_File(void)
rb_define_singleton_method(rb_cFile, "truncate", rb_file_s_truncate, 2);
rb_define_singleton_method(rb_cFile, "expand_path", rb_file_s_expand_path, -1);
rb_define_singleton_method(rb_cFile, "absolute_path", rb_file_s_absolute_path, -1);
rb_define_singleton_method(rb_cFile, "realpath", rb_file_s_realpath, 1);
rb_define_singleton_method(rb_cFile, "realdirpath", rb_file_s_realdirpath, 1);
rb_define_singleton_method(rb_cFile, "realpath", rb_file_s_realpath, -1);
rb_define_singleton_method(rb_cFile, "realdirpath", rb_file_s_realdirpath, -1);
rb_define_singleton_method(rb_cFile, "basename", rb_file_s_basename, -1);
rb_define_singleton_method(rb_cFile, "dirname", rb_file_s_dirname, 1);
rb_define_singleton_method(rb_cFile, "extname", rb_file_s_extname, 1);

Просмотреть файл

@ -442,8 +442,8 @@ class Pathname
# All components of the pathname must exist when this method is
# called.
#
def realpath
self.class.new(File.realpath(@path))
def realpath(basedir=nil)
self.class.new(File.realpath(@path, basedir))
end
#
@ -452,8 +452,8 @@ class Pathname
#
# The last component of the real pathname can be nonexistent.
#
def realdirpath
self.class.new(File.realdirpath(@path))
def realdirpath(basedir=nil)
self.class.new(File.realdirpath(@path, basedir))
end
# #parent returns the parent directory.

Просмотреть файл

@ -288,8 +288,8 @@ class TestPathname < Test::Unit::TestCase
return true
end
def realpath(path)
Pathname.new(path).realpath.to_s
def realpath(path, basedir=nil)
Pathname.new(path).realpath(basedir).to_s
end
def test_realpath
@ -301,6 +301,7 @@ class TestPathname < Test::Unit::TestCase
File.symlink("loop", "#{dir}/loop")
assert_raise(Errno::ELOOP) { realpath("#{dir}/loop") }
assert_raise(Errno::ELOOP) { realpath("#{dir}/loop", dir) }
File.symlink("../#{File.basename(dir)}/./not-exist-target", "#{dir}/not-exist2")
assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist2") }
@ -314,6 +315,7 @@ class TestPathname < Test::Unit::TestCase
Dir.mkdir("exist")
assert_equal("#{dir}/exist", realpath("exist"))
assert_raise(Errno::ELOOP) { realpath("../loop", "#{dir}/exist") }
File.symlink("loop1/loop1", "loop1")
assert_raise(Errno::ELOOP) { realpath("#{dir}/loop1") }

Просмотреть файл

@ -157,4 +157,24 @@ class TestFile < Test::Unit::TestCase
assert_raise(TypeError) { File::Stat.allocate.readable? }
assert_nothing_raised { File::Stat.allocate.inspect }
end
def test_realpath
Dir.mktmpdir('rubytest-realpath') {|tmpdir|
realdir = File.realpath(tmpdir)
tst = realdir.sub(/#{Regexp.escape(File::SEPARATOR)}/, '\0\0\0')
assert_equal(realdir, File.realpath(tst))
assert_equal(realdir, File.realpath(".", tst))
}
end
def test_realdirpath
Dir.mktmpdir('rubytest-realdirpath') {|tmpdir|
realdir = File.realpath(tmpdir)
tst = realdir.sub(/#{Regexp.escape(File::SEPARATOR)}/, '\0\0\0')
assert_equal(realdir, File.realdirpath(tst))
assert_equal(realdir, File.realdirpath(".", tst))
assert_equal(File.join(realdir, "foo"), File.realdirpath("foo", tst))
}
end
end