summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-02-16 16:25:40 +0000
committernagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-02-16 16:25:40 +0000
commiteaba9da1d13fac380fe94f977d7f8d89bd40cde0 (patch)
treeb17e09f3ce10f925571e406c0deed966270c7804
parent99c76a47ef8c65a27ee6d9a7dab03671dc22647a (diff)
merge revision(s) 59983,59984: [Backport #10222] [Backport #14372] [Backport #14424]
file.c: rb_check_realpath * file.c (rb_check_realpath): returns real path which has no symbolic links. similar to rb_realpath except for returning Qnil if any parts did not exist. load.c: real path to load * load.c (rb_construct_expanded_load_path): expand load paths to real paths to get rid of duplicate loading from symbolic-linked directories. [Feature #10222] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_4@62440 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--file.c77
-rw-r--r--internal.h1
-rw-r--r--load.c3
-rw-r--r--test/ruby/test_exception.rb2
-rw-r--r--test/ruby/test_require.rb14
-rw-r--r--version.h2
6 files changed, 78 insertions, 21 deletions
diff --git a/file.c b/file.c
index 55ed82954a..0e67654da2 100644
--- a/file.c
+++ b/file.c
@@ -3757,8 +3757,29 @@ rb_file_s_absolute_path(int argc, const VALUE *argv)
return rb_file_absolute_path(argv[0], argc > 1 ? argv[1] : Qnil);
}
-static void
-realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE loopcheck, int strict, int last)
+#ifdef __native_client__
+VALUE
+rb_realpath_internal(VALUE basedir, VALUE path, int strict)
+{
+ return path;
+}
+
+VALUE
+rb_check_realpath(VALUE basedir, VALUE path)
+{
+ return path;
+}
+#else
+enum rb_realpath_mode {
+ RB_REALPATH_CHECK,
+ RB_REALPATH_DIR,
+ RB_REALPATH_STRICT,
+ RB_REALPATH_MODE_MAX
+};
+
+static int
+realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved,
+ VALUE loopcheck, enum rb_realpath_mode mode, int last)
{
const char *pend = unresolved + strlen(unresolved);
rb_encoding *enc = rb_enc_get(*resolvedp);
@@ -3799,6 +3820,10 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE l
checkval = rb_hash_aref(loopcheck, testpath);
if (!NIL_P(checkval)) {
if (checkval == ID2SYM(resolving)) {
+ if (mode == RB_REALPATH_CHECK) {
+ errno = ELOOP;
+ return -1;
+ }
rb_syserr_fail_path(ELOOP, testpath);
}
else {
@@ -3816,8 +3841,9 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE l
#endif
if (ret == -1) {
int e = errno;
+ if (mode == RB_REALPATH_CHECK) return -1;
if (e == ENOENT) {
- if (strict || !last || *unresolved_firstsep)
+ if (mode == RB_REALPATH_STRICT || !last || *unresolved_firstsep)
rb_syserr_fail_path(e, testpath);
*resolvedp = testpath;
break;
@@ -3846,7 +3872,9 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE l
*resolvedp = link;
*prefixlenp = link_prefixlen;
}
- realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0');
+ if (realpath_rec(prefixlenp, resolvedp, link_names,
+ loopcheck, mode, !*unresolved_firstsep))
+ return -1;
RB_GC_GUARD(link_orig);
rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp));
}
@@ -3860,17 +3888,11 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE l
}
}
}
+ return 0;
}
-#ifdef __native_client__
-VALUE
-rb_realpath_internal(VALUE basedir, VALUE path, int strict)
-{
- return path;
-}
-#else
-VALUE
-rb_realpath_internal(VALUE basedir, VALUE path, int strict)
+static VALUE
+rb_check_realpath_internal(VALUE basedir, VALUE path, enum rb_realpath_mode mode)
{
long prefixlen;
VALUE resolved;
@@ -3937,11 +3959,16 @@ rb_realpath_internal(VALUE basedir, VALUE path, int strict)
}
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);
+ if (curdir_names) {
+ if (realpath_rec(&prefixlen, &resolved, curdir_names, loopcheck, mode, 0))
+ return Qnil;
+ }
+ if (basedir_names) {
+ if (realpath_rec(&prefixlen, &resolved, basedir_names, loopcheck, mode, 0))
+ return Qnil;
+ }
+ if (realpath_rec(&prefixlen, &resolved, path_names, loopcheck, mode, 1))
+ return Qnil;
if (origenc != enc && rb_enc_str_asciionly_p(resolved))
rb_enc_associate(resolved, origenc);
@@ -3949,6 +3976,20 @@ rb_realpath_internal(VALUE basedir, VALUE path, int strict)
OBJ_TAINT(resolved);
return resolved;
}
+
+VALUE
+rb_realpath_internal(VALUE basedir, VALUE path, int strict)
+{
+ const enum rb_realpath_mode mode =
+ strict ? RB_REALPATH_STRICT : RB_REALPATH_DIR;
+ return rb_check_realpath_internal(basedir, path, mode);
+}
+
+VALUE
+rb_check_realpath(VALUE basedir, VALUE path)
+{
+ return rb_check_realpath_internal(basedir, path, RB_REALPATH_CHECK);
+}
#endif
/*
diff --git a/internal.h b/internal.h
index 6012376353..95fc9822e1 100644
--- a/internal.h
+++ b/internal.h
@@ -1051,6 +1051,7 @@ void rb_mark_end_proc(void);
VALUE rb_home_dir_of(VALUE user, VALUE result);
VALUE rb_default_home_dir(VALUE result);
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict);
+VALUE rb_check_realpath(VALUE basedir, VALUE path);
void rb_file_const(const char*, VALUE);
int rb_file_load_ok(const char *);
VALUE rb_file_expand_path_fast(VALUE, VALUE);
diff --git a/load.c b/load.c
index 7778d4f87c..bd0f8b8fdf 100644
--- a/load.c
+++ b/load.c
@@ -85,7 +85,8 @@ rb_construct_expanded_load_path(enum expand_type type, int *has_relative, int *h
if (is_string)
rb_str_freeze(path);
as_str = rb_get_path_check_convert(path, as_str, level);
- expanded_path = rb_file_expand_path_fast(as_str, Qnil);
+ expanded_path = rb_check_realpath(Qnil, as_str);
+ if (NIL_P(expanded_path)) expanded_path = as_str;
rb_str_freeze(expanded_path);
rb_ary_push(ary, rb_fstring(expanded_path));
}
diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb
index d7038bb578..ee212083a3 100644
--- a/test/ruby/test_exception.rb
+++ b/test/ruby/test_exception.rb
@@ -983,7 +983,7 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
path = nil
Tempfile.create(%w[circular .rb]) do |t|
begin
- path = t.path
+ path = File.realpath(t.path)
basename = File.basename(path)
t.puts "require '#{basename}'"
t.close
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb
index dbd6117ba2..533e1b27d7 100644
--- a/test/ruby/test_require.rb
+++ b/test/ruby/test_require.rb
@@ -809,4 +809,18 @@ class TestRequire < Test::Unit::TestCase
end;
end
end
+
+ def test_symlink_load_path
+ Dir.mktmpdir {|tmp|
+ Dir.mkdir(File.join(tmp, "real"))
+ begin
+ File.symlink "real", File.join(tmp, "symlink")
+ rescue NotImplementedError, Errno::EACCES
+ skip "File.symlink is not implemented"
+ end
+ File.write(File.join(tmp, "real/a.rb"), "print __FILE__")
+ result = IO.popen([EnvUtil.rubybin, "-I#{tmp}/symlink", "-e", "require 'a.rb'"], &:read)
+ assert_operator(result, :end_with?, "/real/a.rb")
+ }
+ end
end
diff --git a/version.h b/version.h
index 1665f4e4d3..4ee09f71f0 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.4.4"
#define RUBY_RELEASE_DATE "2018-02-17"
-#define RUBY_PATCHLEVEL 238
+#define RUBY_PATCHLEVEL 239
#define RUBY_RELEASE_YEAR 2018
#define RUBY_RELEASE_MONTH 2