18 #include <sys/types.h>
25 #if defined HAVE_DIRENT_H && !defined _WIN32
27 # define NAMLEN(dirent) strlen((dirent)->d_name)
28 #elif defined HAVE_DIRECT_H && !defined _WIN32
30 # define NAMLEN(dirent) strlen((dirent)->d_name)
32 # define dirent direct
33 # define NAMLEN(dirent) (dirent)->d_namlen
35 # include <sys/ndir.h>
47 #if defined(__native_client__) && defined(NACL_NEWLIB)
69 #define chdir(p) rb_w32_uchdir(p)
71 #define mkdir(p, m) rb_w32_umkdir((p), (m))
73 #define rmdir(p) rb_w32_urmdir(p)
75 #define opendir(p) rb_w32_uopendir(p)
84 #include <sys/param.h>
85 #include <sys/mount.h>
91 if (fstatfs(dirfd(dirp), &buf) == 0) {
92 return buf.f_type == 17;
98 has_nonascii(
const char *ptr,
size_t len)
108 # define IF_HAVE_HFS(something) something
110 # define IF_HAVE_HFS(something)
113 #define FNM_NOESCAPE 0x01
114 #define FNM_PATHNAME 0x02
115 #define FNM_DOTMATCH 0x04
116 #define FNM_CASEFOLD 0x08
117 #define FNM_EXTGLOB 0x10
118 #if CASEFOLD_FILESYSTEM
119 #define FNM_SYSCASE FNM_CASEFOLD
121 #define FNM_SYSCASE 0
124 #define FNM_NOMATCH 1
127 # define Next(p, e, enc) ((p)+ rb_enc_mbclen((p), (e), (enc)))
128 # define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
145 if (p >= pend)
return NULL;
146 if (*p ==
'!' || *p ==
'^') {
153 if (escape && *t1 ==
'\\')
158 if (p >= pend)
return NULL;
159 if (p[0] ==
'-' && p[1] !=
']') {
160 const char *t2 = p + 1;
162 if (escape && *t2 ==
'\\')
168 if ((r <= (send-s) &&
memcmp(t1, s, r) == 0) ||
169 (r2 <= (send-s) &&
memcmp(t2, s, r2) == 0)) {
177 if (c1 < c2)
continue;
180 if (c1 > c2)
continue;
184 if (r <= (send-s) &&
memcmp(t1, s, r) == 0) {
188 if (!nocase)
continue;
191 if (c1 != c2)
continue;
196 return ok == not ?
NULL : (
char *)p + 1;
204 #define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p))
205 #define ISEND(p) (!*(p) || (pathname && *(p) == '/'))
206 #define RETURN(val) return *pcur = p, *scur = s, (val);
220 const char *ptmp = 0;
221 const char *stmp = 0;
223 const char *p = *pcur;
224 const char *pend = p +
strlen(p);
225 const char *s = *scur;
226 const char *send = s +
strlen(s);
230 if (period && *s ==
'.' && *
UNESCAPE(p) !=
'.')
236 do { p++; }
while (*p ==
'*');
258 if ((t =
bracket(p + 1, pend, s, send, flags, enc)) != 0) {
276 if (r <= (send-s) &&
memcmp(p, s, r) == 0) {
281 if (!nocase)
goto failed;
292 Inc(stmp, send, enc);
307 const char *p = pattern;
308 const char *s = string;
309 const char *send = s +
strlen(
string);
313 const char *ptmp = 0;
314 const char *stmp = 0;
318 if (p[0] ==
'*' && p[1] ==
'*' && p[2] ==
'/') {
319 do { p += 3; }
while (p[0] ==
'*' && p[1] ==
'*' && p[2] ==
'/');
324 while (*s && *s !=
'/')
Inc(s, send, enc);
334 if (ptmp && stmp && !(period && *stmp ==
'.')) {
335 while (*stmp && *stmp !=
'/')
Inc(stmp, send, enc);
378 return ptr ?
sizeof(
struct dir_data) : 0;
389 #define GlobPathValue(str, safe) \
391 (!RB_TYPE_P((str), T_STRING) ? \
392 (void)FilePathValue(str) : \
393 (void)(check_safe_glob((str), (safe)), \
394 check_glob_encoding(str), (str)))
395 #define check_safe_glob(str, safe) ((safe) ? rb_check_safe_obj(str) : (void)0)
396 #define check_glob_encoding(str) rb_enc_check((str), rb_enc_from_encoding(rb_usascii_encoding()))
426 VALUE dirname, opt, orig;
427 static ID keyword_ids[1];
429 if (!keyword_ids[0]) {
516 #define GetDIR(obj, dirp) ((dirp) = dir_check(obj))
563 # define READDIR(dir, enc) rb_w32_readdir((dir), (enc))
565 # define READDIR(dir, enc) readdir((dir))
629 const char *
name = dp->d_name;
630 size_t namlen =
NAMLEN(dp);
633 if (hfs_p && has_nonascii(name, namlen) &&
634 !
NIL_P(path = rb_str_normalize_ospath(name, namlen))) {
671 #define dir_tell rb_f_notimplement
700 #define dir_seek rb_f_notimplement
725 #define dir_set_pos rb_f_notimplement
792 if (chdir_thread ==
Qnil)
802 if (chdir_blocking == 0)
859 const char *dist =
getenv(
"HOME");
867 if (chdir_blocking > 0) {
869 rb_warn(
"conflicting chdir during another chdir block");
930 if (pend - path < len) {
936 #if defined(HAVE_CHROOT)
956 #define dir_s_chroot rb_f_notimplement
980 if (
rb_scan_args(argc, argv,
"11", &path, &vmode) == 2) {
1020 #define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1))
1021 #define sys_warning(val) \
1022 (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0))
1024 #define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
1025 #define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n)))
1026 #define GLOB_FREE(ptr) free(ptr)
1027 #define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
1033 #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
1036 #define STAT(p, s) rb_w32_ustati64((p), (s))
1038 #define STAT(p, s) stat((p), (s))
1046 int ret =
STAT(path, pst);
1053 #if defined HAVE_LSTAT || defined lstat
1055 do_lstat(
const char *path,
struct stat *pst,
int flags)
1057 int ret =
lstat(path, pst);
1064 #define do_lstat do_stat
1097 while (p < pend && (c = *p++) != 0) {
1105 if (escape && !(c = *p++))
1114 p =
Next(p-1, pend, enc);
1129 while ((c = *p++) != 0) {
1144 if (escape && !(c = *p++))
1149 p =
Next(p-1, pend, enc);
1199 while (p < e && *p) {
1201 if (!tmp)
goto error;
1202 if (p[0] ==
'*' && p[1] ==
'*' && p[2] ==
'/') {
1204 do { p += 3;
while (*p ==
'/') p++; }
while (p[0] ==
'*' && p[1] ==
'*' && p[2] ==
'/');
1212 int magic =
has_magic(p, m, flags, enc);
1215 if (!magic && !recursive && *m) {
1227 memcpy(buf, p, m-p);
1272 join_path(
const char *path,
long len,
int dirsep,
const char *
name,
size_t namlen)
1277 memcpy(buf, path, len);
1281 memcpy(buf+len, name, namlen);
1282 buf[len+namlen] =
'\0';
1289 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1294 # define S_ISLNK(m) (0)
1296 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1316 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc))
1334 int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
1338 for (cur = beg; cur < end; ++cur) {
1358 rb_bug(
"continuous RECURSIVEs");
1364 if (match_all && exist ==
UNKNOWN) {
1365 if (
do_lstat(path, &st, flags) == 0) {
1374 if (match_dir && isdir ==
UNKNOWN) {
1375 if (
do_stat(path, &st, flags) == 0) {
1384 if (match_all && exist ==
YES) {
1386 if (status)
return status;
1388 if (match_dir && isdir ==
YES) {
1389 char *tmp =
join_path(path, pathlen, dirsep,
"", 0);
1390 if (!tmp)
return -1;
1393 if (status)
return status;
1397 if (exist ==
NO || isdir ==
NO)
return 0;
1399 if (magical || recursive) {
1403 dirp =
do_opendir(*path ? path :
".", flags, enc);
1404 if (dirp ==
NULL)
return 0;
1415 if (recursive && dp->d_name[0] ==
'.') {
1417 if (!dp->d_name[1]) {
1422 else if (dp->d_name[1] ==
'.' && !dp->d_name[2]) {
1431 if (hfs_p && has_nonascii(name, namlen)) {
1432 if (!
NIL_P(utf8str = rb_str_normalize_ospath(name, namlen))) {
1437 buf =
join_path(path, pathlen, dirsep, name, namlen);
1443 name = buf + pathlen + (dirsep != 0);
1444 if (recursive && dotfile < ((flags &
FNM_DOTMATCH) ? 2 : 1)) {
1447 if (
do_lstat(buf, &st, flags) == 0)
1452 new_isdir = dp->d_isdir ? (!dp->d_isrep ?
YES :
UNKNOWN) :
NO;
1463 for (cur = beg; cur < end; ++cur) {
1466 if (new_isdir ==
YES)
1472 *new_end++ = p->
next;
1477 flags, func, arg, enc);
1489 if (!copy_beg)
return -1;
1490 for (cur = beg; cur < end; ++cur)
1491 *copy_end++ = (*cur)->
type ==
PLAIN ? *cur : 0;
1493 for (cur = copy_beg; cur < copy_end; ++cur) {
1497 size_t len =
strlen((*cur)->str) + 1;
1503 memcpy(name, (*cur)->str, len);
1513 *new_end++ = (*cur)->
next;
1514 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
1515 if (*cur2 &&
fnmatch((*cur2)->str, enc, name, flags) == 0) {
1516 *new_end++ = (*cur2)->
next;
1521 buf =
join_path(path, pathlen, dirsep, name, len);
1529 new_end, flags, func, arg, enc);
1546 const char *root, *start;
1551 start = root = path;
1557 if (root && *root ==
'/') root++;
1561 if (!buf)
return -1;
1562 MEMCPY(buf, start,
char, n);
1607 rb_warning(
"Dir.glob() ignores File::FNM_CASEFOLD");
1632 const char *p = str;
1633 const char *pend = p +
strlen(p);
1635 const char *lbrace = 0, *rbrace = 0;
1636 int nest = 0, status = 0;
1639 if (*p ==
'{' && nest++ == 0) {
1642 if (*p ==
'}' && --nest <= 0) {
1646 if (*p ==
'\\' && escape) {
1652 if (lbrace && rbrace) {
1653 size_t len =
strlen(s) + 1;
1657 if (!buf)
return -1;
1658 memcpy(buf, s, lbrace-s);
1661 while (p < rbrace) {
1662 const char *t = ++p;
1664 while (p < rbrace && !(*p ==
',' && nest == 0)) {
1665 if (*p ==
'{') nest++;
1666 if (*p ==
'}') nest--;
1667 if (*p ==
'\\' && escape) {
1668 if (++p == rbrace)
break;
1672 memcpy(buf+shift, t, p-t);
1673 strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
1679 else if (!lbrace && !rbrace) {
1680 status = (*func)(s,
arg,
enc);
1760 while (p < pend && !*p)
1774 for (i = 0; i <
argc; ++i) {
1776 VALUE str = argv[i];
1882 VALUE str, rflags, ary;
1885 if (
rb_scan_args(argc, argv,
"11", &str, &rflags) == 2)
1895 volatile VALUE v = ary;
1981 if (enc_pattern != enc_path) {
1988 long len =
strlen(pattern);
1990 enc_pattern, &cr) != len)
2095 VALUE pattern, path;
2099 if (
rb_scan_args(argc, argv,
"21", &pattern, &path, &rflags) == 3)
2142 user = (argc > 0) ? argv[0] :
Qnil;
2174 rb_warning(
"Dir.exists? is a deprecated name, use Dir.exist? instead");