file.c: realpath on special symlink

* file.c (realpath_rec): fallback to symlink path when it is
  accessible but the link target is not actual entry on file
  systems.  [ruby-dev:50487] [Bug #14557]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62607 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2018-02-28 05:43:53 +00:00
Родитель 1daa624d56
Коммит 5a53cbe314
2 изменённых файлов: 19 добавлений и 5 удалений

16
file.c
Просмотреть файл

@ -3943,7 +3943,7 @@ enum rb_realpath_mode {
};
static int
realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved,
realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE fallback,
VALUE loopcheck, enum rb_realpath_mode mode, int last)
{
const char *pend = unresolved + strlen(unresolved);
@ -4001,6 +4001,12 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved,
ret = lstat_without_gvl(RSTRING_PTR(testpath), &sbuf);
if (ret == -1) {
int e = errno;
if (e == ENOENT && !NIL_P(fallback)) {
if (stat_without_gvl(RSTRING_PTR(fallback), &sbuf) == 0) {
rb_str_replace(*resolvedp, fallback);
return 0;
}
}
if (mode == RB_REALPATH_CHECK) return -1;
if (e == ENOENT) {
if (mode == RB_REALPATH_STRICT || !last || *unresolved_firstsep)
@ -4032,7 +4038,7 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved,
*resolvedp = link;
*prefixlenp = link_prefixlen;
}
if (realpath_rec(prefixlenp, resolvedp, link_names,
if (realpath_rec(prefixlenp, resolvedp, link_names, testpath,
loopcheck, mode, !*unresolved_firstsep))
return -1;
RB_GC_GUARD(link_orig);
@ -4121,14 +4127,14 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, enum rb_realpath_mode mode
loopcheck = rb_hash_new();
if (curdir_names) {
if (realpath_rec(&prefixlen, &resolved, curdir_names, loopcheck, mode, 0))
if (realpath_rec(&prefixlen, &resolved, curdir_names, Qnil, loopcheck, mode, 0))
return Qnil;
}
if (basedir_names) {
if (realpath_rec(&prefixlen, &resolved, basedir_names, loopcheck, mode, 0))
if (realpath_rec(&prefixlen, &resolved, basedir_names, Qnil, loopcheck, mode, 0))
return Qnil;
}
if (realpath_rec(&prefixlen, &resolved, path_names, loopcheck, mode, 1))
if (realpath_rec(&prefixlen, &resolved, path_names, Qnil, loopcheck, mode, 1))
return Qnil;
if (origenc != rb_enc_get(resolved)) {

Просмотреть файл

@ -303,6 +303,14 @@ class TestFile < Test::Unit::TestCase
}
end
def test_realpath_special_symlink
IO.pipe do |r, w|
if File.pipe?(path = "/dev/fd/#{r.fileno}")
assert_file.identical?(File.realpath(path), path)
end
end
end
def test_realdirpath
Dir.mktmpdir('rubytest-realdirpath') {|tmpdir|
realdir = File.realpath(tmpdir)