1
0
Fork 0
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:
akr 2010-03-07 04:55:34 +00:00
parent 8a144fdedc
commit 785b31bed4
5 changed files with 103 additions and 31 deletions

View file

@ -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
View file

@ -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);

View file

@ -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.

View file

@ -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") }

View file

@ -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