From 6b18457d1505f0a432b3d9c1dbd20a4687b46978 Mon Sep 17 00:00:00 2001 From: nobu Date: Mon, 27 Mar 2017 14:57:08 +0000 Subject: 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 --- dir.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 19 deletions(-) (limited to 'dir.c') diff --git a/dir.c b/dir.c index 9fc559756d..e3099f4973 100644 --- a/dir.c +++ b/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 -- cgit v1.2.3