summaryrefslogtreecommitdiff
path: root/dir.c
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2024-07-16 19:20:17 -0700
committerGitHub <noreply@github.com>2024-07-16 19:20:17 -0700
commitdabb6c49aa561ba8a222e8b9baf2cbf2e1a1608d (patch)
tree53f3cbf4e82d0350fd0033d8a469d309ce2d1d86 /dir.c
parentc083a3ffcd3b298784313c1617f2cf98f6fd27eb (diff)
Release GVL around {,f}getattrlist calls in dir.c
Fixes [Bug #20587]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/11176 Merged-By: jeremyevans <code@jeremyevans.net>
Diffstat (limited to 'dir.c')
-rw-r--r--dir.c88
1 files changed, 77 insertions, 11 deletions
diff --git a/dir.c b/dir.c
index 312d10100e..10ed7e62cd 100644
--- a/dir.c
+++ b/dir.c
@@ -143,6 +143,47 @@ char *strchr(char*,char);
# define IS_WIN32 0
#endif
+#ifdef HAVE_GETATTRLIST
+struct getattrlist_args {
+ const char *path;
+ int fd;
+ struct attrlist *list;
+ void *buf;
+ size_t size;
+ unsigned int options;
+};
+
+static void *
+nogvl_getattrlist(void *args)
+{
+ struct getattrlist_args *arg = args;
+ return (void *)(VALUE)getattrlist(arg->path, arg->list, arg->buf, arg->size, arg->options);
+}
+
+static int
+gvl_getattrlist(struct getattrlist_args *args, const char *path)
+{
+ args->path = path;
+ return IO_WITHOUT_GVL_INT(nogvl_getattrlist, args);
+}
+
+# ifdef HAVE_FGETATTRLIST
+static void *
+nogvl_fgetattrlist(void *args)
+{
+ struct getattrlist_args *arg = args;
+ return (void *)(VALUE)fgetattrlist(arg->fd, arg->list, arg->buf, arg->size, arg->options);
+}
+
+static int
+gvl_fgetattrlist(struct getattrlist_args *args, int fd)
+{
+ args->fd = fd;
+ return IO_WITHOUT_GVL_INT(nogvl_fgetattrlist, args);
+}
+# endif
+#endif
+
#if NORMALIZE_UTF8PATH
# if defined HAVE_FGETATTRLIST || !defined HAVE_GETATTRLIST
# define need_normalization(dirp, path) need_normalization(dirp)
@@ -155,10 +196,15 @@ need_normalization(DIR *dirp, const char *path)
# if defined HAVE_FGETATTRLIST || defined HAVE_GETATTRLIST
u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
+ struct getattrlist_args args;
+ args.list = &al;
+ args.buf = attrbuf;
+ args.size = sizeof(attrbuf);
+ args.options = 0;
# if defined HAVE_FGETATTRLIST
- int ret = fgetattrlist(dirfd(dirp), &al, attrbuf, sizeof(attrbuf), 0);
+ int ret = gvl_fgetattrlist(&args, dirfd(dirp));
# else
- int ret = getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0);
+ int ret = gvl_getattrlist(&args, path);
# endif
if (!ret) {
const fsobj_tag_t *tag = (void *)(attrbuf+1);
@@ -555,7 +601,12 @@ dir_initialize(rb_execution_context_t *ec, VALUE dir, VALUE dirname, VALUE enc)
else if (e == EIO) {
u_int32_t attrbuf[1];
struct attrlist al = {ATTR_BIT_MAP_COUNT, 0};
- if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW) == 0) {
+ struct getattrlist_args args;
+ args.list = &al;
+ args.buf = attrbuf;
+ args.size = sizeof(attrbuf);
+ args.options = FSOPT_NOFOLLOW;
+ if (gvl_getattrlist(&args, path) == 0) {
dp->dir = opendir_without_gvl(path);
}
}
@@ -2134,14 +2185,19 @@ is_case_sensitive(DIR *dirp, const char *path)
const vol_capabilities_attr_t *const cap = attrbuf[0].cap;
const int idx = VOL_CAPABILITIES_FORMAT;
const uint32_t mask = VOL_CAP_FMT_CASE_SENSITIVE;
-
+ struct getattrlist_args args;
+ args.list = &al;
+ args.buf = attrbuf;
+ args.size = sizeof(attrbuf);
+ args.options = FSOPT_NOFOLLOW;
# if defined HAVE_FGETATTRLIST
- if (fgetattrlist(dirfd(dirp), &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))
- return -1;
+ int ret = gvl_fgetattrlist(&args, dirfd(dirp));
# else
- if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))
- return -1;
+ int ret = gvl_getattrlist(&args, path);
# endif
+ if (ret)
+ return -1;
+
if (!(cap->valid[idx] & mask))
return -1;
return (cap->capabilities[idx] & mask) != 0;
@@ -2164,7 +2220,12 @@ replace_real_basename(char *path, long base, rb_encoding *enc, int norm_p, int f
IF_NORMALIZE_UTF8PATH(VALUE utf8str = Qnil);
*type = path_noent;
- if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW)) {
+ struct getattrlist_args args;
+ args.list = &al;
+ args.buf = attrbuf;
+ args.size = sizeof(attrbuf);
+ args.options = FSOPT_NOFOLLOW;
+ if (gvl_getattrlist(&args, path)) {
if (!to_be_ignored(errno))
sys_warning(path, enc);
return path;
@@ -3700,12 +3761,17 @@ rb_dir_s_empty_p(VALUE obj, VALUE dirname)
{
u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
- if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) != 0)
+ struct getattrlist_args args;
+ args.list = &al;
+ args.buf = attrbuf;
+ args.size = sizeof(attrbuf);
+ args.options = 0;
+ if (gvl_getattrlist(&args, path) != 0)
rb_sys_fail_path(orig);
if (*(const fsobj_tag_t *)(attrbuf+1) == VT_HFS) {
al.commonattr = 0;
al.dirattr = ATTR_DIR_ENTRYCOUNT;
- if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) == 0) {
+ if (gvl_getattrlist(&args, path) == 0) {
if (attrbuf[0] >= 2 * sizeof(u_int32_t))
return RBOOL(attrbuf[1] == 0);
if (false_on_notdir) return Qfalse;