commit bdbb00871f63edd931b6d8bb6a2ea0061e9b1daa | |
Author: Burke Libbey <burke@libbey.me> | |
Date: Tue Mar 28 12:39:53 2017 -0400 | |
defer load check | |
diff --git a/file.c b/file.c | |
index c57447a..2598574 100644 | |
--- a/file.c | |
+++ b/file.c | |
@@ -5796,11 +5796,11 @@ rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level) | |
VALUE | |
rb_find_file(VALUE path) | |
{ | |
- return rb_find_file_safe(path, rb_safe_level()); | |
+ return rb_find_file_safe(path, rb_safe_level(), 0); | |
} | |
VALUE | |
-rb_find_file_safe(VALUE path, int safe_level) | |
+rb_find_file_safe(VALUE path, int safe_level, int defer_load_check) | |
{ | |
VALUE tmp, load_path; | |
const char *f = StringValueCStr(path); | |
@@ -5820,7 +5820,9 @@ rb_find_file_safe(VALUE path, int safe_level) | |
if (safe_level >= 1 && !fpath_check(path)) { | |
rb_raise(rb_eSecurityError, "loading from unsafe path %s", f); | |
} | |
- if (!rb_file_load_ok(f)) return 0; | |
+ if (!defer_load_check && !rb_file_load_ok(f)) { | |
+ return 0; | |
+ } | |
if (!expanded) | |
path = copy_path_class(file_expand_path_1(path), path); | |
return path; | |
diff --git a/include/ruby/intern.h b/include/ruby/intern.h | |
index aec2d52..c7a952e 100644 | |
--- a/include/ruby/intern.h | |
+++ b/include/ruby/intern.h | |
@@ -478,7 +478,7 @@ VALUE rb_file_s_absolute_path(int, const VALUE *); | |
VALUE rb_file_absolute_path(VALUE, VALUE); | |
VALUE rb_file_dirname(VALUE fname); | |
int rb_find_file_ext_safe(VALUE*, const char* const*, int); | |
-VALUE rb_find_file_safe(VALUE, int); | |
+VALUE rb_find_file_safe(VALUE, int, int); | |
int rb_find_file_ext(VALUE*, const char* const*); | |
VALUE rb_find_file(VALUE); | |
VALUE rb_file_directory_p(VALUE,VALUE); | |
diff --git a/load.c b/load.c | |
index 70c7345..a65446a 100644 | |
--- a/load.c | |
+++ b/load.c | |
@@ -859,7 +859,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level) | |
if (loading) *path = rb_filesystem_str_new_cstr(loading); | |
return 'r'; | |
} | |
- if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) { | |
+ if ((tmp = rb_find_file_safe(fname, safe_level, 1)) != 0) { | |
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); | |
if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading) | |
*path = tmp; | |
@@ -884,7 +884,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level) | |
#else | |
rb_str_cat2(tmp, DLEXT); | |
OBJ_FREEZE(tmp); | |
- if ((tmp = rb_find_file_safe(tmp, safe_level)) != 0) { | |
+ if ((tmp = rb_find_file_safe(tmp, safe_level, 0)) != 0) { | |
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); | |
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading) | |
*path = tmp; | |
@@ -897,7 +897,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level) | |
if (loading) *path = rb_filesystem_str_new_cstr(loading); | |
return 's'; | |
} | |
- if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) { | |
+ if ((tmp = rb_find_file_safe(fname, safe_level, 0)) != 0) { | |
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); | |
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading) | |
*path = tmp; | |
diff --git a/ruby.c b/ruby.c | |
index c780937..317797b 100644 | |
--- a/ruby.c | |
+++ b/ruby.c | |
@@ -1762,17 +1762,17 @@ load_file_internal(VALUE argp_v) | |
} | |
static VALUE | |
-open_load_file(VALUE fname_v, int *xflag) | |
+open_load_file(VALUE fname_v, int *xflag, int script) | |
{ | |
const char *fname = StringValueCStr(fname_v); | |
VALUE f; | |
- int e; | |
+ int e = 0; | |
+ int fd = 0; | |
if (RSTRING_LEN(fname_v) == 1 && fname[0] == '-') { | |
f = rb_stdin; | |
} | |
else { | |
- int fd; | |
/* open(2) may block if fname is point to FIFO and it's empty. Let's | |
use O_NONBLOCK. */ | |
#if defined O_NONBLOCK && HAVE_FCNTL && !(O_NONBLOCK & O_ACCMODE) | |
@@ -1795,7 +1795,8 @@ open_load_file(VALUE fname_v, int *xflag) | |
#endif | |
if ((fd = rb_cloexec_open(fname, mode, 0)) < 0) { | |
- rb_load_fail(fname_v, strerror(errno)); | |
+ e = errno; | |
+ goto fail; | |
} | |
rb_update_max_fd(fd); | |
@@ -1803,8 +1804,7 @@ open_load_file(VALUE fname_v, int *xflag) | |
/* disabling O_NONBLOCK */ | |
if (fcntl(fd, F_SETFL, 0) < 0) { | |
e = errno; | |
- (void)close(fd); | |
- rb_load_fail(fname_v, strerror(e)); | |
+ goto fail; | |
} | |
#endif | |
@@ -1813,8 +1813,7 @@ open_load_file(VALUE fname_v, int *xflag) | |
struct stat st; | |
if (fstat(fd, &st) != 0) { | |
e = errno; | |
- (void)close(fd); | |
- rb_load_fail(fname_v, strerror(e)); | |
+ goto fail; | |
} | |
if (S_ISFIFO(st.st_mode)) { | |
/* | |
@@ -1822,18 +1821,36 @@ open_load_file(VALUE fname_v, int *xflag) | |
rb_thread_wait_fd() release GVL. So, it's safe. | |
*/ | |
rb_thread_wait_fd(fd); | |
+ } else if (S_ISDIR(st.st_mode)) { | |
+ e = EISDIR; | |
+ goto fail; | |
+ } else if (!S_ISREG(st.st_mode)) { | |
+ e = ENXIO; | |
+ goto fail; | |
} | |
} | |
-#endif | |
+#else | |
+ /* Note that we've replicated ruby_is_fd_loadable in S_ISFIFO without | |
+ * calling fstat64 twice. */ | |
if (!ruby_is_fd_loadable(fd)) { | |
e = errno; | |
- (void)close(fd); | |
- rb_load_fail(fname_v, strerror(e)); | |
+ goto fail; | |
} | |
+#endif | |
f = rb_io_fdopen(fd, mode, fname); | |
} | |
return f; | |
+fail: | |
+ if (fd > 0) (void)close(fd); | |
+ if (script) { | |
+ /* when we reach this from `$ ruby bad.rb`, show the reason */ | |
+ rb_load_fail(fname_v, strerror(e)); | |
+ } else { | |
+ /* when called from require/load/etc., just show: | |
+ * "cannot load such file", same as `load_failed`. */ | |
+ rb_load_fail(fname_v, "cannot load such file"); | |
+ } | |
} | |
static VALUE | |
@@ -1874,7 +1891,7 @@ load_file(VALUE parser, VALUE fname, int script, struct cmdline_options *opt) | |
arg.opt = opt; | |
arg.xflag = 0; | |
arg.lineno = rb_gv_get("$."); | |
- arg.f = open_load_file(rb_str_encode_ospath(fname), &arg.xflag); | |
+ arg.f = open_load_file(rb_str_encode_ospath(fname), &arg.xflag, script); | |
return (NODE *)rb_ensure(load_file_internal, (VALUE)&arg, | |
restore_load_file, (VALUE)&arg); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment