dir.c: err at glob failure
* dir.c (glob_helper): raise a SystemCallError exception when opendir() failed, except for ENOENT, ENOTDIR, and EACCES. this behavior predates 1.0; the comments in glob.c claimed that glob() returned -1 on error but actualy the pointer to a global variable, then dir_glob() did check only -1 as the comments, and ignored actual errors. [ruby-core:80226] [Bug #13276] dir.c: ruby_glob_funcs_t git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58156 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
0d40bf8ffe
commit
4756365503
119
dir.c
119
dir.c
@ -1247,6 +1247,12 @@ to_be_ignored(int e)
|
||||
#define STAT(p, s) stat((p), (s))
|
||||
#endif
|
||||
|
||||
typedef int ruby_glob_errfunc(const char*, VALUE, const void*, int);
|
||||
typedef struct {
|
||||
ruby_glob_func *match;
|
||||
ruby_glob_errfunc *error;
|
||||
} ruby_glob_funcs_t;
|
||||
|
||||
/* System call with warning */
|
||||
static int
|
||||
do_stat(const char *path, struct stat *pst, int flags, rb_encoding *enc)
|
||||
@ -1273,7 +1279,8 @@ do_lstat(const char *path, struct stat *pst, int flags, rb_encoding *enc)
|
||||
#endif
|
||||
|
||||
static DIR *
|
||||
do_opendir(const char *path, int flags, rb_encoding *enc)
|
||||
do_opendir(const char *path, int flags, rb_encoding *enc,
|
||||
ruby_glob_errfunc *errfunc, VALUE arg, int *status)
|
||||
{
|
||||
DIR *dirp;
|
||||
#ifdef _WIN32
|
||||
@ -1294,7 +1301,12 @@ do_opendir(const char *path, int flags, rb_encoding *enc)
|
||||
e = errno;
|
||||
/* fallback */
|
||||
case 0:
|
||||
*status = 0;
|
||||
if (to_be_ignored(e)) break;
|
||||
if (errfunc) {
|
||||
*status = (*errfunc)(path, arg, enc, e);
|
||||
break;
|
||||
}
|
||||
sys_warning(path, enc);
|
||||
}
|
||||
}
|
||||
@ -1704,6 +1716,61 @@ glob_func_caller(VALUE val)
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
struct glob_error_args {
|
||||
const char *path;
|
||||
rb_encoding *enc;
|
||||
int error;
|
||||
};
|
||||
|
||||
static VALUE
|
||||
glob_func_warning(VALUE val)
|
||||
{
|
||||
struct glob_error_args *arg = (struct glob_error_args *)val;
|
||||
rb_syserr_enc_warning(arg->error, arg->enc, "%s", arg->path);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
rb_glob_warning(const char *path, VALUE a, const void *enc, int error)
|
||||
{
|
||||
int status;
|
||||
struct glob_error_args args;
|
||||
|
||||
args.path = path;
|
||||
args.enc = enc;
|
||||
args.error = error;
|
||||
rb_protect(glob_func_warning, (VALUE)&args, &status);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
glob_func_error(VALUE val)
|
||||
{
|
||||
struct glob_error_args *arg = (struct glob_error_args *)val;
|
||||
VALUE path = rb_enc_str_new_cstr(arg->path, arg->enc);
|
||||
rb_syserr_fail_str(arg->error, path);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static int
|
||||
rb_glob_error(const char *path, VALUE a, const void *enc, int error)
|
||||
{
|
||||
int status;
|
||||
struct glob_error_args args;
|
||||
VALUE (*errfunc)(VALUE) = glob_func_error;
|
||||
|
||||
if (error == EACCES) {
|
||||
errfunc = glob_func_warning;
|
||||
}
|
||||
args.path = path;
|
||||
args.enc = enc;
|
||||
args.error = error;
|
||||
rb_protect(errfunc, (VALUE)&args, &status);
|
||||
return status;
|
||||
}
|
||||
|
||||
static inline int
|
||||
dirent_match(const char *pat, rb_encoding *enc, const char *name, const struct dirent *dp, int flags)
|
||||
{
|
||||
@ -1725,7 +1792,7 @@ glob_helper(
|
||||
struct glob_pattern **beg,
|
||||
struct glob_pattern **end,
|
||||
int flags,
|
||||
ruby_glob_func *func,
|
||||
const ruby_glob_funcs_t *funcs,
|
||||
VALUE arg,
|
||||
rb_encoding *enc)
|
||||
{
|
||||
@ -1784,13 +1851,13 @@ glob_helper(
|
||||
}
|
||||
}
|
||||
if (match_all && pathtype > path_noent) {
|
||||
status = glob_call_func(func, path, arg, enc);
|
||||
status = glob_call_func(funcs->match, path, arg, enc);
|
||||
if (status) return status;
|
||||
}
|
||||
if (match_dir && pathtype == path_directory) {
|
||||
char *tmp = join_path(path, pathlen, dirsep, "", 0);
|
||||
if (!tmp) return -1;
|
||||
status = glob_call_func(func, tmp, arg, enc);
|
||||
status = glob_call_func(funcs->match, tmp, arg, enc);
|
||||
GLOB_FREE(tmp);
|
||||
if (status) return status;
|
||||
}
|
||||
@ -1809,12 +1876,14 @@ glob_helper(
|
||||
if (cur + 1 == end && (*cur)->type <= ALPHA) {
|
||||
plainname = join_path(path, pathlen, dirsep, (*cur)->str, strlen((*cur)->str));
|
||||
if (!plainname) return -1;
|
||||
dirp = do_opendir(plainname, flags, enc);
|
||||
dirp = do_opendir(plainname, flags, enc, funcs->error, arg, &status);
|
||||
GLOB_FREE(plainname);
|
||||
}
|
||||
else
|
||||
# else
|
||||
;
|
||||
# endif
|
||||
dirp = do_opendir(*path ? path : ".", flags, enc);
|
||||
dirp = do_opendir(*path ? path : ".", flags, enc, funcs->error, arg, &status);
|
||||
if (dirp == NULL) {
|
||||
# if FNM_SYSCASE || NORMALIZE_UTF8PATH
|
||||
if ((magical < 2) && !recursive && (errno == EACCES)) {
|
||||
@ -1822,7 +1891,7 @@ glob_helper(
|
||||
goto literally;
|
||||
}
|
||||
# endif
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
IF_NORMALIZE_UTF8PATH(norm_p = need_normalization(dirp, *path ? path : "."));
|
||||
|
||||
@ -1922,7 +1991,7 @@ glob_helper(
|
||||
|
||||
status = glob_helper(buf, name - buf + namlen, 1,
|
||||
new_pathtype, new_beg, new_end,
|
||||
flags, func, arg, enc);
|
||||
flags, funcs, arg, enc);
|
||||
GLOB_FREE(buf);
|
||||
GLOB_FREE(new_beg);
|
||||
if (status) break;
|
||||
@ -1982,11 +2051,12 @@ glob_helper(
|
||||
long base = pathlen + (dirsep != 0);
|
||||
buf = replace_real_basename(buf, base, enc, IF_NORMALIZE_UTF8PATH(1)+0,
|
||||
flags, &new_pathtype);
|
||||
if (!buf) break;
|
||||
}
|
||||
#endif
|
||||
status = glob_helper(buf, pathlen + strlen(buf + pathlen), 1,
|
||||
new_pathtype, new_beg, new_end,
|
||||
flags, func, arg, enc);
|
||||
flags, funcs, arg, enc);
|
||||
GLOB_FREE(buf);
|
||||
GLOB_FREE(new_beg);
|
||||
if (status) break;
|
||||
@ -2000,7 +2070,9 @@ glob_helper(
|
||||
}
|
||||
|
||||
static int
|
||||
ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
|
||||
ruby_glob0(const char *path, int flags,
|
||||
const ruby_glob_funcs_t *funcs, VALUE arg,
|
||||
rb_encoding *enc)
|
||||
{
|
||||
struct glob_pattern *list;
|
||||
const char *root, *start;
|
||||
@ -2028,7 +2100,7 @@ ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_enco
|
||||
return -1;
|
||||
}
|
||||
status = glob_helper(buf, n, 0, path_unknown, &list, &list + 1,
|
||||
flags, func, arg, enc);
|
||||
flags, funcs, arg, enc);
|
||||
glob_free_pattern(list);
|
||||
GLOB_FREE(buf);
|
||||
|
||||
@ -2038,8 +2110,11 @@ ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_enco
|
||||
int
|
||||
ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
|
||||
{
|
||||
return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
|
||||
rb_ascii8bit_encoding());
|
||||
ruby_glob_funcs_t funcs;
|
||||
funcs.match = func;
|
||||
funcs.error = NULL;
|
||||
return ruby_glob0(path, flags & ~GLOB_VERBOSE,
|
||||
&funcs, arg, rb_ascii8bit_encoding());
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2053,6 +2128,10 @@ rb_glob_caller(const char *path, VALUE a, void *enc)
|
||||
return status;
|
||||
}
|
||||
|
||||
static const ruby_glob_funcs_t rb_glob_funcs = {
|
||||
rb_glob_caller, rb_glob_error,
|
||||
};
|
||||
|
||||
void
|
||||
rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
|
||||
{
|
||||
@ -2063,8 +2142,8 @@ rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
|
||||
args.value = arg;
|
||||
args.enc = rb_ascii8bit_encoding();
|
||||
|
||||
status = ruby_glob0(path, GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
|
||||
args.enc);
|
||||
status = ruby_glob0(path, GLOB_VERBOSE, &rb_glob_funcs,
|
||||
(VALUE)&args, args.enc);
|
||||
if (status) GLOB_JUMP_TAG(status);
|
||||
}
|
||||
|
||||
@ -2142,7 +2221,7 @@ ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
|
||||
}
|
||||
|
||||
struct brace_args {
|
||||
ruby_glob_func *func;
|
||||
ruby_glob_funcs_t funcs;
|
||||
VALUE value;
|
||||
int flags;
|
||||
};
|
||||
@ -2152,7 +2231,7 @@ glob_brace(const char *path, VALUE val, void *enc)
|
||||
{
|
||||
struct brace_args *arg = (struct brace_args *)val;
|
||||
|
||||
return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
|
||||
return ruby_glob0(path, arg->flags, &arg->funcs, arg->value, enc);
|
||||
}
|
||||
|
||||
int
|
||||
@ -2161,7 +2240,8 @@ ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE
|
||||
struct brace_args args;
|
||||
|
||||
flags &= ~GLOB_VERBOSE;
|
||||
args.func = func;
|
||||
args.funcs.match = func;
|
||||
args.funcs.error = NULL;
|
||||
args.value = arg;
|
||||
args.flags = flags;
|
||||
return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
|
||||
@ -2183,7 +2263,8 @@ push_caller(const char *path, VALUE val, void *enc)
|
||||
{
|
||||
struct push_glob_args *arg = (struct push_glob_args *)val;
|
||||
|
||||
return ruby_glob0(path, arg->flags, rb_glob_caller, (VALUE)&arg->glob, enc);
|
||||
return ruby_glob0(path, arg->flags, &rb_glob_funcs,
|
||||
(VALUE)&arg->glob, enc);
|
||||
}
|
||||
|
||||
static int
|
||||
|
2
error.c
2
error.c
@ -2470,7 +2470,6 @@ rb_sys_enc_warning(rb_encoding *enc, const char *fmt, ...)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt, ...)
|
||||
{
|
||||
@ -2480,7 +2479,6 @@ rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt, ...)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
rb_load_fail(VALUE path, const char *err)
|
||||
|
@ -184,6 +184,24 @@ class TestDir < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
if Process.const_defined?(:RLIMIT_NOFILE)
|
||||
def test_glob_too_may_open_files
|
||||
assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}", chdir: @root)
|
||||
begin;
|
||||
n = 16
|
||||
Process.setrlimit(Process::RLIMIT_NOFILE, n)
|
||||
files = []
|
||||
begin
|
||||
n.times {files << File.open('b')}
|
||||
rescue Errno::EMFILE, Errno::ENFILE => e
|
||||
end
|
||||
assert_raise(e.class) {
|
||||
Dir.glob('*')
|
||||
}
|
||||
end;
|
||||
end
|
||||
end
|
||||
|
||||
def assert_entries(entries)
|
||||
entries.sort!
|
||||
assert_equal(%w(. ..) + ("a".."z").to_a, entries)
|
||||
|
Loading…
x
Reference in New Issue
Block a user