mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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:
parent
8a144fdedc
commit
785b31bed4
5 changed files with 103 additions and 31 deletions
10
ChangeLog
10
ChangeLog
|
@ -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>
|
Sun Mar 7 02:05:38 2010 NARUSE, Yui <naruse@ruby-lang.org>
|
||||||
|
|
||||||
* encoding.c (enc_set_filesystem_encoding):
|
* encoding.c (enc_set_filesystem_encoding):
|
||||||
|
|
90
file.c
90
file.c
|
@ -3166,65 +3166,105 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, char *unresolved, VALUE loopche
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
realpath_internal(VALUE path, int strict)
|
realpath_internal(VALUE basedir, VALUE path, int strict)
|
||||||
{
|
{
|
||||||
long prefixlen;
|
long prefixlen;
|
||||||
VALUE resolved;
|
VALUE resolved;
|
||||||
volatile VALUE unresolved_path;
|
volatile VALUE unresolved_path;
|
||||||
char *unresolved_names;
|
|
||||||
VALUE loopcheck;
|
VALUE loopcheck;
|
||||||
|
volatile VALUE curdir = Qnil;
|
||||||
|
|
||||||
|
char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
rb_secure(2);
|
rb_secure(2);
|
||||||
|
|
||||||
FilePathValue(path);
|
FilePathValue(path);
|
||||||
unresolved_path = rb_str_dup_frozen(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();
|
loopcheck = rb_hash_new();
|
||||||
if (prefixlen == 0) {
|
if (curdir_names)
|
||||||
volatile VALUE curdir = rb_dir_getwd();
|
realpath_rec(&prefixlen, &resolved, curdir_names, loopcheck, 1, 0);
|
||||||
char *unresolved_curdir_names = skiproot(RSTRING_PTR(curdir));
|
if (basedir_names)
|
||||||
prefixlen = unresolved_curdir_names - RSTRING_PTR(curdir);
|
realpath_rec(&prefixlen, &resolved, basedir_names, loopcheck, 1, 0);
|
||||||
resolved = rb_str_new(RSTRING_PTR(curdir), prefixlen);
|
realpath_rec(&prefixlen, &resolved, path_names, loopcheck, strict, 1);
|
||||||
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);
|
|
||||||
OBJ_TAINT(resolved);
|
OBJ_TAINT(resolved);
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* 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.
|
* 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
|
* All components of the pathname must exist when this method is
|
||||||
* called.
|
* called.
|
||||||
*/
|
*/
|
||||||
static VALUE
|
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:
|
* 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.
|
* 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.
|
* The last component of the real pathname can be nonexistent.
|
||||||
*/
|
*/
|
||||||
static VALUE
|
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
|
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, "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, "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, "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, "realpath", rb_file_s_realpath, -1);
|
||||||
rb_define_singleton_method(rb_cFile, "realdirpath", rb_file_s_realdirpath, 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, "basename", rb_file_s_basename, -1);
|
||||||
rb_define_singleton_method(rb_cFile, "dirname", rb_file_s_dirname, 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);
|
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
|
# All components of the pathname must exist when this method is
|
||||||
# called.
|
# called.
|
||||||
#
|
#
|
||||||
def realpath
|
def realpath(basedir=nil)
|
||||||
self.class.new(File.realpath(@path))
|
self.class.new(File.realpath(@path, basedir))
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -452,8 +452,8 @@ class Pathname
|
||||||
#
|
#
|
||||||
# The last component of the real pathname can be nonexistent.
|
# The last component of the real pathname can be nonexistent.
|
||||||
#
|
#
|
||||||
def realdirpath
|
def realdirpath(basedir=nil)
|
||||||
self.class.new(File.realdirpath(@path))
|
self.class.new(File.realdirpath(@path, basedir))
|
||||||
end
|
end
|
||||||
|
|
||||||
# #parent returns the parent directory.
|
# #parent returns the parent directory.
|
||||||
|
|
|
@ -288,8 +288,8 @@ class TestPathname < Test::Unit::TestCase
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
def realpath(path)
|
def realpath(path, basedir=nil)
|
||||||
Pathname.new(path).realpath.to_s
|
Pathname.new(path).realpath(basedir).to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_realpath
|
def test_realpath
|
||||||
|
@ -301,6 +301,7 @@ class TestPathname < Test::Unit::TestCase
|
||||||
|
|
||||||
File.symlink("loop", "#{dir}/loop")
|
File.symlink("loop", "#{dir}/loop")
|
||||||
assert_raise(Errno::ELOOP) { realpath("#{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")
|
File.symlink("../#{File.basename(dir)}/./not-exist-target", "#{dir}/not-exist2")
|
||||||
assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist2") }
|
assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist2") }
|
||||||
|
@ -314,6 +315,7 @@ class TestPathname < Test::Unit::TestCase
|
||||||
|
|
||||||
Dir.mkdir("exist")
|
Dir.mkdir("exist")
|
||||||
assert_equal("#{dir}/exist", realpath("exist"))
|
assert_equal("#{dir}/exist", realpath("exist"))
|
||||||
|
assert_raise(Errno::ELOOP) { realpath("../loop", "#{dir}/exist") }
|
||||||
|
|
||||||
File.symlink("loop1/loop1", "loop1")
|
File.symlink("loop1/loop1", "loop1")
|
||||||
assert_raise(Errno::ELOOP) { realpath("#{dir}/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_raise(TypeError) { File::Stat.allocate.readable? }
|
||||||
assert_nothing_raised { File::Stat.allocate.inspect }
|
assert_nothing_raised { File::Stat.allocate.inspect }
|
||||||
end
|
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
|
end
|
||||||
|
|
Loading…
Reference in a new issue