mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
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
This commit is contained in:
parent
99c76a47ef
commit
eaba9da1d1
6 changed files with 78 additions and 21 deletions
77
file.c
77
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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
3
load.c
3
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));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue