summaryrefslogtreecommitdiff
path: root/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'dir.c')
-rw-r--r--dir.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/dir.c b/dir.c
index 36e7a5ed69..5386ff03f2 100644
--- a/dir.c
+++ b/dir.c
@@ -73,6 +73,16 @@ char *strchr(char*,char);
#define opendir(p) rb_w32_uopendir(p)
#endif
+#ifdef HAVE_SYS_ATTR_H
+#include <sys/attr.h>
+#endif
+
+#ifdef HAVE_GETATTRLIST
+# define USE_NAME_ON_FS 1
+#else
+# define USE_NAME_ON_FS 0
+#endif
+
#ifdef __APPLE__
# define HAVE_HFS 1
#else
@@ -1053,6 +1063,7 @@ sys_warning_1(VALUE mesg)
#define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
#define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n)))
+#define GLOB_REALLOC(ptr, size) realloc((ptr), (size))
#define GLOB_FREE(ptr) free(ptr)
#define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
@@ -1241,8 +1252,7 @@ glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
else {
const char *m = find_dirsep(p, e, flags, enc);
const enum glob_pattern_type magic = has_magic(p, m, flags, enc);
- const enum glob_pattern_type non_magic =
- ((HAVE_HFS || FNM_SYSCASE) && (m == e || (m+1 == e && *m == '/'))) ? PLAIN : ALPHA;
+ const enum glob_pattern_type non_magic = (USE_NAME_ON_FS || FNM_SYSCASE) ? PLAIN : ALPHA;
char *buf;
if (!(FNM_SYSCASE || magic > non_magic) && !recursive && *m) {
@@ -1316,6 +1326,45 @@ join_path(const char *path, long len, int dirsep, const char *name, size_t namle
return buf;
}
+#ifdef HAVE_GETATTRLIST
+static char *
+replace_real_basename(char *path, long base, int hfs_p)
+{
+ u_int32_t attrbuf[(sizeof(attrreference_t) + MAXPATHLEN * 3 + sizeof(u_int32_t) - 1) / sizeof(u_int32_t) + 1];
+ struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_NAME};
+ const attrreference_t *ar = (void *)(attrbuf+1);
+ const char *name;
+ long len;
+ char *tmp;
+ IF_HAVE_HFS(VALUE utf8str = Qnil);
+
+ if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))
+ return path;
+
+ name = (char *)ar + ar->attr_dataoffset;
+ len = (long)ar->attr_length - 1;
+ if (name + len > (char *)attrbuf + sizeof(attrbuf))
+ return path;
+
+# if HAVE_HFS
+ if (hfs_p && has_nonascii(name, len)) {
+ if (!NIL_P(utf8str = rb_str_normalize_ospath(name, len))) {
+ RSTRING_GETMEM(utf8str, name, len);
+ }
+ }
+# endif
+
+ tmp = GLOB_REALLOC(path, base + len + 1);
+ if (tmp) {
+ path = tmp;
+ memcpy(path + base, name, len);
+ path[base + len] = '\0';
+ }
+ IF_HAVE_HFS(if (!NIL_P(utf8str)) rb_str_resize(utf8str, 0));
+ return path;
+}
+#endif
+
enum answer {UNKNOWN = -1, NO, YES};
#ifndef S_ISDIR
@@ -1379,7 +1428,11 @@ glob_helper(
plain = 1;
break;
case ALPHA:
+#ifdef HAVE_GETATTRLIST
+ plain = 1;
+#else
magical = 1;
+#endif
break;
case MAGICAL:
magical = 2;
@@ -1602,6 +1655,12 @@ glob_helper(
status = -1;
break;
}
+#ifdef HAVE_GETATTRLIST
+ if ((*cur)->type == ALPHA) {
+ long base = pathlen + (dirsep != 0);
+ buf = replace_real_basename(buf, base, IF_HAVE_HFS(1)+0);
+ }
+#endif
status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
new_end, flags, func, arg, enc);
GLOB_FREE(buf);