ruby-changes:14969
From: akr <ko1@a...>
Date: Sun, 7 Mar 2010 13:55:53 +0900 (JST)
Subject: [ruby-changes:14969] Ruby:r26841 (trunk): * file.c: add optional basedir argument for realpath/realdirpath.
akr 2010-03-07 13:55:34 +0900 (Sun, 07 Mar 2010) New Revision: 26841 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=26841 Log: * 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. Modified files: trunk/ChangeLog trunk/file.c trunk/lib/pathname.rb trunk/test/pathname/test_pathname.rb trunk/test/ruby/test_file.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 26840) +++ ChangeLog (revision 26841) @@ -1,3 +1,13 @@ +Sun Mar 7 13:49:49 2010 Tanaka Akira <akr@f...> + + * 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@r...> * encoding.c (enc_set_filesystem_encoding): Index: lib/pathname.rb =================================================================== --- lib/pathname.rb (revision 26840) +++ lib/pathname.rb (revision 26841) @@ -442,8 +442,8 @@ # 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 @@ # # 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. Index: test/ruby/test_file.rb =================================================================== --- test/ruby/test_file.rb (revision 26840) +++ test/ruby/test_file.rb (revision 26841) @@ -157,4 +157,24 @@ 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 Index: test/pathname/test_pathname.rb =================================================================== --- test/pathname/test_pathname.rb (revision 26840) +++ test/pathname/test_pathname.rb (revision 26841) @@ -288,8 +288,8 @@ 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 @@ 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 @@ 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") } Index: file.c =================================================================== --- file.c (revision 26840) +++ file.c (revision 26841) @@ -3166,65 +3166,105 @@ } 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); - 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); + + if (!NIL_P(basedir)) { + FilePathValue(basedir); + basedir = rb_str_dup_frozen(basedir); } - else { - resolved = rb_str_new(RSTRING_PTR(unresolved_path), prefixlen); + + ptr = RSTRING_PTR(unresolved_path); + path_names = skiproot(ptr); + if (ptr != path_names) { + resolved = rb_str_new(ptr, path_names - ptr); + goto root_found; } - realpath_rec(&prefixlen, &resolved, unresolved_names, loopcheck, strict, 1); + + 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 (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 @@ 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); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/