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>
|
||||
|
||||
* 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
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue