[#39954] Fwd: [ruby-cvs:33451] Ruby:r26235 (trunk): * trace.h: new file. wraps tracing mechanisms. — SASADA Koichi <ko1@...>

 ささだです.

16 messages 2010/01/04
[#39957] Re: Fwd: [ruby-cvs:33451] Ruby:r26235 (trunk): * trace.h: new file. wraps tracing mechanisms. — Yugui <yugui@...> 2010/01/04

2010/1/4 SASADA Koichi <ko1@atdot.net>:

[#39959] Re: Fwd: [ruby-cvs:33451] Ruby:r26235 (trunk): * trace.h: new file. wraps tracing mechanisms. — SASADA Koichi <ko1@...> 2010/01/04

 ささだです.

[#39975] [Feature #2571] 文字列のハミング距離 — Kenta Murata <redmine@...>

Feature #2571: 文字列のハミング距離

14 messages 2010/01/07

[#39978] "require 'logge'" fails on ruby 1.8.7 from http://github.com/shyouhei/ruby — MOROHASHI Kyosuke <moronatural@...>

諸橋です。

7 messages 2010/01/07

[#40004] [Bug:trunk] require_relative depends on current directory — Yusuke ENDOH <mame@...>

遠藤です。

13 messages 2010/01/09

[#40074] [Bug #2603] NetBSD 5.0以降でpthreadの処理に由来する不具合 — Takahiro Kambe <redmine@...>

Bug #2603: NetBSD 5.0以降でpthreadの処理に由来する不具合

29 messages 2010/01/14
[#40086] Re: [Bug #2603] NetBSD 5.0以降でpthreadの処理に由来する不具合 — f-miura@... (MIURA, Fumiaki) 2010/01/14

NTTレゾナントの三浦です。不完全なpatchを書いてすみません。

[#40088] Re: [Bug #2603] NetBSD 5.0以降でpthreadの処理に由来する不具合 — Takahiro Kambe <taca@...> 2010/01/14

こんばんは。

[#40091] Re: [Bug #2603] NetBSD 5.0以降でpthreadの処理に由来する不具合 — KOSAKI Motohiro <kosaki.motohiro@...> 2010/01/15

kosakiです

[#40092] Re: [Bug #2603] NetBSD 5.0以降でpthreadの処理に由来する不具合 — Takahiro Kambe <taca@...> 2010/01/15

こんにちは。

[#40077] [Bug #2604] test_dsa_sign_verify() in test/openssl/test_ec.rb failes — Takahiro Kambe <redmine@...>

Bug #2604: test_dsa_sign_verify() in test/openssl/test_ec.rb failes

11 messages 2010/01/14

[#40153] [Bug:trunk] three bugs of Matrix::Scalar — Yusuke ENDOH <mame@...>

連投すみません。

19 messages 2010/01/25
[#40184] Re: [Bug:trunk] three bugs of Matrix::Scalar — keiju@... (石塚圭樹) 2010/01/27

けいじゅ@いしつかです.

[#40189] Re: [Bug:trunk] three bugs of Matrix::Scalar — Yusuke ENDOH <mame@...> 2010/01/27

遠藤です。

[#40191] Re: [Bug:trunk] three bugs of Matrix::Scalar — keiju@... (石塚圭樹) 2010/01/27

けいじゅ@いしつかです.

[#40224] Re: [Bug:trunk] three bugs of Matrix::Scalar — Yukihiro Matsumoto <matz@...> 2010/01/28

まつもと ゆきひろです

[#40162] [Bug #2658] rubyspec: Ruby character strings interpolates the return value of Object#inspect, without ivars, if Object#to_s does not return a String instance ERROR — Yusuke Endoh <redmine@...>

Bug #2658: rubyspec: Ruby character strings interpolates the return value of Object#inspect, without ivars, if Object#to_s does not return a String instance ERROR

8 messages 2010/01/26
[#40163] Re: [Bug #2658] rubyspec: Ruby character strings interpolates the return value of Object#inspect, without ivars, if Object#to_s does not return a String instance ERROR — Tanaka Akira <akr@...> 2010/01/26

2010年1月26日20:39 Yusuke Endoh <redmine@ruby-lang.org>:

[#40168] [Bug #2662] BigDecimal#ceil, etc. should not return Integer — Yusuke Endoh <redmine@...>

Bug #2662: BigDecimal#ceil, etc. should not return Integer

10 messages 2010/01/26

[#40200] [Feature #2673] the length for an enumerator generated by Array#permutation and Array#combination — Kenta Murata <redmine@...>

Feature #2673: the length for an enumerator generated by Array#permutation and Array#combination

14 messages 2010/01/28

[#40221] [Bug:trunk] rubyspec: SimpleDelegator when frozen creates a frozen clone ERROR — Yusuke ENDOH <mame@...>

まつもとさん、または lib/delegator.rb についてわかる誰か

13 messages 2010/01/28

[#40265] MonitorMixin::ConditionVariable#wait timeout — Tanaka Akira <akr@...>

手元の Ubuntu 9.10 の環境で Ruby 1.9.2 を make test-all すると

38 messages 2010/01/30
[#40326] Re: MonitorMixin::ConditionVariable#wait timeout — Shugo Maeda <shugo@...> 2010/02/05

前田です。

[#41155] Re: MonitorMixin::ConditionVariable#wait timeout — Yusuke ENDOH <mame@...> 2010/05/05

前田さん、akr さん

[#41157] Re: MonitorMixin::ConditionVariable#wait timeout — Tanaka Akira <akr@...> 2010/05/05

2010年5月5日9:32 Yusuke ENDOH <mame@tsg.ne.jp>:

[#41158] Re: MonitorMixin::ConditionVariable#wait timeout — Yusuke ENDOH <mame@...> 2010/05/05

遠藤です。

[#41159] Re: MonitorMixin::ConditionVariable#wait timeout — Tanaka Akira <akr@...> 2010/05/05

2010年5月5日11:46 Yusuke ENDOH <mame@tsg.ne.jp>:

[#41160] Re: MonitorMixin::ConditionVariable#wait timeout — Yusuke ENDOH <mame@...> 2010/05/05

遠藤です。

[#41182] Re: MonitorMixin::ConditionVariable#wait timeout — Tanaka Akira <akr@...> 2010/05/06

2010年5月5日13:22 Yusuke ENDOH <mame@tsg.ne.jp>:

[#41183] Re: MonitorMixin::ConditionVariable#wait timeout — Yusuke ENDOH <mame@...> 2010/05/06

遠藤です。

[#41186] Re: MonitorMixin::ConditionVariable#wait timeout — Tanaka Akira <akr@...> 2010/05/06

2010年5月6日19:58 Yusuke ENDOH <mame@tsg.ne.jp>:

[#41205] Re: MonitorMixin::ConditionVariable#wait timeout — Yusuke ENDOH <mame@...> 2010/05/06

遠藤です。

[#41207] Re: MonitorMixin::ConditionVariable#wait timeout — KOSAKI Motohiro <kosaki.motohiro@...> 2010/05/06

2010年5月6日23:08 Yusuke ENDOH <mame@tsg.ne.jp>:

[#41208] Re: MonitorMixin::ConditionVariable#wait timeout — Tanaka Akira <akr@...> 2010/05/06

2010年5月6日23:15 KOSAKI Motohiro <kosaki.motohiro@gmail.com>:

[#41245] Re: MonitorMixin::ConditionVariable#wait timeout — Yusuke ENDOH <mame@...> 2010/05/10

遠藤です。

[#41252] Re: MonitorMixin::ConditionVariable#wait timeout — KOSAKI Motohiro <kosaki.motohiro@...> 2010/05/10

kosakiです

[#41255] Re: MonitorMixin::ConditionVariable#wait timeout — Yusuke ENDOH <mame@...> 2010/05/10

遠藤です。

[#41256] Re: MonitorMixin::ConditionVariable#wait timeout — Masaya TARUI <tarui@...> 2010/05/10

樽家です。

[#40269] [Feature #2695] Supported Platforms — Kazuhiro NISHIYAMA <redmine@...>

Feature #2695: Supported Platforms

17 messages 2010/01/31
[#40760] [Feature #2695] Supported Platforms — Yusuke Endoh <redmine@...> 2010/03/25

チケット #2695 が更新されました。 (by Yusuke Endoh)

[ruby-dev:40040] File.realpath

From: Tanaka Akira <akr@...>
Date: 2010-01-11 16:54:59 UTC
List: ruby-dev #40040
File.realpath (と File.realdirpath) を提供するのはどうでしょうか。

require_relative を呼び出したファイルをシンボリックリンクを通して
指定したとき、実体のファイルからの相対パスでないライブラリを
ロードしてしまうことがあります。

% ls -l a b
a:
total 8
-rw-r--r-- 1 akr akr 13 Jan 12 01:08 lib.rb
-rw-r--r-- 1 akr akr 23 Jan 12 01:08 tst.rb

b:
total 4
-rw-r--r-- 1 akr akr 13 Jan 12 01:08 lib.rb
lrwxrwxrwx 1 akr akr 11 Jan 12 01:08 tst.rb -> ../a/tst.rb
% cat a/tst.rb
require_relative "lib"
% cat a/lib.rb
p "a/lib.rb"
% cat b/lib.rb
p "b/lib.rb"
% ./ruby a/tst.rb
"a/lib.rb"
% ./ruby b/tst.rb
"b/lib.rb"

つまり、a/tst.rb は a/lib.rb をロードすることを期待して
require_relative を使っているのに
b/tst.rb というシンボリックリンク経由で実行した時は、b/lib.rb を
ロードしてしまいます。

これを防ぐには require_relative 内で呼び出したファイルのパス名の
シンボリックリンクを解決すればいいのですが、
これを行うメソッドは組み込みにはありません。

そこで、pathname.rb の Pathname#realpath を C で書き直して
File.realpath を実装してみました。
(他の File のパス名を操作するクラスメソッド同様、
文字列を受け取って文字列を返します。)

(なお C の realpath はバッファの大きさを指定できない危険な関数なので禁止です)

また、Pathname#realpath と実装が共有されている Pathname#realdirpath も
 File.realdirpath として提供してあります。

で、require_relative で File.realpath を使って、b/tst.rb を実行した場合でも
 a/lib.rb をロードするように
してみました。

% ./ruby a/tst.rb
"a/lib.rb"
% ./ruby b/tst.rb
"a/lib.rb"

どうでしょう?
-- 
[田中 哲][たなか あきら][Tanaka Akira]

Attachments (1)

realpath.patch (10.7 KB, text/x-diff)
% svn diff --diff-cmd diff -x '-u -p'
Index: prelude.rb
===================================================================
--- prelude.rb	(revision 26276)
+++ prelude.rb	(working copy)
@@ -32,7 +32,7 @@ module Kernel
     if /\A\((.*)\)/ =~ file # eval, etc.
       raise LoadError, "require_relative is called in #{$1}"
     end
-    absolute_feature = File.expand_path(File.join(File.dirname(file), relative_feature))
+    absolute_feature = File.join(File.dirname(File.realpath(file)), relative_feature)
     require absolute_feature
   end
 end
Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 26276)
+++ include/ruby/intern.h	(working copy)
@@ -346,6 +346,8 @@ void rb_thread_atfork_before_exec(void);
 VALUE rb_exec_recursive(VALUE(*)(VALUE, VALUE, int),VALUE,VALUE);
 VALUE rb_exec_recursive_paired(VALUE(*)(VALUE, VALUE, int),VALUE,VALUE,VALUE);
 VALUE rb_exec_recursive_outer(VALUE(*)(VALUE, VALUE, int),VALUE,VALUE);
+/* dir.c */
+VALUE rb_dir_getwd(void);
 /* file.c */
 VALUE rb_file_s_expand_path(int, VALUE *);
 VALUE rb_file_expand_path(VALUE, VALUE);
Index: dir.c
===================================================================
--- dir.c	(revision 26276)
+++ dir.c	(working copy)
@@ -851,6 +851,21 @@ dir_s_chdir(int argc, VALUE *argv, VALUE
     return INT2FIX(0);
 }
 
+VALUE
+rb_dir_getwd(void)
+{
+    char *path;
+    VALUE cwd;
+
+    rb_secure(4);
+    path = my_getcwd();
+    cwd = rb_tainted_str_new2(path);
+    rb_enc_associate(cwd, rb_filesystem_encoding());
+
+    xfree(path);
+    return cwd;
+}
+
 /*
  *  call-seq:
  *     Dir.getwd => string
@@ -865,16 +880,7 @@ dir_s_chdir(int argc, VALUE *argv, VALUE
 static VALUE
 dir_s_getwd(VALUE dir)
 {
-    char *path;
-    VALUE cwd;
-
-    rb_secure(4);
-    path = my_getcwd();
-    cwd = rb_tainted_str_new2(path);
-    rb_enc_associate(cwd, rb_filesystem_encoding());
-
-    xfree(path);
-    return cwd;
+    return rb_dir_getwd();
 }
 
 static void
Index: file.c
===================================================================
--- file.c	(revision 26276)
+++ file.c	(working copy)
@@ -3082,6 +3082,145 @@ rb_file_s_absolute_path(int argc, VALUE 
     return rb_file_absolute_path(fname, dname);
 }
 
+static void
+realpath_rec(long *prefixlenp, VALUE *resolvedp, char *unresolved, VALUE loopcheck, int strict, int last)
+{
+    while (*unresolved) {
+        char *testname = unresolved;
+        char *unresolved_firstsep = rb_path_next(unresolved);
+        long testnamelen = unresolved_firstsep - unresolved;
+        char *unresolved_nextname = unresolved_firstsep;
+        while (isdirsep(*unresolved_nextname)) unresolved_nextname++;
+        unresolved = unresolved_nextname;
+        if (testnamelen == 1 && testname[0] == '.') {
+        }
+        else if (testnamelen == 2 && testname[0] == '.' && testname[1] == '.') {
+            if (*prefixlenp < RSTRING_LEN(*resolvedp)) {
+                char *resolved_names = RSTRING_PTR(*resolvedp) + *prefixlenp;
+                long len = rb_path_last_separator(resolved_names) - resolved_names;
+                rb_str_modify(*resolvedp);
+                rb_str_set_len(*resolvedp, *prefixlenp + len);
+            }
+        }
+        else {
+            VALUE checkval;
+            VALUE testpath = rb_str_dup(*resolvedp);
+            if (*prefixlenp < RSTRING_LEN(testpath))
+                rb_str_cat2(testpath, "/");
+            rb_str_cat(testpath, testname, testnamelen);
+            checkval = rb_hash_aref(loopcheck, testpath);
+            if (!NIL_P(checkval)) {
+                if (checkval == ID2SYM(rb_intern("resolving"))) {
+                    errno = ELOOP;
+                    rb_sys_fail(RSTRING_PTR(testpath));
+                }
+                else {
+                    *resolvedp = rb_str_dup(checkval);
+                }
+            }
+            else {
+                struct stat sbuf;
+                int ret;
+                ret = lstat(RSTRING_PTR(testpath), &sbuf);
+                if (ret == -1) {
+                    if (errno == ENOENT) {
+                        if (strict || !last || *unresolved_firstsep)
+                            rb_sys_fail(RSTRING_PTR(testpath));
+                        *resolvedp = testpath;
+                        break;
+                    }
+                    else {
+                        rb_sys_fail(RSTRING_PTR(testpath));
+                    }
+                }
+                if (S_ISLNK(sbuf.st_mode)) {
+                    volatile VALUE link;
+                    char *link_prefix, *link_names;
+                    long link_prefixlen;
+                    rb_hash_aset(loopcheck, testpath, ID2SYM(rb_intern("resolving")));
+                    link = rb_file_s_readlink(rb_cFile, testpath);
+                    link_prefix = RSTRING_PTR(link);
+                    link_names = skiproot(link_prefix);
+                    link_prefixlen = link_names - link_prefix;
+                    if (link_prefixlen == 0) {
+                        realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0');
+                    }
+                    else {
+                        *resolvedp = rb_str_new(link_prefix, link_prefixlen);
+                        *prefixlenp = link_prefixlen;
+                        realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0');
+                    }
+                    rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp));
+                }
+                else {
+                    VALUE s = rb_str_dup_frozen(testpath);
+                    rb_hash_aset(loopcheck, s, s);
+                    *resolvedp = testpath;
+                }
+            }
+        }
+    }
+}
+
+static VALUE
+realpath_internal(VALUE path, int strict)
+{
+    long prefixlen;
+    VALUE resolved;
+    volatile VALUE unresolved_path;
+    char *unresolved_names;
+    VALUE loopcheck;
+    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);
+    }
+    else {
+        resolved = rb_str_new(RSTRING_PTR(unresolved_path), prefixlen);
+    }
+    realpath_rec(&prefixlen, &resolved, unresolved_names, loopcheck, strict, 1);
+    OBJ_TAINT(resolved);
+    return resolved;
+}
+
+/*
+ * call-seq:
+ *     File.realpath(pathname) -> real_pathname
+ *
+ *  Returns the real (absolute) pathname of +pathname+ in the actual
+ *  filesystem not containing symlinks or useless dots.
+ * 
+ *  All components of the pathname must exist when this method is
+ *  called.
+ */
+static VALUE
+rb_file_s_realpath(VALUE klass, VALUE path)
+{
+    return realpath_internal(path, 1);
+}
+
+/*
+ * call-seq:
+ *     File.realdirpath(pathname) -> real_pathname
+ *
+ *  Returns the real (absolute) pathname of +pathname+ in the actual filesystem.
+ *  The real pathname doesn't contain symlinks or useless dots.
+ * 
+ *  The last component of the real pathname can be nonexistent.
+ */
+static VALUE
+rb_file_s_realdirpath(VALUE klass, VALUE path)
+{
+    return realpath_internal(path, 0);
+}
+
 static size_t
 rmext(const char *p, long l1, const char *e)
 {
@@ -4896,6 +5035,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, "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);
Index: lib/pathname.rb
===================================================================
--- lib/pathname.rb	(revision 26276)
+++ lib/pathname.rb	(working copy)
@@ -435,61 +435,6 @@ class Pathname
   end
   private :cleanpath_conservative
 
-  def realpath_rec(prefix, unresolved, h, strict, last = true)
-    resolved = []
-    until unresolved.empty?
-      n = unresolved.shift
-      if n == '.'
-        next
-      elsif n == '..'
-        resolved.pop
-      else
-        path = prepend_prefix(prefix, File.join(*(resolved + [n])))
-        if h.include? path
-          if h[path] == :resolving
-            raise Errno::ELOOP.new(path)
-          else
-            prefix, *resolved = h[path]
-          end
-        else
-          begin
-            s = File.lstat(path)
-          rescue Errno::ENOENT => e
-            raise e if strict || !last || !unresolved.empty?
-            resolved << n
-            break
-          end
-          if s.symlink?
-            h[path] = :resolving
-            link_prefix, link_names = split_names(File.readlink(path))
-            if link_prefix == ''
-              prefix, *resolved = h[path] = realpath_rec(prefix, resolved + link_names, h, strict, unresolved.empty?)
-            else
-              prefix, *resolved = h[path] = realpath_rec(link_prefix, link_names, h, strict, unresolved.empty?)
-            end
-          else
-            resolved << n
-            h[path] = [prefix, *resolved]
-          end
-        end
-      end
-    end
-    return prefix, *resolved
-  end
-  private :realpath_rec
-
-  def real_path_internal(strict = false)
-    path = @path
-    prefix, names = split_names(path)
-    if prefix == ''
-      prefix, names2 = split_names(Dir.pwd)
-      names = names2 + names
-    end
-    prefix, *names = realpath_rec(prefix, names, {}, strict)
-    self.class.new(prepend_prefix(prefix, File.join(*names)))
-  end
-  private :real_path_internal
-
   #
   # Returns the real (absolute) pathname of +self+ in the actual
   # filesystem not containing symlinks or useless dots.
@@ -498,7 +443,7 @@ class Pathname
   # called.
   #
   def realpath
-    real_path_internal(true)
+    self.class.new(File.realpath(@path))
   end
 
   #
@@ -508,7 +453,7 @@ class Pathname
   # The last component of the real pathname can be nonexistent.
   #
   def realdirpath
-    real_path_internal(false)
+    self.class.new(File.realdirpath(@path))
   end
 
   # #parent returns the parent directory.

In This Thread

Prev Next