Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

dir.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 dir.c -
4
5 $Author$
6 created at: Wed Jan 5 09:51:01 JST 1994
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12 **********************************************************************/
13
14 #include "ruby/encoding.h"
15 #include "ruby/thread.h"
16 #include "internal.h"
17 #include "id.h"
18 #include "encindex.h"
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26
27 #ifndef O_CLOEXEC
28 # define O_CLOEXEC 0
29 #endif
30
31 #ifndef USE_OPENDIR_AT
32 # if defined(HAVE_FDOPENDIR) && defined(HAVE_DIRFD) && \
33 defined(HAVE_OPENAT) && defined(HAVE_FSTATAT)
34 # define USE_OPENDIR_AT 1
35 # else
36 # define USE_OPENDIR_AT 0
37 # endif
38 #endif
39 #if USE_OPENDIR_AT
40 # include <fcntl.h>
41 #endif
42 #ifndef AT_FDCWD
43 # define AT_FDCWD -1
44 #endif
45
46 #undef HAVE_DIRENT_NAMLEN
47 #if defined HAVE_DIRENT_H && !defined _WIN32
48 # include <dirent.h>
49 # define NAMLEN(dirent) strlen((dirent)->d_name)
50 #elif defined HAVE_DIRECT_H && !defined _WIN32
51 # include <direct.h>
52 # define NAMLEN(dirent) strlen((dirent)->d_name)
53 #else
54 # define dirent direct
55 # define NAMLEN(dirent) (dirent)->d_namlen
56 # define HAVE_DIRENT_NAMLEN 1
57 # if HAVE_SYS_NDIR_H
58 # include <sys/ndir.h>
59 # endif
60 # if HAVE_SYS_DIR_H
61 # include <sys/dir.h>
62 # endif
63 # if HAVE_NDIR_H
64 # include <ndir.h>
65 # endif
66 # ifdef _WIN32
67 # include "win32/dir.h"
68 # endif
69 #endif
70
71 #include <errno.h>
72
73 #ifndef HAVE_STDLIB_H
74 char *getenv();
75 #endif
76
77 #ifndef HAVE_STRING_H
78 char *strchr(char*,char);
79 #endif
80
81 #include <ctype.h>
82
83 #include "ruby/util.h"
84
85 #define vm_initialized rb_cThread
86
87 /* define system APIs */
88 #ifdef _WIN32
89 #undef chdir
90 #define chdir(p) rb_w32_uchdir(p)
91 #undef mkdir
92 #define mkdir(p, m) rb_w32_umkdir((p), (m))
93 #undef rmdir
94 #define rmdir(p) rb_w32_urmdir(p)
95 #undef opendir
96 #define opendir(p) rb_w32_uopendir(p)
97 #define ruby_getcwd() rb_w32_ugetcwd(NULL, 0)
98 #define IS_WIN32 1
99 #else
100 #define IS_WIN32 0
101 #endif
102
103 #ifdef HAVE_SYS_ATTR_H
104 #include <sys/attr.h>
105 #endif
106
107 #define USE_NAME_ON_FS_REAL_BASENAME 1 /* platform dependent APIs to
108 * get real basenames */
109 #define USE_NAME_ON_FS_BY_FNMATCH 2 /* select the matching
110 * basename by fnmatch */
111
112 #ifdef HAVE_GETATTRLIST
113 # define USE_NAME_ON_FS USE_NAME_ON_FS_REAL_BASENAME
114 # define RUP32(size) ((size)+3/4)
115 # define SIZEUP32(type) RUP32(sizeof(type))
116 #elif defined _WIN32
117 # define USE_NAME_ON_FS USE_NAME_ON_FS_REAL_BASENAME
118 #elif defined DOSISH
119 # define USE_NAME_ON_FS USE_NAME_ON_FS_BY_FNMATCH
120 #else
121 # define USE_NAME_ON_FS 0
122 #endif
123
124 #ifdef __APPLE__
125 # define NORMALIZE_UTF8PATH 1
126 #else
127 # define NORMALIZE_UTF8PATH 0
128 #endif
129
130 #if NORMALIZE_UTF8PATH
131 #include <sys/param.h>
132 #include <sys/mount.h>
133 #include <sys/vnode.h>
134
135 # if defined HAVE_FGETATTRLIST || !defined HAVE_GETATTRLIST
136 # define need_normalization(dirp, path) need_normalization(dirp)
137 # else
138 # define need_normalization(dirp, path) need_normalization(path)
139 # endif
140 static inline int
141 need_normalization(DIR *dirp, const char *path)
142 {
143 # if defined HAVE_FGETATTRLIST || defined HAVE_GETATTRLIST
144 u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
145 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
146 # if defined HAVE_FGETATTRLIST
147 int ret = fgetattrlist(dirfd(dirp), &al, attrbuf, sizeof(attrbuf), 0);
148 # else
149 int ret = getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0);
150 # endif
151 if (!ret) {
152 const fsobj_tag_t *tag = (void *)(attrbuf+1);
153 switch (*tag) {
154 case VT_HFS:
155 case VT_CIFS:
156 return TRUE;
157 }
158 }
159 # endif
160 return FALSE;
161 }
162
163 static inline int
164 has_nonascii(const char *ptr, size_t len)
165 {
166 while (len > 0) {
167 if (!ISASCII(*ptr)) return 1;
168 ptr++;
169 --len;
170 }
171 return 0;
172 }
173
174 # define IF_NORMALIZE_UTF8PATH(something) something
175 #else
176 # define IF_NORMALIZE_UTF8PATH(something) /* nothing */
177 #endif
178
179 #ifndef IFTODT
180 # define IFTODT(m) (((m) & S_IFMT) / ((~S_IFMT & (S_IFMT-1)) + 1))
181 #endif
182
183 typedef enum {
184 #ifdef DT_UNKNOWN
185 path_exist = DT_UNKNOWN,
186 path_directory = DT_DIR,
187 path_regular = DT_REG,
188 path_symlink = DT_LNK,
189 #else
190 path_exist,
191 path_directory = IFTODT(S_IFDIR),
192 path_regular = IFTODT(S_IFREG),
193 path_symlink = IFTODT(S_IFLNK),
194 #endif
195 path_noent = -1,
196 path_unknown = -2
197 } rb_pathtype_t;
198
199 #define FNM_NOESCAPE 0x01
200 #define FNM_PATHNAME 0x02
201 #define FNM_DOTMATCH 0x04
202 #define FNM_CASEFOLD 0x08
203 #define FNM_EXTGLOB 0x10
204 #if CASEFOLD_FILESYSTEM
205 #define FNM_SYSCASE FNM_CASEFOLD
206 #else
207 #define FNM_SYSCASE 0
208 #endif
209 #if _WIN32
210 #define FNM_SHORTNAME 0x20
211 #else
212 #define FNM_SHORTNAME 0
213 #endif
214
215 #define FNM_NOMATCH 1
216 #define FNM_ERROR 2
217
218 # define Next(p, e, enc) ((p)+ rb_enc_mbclen((p), (e), (enc)))
219 # define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
220
221 static char *
222 bracket(
223 const char *p, /* pattern (next to '[') */
224 const char *pend,
225 const char *s, /* string */
226 const char *send,
227 int flags,
228 rb_encoding *enc)
229 {
230 const int nocase = flags & FNM_CASEFOLD;
231 const int escape = !(flags & FNM_NOESCAPE);
232 unsigned int c1, c2;
233 int r;
234 int ok = 0, not = 0;
235
236 if (p >= pend) return NULL;
237 if (*p == '!' || *p == '^') {
238 not = 1;
239 p++;
240 }
241
242 while (*p != ']') {
243 const char *t1 = p;
244 if (escape && *t1 == '\\')
245 t1++;
246 if (!*t1)
247 return NULL;
248 p = t1 + (r = rb_enc_mbclen(t1, pend, enc));
249 if (p >= pend) return NULL;
250 if (p[0] == '-' && p[1] != ']') {
251 const char *t2 = p + 1;
252 int r2;
253 if (escape && *t2 == '\\')
254 t2++;
255 if (!*t2)
256 return NULL;
257 p = t2 + (r2 = rb_enc_mbclen(t2, pend, enc));
258 if (ok) continue;
259 if ((r <= (send-s) && memcmp(t1, s, r) == 0) ||
260 (r2 <= (send-s) && memcmp(t2, s, r2) == 0)) {
261 ok = 1;
262 continue;
263 }
264 c1 = rb_enc_codepoint(s, send, enc);
265 if (nocase) c1 = rb_enc_toupper(c1, enc);
266 c2 = rb_enc_codepoint(t1, pend, enc);
267 if (nocase) c2 = rb_enc_toupper(c2, enc);
268 if (c1 < c2) continue;
269 c2 = rb_enc_codepoint(t2, pend, enc);
270 if (nocase) c2 = rb_enc_toupper(c2, enc);
271 if (c1 > c2) continue;
272 }
273 else {
274 if (ok) continue;
275 if (r <= (send-s) && memcmp(t1, s, r) == 0) {
276 ok = 1;
277 continue;
278 }
279 if (!nocase) continue;
280 c1 = rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc);
281 c2 = rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc);
282 if (c1 != c2) continue;
283 }
284 ok = 1;
285 }
286
287 return ok == not ? NULL : (char *)p + 1;
288 }
289
290 /* If FNM_PATHNAME is set, only path element will be matched. (up to '/' or '\0')
291 Otherwise, entire string will be matched.
292 End marker itself won't be compared.
293 And if function succeeds, *pcur reaches end marker.
294 */
295 #define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p))
296 #define ISEND(p) (!*(p) || (pathname && *(p) == '/'))
297 #define RETURN(val) return *pcur = p, *scur = s, (val);
298
299 static int
300 fnmatch_helper(
301 const char **pcur, /* pattern */
302 const char **scur, /* string */
303 int flags,
304 rb_encoding *enc)
305 {
306 const int period = !(flags & FNM_DOTMATCH);
307 const int pathname = flags & FNM_PATHNAME;
308 const int escape = !(flags & FNM_NOESCAPE);
309 const int nocase = flags & FNM_CASEFOLD;
310
311 const char *ptmp = 0;
312 const char *stmp = 0;
313
314 const char *p = *pcur;
315 const char *pend = p + strlen(p);
316 const char *s = *scur;
317 const char *send = s + strlen(s);
318
319 int r;
320
321 if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */
322 RETURN(FNM_NOMATCH);
323
324 while (1) {
325 switch (*p) {
326 case '*':
327 do { p++; } while (*p == '*');
328 if (ISEND(UNESCAPE(p))) {
329 p = UNESCAPE(p);
330 RETURN(0);
331 }
332 if (ISEND(s))
333 RETURN(FNM_NOMATCH);
334 ptmp = p;
335 stmp = s;
336 continue;
337
338 case '?':
339 if (ISEND(s))
340 RETURN(FNM_NOMATCH);
341 p++;
342 Inc(s, send, enc);
343 continue;
344
345 case '[': {
346 const char *t;
347 if (ISEND(s))
348 RETURN(FNM_NOMATCH);
349 if ((t = bracket(p + 1, pend, s, send, flags, enc)) != 0) {
350 p = t;
351 Inc(s, send, enc);
352 continue;
353 }
354 goto failed;
355 }
356 }
357
358 /* ordinary */
359 p = UNESCAPE(p);
360 if (ISEND(s))
361 RETURN(ISEND(p) ? 0 : FNM_NOMATCH);
362 if (ISEND(p))
363 goto failed;
364 r = rb_enc_precise_mbclen(p, pend, enc);
365 if (!MBCLEN_CHARFOUND_P(r))
366 goto failed;
367 if (r <= (send-s) && memcmp(p, s, r) == 0) {
368 p += r;
369 s += r;
370 continue;
371 }
372 if (!nocase) goto failed;
373 if (rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc) !=
374 rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc))
375 goto failed;
376 p += r;
377 Inc(s, send, enc);
378 continue;
379
380 failed: /* try next '*' position */
381 if (ptmp && stmp) {
382 p = ptmp;
383 Inc(stmp, send, enc); /* !ISEND(*stmp) */
384 s = stmp;
385 continue;
386 }
387 RETURN(FNM_NOMATCH);
388 }
389 }
390
391 static int
392 fnmatch(
393 const char *pattern,
394 rb_encoding *enc,
395 const char *string,
396 int flags)
397 {
398 const char *p = pattern;
399 const char *s = string;
400 const char *send = s + strlen(string);
401 const int period = !(flags & FNM_DOTMATCH);
402 const int pathname = flags & FNM_PATHNAME;
403
404 const char *ptmp = 0;
405 const char *stmp = 0;
406
407 if (pathname) {
408 while (1) {
409 if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
410 do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
411 ptmp = p;
412 stmp = s;
413 }
414 if (fnmatch_helper(&p, &s, flags, enc) == 0) {
415 while (*s && *s != '/') Inc(s, send, enc);
416 if (*p && *s) {
417 p++;
418 s++;
419 continue;
420 }
421 if (!*p && !*s)
422 return 0;
423 }
424 /* failed : try next recursion */
425 if (ptmp && stmp && !(period && *stmp == '.')) {
426 while (*stmp && *stmp != '/') Inc(stmp, send, enc);
427 if (*stmp) {
428 p = ptmp;
429 stmp++;
430 s = stmp;
431 continue;
432 }
433 }
434 return FNM_NOMATCH;
435 }
436 }
437 else
438 return fnmatch_helper(&p, &s, flags, enc);
439 }
440
441 VALUE rb_cDir;
442
443 struct dir_data {
444 DIR *dir;
445 const VALUE path;
446 rb_encoding *enc;
447 };
448
449 static void
450 dir_mark(void *ptr)
451 {
452 struct dir_data *dir = ptr;
453 rb_gc_mark(dir->path);
454 }
455
456 static void
457 dir_free(void *ptr)
458 {
459 struct dir_data *dir = ptr;
460
461 if (dir->dir) closedir(dir->dir);
462 xfree(dir);
463 }
464
465 static size_t
466 dir_memsize(const void *ptr)
467 {
468 return sizeof(struct dir_data);
469 }
470
471 static const rb_data_type_t dir_data_type = {
472 "dir",
473 {dir_mark, dir_free, dir_memsize,},
474 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
475 };
476
477 static VALUE dir_close(VALUE);
478
479 static VALUE
480 dir_s_alloc(VALUE klass)
481 {
482 struct dir_data *dirp;
483 VALUE obj = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dirp);
484
485 dirp->dir = NULL;
486 RB_OBJ_WRITE(obj, &dirp->path, Qnil);
487 dirp->enc = NULL;
488
489 return obj;
490 }
491
492 static void *
493 nogvl_opendir(void *ptr)
494 {
495 const char *path = ptr;
496
497 return (void *)opendir(path);
498 }
499
500 static DIR *
501 opendir_without_gvl(const char *path)
502 {
503 if (vm_initialized) {
504 union { const void *in; void *out; } u;
505
506 u.in = path;
507
508 return rb_thread_call_without_gvl(nogvl_opendir, u.out, RUBY_UBF_IO, 0);
509 }
510 else
511 return opendir(path);
512 }
513
514 /*
515 * call-seq:
516 * Dir.new( string ) -> aDir
517 * Dir.new( string, encoding: enc ) -> aDir
518 *
519 * Returns a new directory object for the named directory.
520 *
521 * The optional <i>encoding</i> keyword argument specifies the encoding of the directory.
522 * If not specified, the filesystem encoding is used.
523 */
524 static VALUE
525 dir_initialize(int argc, VALUE *argv, VALUE dir)
526 {
527 struct dir_data *dp;
528 rb_encoding *fsenc;
529 VALUE dirname, opt, orig;
530 static ID keyword_ids[1];
531 const char *path;
532
533 if (!keyword_ids[0]) {
534 keyword_ids[0] = rb_id_encoding();
535 }
536
537 fsenc = rb_filesystem_encoding();
538
539 rb_scan_args(argc, argv, "1:", &dirname, &opt);
540
541 if (!NIL_P(opt)) {
542 VALUE enc;
543 rb_get_kwargs(opt, keyword_ids, 0, 1, &enc);
544 if (enc != Qundef && !NIL_P(enc)) {
545 fsenc = rb_to_encoding(enc);
546 }
547 }
548
549 FilePathValue(dirname);
550 orig = rb_str_dup_frozen(dirname);
551 dirname = rb_str_encode_ospath(dirname);
552 dirname = rb_str_dup_frozen(dirname);
553
554 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dp);
555 if (dp->dir) closedir(dp->dir);
556 dp->dir = NULL;
557 RB_OBJ_WRITE(dir, &dp->path, Qnil);
558 dp->enc = fsenc;
559 path = RSTRING_PTR(dirname);
560 dp->dir = opendir_without_gvl(path);
561 if (dp->dir == NULL) {
562 int e = errno;
563 if (rb_gc_for_fd(e)) {
564 dp->dir = opendir_without_gvl(path);
565 }
566 #ifdef HAVE_GETATTRLIST
567 else if (e == EIO) {
568 u_int32_t attrbuf[1];
569 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0};
570 if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW) == 0) {
571 dp->dir = opendir_without_gvl(path);
572 }
573 }
574 #endif
575 if (dp->dir == NULL) {
576 RB_GC_GUARD(dirname);
577 rb_syserr_fail_path(e, orig);
578 }
579 }
580 RB_OBJ_WRITE(dir, &dp->path, orig);
581
582 return dir;
583 }
584
585 /*
586 * call-seq:
587 * Dir.open( string ) -> aDir
588 * Dir.open( string, encoding: enc ) -> aDir
589 * Dir.open( string ) {| aDir | block } -> anObject
590 * Dir.open( string, encoding: enc ) {| aDir | block } -> anObject
591 *
592 * The optional <i>encoding</i> keyword argument specifies the encoding of the directory.
593 * If not specified, the filesystem encoding is used.
594 *
595 * With no block, <code>open</code> is a synonym for Dir::new. If a
596 * block is present, it is passed <i>aDir</i> as a parameter. The
597 * directory is closed at the end of the block, and Dir::open returns
598 * the value of the block.
599 */
600 static VALUE
601 dir_s_open(int argc, VALUE *argv, VALUE klass)
602 {
603 struct dir_data *dp;
604 VALUE dir = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dp);
605
606 dir_initialize(argc, argv, dir);
607 if (rb_block_given_p()) {
608 return rb_ensure(rb_yield, dir, dir_close, dir);
609 }
610
611 return dir;
612 }
613
614 NORETURN(static void dir_closed(void));
615
616 static void
617 dir_closed(void)
618 {
619 rb_raise(rb_eIOError, "closed directory");
620 }
621
622 static struct dir_data *
623 dir_get(VALUE dir)
624 {
625 rb_check_frozen(dir);
626 return rb_check_typeddata(dir, &dir_data_type);
627 }
628
629 static struct dir_data *
630 dir_check(VALUE dir)
631 {
632 struct dir_data *dirp = dir_get(dir);
633 if (!dirp->dir) dir_closed();
634 return dirp;
635 }
636
637 #define GetDIR(obj, dirp) ((dirp) = dir_check(obj))
638
639
640 /*
641 * call-seq:
642 * dir.inspect -> string
643 *
644 * Return a string describing this Dir object.
645 */
646 static VALUE
647 dir_inspect(VALUE dir)
648 {
649 struct dir_data *dirp;
650
651 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
652 if (!NIL_P(dirp->path)) {
653 VALUE str = rb_str_new_cstr("#<");
654 rb_str_append(str, rb_class_name(CLASS_OF(dir)));
655 rb_str_cat2(str, ":");
656 rb_str_append(str, dirp->path);
657 rb_str_cat2(str, ">");
658 return str;
659 }
660 return rb_funcallv(dir, idTo_s, 0, 0);
661 }
662
663 /* Workaround for Solaris 10 that does not have dirfd.
664 Note: Solaris 11 (POSIX.1-2008 compliant) has dirfd(3C).
665 */
666 #if defined(__sun) && !defined(HAVE_DIRFD)
667 # if defined(HAVE_DIR_D_FD)
668 # define dirfd(x) ((x)->d_fd)
669 # define HAVE_DIRFD 1
670 # elif defined(HAVE_DIR_DD_FD)
671 # define dirfd(x) ((x)->dd_fd)
672 # define HAVE_DIRFD 1
673 # endif
674 #endif
675
676 #ifdef HAVE_DIRFD
677 /*
678 * call-seq:
679 * dir.fileno -> integer
680 *
681 * Returns the file descriptor used in <em>dir</em>.
682 *
683 * d = Dir.new("..")
684 * d.fileno #=> 8
685 *
686 * This method uses dirfd() function defined by POSIX 2008.
687 * NotImplementedError is raised on other platforms, such as Windows,
688 * which doesn't provide the function.
689 *
690 */
691 static VALUE
692 dir_fileno(VALUE dir)
693 {
694 struct dir_data *dirp;
695 int fd;
696
697 GetDIR(dir, dirp);
698 fd = dirfd(dirp->dir);
699 if (fd == -1)
700 rb_sys_fail("dirfd");
701 return INT2NUM(fd);
702 }
703 #else
704 #define dir_fileno rb_f_notimplement
705 #endif
706
707 /*
708 * call-seq:
709 * dir.path -> string or nil
710 * dir.to_path -> string or nil
711 *
712 * Returns the path parameter passed to <em>dir</em>'s constructor.
713 *
714 * d = Dir.new("..")
715 * d.path #=> ".."
716 */
717 static VALUE
718 dir_path(VALUE dir)
719 {
720 struct dir_data *dirp;
721
722 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
723 if (NIL_P(dirp->path)) return Qnil;
724 return rb_str_dup(dirp->path);
725 }
726
727 #if defined _WIN32
728 static int
729 fundamental_encoding_p(rb_encoding *enc)
730 {
731 switch (rb_enc_to_index(enc)) {
732 case ENCINDEX_ASCII:
733 case ENCINDEX_US_ASCII:
734 case ENCINDEX_UTF_8:
735 return TRUE;
736 default:
737 return FALSE;
738 }
739 }
740 # define READDIR(dir, enc) rb_w32_readdir((dir), (enc))
741 #else
742 # define READDIR(dir, enc) readdir((dir))
743 #endif
744
745 /* safe to use without GVL */
746 static int
747 to_be_skipped(const struct dirent *dp)
748 {
749 const char *name = dp->d_name;
750 if (name[0] != '.') return FALSE;
751 #ifdef HAVE_DIRENT_NAMLEN
752 switch (NAMLEN(dp)) {
753 case 2:
754 if (name[1] != '.') return FALSE;
755 case 1:
756 return TRUE;
757 default:
758 break;
759 }
760 #else
761 if (!name[1]) return TRUE;
762 if (name[1] != '.') return FALSE;
763 if (!name[2]) return TRUE;
764 #endif
765 return FALSE;
766 }
767
768 /*
769 * call-seq:
770 * dir.read -> string or nil
771 *
772 * Reads the next entry from <em>dir</em> and returns it as a string.
773 * Returns <code>nil</code> at the end of the stream.
774 *
775 * d = Dir.new("testdir")
776 * d.read #=> "."
777 * d.read #=> ".."
778 * d.read #=> "config.h"
779 */
780 static VALUE
781 dir_read(VALUE dir)
782 {
783 struct dir_data *dirp;
784 struct dirent *dp;
785
786 GetDIR(dir, dirp);
787 errno = 0;
788 if ((dp = READDIR(dirp->dir, dirp->enc)) != NULL) {
789 return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc);
790 }
791 else {
792 int e = errno;
793 if (e != 0) rb_syserr_fail(e, 0);
794 return Qnil; /* end of stream */
795 }
796 }
797
798 static VALUE dir_each_entry(VALUE, VALUE (*)(VALUE, VALUE), VALUE, int);
799
800 static VALUE
801 dir_yield(VALUE arg, VALUE path)
802 {
803 return rb_yield(path);
804 }
805
806 /*
807 * call-seq:
808 * dir.each { |filename| block } -> dir
809 * dir.each -> an_enumerator
810 *
811 * Calls the block once for each entry in this directory, passing the
812 * filename of each entry as a parameter to the block.
813 *
814 * If no block is given, an enumerator is returned instead.
815 *
816 * d = Dir.new("testdir")
817 * d.each {|x| puts "Got #{x}" }
818 *
819 * <em>produces:</em>
820 *
821 * Got .
822 * Got ..
823 * Got config.h
824 * Got main.rb
825 */
826 static VALUE
827 dir_each(VALUE dir)
828 {
829 RETURN_ENUMERATOR(dir, 0, 0);
830 return dir_each_entry(dir, dir_yield, Qnil, FALSE);
831 }
832
833 static VALUE
834 dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE), VALUE arg, int children_only)
835 {
836 struct dir_data *dirp;
837 struct dirent *dp;
838 IF_NORMALIZE_UTF8PATH(int norm_p);
839
840 GetDIR(dir, dirp);
841 rewinddir(dirp->dir);
842 IF_NORMALIZE_UTF8PATH(norm_p = need_normalization(dirp->dir, RSTRING_PTR(dirp->path)));
843 while ((dp = READDIR(dirp->dir, dirp->enc)) != NULL) {
844 const char *name = dp->d_name;
845 size_t namlen = NAMLEN(dp);
846 VALUE path;
847
848 if (children_only && name[0] == '.') {
849 if (namlen == 1) continue; /* current directory */
850 if (namlen == 2 && name[1] == '.') continue; /* parent directory */
851 }
852 #if NORMALIZE_UTF8PATH
853 if (norm_p && has_nonascii(name, namlen) &&
854 !NIL_P(path = rb_str_normalize_ospath(name, namlen))) {
855 path = rb_external_str_with_enc(path, dirp->enc);
856 }
857 else
858 #endif
859 path = rb_external_str_new_with_enc(name, namlen, dirp->enc);
860 (*each)(arg, path);
861 }
862 return dir;
863 }
864
865 #ifdef HAVE_TELLDIR
866 /*
867 * call-seq:
868 * dir.pos -> integer
869 * dir.tell -> integer
870 *
871 * Returns the current position in <em>dir</em>. See also Dir#seek.
872 *
873 * d = Dir.new("testdir")
874 * d.tell #=> 0
875 * d.read #=> "."
876 * d.tell #=> 12
877 */
878 static VALUE
879 dir_tell(VALUE dir)
880 {
881 struct dir_data *dirp;
882 long pos;
883
884 GetDIR(dir, dirp);
885 pos = telldir(dirp->dir);
886 return rb_int2inum(pos);
887 }
888 #else
889 #define dir_tell rb_f_notimplement
890 #endif
891
892 #ifdef HAVE_SEEKDIR
893 /*
894 * call-seq:
895 * dir.seek( integer ) -> dir
896 *
897 * Seeks to a particular location in <em>dir</em>. <i>integer</i>
898 * must be a value returned by Dir#tell.
899 *
900 * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
901 * d.read #=> "."
902 * i = d.tell #=> 12
903 * d.read #=> ".."
904 * d.seek(i) #=> #<Dir:0x401b3c40>
905 * d.read #=> ".."
906 */
907 static VALUE
908 dir_seek(VALUE dir, VALUE pos)
909 {
910 struct dir_data *dirp;
911 long p = NUM2LONG(pos);
912
913 GetDIR(dir, dirp);
914 seekdir(dirp->dir, p);
915 return dir;
916 }
917 #else
918 #define dir_seek rb_f_notimplement
919 #endif
920
921 #ifdef HAVE_SEEKDIR
922 /*
923 * call-seq:
924 * dir.pos = integer -> integer
925 *
926 * Synonym for Dir#seek, but returns the position parameter.
927 *
928 * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
929 * d.read #=> "."
930 * i = d.pos #=> 12
931 * d.read #=> ".."
932 * d.pos = i #=> 12
933 * d.read #=> ".."
934 */
935 static VALUE
936 dir_set_pos(VALUE dir, VALUE pos)
937 {
938 dir_seek(dir, pos);
939 return pos;
940 }
941 #else
942 #define dir_set_pos rb_f_notimplement
943 #endif
944
945 /*
946 * call-seq:
947 * dir.rewind -> dir
948 *
949 * Repositions <em>dir</em> to the first entry.
950 *
951 * d = Dir.new("testdir")
952 * d.read #=> "."
953 * d.rewind #=> #<Dir:0x401b3fb0>
954 * d.read #=> "."
955 */
956 static VALUE
957 dir_rewind(VALUE dir)
958 {
959 struct dir_data *dirp;
960
961 GetDIR(dir, dirp);
962 rewinddir(dirp->dir);
963 return dir;
964 }
965
966 /*
967 * call-seq:
968 * dir.close -> nil
969 *
970 * Closes the directory stream.
971 * Calling this method on closed Dir object is ignored since Ruby 2.3.
972 *
973 * d = Dir.new("testdir")
974 * d.close #=> nil
975 */
976 static VALUE
977 dir_close(VALUE dir)
978 {
979 struct dir_data *dirp;
980
981 dirp = dir_get(dir);
982 if (!dirp->dir) return Qnil;
983 closedir(dirp->dir);
984 dirp->dir = NULL;
985
986 return Qnil;
987 }
988
989 static void *
990 nogvl_chdir(void *ptr)
991 {
992 const char *path = ptr;
993
994 return (void *)(VALUE)chdir(path);
995 }
996
997 static void
998 dir_chdir(VALUE path)
999 {
1000 if (chdir(RSTRING_PTR(path)) < 0)
1001 rb_sys_fail_path(path);
1002 }
1003
1004 static int chdir_blocking = 0;
1005 static VALUE chdir_thread = Qnil;
1006
1007 struct chdir_data {
1008 VALUE old_path, new_path;
1009 int done;
1010 };
1011
1012 static VALUE
1013 chdir_yield(VALUE v)
1014 {
1015 struct chdir_data *args = (void *)v;
1016 dir_chdir(args->new_path);
1017 args->done = TRUE;
1018 chdir_blocking++;
1019 if (chdir_thread == Qnil)
1020 chdir_thread = rb_thread_current();
1021 return rb_yield(args->new_path);
1022 }
1023
1024 static VALUE
1025 chdir_restore(VALUE v)
1026 {
1027 struct chdir_data *args = (void *)v;
1028 if (args->done) {
1029 chdir_blocking--;
1030 if (chdir_blocking == 0)
1031 chdir_thread = Qnil;
1032 dir_chdir(args->old_path);
1033 }
1034 return Qnil;
1035 }
1036
1037 /*
1038 * call-seq:
1039 * Dir.chdir( [ string] ) -> 0
1040 * Dir.chdir( [ string] ) {| path | block } -> anObject
1041 *
1042 * Changes the current working directory of the process to the given
1043 * string. When called without an argument, changes the directory to
1044 * the value of the environment variable <code>HOME</code>, or
1045 * <code>LOGDIR</code>. SystemCallError (probably Errno::ENOENT) if
1046 * the target directory does not exist.
1047 *
1048 * If a block is given, it is passed the name of the new current
1049 * directory, and the block is executed with that as the current
1050 * directory. The original working directory is restored when the block
1051 * exits. The return value of <code>chdir</code> is the value of the
1052 * block. <code>chdir</code> blocks can be nested, but in a
1053 * multi-threaded program an error will be raised if a thread attempts
1054 * to open a <code>chdir</code> block while another thread has one
1055 * open.
1056 *
1057 * Dir.chdir("/var/spool/mail")
1058 * puts Dir.pwd
1059 * Dir.chdir("/tmp") do
1060 * puts Dir.pwd
1061 * Dir.chdir("/usr") do
1062 * puts Dir.pwd
1063 * end
1064 * puts Dir.pwd
1065 * end
1066 * puts Dir.pwd
1067 *
1068 * <em>produces:</em>
1069 *
1070 * /var/spool/mail
1071 * /tmp
1072 * /usr
1073 * /tmp
1074 * /var/spool/mail
1075 */
1076 static VALUE
1077 dir_s_chdir(int argc, VALUE *argv, VALUE obj)
1078 {
1079 VALUE path = Qnil;
1080
1081 if (rb_check_arity(argc, 0, 1) == 1) {
1082 path = rb_str_encode_ospath(rb_get_path(argv[0]));
1083 }
1084 else {
1085 const char *dist = getenv("HOME");
1086 if (!dist) {
1087 dist = getenv("LOGDIR");
1088 if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
1089 }
1090 path = rb_str_new2(dist);
1091 }
1092
1093 if (chdir_blocking > 0) {
1094 if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
1095 rb_warn("conflicting chdir during another chdir block");
1096 }
1097
1098 if (rb_block_given_p()) {
1099 struct chdir_data args;
1100
1101 args.old_path = rb_str_encode_ospath(rb_dir_getwd());
1102 args.new_path = path;
1103 args.done = FALSE;
1104 return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
1105 }
1106 else {
1107 char *p = RSTRING_PTR(path);
1108 int r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_chdir, p,
1109 RUBY_UBF_IO, 0);
1110 if (r < 0)
1111 rb_sys_fail_path(path);
1112 }
1113
1114 return INT2FIX(0);
1115 }
1116
1117 #ifndef _WIN32
1118 VALUE
1119 rb_dir_getwd_ospath(void)
1120 {
1121 char *path;
1122 VALUE cwd;
1123 VALUE path_guard;
1124
1125 #undef RUBY_UNTYPED_DATA_WARNING
1126 #define RUBY_UNTYPED_DATA_WARNING 0
1127 path_guard = Data_Wrap_Struct((VALUE)0, NULL, RUBY_DEFAULT_FREE, NULL);
1128 path = ruby_getcwd();
1129 DATA_PTR(path_guard) = path;
1130 #ifdef __APPLE__
1131 cwd = rb_str_normalize_ospath(path, strlen(path));
1132 #else
1133 cwd = rb_str_new2(path);
1134 #endif
1135 DATA_PTR(path_guard) = 0;
1136
1137 xfree(path);
1138 return cwd;
1139 }
1140 #endif
1141
1142 VALUE
1143 rb_dir_getwd(void)
1144 {
1145 rb_encoding *fs = rb_filesystem_encoding();
1146 int fsenc = rb_enc_to_index(fs);
1147 VALUE cwd = rb_dir_getwd_ospath();
1148
1149 switch (fsenc) {
1150 case ENCINDEX_US_ASCII:
1151 fsenc = ENCINDEX_ASCII;
1152 case ENCINDEX_ASCII:
1153 break;
1154 #if defined _WIN32 || defined __APPLE__
1155 default:
1156 return rb_str_conv_enc(cwd, NULL, fs);
1157 #endif
1158 }
1159 return rb_enc_associate_index(cwd, fsenc);
1160 }
1161
1162 /*
1163 * call-seq:
1164 * Dir.getwd -> string
1165 * Dir.pwd -> string
1166 *
1167 * Returns the path to the current working directory of this process as
1168 * a string.
1169 *
1170 * Dir.chdir("/tmp") #=> 0
1171 * Dir.getwd #=> "/tmp"
1172 * Dir.pwd #=> "/tmp"
1173 */
1174 static VALUE
1175 dir_s_getwd(VALUE dir)
1176 {
1177 return rb_dir_getwd();
1178 }
1179
1180 static VALUE
1181 check_dirname(VALUE dir)
1182 {
1183 VALUE d = dir;
1184 char *path, *pend;
1185 long len;
1186 rb_encoding *enc;
1187
1188 FilePathValue(d);
1189 enc = rb_enc_get(d);
1190 RSTRING_GETMEM(d, path, len);
1191 pend = path + len;
1192 pend = rb_enc_path_end(rb_enc_path_skip_prefix(path, pend, enc), pend, enc);
1193 if (pend - path < len) {
1194 d = rb_str_subseq(d, 0, pend - path);
1195 StringValueCStr(d);
1196 }
1197 return rb_str_encode_ospath(d);
1198 }
1199
1200 #if defined(HAVE_CHROOT)
1201 /*
1202 * call-seq:
1203 * Dir.chroot( string ) -> 0
1204 *
1205 * Changes this process's idea of the file system root. Only a
1206 * privileged process may make this call. Not available on all
1207 * platforms. On Unix systems, see <code>chroot(2)</code> for more
1208 * information.
1209 */
1210 static VALUE
1211 dir_s_chroot(VALUE dir, VALUE path)
1212 {
1213 path = check_dirname(path);
1214 if (chroot(RSTRING_PTR(path)) == -1)
1215 rb_sys_fail_path(path);
1216
1217 return INT2FIX(0);
1218 }
1219 #else
1220 #define dir_s_chroot rb_f_notimplement
1221 #endif
1222
1223 struct mkdir_arg {
1224 const char *path;
1225 mode_t mode;
1226 };
1227
1228 static void *
1229 nogvl_mkdir(void *ptr)
1230 {
1231 struct mkdir_arg *m = ptr;
1232
1233 return (void *)(VALUE)mkdir(m->path, m->mode);
1234 }
1235
1236 /*
1237 * call-seq:
1238 * Dir.mkdir( string [, integer] ) -> 0
1239 *
1240 * Makes a new directory named by <i>string</i>, with permissions
1241 * specified by the optional parameter <i>anInteger</i>. The
1242 * permissions may be modified by the value of File::umask, and are
1243 * ignored on NT. Raises a SystemCallError if the directory cannot be
1244 * created. See also the discussion of permissions in the class
1245 * documentation for File.
1246 *
1247 * Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0
1248 *
1249 */
1250 static VALUE
1251 dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
1252 {
1253 struct mkdir_arg m;
1254 VALUE path, vmode;
1255 int r;
1256
1257 if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
1258 m.mode = NUM2MODET(vmode);
1259 }
1260 else {
1261 m.mode = 0777;
1262 }
1263
1264 path = check_dirname(path);
1265 m.path = RSTRING_PTR(path);
1266 r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_mkdir, &m, RUBY_UBF_IO, 0);
1267 if (r < 0)
1268 rb_sys_fail_path(path);
1269
1270 return INT2FIX(0);
1271 }
1272
1273 static void *
1274 nogvl_rmdir(void *ptr)
1275 {
1276 const char *path = ptr;
1277
1278 return (void *)(VALUE)rmdir(path);
1279 }
1280
1281 /*
1282 * call-seq:
1283 * Dir.delete( string ) -> 0
1284 * Dir.rmdir( string ) -> 0
1285 * Dir.unlink( string ) -> 0
1286 *
1287 * Deletes the named directory. Raises a subclass of SystemCallError
1288 * if the directory isn't empty.
1289 */
1290 static VALUE
1291 dir_s_rmdir(VALUE obj, VALUE dir)
1292 {
1293 const char *p;
1294 int r;
1295
1296 dir = check_dirname(dir);
1297 p = RSTRING_PTR(dir);
1298 r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_rmdir, (void *)p, RUBY_UBF_IO, 0);
1299 if (r < 0)
1300 rb_sys_fail_path(dir);
1301
1302 return INT2FIX(0);
1303 }
1304
1305 struct warning_args {
1306 #ifdef RUBY_FUNCTION_NAME_STRING
1307 const char *func;
1308 #endif
1309 const char *mesg;
1310 rb_encoding *enc;
1311 };
1312
1313 #ifndef RUBY_FUNCTION_NAME_STRING
1314 #define sys_enc_warning_in(func, mesg, enc) sys_enc_warning(mesg, enc)
1315 #endif
1316
1317 static VALUE
1318 sys_warning_1(VALUE mesg)
1319 {
1320 const struct warning_args *arg = (struct warning_args *)mesg;
1321 #ifdef RUBY_FUNCTION_NAME_STRING
1322 rb_sys_enc_warning(arg->enc, "%s: %s", arg->func, arg->mesg);
1323 #else
1324 rb_sys_enc_warning(arg->enc, "%s", arg->mesg);
1325 #endif
1326 return Qnil;
1327 }
1328
1329 static void
1330 sys_enc_warning_in(const char *func, const char *mesg, rb_encoding *enc)
1331 {
1332 struct warning_args arg;
1333 #ifdef RUBY_FUNCTION_NAME_STRING
1334 arg.func = func;
1335 #endif
1336 arg.mesg = mesg;
1337 arg.enc = enc;
1338 rb_protect(sys_warning_1, (VALUE)&arg, 0);
1339 }
1340
1341 #define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1))
1342 #define sys_warning(val, enc) \
1343 ((flags & GLOB_VERBOSE) ? sys_enc_warning_in(RUBY_FUNCTION_NAME_STRING, (val), (enc)) :(void)0)
1344
1345 static inline void *
1346 glob_alloc_n(size_t x, size_t y)
1347 {
1348 size_t z;
1349 if (rb_mul_size_overflow(x, y, SSIZE_MAX, &z)) {
1350 rb_memerror(); /* or...? */
1351 }
1352 else {
1353 return malloc(z);
1354 }
1355 }
1356
1357 #define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
1358 #define GLOB_ALLOC_N(type, n) ((type *)glob_alloc_n(sizeof(type), n))
1359 #define GLOB_REALLOC(ptr, size) realloc((ptr), (size))
1360 #define GLOB_FREE(ptr) free(ptr)
1361 #define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
1362
1363 /*
1364 * ENOTDIR can be returned by stat(2) if a non-leaf element of the path
1365 * is not a directory.
1366 */
1367 ALWAYS_INLINE(static int to_be_ignored(int e));
1368 static inline int
1369 to_be_ignored(int e)
1370 {
1371 return e == ENOENT || e == ENOTDIR;
1372 }
1373
1374 #ifdef _WIN32
1375 #define STAT(p, s) rb_w32_ustati128((p), (s))
1376 #undef lstat
1377 #define lstat(p, s) rb_w32_ulstati128((p), (s))
1378 #else
1379 #define STAT(p, s) stat((p), (s))
1380 #endif
1381
1382 typedef int ruby_glob_errfunc(const char*, VALUE, const void*, int);
1383 typedef struct {
1384 ruby_glob_func *match;
1385 ruby_glob_errfunc *error;
1386 } ruby_glob_funcs_t;
1387
1388 static const char *
1389 at_subpath(int fd, size_t baselen, const char *path)
1390 {
1391 #if USE_OPENDIR_AT
1392 if (fd != (int)AT_FDCWD && baselen > 0) {
1393 path += baselen;
1394 if (*path == '/') ++path;
1395 }
1396 #endif
1397 return *path ? path : ".";
1398 }
1399
1400 /* System call with warning */
1401 static int
1402 do_stat(int fd, size_t baselen, const char *path, struct stat *pst, int flags, rb_encoding *enc)
1403 {
1404 #if USE_OPENDIR_AT
1405 int ret = fstatat(fd, at_subpath(fd, baselen, path), pst, 0);
1406 #else
1407 int ret = STAT(path, pst);
1408 #endif
1409 if (ret < 0 && !to_be_ignored(errno))
1410 sys_warning(path, enc);
1411
1412 return ret;
1413 }
1414
1415 #if defined HAVE_LSTAT || defined lstat || USE_OPENDIR_AT
1416 static int
1417 do_lstat(int fd, size_t baselen, const char *path, struct stat *pst, int flags, rb_encoding *enc)
1418 {
1419 #if USE_OPENDIR_AT
1420 int ret = fstatat(fd, at_subpath(fd, baselen, path), pst, AT_SYMLINK_NOFOLLOW);
1421 #else
1422 int ret = lstat(path, pst);
1423 #endif
1424 if (ret < 0 && !to_be_ignored(errno))
1425 sys_warning(path, enc);
1426
1427 return ret;
1428 }
1429 #else
1430 #define do_lstat do_stat
1431 #endif
1432
1433 struct opendir_at_arg {
1434 int basefd;
1435 const char *path;
1436 };
1437
1438 static void *
1439 with_gvl_gc_for_fd(void *ptr)
1440 {
1441 int *e = ptr;
1442
1443 return (void *)(rb_gc_for_fd(*e) ? Qtrue : Qfalse);
1444 }
1445
1446 static int
1447 gc_for_fd_with_gvl(int e)
1448 {
1449 if (vm_initialized)
1450 return (int)(VALUE)rb_thread_call_with_gvl(with_gvl_gc_for_fd, &e);
1451 else
1452 return rb_gc_for_fd(e) ? Qtrue : Qfalse;
1453 }
1454
1455 static void *
1456 nogvl_opendir_at(void *ptr)
1457 {
1458 const struct opendir_at_arg *oaa = ptr;
1459 DIR *dirp;
1460
1461 #if USE_OPENDIR_AT
1462 const int opendir_flags = (O_RDONLY|O_CLOEXEC|
1463 # ifdef O_DIRECTORY
1464 O_DIRECTORY|
1465 # endif /* O_DIRECTORY */
1466 0);
1467 int fd = openat(oaa->basefd, oaa->path, opendir_flags);
1468
1469 dirp = fd >= 0 ? fdopendir(fd) : 0;
1470 if (!dirp) {
1471 int e = errno;
1472
1473 switch (gc_for_fd_with_gvl(e)) {
1474 default:
1475 if (fd < 0) fd = openat(oaa->basefd, oaa->path, opendir_flags);
1476 if (fd >= 0) dirp = fdopendir(fd);
1477 if (dirp) return dirp;
1478
1479 e = errno;
1480 /* fallthrough*/
1481 case 0:
1482 if (fd >= 0) close(fd);
1483 errno = e;
1484 }
1485 }
1486 #else /* !USE_OPENDIR_AT */
1487 dirp = opendir(oaa->path);
1488 if (!dirp && gc_for_fd_with_gvl(errno))
1489 dirp = opendir(oaa->path);
1490 #endif /* !USE_OPENDIR_AT */
1491
1492 return dirp;
1493 }
1494
1495 static DIR *
1496 opendir_at(int basefd, const char *path)
1497 {
1498 struct opendir_at_arg oaa;
1499
1500 oaa.basefd = basefd;
1501 oaa.path = path;
1502
1503 if (vm_initialized)
1504 return rb_thread_call_without_gvl(nogvl_opendir_at, &oaa, RUBY_UBF_IO, 0);
1505 else
1506 return nogvl_opendir_at(&oaa);
1507 }
1508
1509 static DIR *
1510 do_opendir(const int basefd, size_t baselen, const char *path, int flags, rb_encoding *enc,
1511 ruby_glob_errfunc *errfunc, VALUE arg, int *status)
1512 {
1513 DIR *dirp;
1514 #ifdef _WIN32
1515 VALUE tmp = 0;
1516 if (!fundamental_encoding_p(enc)) {
1517 tmp = rb_enc_str_new(path, strlen(path), enc);
1518 tmp = rb_str_encode_ospath(tmp);
1519 path = RSTRING_PTR(tmp);
1520 }
1521 #endif
1522 dirp = opendir_at(basefd, at_subpath(basefd, baselen, path));
1523 if (!dirp) {
1524 int e = errno;
1525
1526 *status = 0;
1527 if (!to_be_ignored(e)) {
1528 if (errfunc) {
1529 *status = (*errfunc)(path, arg, enc, e);
1530 }
1531 else {
1532 sys_warning(path, enc);
1533 }
1534 }
1535 }
1536 #ifdef _WIN32
1537 if (tmp) rb_str_resize(tmp, 0); /* GC guard */
1538 #endif
1539
1540 return dirp;
1541 }
1542
1543 /* Globing pattern */
1544 enum glob_pattern_type { PLAIN, ALPHA, BRACE, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
1545
1546 /* Return nonzero if S has any special globbing chars in it. */
1547 static enum glob_pattern_type
1548 has_magic(const char *p, const char *pend, int flags, rb_encoding *enc)
1549 {
1550 const int escape = !(flags & FNM_NOESCAPE);
1551 int hasalpha = 0;
1552 int hasmagical = 0;
1553
1554 register char c;
1555
1556 while (p < pend && (c = *p++) != 0) {
1557 switch (c) {
1558 case '{':
1559 return BRACE;
1560
1561 case '*':
1562 case '?':
1563 case '[':
1564 hasmagical = 1;
1565 break;
1566
1567 case '\\':
1568 if (escape && p++ >= pend)
1569 continue;
1570 break;
1571
1572 #ifdef _WIN32
1573 case '.':
1574 break;
1575
1576 case '~':
1577 hasalpha = 1;
1578 break;
1579 #endif
1580 default:
1581 if (IS_WIN32 || ISALPHA(c)) {
1582 hasalpha = 1;
1583 }
1584 break;
1585 }
1586
1587 p = Next(p-1, pend, enc);
1588 }
1589
1590 return hasmagical ? MAGICAL : hasalpha ? ALPHA : PLAIN;
1591 }
1592
1593 /* Find separator in globbing pattern. */
1594 static char *
1595 find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc)
1596 {
1597 const int escape = !(flags & FNM_NOESCAPE);
1598
1599 register char c;
1600 int open = 0;
1601
1602 while ((c = *p++) != 0) {
1603 switch (c) {
1604 case '[':
1605 open = 1;
1606 continue;
1607 case ']':
1608 open = 0;
1609 continue;
1610
1611 case '{':
1612 open = 1;
1613 continue;
1614 case '}':
1615 open = 0;
1616 continue;
1617
1618 case '/':
1619 if (!open)
1620 return (char *)p-1;
1621 continue;
1622
1623 case '\\':
1624 if (escape && !(c = *p++))
1625 return (char *)p-1;
1626 continue;
1627 }
1628
1629 p = Next(p-1, pend, enc);
1630 }
1631
1632 return (char *)p-1;
1633 }
1634
1635 /* Remove escaping backslashes */
1636 static char *
1637 remove_backslashes(char *p, register const char *pend, rb_encoding *enc)
1638 {
1639 char *t = p;
1640 char *s = p;
1641
1642 while (*p) {
1643 if (*p == '\\') {
1644 if (t != s)
1645 memmove(t, s, p - s);
1646 t += p - s;
1647 s = ++p;
1648 if (!*p) break;
1649 }
1650 Inc(p, pend, enc);
1651 }
1652
1653 while (*p++);
1654
1655 if (t != s)
1656 memmove(t, s, p - s); /* move '\0' too */
1657
1658 return p;
1659 }
1660
1661 struct glob_pattern {
1662 char *str;
1663 enum glob_pattern_type type;
1664 struct glob_pattern *next;
1665 };
1666
1667 static void glob_free_pattern(struct glob_pattern *list);
1668
1669 static struct glob_pattern *
1670 glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
1671 {
1672 struct glob_pattern *list, *tmp, **tail = &list;
1673 int dirsep = 0; /* pattern is terminated with '/' */
1674 int recursive = 0;
1675
1676 while (p < e && *p) {
1677 tmp = GLOB_ALLOC(struct glob_pattern);
1678 if (!tmp) goto error;
1679 if (p + 2 < e && p[0] == '*' && p[1] == '*' && p[2] == '/') {
1680 /* fold continuous RECURSIVEs (needed in glob_helper) */
1681 do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
1682 tmp->type = RECURSIVE;
1683 tmp->str = 0;
1684 dirsep = 1;
1685 recursive = 1;
1686 }
1687 else {
1688 const char *m = find_dirsep(p, e, flags, enc);
1689 const enum glob_pattern_type magic = has_magic(p, m, flags, enc);
1690 const enum glob_pattern_type non_magic = (USE_NAME_ON_FS || FNM_SYSCASE) ? PLAIN : ALPHA;
1691 char *buf;
1692
1693 if (!(FNM_SYSCASE || magic > non_magic) && !recursive && *m) {
1694 const char *m2;
1695 while (has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) <= non_magic &&
1696 *m2) {
1697 m = m2;
1698 }
1699 }
1700 buf = GLOB_ALLOC_N(char, m-p+1);
1701 if (!buf) {
1702 GLOB_FREE(tmp);
1703 goto error;
1704 }
1705 memcpy(buf, p, m-p);
1706 buf[m-p] = '\0';
1707 tmp->type = magic > MAGICAL ? MAGICAL : magic > non_magic ? magic : PLAIN;
1708 tmp->str = buf;
1709 if (*m) {
1710 dirsep = 1;
1711 p = m + 1;
1712 }
1713 else {
1714 dirsep = 0;
1715 p = m;
1716 }
1717 }
1718 *tail = tmp;
1719 tail = &tmp->next;
1720 }
1721
1722 tmp = GLOB_ALLOC(struct glob_pattern);
1723 if (!tmp) {
1724 error:
1725 *tail = 0;
1726 glob_free_pattern(list);
1727 return 0;
1728 }
1729 tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
1730 tmp->str = 0;
1731 *tail = tmp;
1732 tmp->next = 0;
1733
1734 return list;
1735 }
1736
1737 static void
1738 glob_free_pattern(struct glob_pattern *list)
1739 {
1740 while (list) {
1741 struct glob_pattern *tmp = list;
1742 list = list->next;
1743 if (tmp->str)
1744 GLOB_FREE(tmp->str);
1745 GLOB_FREE(tmp);
1746 }
1747 }
1748
1749 static char *
1750 join_path(const char *path, size_t len, int dirsep, const char *name, size_t namlen)
1751 {
1752 char *buf = GLOB_ALLOC_N(char, len+namlen+(dirsep?1:0)+1);
1753
1754 if (!buf) return 0;
1755 memcpy(buf, path, len);
1756 if (dirsep) {
1757 buf[len++] = '/';
1758 }
1759 memcpy(buf+len, name, namlen);
1760 buf[len+namlen] = '\0';
1761 return buf;
1762 }
1763
1764 #ifdef HAVE_GETATTRLIST
1765 # if defined HAVE_FGETATTRLIST
1766 # define is_case_sensitive(dirp, path) is_case_sensitive(dirp)
1767 # else
1768 # define is_case_sensitive(dirp, path) is_case_sensitive(path)
1769 # endif
1770 static int
1771 is_case_sensitive(DIR *dirp, const char *path)
1772 {
1773 struct {
1774 u_int32_t length;
1775 vol_capabilities_attr_t cap[1];
1776 } __attribute__((aligned(4), packed)) attrbuf[1];
1777 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, 0, ATTR_VOL_INFO|ATTR_VOL_CAPABILITIES};
1778 const vol_capabilities_attr_t *const cap = attrbuf[0].cap;
1779 const int idx = VOL_CAPABILITIES_FORMAT;
1780 const uint32_t mask = VOL_CAP_FMT_CASE_SENSITIVE;
1781
1782 # if defined HAVE_FGETATTRLIST
1783 if (fgetattrlist(dirfd(dirp), &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))
1784 return -1;
1785 # else
1786 if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))
1787 return -1;
1788 # endif
1789 if (!(cap->valid[idx] & mask))
1790 return -1;
1791 return (cap->capabilities[idx] & mask) != 0;
1792 }
1793
1794 static char *
1795 replace_real_basename(char *path, long base, rb_encoding *enc, int norm_p, int flags, rb_pathtype_t *type)
1796 {
1797 struct {
1798 u_int32_t length;
1799 attrreference_t ref[1];
1800 fsobj_type_t objtype;
1801 char path[MAXPATHLEN * 3];
1802 } __attribute__((aligned(4), packed)) attrbuf[1];
1803 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_NAME|ATTR_CMN_OBJTYPE};
1804 const attrreference_t *const ar = attrbuf[0].ref;
1805 const char *name;
1806 long len;
1807 char *tmp;
1808 IF_NORMALIZE_UTF8PATH(VALUE utf8str = Qnil);
1809
1810 *type = path_noent;
1811 if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW)) {
1812 if (!to_be_ignored(errno))
1813 sys_warning(path, enc);
1814 return path;
1815 }
1816
1817 switch (attrbuf[0].objtype) {
1818 case VREG: *type = path_regular; break;
1819 case VDIR: *type = path_directory; break;
1820 case VLNK: *type = path_symlink; break;
1821 default: *type = path_exist; break;
1822 }
1823 name = (char *)ar + ar->attr_dataoffset;
1824 len = (long)ar->attr_length - 1;
1825 if (name + len > (char *)attrbuf + sizeof(attrbuf))
1826 return path;
1827
1828 # if NORMALIZE_UTF8PATH
1829 if (norm_p && has_nonascii(name, len)) {
1830 if (!NIL_P(utf8str = rb_str_normalize_ospath(name, len))) {
1831 RSTRING_GETMEM(utf8str, name, len);
1832 }
1833 }
1834 # endif
1835
1836 tmp = GLOB_REALLOC(path, base + len + 1);
1837 if (tmp) {
1838 path = tmp;
1839 memcpy(path + base, name, len);
1840 path[base + len] = '\0';
1841 }
1842 IF_NORMALIZE_UTF8PATH(if (!NIL_P(utf8str)) rb_str_resize(utf8str, 0));
1843 return path;
1844 }
1845 #elif defined _WIN32
1846 VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
1847 int rb_w32_reparse_symlink_p(const WCHAR *path);
1848
1849 static char *
1850 replace_real_basename(char *path, long base, rb_encoding *enc, int norm_p, int flags, rb_pathtype_t *type)
1851 {
1852 char *plainname = path;
1853 volatile VALUE tmp = 0;
1854 WIN32_FIND_DATAW fd;
1855 WIN32_FILE_ATTRIBUTE_DATA fa;
1856 WCHAR *wplain;
1857 HANDLE h = INVALID_HANDLE_VALUE;
1858 long wlen;
1859 int e = 0;
1860 if (!fundamental_encoding_p(enc)) {
1861 tmp = rb_enc_str_new_cstr(plainname, enc);
1862 tmp = rb_str_encode_ospath(tmp);
1863 plainname = RSTRING_PTR(tmp);
1864 }
1865 wplain = rb_w32_mbstr_to_wstr(CP_UTF8, plainname, -1, &wlen);
1866 if (tmp) rb_str_resize(tmp, 0);
1867 if (!wplain) return path;
1868 if (GetFileAttributesExW(wplain, GetFileExInfoStandard, &fa)) {
1869 h = FindFirstFileW(wplain, &fd);
1870 e = rb_w32_map_errno(GetLastError());
1871 }
1872 if (fa.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1873 if (!rb_w32_reparse_symlink_p(wplain))
1874 fa.dwFileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1875 }
1876 free(wplain);
1877 if (h == INVALID_HANDLE_VALUE) {
1878 *type = path_noent;
1879 if (e && !to_be_ignored(e)) {
1880 errno = e;
1881 sys_warning(path, enc);
1882 }
1883 return path;
1884 }
1885 FindClose(h);
1886 *type =
1887 (fa.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? path_symlink :
1888 (fa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? path_directory :
1889 path_regular;
1890 if (tmp) {
1891 char *buf;
1892 tmp = rb_w32_conv_from_wchar(fd.cFileName, enc);
1893 wlen = RSTRING_LEN(tmp);
1894 buf = GLOB_REALLOC(path, base + wlen + 1);
1895 if (buf) {
1896 path = buf;
1897 memcpy(path + base, RSTRING_PTR(tmp), wlen);
1898 path[base + wlen] = 0;
1899 }
1900 rb_str_resize(tmp, 0);
1901 }
1902 else {
1903 char *utf8filename;
1904 wlen = WideCharToMultiByte(CP_UTF8, 0, fd.cFileName, -1, NULL, 0, NULL, NULL);
1905 utf8filename = GLOB_REALLOC(0, wlen);
1906 if (utf8filename) {
1907 char *buf;
1908 WideCharToMultiByte(CP_UTF8, 0, fd.cFileName, -1, utf8filename, wlen, NULL, NULL);
1909 buf = GLOB_REALLOC(path, base + wlen + 1);
1910 if (buf) {
1911 path = buf;
1912 memcpy(path + base, utf8filename, wlen);
1913 path[base + wlen] = 0;
1914 }
1915 GLOB_FREE(utf8filename);
1916 }
1917 }
1918 return path;
1919 }
1920 #elif USE_NAME_ON_FS == USE_NAME_ON_FS_REAL_BASENAME
1921 # error not implemented
1922 #endif
1923
1924 #ifndef S_ISDIR
1925 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1926 #endif
1927
1928 #ifndef S_ISLNK
1929 # ifndef S_IFLNK
1930 # define S_ISLNK(m) (0)
1931 # else
1932 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1933 # endif
1934 #endif
1935
1936 struct glob_args {
1937 void (*func)(const char *, VALUE, void *);
1938 const char *path;
1939 const char *base;
1940 size_t baselen;
1941 VALUE value;
1942 rb_encoding *enc;
1943 };
1944
1945 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (void *)(enc))
1946
1947 static VALUE
1948 glob_func_caller(VALUE val)
1949 {
1950 struct glob_args *args = (struct glob_args *)val;
1951
1952 glob_call_func(args->func, args->path, args->value, args->enc);
1953 return Qnil;
1954 }
1955
1956 struct glob_error_args {
1957 const char *path;
1958 rb_encoding *enc;
1959 int error;
1960 };
1961
1962 static VALUE
1963 glob_func_warning(VALUE val)
1964 {
1965 struct glob_error_args *arg = (struct glob_error_args *)val;
1966 rb_syserr_enc_warning(arg->error, arg->enc, "%s", arg->path);
1967 return Qnil;
1968 }
1969
1970 #if 0
1971 static int
1972 rb_glob_warning(const char *path, VALUE a, const void *enc, int error)
1973 {
1974 int status;
1975 struct glob_error_args args;
1976
1977 args.path = path;
1978 args.enc = enc;
1979 args.error = error;
1980 rb_protect(glob_func_warning, (VALUE)&args, &status);
1981 return status;
1982 }
1983 #endif
1984
1985 static VALUE
1986 glob_func_error(VALUE val)
1987 {
1988 struct glob_error_args *arg = (struct glob_error_args *)val;
1989 VALUE path = rb_enc_str_new_cstr(arg->path, arg->enc);
1990 rb_syserr_fail_str(arg->error, path);
1991 return Qnil;
1992 }
1993
1994 static int
1995 rb_glob_error(const char *path, VALUE a, const void *enc, int error)
1996 {
1997 int status;
1998 struct glob_error_args args;
1999 VALUE (*errfunc)(VALUE) = glob_func_error;
2000
2001 if (error == EACCES) {
2002 errfunc = glob_func_warning;
2003 }
2004 args.path = path;
2005 args.enc = enc;
2006 args.error = error;
2007 rb_protect(errfunc, (VALUE)&args, &status);
2008 return status;
2009 }
2010
2011 static inline int
2012 dirent_match(const char *pat, rb_encoding *enc, const char *name, const struct dirent *dp, int flags)
2013 {
2014 if (fnmatch(pat, enc, name, flags) == 0) return 1;
2015 #ifdef _WIN32
2016 if (dp->d_altname && (flags & FNM_SHORTNAME)) {
2017 if (fnmatch(pat, enc, dp->d_altname, flags) == 0) return 1;
2018 }
2019 #endif
2020 return 0;
2021 }
2022
2023 struct push_glob_args {
2024 int fd;
2025 const char *path;
2026 size_t baselen;
2027 size_t namelen;
2028 int dirsep; /* '/' should be placed before appending child entry's name to 'path'. */
2029 rb_pathtype_t pathtype; /* type of 'path' */
2030 int flags;
2031 const ruby_glob_funcs_t *funcs;
2032 VALUE arg;
2033 };
2034
2035 struct dirent_brace_args {
2036 const char *name;
2037 const struct dirent *dp;
2038 int flags;
2039 };
2040
2041 static int
2042 dirent_match_brace(const char *pattern, VALUE val, void *enc)
2043 {
2044 struct dirent_brace_args *arg = (struct dirent_brace_args *)val;
2045
2046 return dirent_match(pattern, enc, arg->name, arg->dp, arg->flags);
2047 }
2048
2049 /* join paths from pattern list of glob_make_pattern() */
2050 static char*
2051 join_path_from_pattern(struct glob_pattern **beg)
2052 {
2053 struct glob_pattern *p;
2054 char *path = NULL;
2055 size_t path_len = 0;
2056
2057 for (p = *beg; p; p = p->next) {
2058 const char *str;
2059 switch (p->type) {
2060 case RECURSIVE:
2061 str = "**";
2062 break;
2063 case MATCH_DIR:
2064 /* append last slash */
2065 str = "";
2066 break;
2067 default:
2068 str = p->str;
2069 if (!str) continue;
2070 }
2071 if (!path) {
2072 path_len = strlen(str);
2073 path = GLOB_ALLOC_N(char, path_len + 1);
2074 if (path) {
2075 memcpy(path, str, path_len);
2076 path[path_len] = '\0';
2077 }
2078 }
2079 else {
2080 size_t len = strlen(str);
2081 char *tmp;
2082 tmp = GLOB_REALLOC(path, path_len + len + 2);
2083 if (tmp) {
2084 path = tmp;
2085 path[path_len++] = '/';
2086 memcpy(path + path_len, str, len);
2087 path_len += len;
2088 path[path_len] = '\0';
2089 }
2090 }
2091 }
2092 return path;
2093 }
2094
2095 static int push_caller(const char *path, VALUE val, void *enc);
2096
2097 static int ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
2098 rb_encoding *enc, VALUE var);
2099
2100 static int
2101 glob_helper(
2102 int fd,
2103 const char *path,
2104 size_t baselen,
2105 size_t namelen,
2106 int dirsep, /* '/' should be placed before appending child entry's name to 'path'. */
2107 rb_pathtype_t pathtype, /* type of 'path' */
2108 struct glob_pattern **beg,
2109 struct glob_pattern **end,
2110 int flags,
2111 const ruby_glob_funcs_t *funcs,
2112 VALUE arg,
2113 rb_encoding *enc)
2114 {
2115 struct stat st;
2116 int status = 0;
2117 struct glob_pattern **cur, **new_beg, **new_end;
2118 int plain = 0, brace = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
2119 int escape = !(flags & FNM_NOESCAPE);
2120 size_t pathlen = baselen + namelen;
2121
2122 for (cur = beg; cur < end; ++cur) {
2123 struct glob_pattern *p = *cur;
2124 if (p->type == RECURSIVE) {
2125 recursive = 1;
2126 p = p->next;
2127 }
2128 switch (p->type) {
2129 case PLAIN:
2130 plain = 1;
2131 break;
2132 case ALPHA:
2133 #if USE_NAME_ON_FS == USE_NAME_ON_FS_REAL_BASENAME
2134 plain = 1;
2135 #else
2136 magical = 1;
2137 #endif
2138 break;
2139 case BRACE:
2140 if (!recursive) {
2141 brace = 1;
2142 }
2143 break;
2144 case MAGICAL:
2145 magical = 2;
2146 break;
2147 case MATCH_ALL:
2148 match_all = 1;
2149 break;
2150 case MATCH_DIR:
2151 match_dir = 1;
2152 break;
2153 case RECURSIVE:
2154 rb_bug("continuous RECURSIVEs");
2155 }
2156 }
2157
2158 if (brace) {
2159 struct push_glob_args args;
2160 char* brace_path = join_path_from_pattern(beg);
2161 if (!brace_path) return -1;
2162 args.fd = fd;
2163 args.path = path;
2164 args.baselen = baselen;
2165 args.namelen = namelen;
2166 args.dirsep = dirsep;
2167 args.pathtype = pathtype;
2168 args.flags = flags;
2169 args.funcs = funcs;
2170 args.arg = arg;
2171 status = ruby_brace_expand(brace_path, flags, push_caller, (VALUE)&args, enc, Qfalse);
2172 GLOB_FREE(brace_path);
2173 return status;
2174 }
2175
2176 if (*path) {
2177 if (match_all && pathtype == path_unknown) {
2178 if (do_lstat(fd, baselen, path, &st, flags, enc) == 0) {
2179 pathtype = IFTODT(st.st_mode);
2180 }
2181 else {
2182 pathtype = path_noent;
2183 }
2184 }
2185 if (match_dir && (pathtype == path_unknown || pathtype == path_symlink)) {
2186 if (do_stat(fd, baselen, path, &st, flags, enc) == 0) {
2187 pathtype = IFTODT(st.st_mode);
2188 }
2189 else {
2190 pathtype = path_noent;
2191 }
2192 }
2193 if (match_all && pathtype > path_noent) {
2194 const char *subpath = path + baselen + (baselen && path[baselen] == '/');
2195 status = glob_call_func(funcs->match, subpath, arg, enc);
2196 if (status) return status;
2197 }
2198 if (match_dir && pathtype == path_directory) {
2199 int seplen = (baselen && path[baselen] == '/');
2200 const char *subpath = path + baselen + seplen;
2201 char *tmp = join_path(subpath, namelen - seplen, dirsep, "", 0);
2202 if (!tmp) return -1;
2203 status = glob_call_func(funcs->match, tmp, arg, enc);
2204 GLOB_FREE(tmp);
2205 if (status) return status;
2206 }
2207 }
2208
2209 if (pathtype == path_noent) return 0;
2210
2211 if (magical || recursive) {
2212 struct dirent *dp;
2213 DIR *dirp;
2214 # if USE_NAME_ON_FS == USE_NAME_ON_FS_BY_FNMATCH
2215 char *plainname = 0;
2216 # endif
2217 IF_NORMALIZE_UTF8PATH(int norm_p);
2218 # if USE_NAME_ON_FS == USE_NAME_ON_FS_BY_FNMATCH
2219 if (cur + 1 == end && (*cur)->type <= ALPHA) {
2220 plainname = join_path(path, pathlen, dirsep, (*cur)->str, strlen((*cur)->str));
2221 if (!plainname) return -1;
2222 dirp = do_opendir(fd, basename, plainname, flags, enc, funcs->error, arg, &status);
2223 GLOB_FREE(plainname);
2224 }
2225 else
2226 # else
2227 ;
2228 # endif
2229 dirp = do_opendir(fd, baselen, path, flags, enc, funcs->error, arg, &status);
2230 if (dirp == NULL) {
2231 # if FNM_SYSCASE || NORMALIZE_UTF8PATH
2232 if ((magical < 2) && !recursive && (errno == EACCES)) {
2233 /* no read permission, fallback */
2234 goto literally;
2235 }
2236 # endif
2237 return status;
2238 }
2239 IF_NORMALIZE_UTF8PATH(norm_p = need_normalization(dirp, *path ? path : "."));
2240
2241 # if NORMALIZE_UTF8PATH
2242 if (!(norm_p || magical || recursive)) {
2243 closedir(dirp);
2244 goto literally;
2245 }
2246 # endif
2247 # ifdef HAVE_GETATTRLIST
2248 if (is_case_sensitive(dirp, path) == 0)
2249 flags |= FNM_CASEFOLD;
2250 # endif
2251 while ((dp = READDIR(dirp, enc)) != NULL) {
2252 char *buf;
2253 rb_pathtype_t new_pathtype = path_unknown;
2254 const char *name;
2255 size_t namlen;
2256 int dotfile = 0;
2257 IF_NORMALIZE_UTF8PATH(VALUE utf8str = Qnil);
2258
2259 name = dp->d_name;
2260 namlen = NAMLEN(dp);
2261 if (recursive && name[0] == '.') {
2262 ++dotfile;
2263 if (namlen == 1) {
2264 /* unless DOTMATCH, skip current directories not to recurse infinitely */
2265 if (!(flags & FNM_DOTMATCH)) continue;
2266 ++dotfile;
2267 new_pathtype = path_directory; /* force to skip stat/lstat */
2268 }
2269 else if (namlen == 2 && name[1] == '.') {
2270 /* always skip parent directories not to recurse infinitely */
2271 continue;
2272 }
2273 }
2274
2275 # if NORMALIZE_UTF8PATH
2276 if (norm_p && has_nonascii(name, namlen)) {
2277 if (!NIL_P(utf8str = rb_str_normalize_ospath(name, namlen))) {
2278 RSTRING_GETMEM(utf8str, name, namlen);
2279 }
2280 }
2281 # endif
2282 buf = join_path(path, pathlen, dirsep, name, namlen);
2283 IF_NORMALIZE_UTF8PATH(if (!NIL_P(utf8str)) rb_str_resize(utf8str, 0));
2284 if (!buf) {
2285 status = -1;
2286 break;
2287 }
2288 name = buf + pathlen + (dirsep != 0);
2289 #ifdef DT_UNKNOWN
2290 if (dp->d_type != DT_UNKNOWN) {
2291 /* Got it. We need no more lstat. */
2292 new_pathtype = dp->d_type;
2293 }
2294 #endif
2295 if (recursive && dotfile < ((flags & FNM_DOTMATCH) ? 2 : 1) &&
2296 new_pathtype == path_unknown) {
2297 /* RECURSIVE never match dot files unless FNM_DOTMATCH is set */
2298 if (do_lstat(fd, baselen, buf, &st, flags, enc) == 0)
2299 new_pathtype = IFTODT(st.st_mode);
2300 else
2301 new_pathtype = path_noent;
2302 }
2303
2304 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
2305 if (!new_beg) {
2306 GLOB_FREE(buf);
2307 status = -1;
2308 break;
2309 }
2310
2311 for (cur = beg; cur < end; ++cur) {
2312 struct glob_pattern *p = *cur;
2313 struct dirent_brace_args args;
2314 if (p->type == RECURSIVE) {
2315 if (new_pathtype == path_directory || /* not symlink but real directory */
2316 new_pathtype == path_exist) {
2317 if (dotfile < ((flags & FNM_DOTMATCH) ? 2 : 1))
2318 *new_end++ = p; /* append recursive pattern */
2319 }
2320 p = p->next; /* 0 times recursion */
2321 }
2322 switch (p->type) {
2323 case BRACE:
2324 args.name = name;
2325 args.dp = dp;
2326 args.flags = flags;
2327 if (ruby_brace_expand(p->str, flags, dirent_match_brace,
2328 (VALUE)&args, enc, Qfalse) > 0)
2329 *new_end++ = p->next;
2330 break;
2331 case ALPHA:
2332 # if USE_NAME_ON_FS == USE_NAME_ON_FS_BY_FNMATCH
2333 if (plainname) {
2334 *new_end++ = p->next;
2335 break;
2336 }
2337 # endif
2338 case PLAIN:
2339 case MAGICAL:
2340 if (dirent_match(p->str, enc, name, dp, flags))
2341 *new_end++ = p->next;
2342 default:
2343 break;
2344 }
2345 }
2346
2347 status = glob_helper(fd, buf, baselen, name - buf - baselen + namlen, 1,
2348 new_pathtype, new_beg, new_end,
2349 flags, funcs, arg, enc);
2350 GLOB_FREE(buf);
2351 GLOB_FREE(new_beg);
2352 if (status) break;
2353 }
2354
2355 closedir(dirp);
2356 }
2357 else if (plain) {
2358 struct glob_pattern **copy_beg, **copy_end, **cur2;
2359
2360 # if FNM_SYSCASE || NORMALIZE_UTF8PATH
2361 literally:
2362 # endif
2363 copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
2364 if (!copy_beg) return -1;
2365 for (cur = beg; cur < end; ++cur)
2366 *copy_end++ = (*cur)->type <= ALPHA ? *cur : 0;
2367
2368 for (cur = copy_beg; cur < copy_end; ++cur) {
2369 if (*cur) {
2370 rb_pathtype_t new_pathtype = path_unknown;
2371 char *buf;
2372 char *name;
2373 size_t len = strlen((*cur)->str) + 1;
2374 name = GLOB_ALLOC_N(char, len);
2375 if (!name) {
2376 status = -1;
2377 break;
2378 }
2379 memcpy(name, (*cur)->str, len);
2380 if (escape)
2381 len = remove_backslashes(name, name+len-1, enc) - name;
2382
2383 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
2384 if (!new_beg) {
2385 GLOB_FREE(name);
2386 status = -1;
2387 break;
2388 }
2389 *new_end++ = (*cur)->next;
2390 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
2391 if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
2392 *new_end++ = (*cur2)->next;
2393 *cur2 = 0;
2394 }
2395 }
2396
2397 buf = join_path(path, pathlen, dirsep, name, len);
2398 GLOB_FREE(name);
2399 if (!buf) {
2400 GLOB_FREE(new_beg);
2401 status = -1;
2402 break;
2403 }
2404 #if USE_NAME_ON_FS == USE_NAME_ON_FS_REAL_BASENAME
2405 if ((*cur)->type == ALPHA) {
2406 buf = replace_real_basename(buf, pathlen + (dirsep != 0), enc,
2407 IF_NORMALIZE_UTF8PATH(1)+0,
2408 flags, &new_pathtype);
2409 if (!buf) break;
2410 }
2411 #endif
2412 status = glob_helper(fd, buf, baselen,
2413 namelen + strlen(buf + pathlen), 1,
2414 new_pathtype, new_beg, new_end,
2415 flags, funcs, arg, enc);
2416 GLOB_FREE(buf);
2417 GLOB_FREE(new_beg);
2418 if (status) break;
2419 }
2420 }
2421
2422 GLOB_FREE(copy_beg);
2423 }
2424
2425 return status;
2426 }
2427
2428 static int
2429 push_caller(const char *path, VALUE val, void *enc)
2430 {
2431 struct push_glob_args *arg = (struct push_glob_args *)val;
2432 struct glob_pattern *list;
2433 int status;
2434
2435 list = glob_make_pattern(path, path + strlen(path), arg->flags, enc);
2436 if (!list) {
2437 return -1;
2438 }
2439 status = glob_helper(arg->fd, arg->path, arg->baselen, arg->namelen, arg->dirsep,
2440 arg->pathtype, &list, &list + 1, arg->flags, arg->funcs,
2441 arg->arg, enc);
2442 glob_free_pattern(list);
2443 return status;
2444 }
2445
2446 static int ruby_glob0(const char *path, int fd, const char *base, int flags,
2447 const ruby_glob_funcs_t *funcs, VALUE arg, rb_encoding *enc);
2448
2449 struct push_glob0_args {
2450 int fd;
2451 const char *base;
2452 int flags;
2453 const ruby_glob_funcs_t *funcs;
2454 VALUE arg;
2455 };
2456
2457 static int
2458 push_glob0_caller(const char *path, VALUE val, void *enc)
2459 {
2460 struct push_glob0_args *arg = (struct push_glob0_args *)val;
2461 return ruby_glob0(path, arg->fd, arg->base, arg->flags, arg->funcs, arg->arg, enc);
2462 }
2463
2464 static int
2465 ruby_glob0(const char *path, int fd, const char *base, int flags,
2466 const ruby_glob_funcs_t *funcs, VALUE arg,
2467 rb_encoding *enc)
2468 {
2469 struct glob_pattern *list;
2470 const char *root, *start;
2471 char *buf;
2472 size_t n, baselen = 0;
2473 int status, dirsep = FALSE;
2474
2475 start = root = path;
2476
2477 if (*root == '{') {
2478 struct push_glob0_args args;
2479 args.fd = fd;
2480 args.base = base;
2481 args.flags = flags;
2482 args.funcs = funcs;
2483 args.arg = arg;
2484 return ruby_brace_expand(path, flags, push_glob0_caller, (VALUE)&args, enc, Qfalse);
2485 }
2486
2487 flags |= FNM_SYSCASE;
2488 #if defined DOSISH
2489 root = rb_enc_path_skip_prefix(root, root + strlen(root), enc);
2490 #endif
2491
2492 if (*root == '/') root++;
2493
2494 n = root - start;
2495 if (!n && base) {
2496 n = strlen(base);
2497 baselen = n;
2498 start = base;
2499 dirsep = TRUE;
2500 }
2501 buf = GLOB_ALLOC_N(char, n + 1);
2502 if (!buf) return -1;
2503 MEMCPY(buf, start, char, n);
2504 buf[n] = '\0';
2505
2506 list = glob_make_pattern(root, root + strlen(root), flags, enc);
2507 if (!list) {
2508 GLOB_FREE(buf);
2509 return -1;
2510 }
2511 status = glob_helper(fd, buf, baselen, n-baselen, dirsep,
2512 path_unknown, &list, &list + 1,
2513 flags, funcs, arg, enc);
2514 glob_free_pattern(list);
2515 GLOB_FREE(buf);
2516
2517 return status;
2518 }
2519
2520 int
2521 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
2522 {
2523 ruby_glob_funcs_t funcs;
2524 funcs.match = func;
2525 funcs.error = NULL;
2526 return ruby_glob0(path, AT_FDCWD, 0, flags & ~GLOB_VERBOSE,
2527 &funcs, arg, rb_ascii8bit_encoding());
2528 }
2529
2530 static int
2531 rb_glob_caller(const char *path, VALUE a, void *enc)
2532 {
2533 int status;
2534 struct glob_args *args = (struct glob_args *)a;
2535
2536 args->path = path;
2537 rb_protect(glob_func_caller, a, &status);
2538 return status;
2539 }
2540
2541 static const ruby_glob_funcs_t rb_glob_funcs = {
2542 rb_glob_caller, rb_glob_error,
2543 };
2544
2545 void
2546 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
2547 {
2548 struct glob_args args;
2549 int status;
2550
2551 args.func = func;
2552 args.value = arg;
2553 args.enc = rb_ascii8bit_encoding();
2554
2555 status = ruby_glob0(path, AT_FDCWD, 0, GLOB_VERBOSE, &rb_glob_funcs,
2556 (VALUE)&args, args.enc);
2557 if (status) GLOB_JUMP_TAG(status);
2558 }
2559
2560 static void
2561 push_pattern(const char *path, VALUE ary, void *enc)
2562 {
2563 #if defined _WIN32 || defined __APPLE__
2564 VALUE name = rb_utf8_str_new_cstr(path);
2565 rb_encoding *eenc = rb_default_internal_encoding();
2566 name = rb_str_conv_enc(name, NULL, eenc ? eenc : enc);
2567 #else
2568 VALUE name = rb_external_str_new_with_enc(path, strlen(path), enc);
2569 #endif
2570 rb_ary_push(ary, name);
2571 }
2572
2573 static int
2574 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
2575 rb_encoding *enc, VALUE var)
2576 {
2577 const int escape = !(flags & FNM_NOESCAPE);
2578 const char *p = str;
2579 const char *pend = p + strlen(p);
2580 const char *s = p;
2581 const char *lbrace = 0, *rbrace = 0;
2582 int nest = 0, status = 0;
2583
2584 while (*p) {
2585 if (*p == '{' && nest++ == 0) {
2586 lbrace = p;
2587 }
2588 if (*p == '}' && lbrace && --nest == 0) {
2589 rbrace = p;
2590 break;
2591 }
2592 if (*p == '\\' && escape) {
2593 if (!*++p) break;
2594 }
2595 Inc(p, pend, enc);
2596 }
2597
2598 if (lbrace && rbrace) {
2599 size_t len = strlen(s) + 1;
2600 char *buf = GLOB_ALLOC_N(char, len);
2601 long shift;
2602
2603 if (!buf) return -1;
2604 memcpy(buf, s, lbrace-s);
2605 shift = (lbrace-s);
2606 p = lbrace;
2607 while (p < rbrace) {
2608 const char *t = ++p;
2609 nest = 0;
2610 while (p < rbrace && !(*p == ',' && nest == 0)) {
2611 if (*p == '{') nest++;
2612 if (*p == '}') nest--;
2613 if (*p == '\\' && escape) {
2614 if (++p == rbrace) break;
2615 }
2616 Inc(p, pend, enc);
2617 }
2618 memcpy(buf+shift, t, p-t);
2619 strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
2620 status = ruby_brace_expand(buf, flags, func, arg, enc, var);
2621 if (status) break;
2622 }
2623 GLOB_FREE(buf);
2624 }
2625 else if (!lbrace && !rbrace) {
2626 status = glob_call_func(func, s, arg, enc);
2627 }
2628
2629 RB_GC_GUARD(var);
2630 return status;
2631 }
2632
2633 struct brace_args {
2634 ruby_glob_funcs_t funcs;
2635 VALUE value;
2636 int flags;
2637 };
2638
2639 static int
2640 glob_brace(const char *path, VALUE val, void *enc)
2641 {
2642 struct brace_args *arg = (struct brace_args *)val;
2643
2644 return ruby_glob0(path, AT_FDCWD, 0, arg->flags, &arg->funcs, arg->value, enc);
2645 }
2646
2647 int
2648 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
2649 {
2650 struct brace_args args;
2651
2652 flags &= ~GLOB_VERBOSE;
2653 args.funcs.match = func;
2654 args.funcs.error = NULL;
2655 args.value = arg;
2656 args.flags = flags;
2657 return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc, Qfalse);
2658 }
2659
2660 int
2661 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
2662 {
2663 return ruby_brace_glob_with_enc(str, flags, func, arg, rb_ascii8bit_encoding());
2664 }
2665
2666 static int
2667 push_glob(VALUE ary, VALUE str, VALUE base, int flags)
2668 {
2669 struct glob_args args;
2670 int fd;
2671 rb_encoding *enc = rb_enc_get(str);
2672
2673 #if defined _WIN32 || defined __APPLE__
2674 str = rb_str_encode_ospath(str);
2675 #endif
2676 if (rb_enc_to_index(enc) == ENCINDEX_US_ASCII)
2677 enc = rb_filesystem_encoding();
2678 if (rb_enc_to_index(enc) == ENCINDEX_US_ASCII)
2679 enc = rb_ascii8bit_encoding();
2680 flags |= GLOB_VERBOSE;
2681 args.func = push_pattern;
2682 args.value = ary;
2683 args.enc = enc;
2684 args.base = 0;
2685 fd = AT_FDCWD;
2686 if (!NIL_P(base)) {
2687 if (!RB_TYPE_P(base, T_STRING) || !rb_enc_check(str, base)) {
2688 struct dir_data *dirp = DATA_PTR(base);
2689 if (!dirp->dir) dir_closed();
2690 #ifdef HAVE_DIRFD
2691 if ((fd = dirfd(dirp->dir)) == -1)
2692 rb_sys_fail_path(dir_inspect(base));
2693 #endif
2694 base = dirp->path;
2695 }
2696 args.base = RSTRING_PTR(base);
2697 }
2698 #if defined _WIN32 || defined __APPLE__
2699 enc = rb_utf8_encoding();
2700 #endif
2701
2702 return ruby_glob0(RSTRING_PTR(str), fd, args.base, flags, &rb_glob_funcs,
2703 (VALUE)&args, enc);
2704 }
2705
2706 static VALUE
2707 rb_push_glob(VALUE str, VALUE base, int flags) /* '\0' is delimiter */
2708 {
2709 VALUE ary;
2710 int status;
2711
2712 /* can contain null bytes as separators */
2713 if (!RB_TYPE_P(str, T_STRING)) {
2714 FilePathValue(str);
2715 }
2716 else if (!rb_str_to_cstr(str)) {
2717 rb_raise(rb_eArgError, "nul-separated glob pattern is deprecated");
2718 }
2719 else {
2720 rb_enc_check(str, rb_enc_from_encoding(rb_usascii_encoding()));
2721 }
2722 ary = rb_ary_new();
2723
2724 status = push_glob(ary, str, base, flags);
2725 if (status) GLOB_JUMP_TAG(status);
2726
2727 return ary;
2728 }
2729
2730 static VALUE
2731 dir_globs(long argc, const VALUE *argv, VALUE base, int flags)
2732 {
2733 VALUE ary = rb_ary_new();
2734 long i;
2735
2736 for (i = 0; i < argc; ++i) {
2737 int status;
2738 VALUE str = argv[i];
2739 FilePathValue(str);
2740 status = push_glob(ary, str, base, flags);
2741 if (status) GLOB_JUMP_TAG(status);
2742 }
2743
2744 return ary;
2745 }
2746
2747 static void
2748 dir_glob_options(VALUE opt, VALUE *base, int *flags)
2749 {
2750 ID kw[2];
2751 VALUE args[2];
2752 kw[0] = rb_intern("base");
2753 if (flags) kw[1] = rb_intern("flags");
2754 rb_get_kwargs(opt, kw, 0, flags ? 2 : 1, args);
2755 if (args[0] == Qundef || NIL_P(args[0])) {
2756 *base = Qnil;
2757 }
2758 #if USE_OPENDIR_AT
2759 else if (rb_typeddata_is_kind_of(args[0], &dir_data_type)) {
2760 *base = args[0];
2761 }
2762 #endif
2763 else {
2764 FilePathValue(args[0]);
2765 if (!RSTRING_LEN(args[0])) args[0] = Qnil;
2766 *base = args[0];
2767 }
2768 if (flags && args[1] != Qundef) {
2769 *flags = NUM2INT(args[1]);
2770 }
2771 }
2772
2773 /*
2774 * call-seq:
2775 * Dir[ string [, string ...] [, base: path] ] -> array
2776 *
2777 * Equivalent to calling
2778 * <code>Dir.glob([</code><i>string,...</i><code>], 0)</code>.
2779 *
2780 */
2781 static VALUE
2782 dir_s_aref(int argc, VALUE *argv, VALUE obj)
2783 {
2784 VALUE opts, base;
2785 argc = rb_scan_args(argc, argv, "*:", NULL, &opts);
2786 dir_glob_options(opts, &base, NULL);
2787 if (argc == 1) {
2788 return rb_push_glob(argv[0], base, 0);
2789 }
2790 return dir_globs(argc, argv, base, 0);
2791 }
2792
2793 /*
2794 * call-seq:
2795 * Dir.glob( pattern, [flags], [base: path] ) -> array
2796 * Dir.glob( pattern, [flags], [base: path] ) { |filename| block } -> nil
2797 *
2798 * Expands +pattern+, which is a pattern string or an Array of pattern
2799 * strings, and returns an array containing the matching filenames.
2800 * If a block is given, calls the block once for each matching filename,
2801 * passing the filename as a parameter to the block.
2802 *
2803 * The optional +base+ keyword argument specifies the base directory for
2804 * interpreting relative pathnames instead of the current working directory.
2805 * As the results are not prefixed with the base directory name in this
2806 * case, you will need to prepend the base directory name if you want real
2807 * paths.
2808 *
2809 * Note that the pattern is not a regexp, it's closer to a shell glob.
2810 * See File::fnmatch for the meaning of the +flags+ parameter.
2811 * Case sensitivity depends on your system (File::FNM_CASEFOLD is ignored),
2812 * as does the order in which the results are returned.
2813 *
2814 * <code>*</code>::
2815 * Matches any file. Can be restricted by other values in the glob.
2816 * Equivalent to <code>/ .* /mx</code> in regexp.
2817 *
2818 * <code>*</code>:: Matches all files
2819 * <code>c*</code>:: Matches all files beginning with <code>c</code>
2820 * <code>*c</code>:: Matches all files ending with <code>c</code>
2821 * <code>\*c\*</code>:: Match all files that have <code>c</code> in them
2822 * (including at the beginning or end).
2823 *
2824 * Note, this will not match Unix-like hidden files (dotfiles). In order
2825 * to include those in the match results, you must use the
2826 * File::FNM_DOTMATCH flag or something like <code>"{*,.*}"</code>.
2827 *
2828 * <code>**</code>::
2829 * Matches directories recursively.
2830 *
2831 * <code>?</code>::
2832 * Matches any one character. Equivalent to <code>/.{1}/</code> in regexp.
2833 *
2834 * <code>[set]</code>::
2835 * Matches any one character in +set+. Behaves exactly like character sets
2836 * in Regexp, including set negation (<code>[^a-z]</code>).
2837 *
2838 * <code>{p,q}</code>::
2839 * Matches either literal <code>p</code> or literal <code>q</code>.
2840 * Equivalent to pattern alternation in regexp.
2841 *
2842 * Matching literals may be more than one character in length. More than
2843 * two literals may be specified.
2844 *
2845 * <code> \\ </code>::
2846 * Escapes the next metacharacter.
2847 *
2848 * Note that this means you cannot use backslash on windows as part of a
2849 * glob, i.e. <code>Dir["c:\\foo*"]</code> will not work, use
2850 * <code>Dir["c:/foo*"]</code> instead.
2851 *
2852 * Examples:
2853 *
2854 * Dir["config.?"] #=> ["config.h"]
2855 * Dir.glob("config.?") #=> ["config.h"]
2856 * Dir.glob("*.[a-z][a-z]") #=> ["main.rb"]
2857 * Dir.glob("*.[^r]*") #=> ["config.h"]
2858 * Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"]
2859 * Dir.glob("*") #=> ["config.h", "main.rb"]
2860 * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"]
2861 * Dir.glob(["*.rb", "*.h"]) #=> ["main.rb", "config.h"]
2862 *
2863 * rbfiles = File.join("**", "*.rb")
2864 * Dir.glob(rbfiles) #=> ["main.rb",
2865 * # "lib/song.rb",
2866 * # "lib/song/karaoke.rb"]
2867 *
2868 * Dir.glob(rbfiles, base: "lib") #=> ["song.rb",
2869 * # "song/karaoke.rb"]
2870 *
2871 * libdirs = File.join("**", "lib")
2872 * Dir.glob(libdirs) #=> ["lib"]
2873 *
2874 * librbfiles = File.join("**", "lib", "**", "*.rb")
2875 * Dir.glob(librbfiles) #=> ["lib/song.rb",
2876 * # "lib/song/karaoke.rb"]
2877 *
2878 * librbfiles = File.join("**", "lib", "*.rb")
2879 * Dir.glob(librbfiles) #=> ["lib/song.rb"]
2880 */
2881 static VALUE
2882 dir_s_glob(int argc, VALUE *argv, VALUE obj)
2883 {
2884 VALUE str, rflags, ary, opts, base;
2885 int flags;
2886
2887 argc = rb_scan_args(argc, argv, "11:", &str, &rflags, &opts);
2888 if (argc == 2)
2889 flags = NUM2INT(rflags);
2890 else
2891 flags = 0;
2892 dir_glob_options(opts, &base, &flags);
2893
2894 ary = rb_check_array_type(str);
2895 if (NIL_P(ary)) {
2896 ary = rb_push_glob(str, base, flags);
2897 }
2898 else {
2899 VALUE v = ary;
2900 ary = dir_globs(RARRAY_LEN(v), RARRAY_CONST_PTR(v), base, flags);
2901 RB_GC_GUARD(v);
2902 }
2903
2904 if (rb_block_given_p()) {
2905 rb_ary_each(ary);
2906 return Qnil;
2907 }
2908 return ary;
2909 }
2910
2911 static VALUE
2912 dir_open_dir(int argc, VALUE *argv)
2913 {
2914 VALUE dir = rb_funcallv_kw(rb_cDir, rb_intern("open"), argc, argv, RB_PASS_CALLED_KEYWORDS);
2915
2916 rb_check_typeddata(dir, &dir_data_type);
2917 return dir;
2918 }
2919
2920
2921 /*
2922 * call-seq:
2923 * Dir.foreach( dirname ) {| filename | block } -> nil
2924 * Dir.foreach( dirname, encoding: enc ) {| filename | block } -> nil
2925 * Dir.foreach( dirname ) -> an_enumerator
2926 * Dir.foreach( dirname, encoding: enc ) -> an_enumerator
2927 *
2928 * Calls the block once for each entry in the named directory, passing
2929 * the filename of each entry as a parameter to the block.
2930 *
2931 * If no block is given, an enumerator is returned instead.
2932 *
2933 * Dir.foreach("testdir") {|x| puts "Got #{x}" }
2934 *
2935 * <em>produces:</em>
2936 *
2937 * Got .
2938 * Got ..
2939 * Got config.h
2940 * Got main.rb
2941 *
2942 */
2943 static VALUE
2944 dir_foreach(int argc, VALUE *argv, VALUE io)
2945 {
2946 VALUE dir;
2947
2948 RETURN_ENUMERATOR(io, argc, argv);
2949 dir = dir_open_dir(argc, argv);
2950 rb_ensure(dir_each, dir, dir_close, dir);
2951 return Qnil;
2952 }
2953
2954 static VALUE
2955 dir_collect(VALUE dir)
2956 {
2957 VALUE ary = rb_ary_new();
2958 dir_each_entry(dir, rb_ary_push, ary, FALSE);
2959 return ary;
2960 }
2961
2962 /*
2963 * call-seq:
2964 * Dir.entries( dirname ) -> array
2965 * Dir.entries( dirname, encoding: enc ) -> array
2966 *
2967 * Returns an array containing all of the filenames in the given
2968 * directory. Will raise a SystemCallError if the named directory
2969 * doesn't exist.
2970 *
2971 * The optional <i>encoding</i> keyword argument specifies the encoding of the
2972 * directory. If not specified, the filesystem encoding is used.
2973 *
2974 * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"]
2975 *
2976 */
2977 static VALUE
2978 dir_entries(int argc, VALUE *argv, VALUE io)
2979 {
2980 VALUE dir;
2981
2982 dir = dir_open_dir(argc, argv);
2983 return rb_ensure(dir_collect, dir, dir_close, dir);
2984 }
2985
2986 static VALUE
2987 dir_each_child(VALUE dir)
2988 {
2989 return dir_each_entry(dir, dir_yield, Qnil, TRUE);
2990 }
2991
2992 /*
2993 * call-seq:
2994 * Dir.each_child( dirname ) {| filename | block } -> nil
2995 * Dir.each_child( dirname, encoding: enc ) {| filename | block } -> nil
2996 * Dir.each_child( dirname ) -> an_enumerator
2997 * Dir.each_child( dirname, encoding: enc ) -> an_enumerator
2998 *
2999 * Calls the block once for each entry except for "." and ".." in the
3000 * named directory, passing the filename of each entry as a parameter
3001 * to the block.
3002 *
3003 * If no block is given, an enumerator is returned instead.
3004 *
3005 * Dir.each_child("testdir") {|x| puts "Got #{x}" }
3006 *
3007 * <em>produces:</em>
3008 *
3009 * Got config.h
3010 * Got main.rb
3011 *
3012 */
3013 static VALUE
3014 dir_s_each_child(int argc, VALUE *argv, VALUE io)
3015 {
3016 VALUE dir;
3017
3018 RETURN_ENUMERATOR(io, argc, argv);
3019 dir = dir_open_dir(argc, argv);
3020 rb_ensure(dir_each_child, dir, dir_close, dir);
3021 return Qnil;
3022 }
3023
3024 /*
3025 * call-seq:
3026 * dir.each_child {| filename | block } -> nil
3027 * dir.each_child -> an_enumerator
3028 *
3029 * Calls the block once for each entry except for "." and ".." in
3030 * this directory, passing the filename of each entry as a parameter
3031 * to the block.
3032 *
3033 * If no block is given, an enumerator is returned instead.
3034 *
3035 * d = Dir.new("testdir")
3036 * d.each_child {|x| puts "Got #{x}" }
3037 *
3038 * <em>produces:</em>
3039 *
3040 * Got config.h
3041 * Got main.rb
3042 *
3043 */
3044 static VALUE
3045 dir_each_child_m(VALUE dir)
3046 {
3047 RETURN_ENUMERATOR(dir, 0, 0);
3048 return dir_each_entry(dir, dir_yield, Qnil, TRUE);
3049 }
3050
3051 /*
3052 * call-seq:
3053 * dir.children -> array
3054 *
3055 * Returns an array containing all of the filenames except for "."
3056 * and ".." in this directory.
3057 *
3058 * d = Dir.new("testdir")
3059 * d.children #=> ["config.h", "main.rb"]
3060 *
3061 */
3062 static VALUE
3063 dir_collect_children(VALUE dir)
3064 {
3065 VALUE ary = rb_ary_new();
3066 dir_each_entry(dir, rb_ary_push, ary, TRUE);
3067 return ary;
3068 }
3069
3070 /*
3071 * call-seq:
3072 * Dir.children( dirname ) -> array
3073 * Dir.children( dirname, encoding: enc ) -> array
3074 *
3075 * Returns an array containing all of the filenames except for "."
3076 * and ".." in the given directory. Will raise a SystemCallError if
3077 * the named directory doesn't exist.
3078 *
3079 * The optional <i>encoding</i> keyword argument specifies the encoding of the
3080 * directory. If not specified, the filesystem encoding is used.
3081 *
3082 * Dir.children("testdir") #=> ["config.h", "main.rb"]
3083 *
3084 */
3085 static VALUE
3086 dir_s_children(int argc, VALUE *argv, VALUE io)
3087 {
3088 VALUE dir;
3089
3090 dir = dir_open_dir(argc, argv);
3091 return rb_ensure(dir_collect_children, dir, dir_close, dir);
3092 }
3093
3094 static int
3095 fnmatch_brace(const char *pattern, VALUE val, void *enc)
3096 {
3097 struct brace_args *arg = (struct brace_args *)val;
3098 VALUE path = arg->value;
3099 rb_encoding *enc_pattern = enc;
3100 rb_encoding *enc_path = rb_enc_get(path);
3101
3102 if (enc_pattern != enc_path) {
3103 if (!rb_enc_asciicompat(enc_pattern))
3104 return FNM_NOMATCH;
3105 if (!rb_enc_asciicompat(enc_path))
3106 return FNM_NOMATCH;
3107 if (!rb_enc_str_asciionly_p(path)) {
3108 int cr = ENC_CODERANGE_7BIT;
3109 long len = strlen(pattern);
3110 if (rb_str_coderange_scan_restartable(pattern, pattern + len,
3111 enc_pattern, &cr) != len)
3112 return FNM_NOMATCH;
3113 if (cr != ENC_CODERANGE_7BIT)
3114 return FNM_NOMATCH;
3115 }
3116 }
3117 return (fnmatch(pattern, enc, RSTRING_PTR(path), arg->flags) == 0);
3118 }
3119
3120 /*
3121 * call-seq:
3122 * File.fnmatch( pattern, path, [flags] ) -> (true or false)
3123 * File.fnmatch?( pattern, path, [flags] ) -> (true or false)
3124 *
3125 * Returns true if +path+ matches against +pattern+. The pattern is not a
3126 * regular expression; instead it follows rules similar to shell filename
3127 * globbing. It may contain the following metacharacters:
3128 *
3129 * <code>*</code>::
3130 * Matches any file. Can be restricted by other values in the glob.
3131 * Equivalent to <code>/ .* /x</code> in regexp.
3132 *
3133 * <code>*</code>:: Matches all files regular files
3134 * <code>c*</code>:: Matches all files beginning with <code>c</code>
3135 * <code>*c</code>:: Matches all files ending with <code>c</code>
3136 * <code>\*c*</code>:: Matches all files that have <code>c</code> in them
3137 * (including at the beginning or end).
3138 *
3139 * To match hidden files (that start with a <code>.</code> set the
3140 * File::FNM_DOTMATCH flag.
3141 *
3142 * <code>**</code>::
3143 * Matches directories recursively or files expansively.
3144 *
3145 * <code>?</code>::
3146 * Matches any one character. Equivalent to <code>/.{1}/</code> in regexp.
3147 *
3148 * <code>[set]</code>::
3149 * Matches any one character in +set+. Behaves exactly like character sets
3150 * in Regexp, including set negation (<code>[^a-z]</code>).
3151 *
3152 * <code> \ </code>::
3153 * Escapes the next metacharacter.
3154 *
3155 * <code>{a,b}</code>::
3156 * Matches pattern a and pattern b if File::FNM_EXTGLOB flag is enabled.
3157 * Behaves like a Regexp union (<code>(?:a|b)</code>).
3158 *
3159 * +flags+ is a bitwise OR of the <code>FNM_XXX</code> constants. The same
3160 * glob pattern and flags are used by Dir::glob.
3161 *
3162 * Examples:
3163 *
3164 * File.fnmatch('cat', 'cat') #=> true # match entire string
3165 * File.fnmatch('cat', 'category') #=> false # only match partial string
3166 *
3167 * File.fnmatch('c{at,ub}s', 'cats') #=> false # { } isn't supported by default
3168 * File.fnmatch('c{at,ub}s', 'cats', File::FNM_EXTGLOB) #=> true # { } is supported on FNM_EXTGLOB
3169 *
3170 * File.fnmatch('c?t', 'cat') #=> true # '?' match only 1 character
3171 * File.fnmatch('c??t', 'cat') #=> false # ditto
3172 * File.fnmatch('c*', 'cats') #=> true # '*' match 0 or more characters
3173 * File.fnmatch('c*t', 'c/a/b/t') #=> true # ditto
3174 * File.fnmatch('ca[a-z]', 'cat') #=> true # inclusive bracket expression
3175 * File.fnmatch('ca[^t]', 'cat') #=> false # exclusive bracket expression ('^' or '!')
3176 *
3177 * File.fnmatch('cat', 'CAT') #=> false # case sensitive
3178 * File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true # case insensitive
3179 * File.fnmatch('cat', 'CAT', File::FNM_SYSCASE) #=> true or false # depends on the system default
3180 *
3181 * File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false # wildcard doesn't match '/' on FNM_PATHNAME
3182 * File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false # ditto
3183 * File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false # ditto
3184 *
3185 * File.fnmatch('\?', '?') #=> true # escaped wildcard becomes ordinary
3186 * File.fnmatch('\a', 'a') #=> true # escaped ordinary remains ordinary
3187 * File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true # FNM_NOESCAPE makes '\' ordinary
3188 * File.fnmatch('[\?]', '?') #=> true # can escape inside bracket expression
3189 *
3190 * File.fnmatch('*', '.profile') #=> false # wildcard doesn't match leading
3191 * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true # period by default.
3192 * File.fnmatch('.*', '.profile') #=> true
3193 *
3194 * rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string.
3195 * File.fnmatch(rbfiles, 'main.rb') #=> false
3196 * File.fnmatch(rbfiles, './main.rb') #=> false
3197 * File.fnmatch(rbfiles, 'lib/song.rb') #=> true
3198 * File.fnmatch('**.rb', 'main.rb') #=> true
3199 * File.fnmatch('**.rb', './main.rb') #=> false
3200 * File.fnmatch('**.rb', 'lib/song.rb') #=> true
3201 * File.fnmatch('*', 'dave/.profile') #=> true
3202 *
3203 * pattern = '*' '/' '*'
3204 * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME) #=> false
3205 * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
3206 *
3207 * pattern = '**' '/' 'foo'
3208 * File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME) #=> true
3209 * File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME) #=> true
3210 * File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true
3211 * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME) #=> false
3212 * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
3213 */
3214 static VALUE
3215 file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
3216 {
3217 VALUE pattern, path;
3218 VALUE rflags;
3219 int flags;
3220
3221 if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
3222 flags = NUM2INT(rflags);
3223 else
3224 flags = 0;
3225
3226 StringValueCStr(pattern);
3227 FilePathStringValue(path);
3228
3229 if (flags & FNM_EXTGLOB) {
3230 struct brace_args args;
3231
3232 args.value = path;
3233 args.flags = flags;
3234 if (ruby_brace_expand(RSTRING_PTR(pattern), flags, fnmatch_brace,
3235 (VALUE)&args, rb_enc_get(pattern), pattern) > 0)
3236 return Qtrue;
3237 }
3238 else {
3239 rb_encoding *enc = rb_enc_compatible(pattern, path);
3240 if (!enc) return Qfalse;
3241 if (fnmatch(RSTRING_PTR(pattern), enc, RSTRING_PTR(path), flags) == 0)
3242 return Qtrue;
3243 }
3244 RB_GC_GUARD(pattern);
3245
3246 return Qfalse;
3247 }
3248
3249 /*
3250 * call-seq:
3251 * Dir.home() -> "/home/me"
3252 * Dir.home("root") -> "/root"
3253 *
3254 * Returns the home directory of the current user or the named user
3255 * if given.
3256 */
3257 static VALUE
3258 dir_s_home(int argc, VALUE *argv, VALUE obj)
3259 {
3260 VALUE user;
3261 const char *u = 0;
3262
3263 rb_check_arity(argc, 0, 1);
3264 user = (argc > 0) ? argv[0] : Qnil;
3265 if (!NIL_P(user)) {
3266 SafeStringValue(user);
3267 rb_must_asciicompat(user);
3268 u = StringValueCStr(user);
3269 if (*u) {
3270 return rb_home_dir_of(user, rb_str_new(0, 0));
3271 }
3272 }
3273 return rb_default_home_dir(rb_str_new(0, 0));
3274
3275 }
3276
3277 #if 0
3278 /*
3279 * call-seq:
3280 * Dir.exist?(file_name) -> true or false
3281 *
3282 * Returns <code>true</code> if the named file is a directory,
3283 * <code>false</code> otherwise.
3284 *
3285 */
3286 VALUE
3287 rb_file_directory_p(void)
3288 {
3289 }
3290 #endif
3291
3292 /*
3293 * call-seq:
3294 * Dir.exists?(file_name) -> true or false
3295 *
3296 * Deprecated method. Don't use.
3297 */
3298 static VALUE
3299 rb_dir_exists_p(VALUE obj, VALUE fname)
3300 {
3301 rb_warning("Dir.exists? is a deprecated name, use Dir.exist? instead");
3302 return rb_file_directory_p(obj, fname);
3303 }
3304
3305 static void *
3306 nogvl_dir_empty_p(void *ptr)
3307 {
3308 const char *path = ptr;
3309 DIR *dir = opendir(path);
3310 struct dirent *dp;
3311 VALUE result = Qtrue;
3312
3313 if (!dir) {
3314 int e = errno;
3315 switch (gc_for_fd_with_gvl(e)) {
3316 default:
3317 dir = opendir(path);
3318 if (dir) break;
3319 e = errno;
3320 /* fall through */
3321 case 0:
3322 if (e == ENOTDIR) return (void *)Qfalse;
3323 errno = e; /* for rb_sys_fail_path */
3324 return (void *)Qundef;
3325 }
3326 }
3327 while ((dp = READDIR(dir, NULL)) != NULL) {
3328 if (!to_be_skipped(dp)) {
3329 result = Qfalse;
3330 break;
3331 }
3332 }
3333 closedir(dir);
3334 return (void *)result;
3335 }
3336
3337 /*
3338 * call-seq:
3339 * Dir.empty?(path_name) -> true or false
3340 *
3341 * Returns <code>true</code> if the named file is an empty directory,
3342 * <code>false</code> if it is not a directory or non-empty.
3343 */
3344 static VALUE
3345 rb_dir_s_empty_p(VALUE obj, VALUE dirname)
3346 {
3347 VALUE result, orig;
3348 const char *path;
3349 enum {false_on_notdir = 1};
3350
3351 FilePathValue(dirname);
3352 orig = rb_str_dup_frozen(dirname);
3353 dirname = rb_str_encode_ospath(dirname);
3354 dirname = rb_str_dup_frozen(dirname);
3355 path = RSTRING_PTR(dirname);
3356
3357 #if defined HAVE_GETATTRLIST && defined ATTR_DIR_ENTRYCOUNT
3358 {
3359 u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
3360 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
3361 if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) != 0)
3362 rb_sys_fail_path(orig);
3363 if (*(const fsobj_tag_t *)(attrbuf+1) == VT_HFS) {
3364 al.commonattr = 0;
3365 al.dirattr = ATTR_DIR_ENTRYCOUNT;
3366 if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) == 0) {
3367 if (attrbuf[0] >= 2 * sizeof(u_int32_t))
3368 return attrbuf[1] ? Qfalse : Qtrue;
3369 if (false_on_notdir) return Qfalse;
3370 }
3371 rb_sys_fail_path(orig);
3372 }
3373 }
3374 #endif
3375
3376 result = (VALUE)rb_thread_call_without_gvl(nogvl_dir_empty_p, (void *)path,
3377 RUBY_UBF_IO, 0);
3378 if (result == Qundef) {
3379 rb_sys_fail_path(orig);
3380 }
3381 return result;
3382 }
3383
3384 /*
3385 * Objects of class Dir are directory streams representing
3386 * directories in the underlying file system. They provide a variety
3387 * of ways to list directories and their contents. See also File.
3388 *
3389 * The directory used in these examples contains the two regular files
3390 * (<code>config.h</code> and <code>main.rb</code>), the parent
3391 * directory (<code>..</code>), and the directory itself
3392 * (<code>.</code>).
3393 */
3394 void
3395 Init_Dir(void)
3396 {
3397 rb_cDir = rb_define_class("Dir", rb_cObject);
3398
3399 rb_include_module(rb_cDir, rb_mEnumerable);
3400
3401 rb_define_alloc_func(rb_cDir, dir_s_alloc);
3402 rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1);
3403 rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
3404 rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
3405 rb_define_singleton_method(rb_cDir, "each_child", dir_s_each_child, -1);
3406 rb_define_singleton_method(rb_cDir, "children", dir_s_children, -1);
3407
3408 rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
3409 rb_define_method(rb_cDir,"fileno", dir_fileno, 0);
3410 rb_define_method(rb_cDir,"path", dir_path, 0);
3411 rb_define_method(rb_cDir,"to_path", dir_path, 0);
3412 rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
3413 rb_define_method(rb_cDir,"read", dir_read, 0);
3414 rb_define_method(rb_cDir,"each", dir_each, 0);
3415 rb_define_method(rb_cDir,"each_child", dir_each_child_m, 0);
3416 rb_define_method(rb_cDir,"children", dir_collect_children, 0);
3417 rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
3418 rb_define_method(rb_cDir,"tell", dir_tell, 0);
3419 rb_define_method(rb_cDir,"seek", dir_seek, 1);
3420 rb_define_method(rb_cDir,"pos", dir_tell, 0);
3421 rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
3422 rb_define_method(rb_cDir,"close", dir_close, 0);
3423
3424 rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
3425 rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
3426 rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
3427 rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
3428 rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
3429 rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
3430 rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
3431 rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
3432 rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
3433
3434 rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
3435 rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
3436 rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1);
3437 rb_define_singleton_method(rb_cDir,"exists?", rb_dir_exists_p, 1);
3438 rb_define_singleton_method(rb_cDir,"empty?", rb_dir_s_empty_p, 1);
3439
3440 rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
3441 rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
3442
3443 /* Document-const: File::Constants::FNM_NOESCAPE
3444 *
3445 * Disables escapes in File.fnmatch and Dir.glob patterns
3446 */
3447 rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
3448
3449 /* Document-const: File::Constants::FNM_PATHNAME
3450 *
3451 * Wildcards in File.fnmatch and Dir.glob patterns do not match directory
3452 * separators
3453 */
3454 rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
3455
3456 /* Document-const: File::Constants::FNM_DOTMATCH
3457 *
3458 * The '*' wildcard matches filenames starting with "." in File.fnmatch
3459 * and Dir.glob patterns
3460 */
3461 rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
3462
3463 /* Document-const: File::Constants::FNM_CASEFOLD
3464 *
3465 * Makes File.fnmatch patterns case insensitive (but not Dir.glob
3466 * patterns).
3467 */
3468 rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
3469
3470 /* Document-const: File::Constants::FNM_EXTGLOB
3471 *
3472 * Allows file globbing through "{a,b}" in File.fnmatch patterns.
3473 */
3474 rb_file_const("FNM_EXTGLOB", INT2FIX(FNM_EXTGLOB));
3475
3476 /* Document-const: File::Constants::FNM_SYSCASE
3477 *
3478 * System default case insensitiveness, equals to FNM_CASEFOLD or
3479 * 0.
3480 */
3481 rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
3482
3483 /* Document-const: File::Constants::FNM_SHORTNAME
3484 *
3485 * Makes patterns to match short names if existing. Valid only
3486 * on Microsoft Windows.
3487 */
3488 rb_file_const("FNM_SHORTNAME", INT2FIX(FNM_SHORTNAME));
3489 }
rb_w32_map_errno
int rb_w32_map_errno(DWORD)
Definition: win32.c:273
ruby_brace_glob
int ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
Definition: dir.c:2659
rb_file_directory_p
VALUE rb_file_directory_p(VALUE obj, VALUE fname)
Definition: file.c:1577
push_glob0_args::funcs
const ruby_glob_funcs_t * funcs
Definition: dir.c:2451
__attribute__
unsigned int UINT8 __attribute__((__mode__(__QI__)))
Definition: ffi_common.h:110
ISEND
#define ISEND(p)
Definition: dir.c:294
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Definition: class.c:1886
ISASCII
#define ISASCII(c)
Definition: ruby.h:2304
ID
unsigned long ID
Definition: ruby.h:103
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:649
rb_home_dir_of
VALUE rb_home_dir_of(VALUE user, VALUE result)
Definition: file.c:3536
glob_error_args::enc
rb_encoding * enc
Definition: dir.c:1956
void
void
Definition: rb_mjit_min_header-2.7.0.h:13273
opendir_at_arg::path
const char * path
Definition: dir.c:1433
AT_FDCWD
#define AT_FDCWD
Definition: dir.c:43
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1244
idTo_s
@ idTo_s
Definition: rb_mjit_min_header-2.7.0.h:8721
TRUE
#define TRUE
Definition: nkf.h:175
dir_data::enc
rb_encoding * enc
Definition: dir.c:444
dirent_brace_args::dp
const struct dirent * dp
Definition: dir.c:2035
stat
Definition: rb_mjit_min_header-2.7.0.h:2384
RSTRING_GETMEM
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Definition: ruby.h:1018
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:869
r2
#define r2
rb_gc_for_fd
int rb_gc_for_fd(int err)
Definition: io.c:953
rb_dir_getwd_ospath
VALUE rb_dir_getwd_ospath(void)
Definition: dir.c:1117
rb_str_new2
#define rb_str_new2
Definition: intern.h:903
IFTODT
#define IFTODT(m)
Definition: dir.c:178
rb_filesystem_encoding
rb_encoding * rb_filesystem_encoding(void)
Definition: encoding.c:1387
ENCINDEX_UTF_8
#define ENCINDEX_UTF_8
Definition: encindex.h:43
do_lstat
#define do_lstat
Definition: dir.c:1428
RB_PASS_CALLED_KEYWORDS
#define RB_PASS_CALLED_KEYWORDS
Definition: ruby.h:1980
dir_data
Definition: dir.c:441
chroot
int chroot(const char *__path)
rb_enc_codepoint
#define rb_enc_codepoint(p, e, enc)
Definition: encoding.h:207
rb_enc_mbclen
int rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc)
Definition: encoding.c:1020
close
int close(int __fildes)
path
VALUE path
Definition: rb_mjit_min_header-2.7.0.h:7351
mkdir_arg::path
const char * path
Definition: dir.c:1222
glob_call_func
#define glob_call_func(func, path, arg, enc)
Definition: dir.c:1943
push_glob_args::funcs
const ruby_glob_funcs_t * funcs
Definition: dir.c:2029
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:313
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:897
getenv
char * getenv()
rb_warning
void rb_warning(const char *fmt,...)
Definition: error.c:334
Next
#define Next(p, e, enc)
Definition: dir.c:216
rb_cDir
VALUE rb_cDir
Definition: dir.c:439
rb_funcallv_kw
VALUE rb_funcallv_kw(VALUE, ID, int, const VALUE *, int)
Definition: vm_eval.c:962
chdir_data::done
int done
Definition: dir.c:1007
rb_scan_args
#define rb_scan_args(argc, argvp, fmt,...)
Definition: rb_mjit_min_header-2.7.0.h:6372
USE_NAME_ON_FS
#define USE_NAME_ON_FS
Definition: dir.c:119
ALPHA
@ ALPHA
Definition: dir.c:1542
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:263
strchr
char * strchr(char *, char)
push_glob0_args::arg
VALUE arg
Definition: dir.c:2452
FNM_EXTGLOB
#define FNM_EXTGLOB
Definition: dir.c:201
ruby_glob_funcs_t::match
ruby_glob_func * match
Definition: dir.c:1382
DT_REG
#define DT_REG
Definition: dir.h:6
rb_dir_getwd
VALUE rb_dir_getwd(void)
Definition: dir.c:1141
chdir_data
Definition: dir.c:1005
rb_utf8_str_new_cstr
#define rb_utf8_str_new_cstr(str)
Definition: rb_mjit_min_header-2.7.0.h:6122
O_CLOEXEC
#define O_CLOEXEC
Definition: dir.c:28
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
NUM2LONG
#define NUM2LONG(x)
Definition: ruby.h:679
FNM_CASEFOLD
#define FNM_CASEFOLD
Definition: dir.c:200
dir_tell
#define dir_tell
Definition: dir.c:887
dir_s_chroot
#define dir_s_chroot
Definition: dir.c:1218
VALUE
unsigned long VALUE
Definition: ruby.h:102
closedir
#define closedir(d)
Definition: dir.h:43
rb_eArgError
VALUE rb_eArgError
Definition: error.c:923
encoding.h
rb_intern
#define rb_intern(str)
malloc
void * malloc(size_t) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__alloc_size__(1)))
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:560
GLOB_REALLOC
#define GLOB_REALLOC(ptr, size)
Definition: dir.c:1357
glob_args::baselen
size_t baselen
Definition: dir.c:1938
rb_str_to_cstr
char * rb_str_to_cstr(VALUE str)
Definition: string.c:2284
rb_thread_current
VALUE rb_thread_current(void)
Definition: thread.c:2676
rb_enc_get
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:872
push_glob_args::pathtype
rb_pathtype_t pathtype
Definition: dir.c:2027
rb_enc_asciicompat
#define rb_enc_asciicompat(enc)
Definition: encoding.h:245
FNM_NOESCAPE
#define FNM_NOESCAPE
Definition: dir.c:197
rb_ary_each
VALUE rb_ary_each(VALUE ary)
Definition: array.c:2129
rb_enc_check
rb_encoding * rb_enc_check(VALUE str1, VALUE str2)
Definition: encoding.c:891
rb_enc_precise_mbclen
int rb_enc_precise_mbclen(const char *p, const char *e, rb_encoding *enc)
Definition: encoding.c:1032
int
__inline__ int
Definition: rb_mjit_min_header-2.7.0.h:2839
dir_seek
#define dir_seek
Definition: dir.c:916
rb_sys_fail_path
#define rb_sys_fail_path(path)
Definition: internal.h:1627
rewinddir
#define rewinddir(d)
Definition: dir.h:42
id.h
MATCH_DIR
@ MATCH_DIR
Definition: dir.c:1542
push_glob0_args
Definition: dir.c:2447
rb_str_dup
VALUE rb_str_dup(VALUE)
Definition: string.c:1516
ISALPHA
#define ISALPHA(c)
Definition: ruby.h:2311
rb_str_cat2
#define rb_str_cat2
Definition: intern.h:912
RECURSIVE
@ RECURSIVE
Definition: dir.c:1542
Qundef
#define Qundef
Definition: ruby.h:470
path_unknown
@ path_unknown
Definition: dir.c:194
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1755
FNM_DOTMATCH
#define FNM_DOTMATCH
Definition: dir.c:199
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1551
FNM_SHORTNAME
#define FNM_SHORTNAME
Definition: dir.c:210
Data_Wrap_Struct
#define Data_Wrap_Struct(klass, mark, free, sval)
Definition: ruby.h:1211
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1609
rb_eIOError
RUBY_EXTERN VALUE rb_eIOError
Definition: ruby.h:2064
ptr
struct RIMemo * ptr
Definition: debug.c:74
push_glob0_args::flags
int flags
Definition: dir.c:2450
path_regular
@ path_regular
Definition: dir.c:190
Qfalse
#define Qfalse
Definition: ruby.h:467
Init_Dir
void Init_Dir(void)
Definition: dir.c:3393
dir_fileno
#define dir_fileno
Definition: dir.c:702
rb_get_path
VALUE rb_get_path(VALUE obj)
Definition: file.c:230
dirent_brace_args::name
const char * name
Definition: dir.c:2034
rb_external_str_with_enc
VALUE rb_external_str_with_enc(VALUE str, rb_encoding *eenc)
Definition: string.c:1074
FilePathValue
#define FilePathValue(v)
Definition: ruby.h:624
glob_pattern::type
enum glob_pattern_type type
Definition: dir.c:1661
u_int32_t
__uint32_t u_int32_t
Definition: rb_mjit_min_header-2.7.0.h:1159
dp
#define dp(v)
Definition: vm_debug.h:21
glob_pattern_type
glob_pattern_type
Definition: dir.c:1542
NULL
#define NULL
Definition: _sdbm.c:101
push_glob_args::dirsep
int dirsep
Definition: dir.c:2026
path_noent
@ path_noent
Definition: dir.c:193
uint32_t
unsigned int uint32_t
Definition: sha2.h:101
SafeStringValue
#define SafeStringValue(v)
Definition: ruby.h:607
FNM_SYSCASE
#define FNM_SYSCASE
Definition: dir.c:205
dirent
#define dirent
Definition: dir.c:54
ruby_glob_funcs_t::error
ruby_glob_errfunc * error
Definition: dir.c:1383
rb_enc_from_encoding
VALUE rb_enc_from_encoding(rb_encoding *encoding)
Definition: encoding.c:116
DT_UNKNOWN
#define DT_UNKNOWN
Definition: dir.h:4
error
const rb_iseq_t const char * error
Definition: rb_mjit_min_header-2.7.0.h:13506
strlen
size_t strlen(const char *)
GLOB_ALLOC_N
#define GLOB_ALLOC_N(type, n)
Definition: dir.c:1356
rb_cFile
VALUE rb_cFile
Definition: file.c:159
MAXPATHLEN
#define MAXPATHLEN
Definition: dln.c:69
S_IFLNK
#define S_IFLNK
Definition: win32.h:422
GLOB_JUMP_TAG
#define GLOB_JUMP_TAG(status)
Definition: dir.c:1359
rb_protect
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *pstate)
Protects a function call from potential global escapes from the function.
Definition: eval.c:1071
rb_check_arity
#define rb_check_arity
Definition: intern.h:347
rb_enc_str_new_cstr
VALUE rb_enc_str_new_cstr(const char *, rb_encoding *)
Definition: string.c:836
v
int VALUE v
Definition: rb_mjit_min_header-2.7.0.h:12332
rb_str_resize
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2709
rb_funcallv
#define rb_funcallv(recv, mid, argc, argv)
Definition: rb_mjit_min_header-2.7.0.h:7899
push_glob_args::namelen
size_t namelen
Definition: dir.c:2025
ruby_glob_errfunc
int ruby_glob_errfunc(const char *, VALUE, const void *, int)
Definition: dir.c:1380
glob_error_args
Definition: dir.c:1954
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2669
path_symlink
@ path_symlink
Definition: dir.c:191
rb_id_encoding
ID rb_id_encoding(void)
Definition: encoding.c:759
rb_int2inum
VALUE rb_int2inum(intptr_t n)
Definition: bignum.c:3208
brace_args::flags
int flags
Definition: dir.c:2634
opendir
#define opendir(s)
Definition: dir.h:38
RUBY_DEFAULT_FREE
#define RUBY_DEFAULT_FREE
Definition: ruby.h:1201
vm_initialized
#define vm_initialized
Definition: dir.c:85
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.0.h:5742
glob_pattern::next
struct glob_pattern * next
Definition: dir.c:1662
EIO
#define EIO
Definition: rb_mjit_min_header-2.7.0.h:10942
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
rb_syserr_fail
void rb_syserr_fail(int e, const char *mesg)
Definition: error.c:2781
rb_ascii8bit_encoding
rb_encoding * rb_ascii8bit_encoding(void)
Definition: encoding.c:1316
ruby_glob_funcs_t
Definition: dir.c:1381
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:1175
rb_sys_enc_warning
void rb_sys_enc_warning(rb_encoding *enc, const char *fmt,...)
Definition: error.c:2943
rb_encoding
const typedef OnigEncodingType rb_encoding
Definition: encoding.h:115
rb_must_asciicompat
void rb_must_asciicompat(VALUE)
Definition: string.c:2166
rb_check_frozen
#define rb_check_frozen(obj)
Definition: intern.h:319
memmove
#define memmove(dst, src, len)
Definition: rb_mjit_min_header-2.7.0.h:2848
GLOB_ALLOC
#define GLOB_ALLOC(type)
Definition: dir.c:1355
push_glob_args::path
const char * path
Definition: dir.c:2023
MAGICAL
@ MAGICAL
Definition: dir.c:1542
rb_file_const
void rb_file_const(const char *name, VALUE value)
Definition: file.c:6083
NORETURN
NORETURN(static void dir_closed(void))
i
uint32_t i
Definition: rb_mjit_min_header-2.7.0.h:5464
push_glob_args::baselen
size_t baselen
Definition: dir.c:2024
rb_str_dup_frozen
#define rb_str_dup_frozen
Definition: intern.h:792
EACCES
#define EACCES
Definition: rb_mjit_min_header-2.7.0.h:10950
mask
enum @11::@13::@14 mask
sys_warning
#define sys_warning(val, enc)
Definition: dir.c:1340
Inc
#define Inc(p, e, enc)
Definition: dir.c:217
IF_NORMALIZE_UTF8PATH
#define IF_NORMALIZE_UTF8PATH(something)
Definition: dir.c:174
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1195
ALWAYS_INLINE
ALWAYS_INLINE(static int to_be_ignored(int e))
IS_WIN32
#define IS_WIN32
Definition: dir.c:100
rb_enc_to_index
int rb_enc_to_index(rb_encoding *enc)
Definition: encoding.c:125
RUBY_UBF_IO
#define RUBY_UBF_IO
Definition: intern.h:945
SSIZE_MAX
#define SSIZE_MAX
Definition: ruby.h:323
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:2793
opendir_at_arg
Definition: dir.c:1431
rb_thread_call_without_gvl
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
dirent_brace_args
Definition: dir.c:2033
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: intern.h:279
rb_enc_compatible
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Definition: encoding.c:974
strlcpy
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
Definition: strlcpy.c:29
FALSE
#define FALSE
Definition: nkf.h:174
mkdir_arg::mode
mode_t mode
Definition: dir.c:1223
mkdir
int mkdir(const char *_path, mode_t __mode)
brace_args::value
VALUE value
Definition: dir.c:2633
dirent_brace_args::flags
int flags
Definition: dir.c:2036
DT_DIR
#define DT_DIR
Definition: dir.h:5
glob_pattern
Definition: dir.c:1659
brace_args::funcs
ruby_glob_funcs_t funcs
Definition: dir.c:2632
list
struct rb_encoding_entry * list
Definition: encoding.c:56
rmdir
int rmdir(const char *__path)
memcmp
int memcmp(const void *s1, const void *s2, size_t len)
Definition: memcmp.c:7
rb_str_new_cstr
#define rb_str_new_cstr(str)
Definition: rb_mjit_min_header-2.7.0.h:6117
rb_default_home_dir
VALUE rb_default_home_dir(VALUE result)
Definition: file.c:3576
rb_default_internal_encoding
rb_encoding * rb_default_internal_encoding(void)
Definition: encoding.c:1512
RB_OBJ_WRITE
#define RB_OBJ_WRITE(a, slot, b)
Definition: ruby.h:1508
ENOTDIR
#define ENOTDIR
Definition: rb_mjit_min_header-2.7.0.h:10957
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:604
rb_check_array_type
VALUE rb_check_array_type(VALUE ary)
Definition: array.c:909
push_glob0_args::base
const char * base
Definition: dir.c:2449
FNM_NOMATCH
#define FNM_NOMATCH
Definition: dir.c:213
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR(a)
Definition: ruby.h:1072
rb_glob
void rb_glob(const char *path, void(*func)(const char *, VALUE, void *), VALUE arg)
Definition: dir.c:2544
rb_typeddata_is_kind_of
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:872
NUM2MODET
#define NUM2MODET(v)
Definition: ruby.h:372
push_glob0_args::fd
int fd
Definition: dir.c:2448
push_glob_args::fd
int fd
Definition: dir.c:2022
CLASS_OF
#define CLASS_OF(v)
Definition: ruby.h:484
FNM_PATHNAME
#define FNM_PATHNAME
Definition: dir.c:198
warning_args
Definition: dir.c:1303
glob_args::path
const char * path
Definition: dir.c:1936
NAMLEN
#define NAMLEN(dirent)
Definition: dir.c:55
MBCLEN_CHARFOUND_P
#define MBCLEN_CHARFOUND_P(ret)
Definition: encoding.h:191
RARRAY_LEN
#define RARRAY_LEN(a)
Definition: ruby.h:1070
BRACE
@ BRACE
Definition: dir.c:1542
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:2010
n
const char size_t n
Definition: rb_mjit_min_header-2.7.0.h:5456
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4322
rb_syserr_fail_path
#define rb_syserr_fail_path(err, path)
Definition: internal.h:1628
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1252
path_exist
@ path_exist
Definition: dir.c:188
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2965
rb_enc_path_end
char * rb_enc_path_end(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:3440
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:634
internal.h
rb_to_encoding
rb_encoding * rb_to_encoding(VALUE enc)
Definition: encoding.c:245
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.0.h:5601
argv
char ** argv
Definition: ruby.c:223
rb_pathtype_t
rb_pathtype_t
Definition: dir.c:181
PLAIN
@ PLAIN
Definition: dir.c:1542
rb_syserr_enc_warning
void rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt,...)
Definition: error.c:2955
klass
VALUE klass
Definition: rb_mjit_min_header-2.7.0.h:13254
rb_str_subseq
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:2474
ruby_brace_glob_with_enc
int ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
Definition: dir.c:2646
rb_utf8_encoding
rb_encoding * rb_utf8_encoding(void)
Definition: encoding.c:1328
path_directory
@ path_directory
Definition: dir.c:189
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
chdir_data::new_path
VALUE new_path
Definition: dir.c:1006
telldir
#define telldir(d)
Definition: dir.h:40
ruby_glob
int ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
Definition: dir.c:2519
fstatat
int fstatat(int, const char *__restrict, struct stat *__restrict, int)
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1207
ENC_CODERANGE_7BIT
#define ENC_CODERANGE_7BIT
Definition: encoding.h:104
MEMCPY
#define MEMCPY(p1, p2, type, n)
Definition: ruby.h:1753
dir_data::dir
DIR * dir
Definition: dir.c:442
STAT
#define STAT(p, s)
Definition: dir.c:1377
dir_data::path
const VALUE path
Definition: dir.c:443
ENOENT
#define ENOENT
Definition: rb_mjit_min_header-2.7.0.h:10939
warning_args::enc
rb_encoding * enc
Definition: dir.c:1308
rb_str_encode_ospath
VALUE rb_str_encode_ospath(VALUE path)
Definition: file.c:236
NIL_P
#define NIL_P(v)
Definition: ruby.h:482
GLOB_VERBOSE
#define GLOB_VERBOSE
Definition: dir.c:1339
rb_external_str_new_with_enc
VALUE rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *)
Definition: string.c:1036
argc
int argc
Definition: ruby.c:222
DIR
Definition: dir.h:18
st
enum ruby_tag_type st
Definition: rb_mjit_min_header-2.7.0.h:11111
free
#define free(x)
Definition: dln.c:52
READDIR
#define READDIR(dir, enc)
Definition: dir.c:740
rb_enc_toupper
int rb_enc_toupper(int c, rb_encoding *enc)
Definition: encoding.c:1106
encindex.h
basename
#define basename
Definition: rb_mjit_min_header-2.7.0.h:2815
rb_data_type_struct
Definition: ruby.h:1148
xfree
#define xfree
Definition: defines.h:216
ruby_getcwd
char * ruby_getcwd(void)
Definition: util.c:539
ruby_glob_func
int ruby_glob_func(const char *, VALUE, void *)
Definition: ruby.h:1768
glob_args::value
VALUE value
Definition: dir.c:1939
opendir_at_arg::basefd
int basefd
Definition: dir.c:1432
mkdir_arg
Definition: dir.c:1221
rb_str_new
#define rb_str_new(str, len)
Definition: rb_mjit_min_header-2.7.0.h:6116
MATCH_ALL
@ MATCH_ALL
Definition: dir.c:1542
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:5212
S_IFDIR
#define S_IFDIR
Definition: rb_mjit_min_header-2.7.0.h:2425
rb_check_typeddata
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:889
glob_args::base
const char * base
Definition: dir.c:1937
ENCINDEX_US_ASCII
#define ENCINDEX_US_ASCII
Definition: encindex.h:44
Qtrue
#define Qtrue
Definition: ruby.h:468
errno
int errno
warning_args::mesg
const char * mesg
Definition: dir.c:1307
rb_class_name
VALUE rb_class_name(VALUE)
Definition: variable.c:274
rb_enc_path_skip_prefix
char * rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:3372
GLOB_FREE
#define GLOB_FREE(ptr)
Definition: dir.c:1358
sys_enc_warning_in
#define sys_enc_warning_in(func, mesg, enc)
Definition: dir.c:1312
push_glob_args::arg
VALUE arg
Definition: dir.c:2030
len
uint8_t len
Definition: escape.c:17
rb_memerror
void rb_memerror(void)
Definition: gc.c:9578
dir_set_pos
#define dir_set_pos
Definition: dir.c:940
S_IFREG
#define S_IFREG
Definition: rb_mjit_min_header-2.7.0.h:2428
T_STRING
#define T_STRING
Definition: ruby.h:528
FilePathStringValue
#define FilePathStringValue(v)
Definition: ruby.h:627
rb_w32_reparse_symlink_p
int rb_w32_reparse_symlink_p(const WCHAR *path)
Definition: win32.c:4987
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1237
glob_args::enc
rb_encoding * enc
Definition: dir.c:1940
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1114
ENCINDEX_ASCII
#define ENCINDEX_ASCII
Definition: encindex.h:42
rb_enc_str_asciionly_p
int rb_enc_str_asciionly_p(VALUE)
Definition: string.c:678
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:723
UNESCAPE
#define UNESCAPE(p)
Definition: dir.c:293
DT_LNK
#define DT_LNK
Definition: dir.h:7
glob_pattern::str
char * str
Definition: dir.c:1660
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:715
Qnil
#define Qnil
Definition: ruby.h:469
dir.h
thread.h
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:20
h
size_t st_index_t h
Definition: rb_mjit_min_header-2.7.0.h:5462
mode_t
__mode_t mode_t
Definition: rb_mjit_min_header-2.7.0.h:1331
util.h
GetDIR
#define GetDIR(obj, dirp)
Definition: dir.c:635
RB_GC_GUARD
#define RB_GC_GUARD(v)
Definition: ruby.h:585
rb_str_coderange_scan_restartable
long rb_str_coderange_scan_restartable(const char *, const char *, rb_encoding *, int *)
Definition: string.c:567
push_glob_args::flags
int flags
Definition: dir.c:2028
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:1005
lstat
int lstat(const char *__restrict __path, struct stat *__restrict __buf)
RETURN
#define RETURN(val)
Definition: dir.c:295
push_glob_args
Definition: dir.c:2021
glob_args
Definition: dir.c:1934
rb_str_conv_enc
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Definition: string.c:1030
rb_enc_str_new
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:796
seekdir
#define seekdir(d, l)
Definition: dir.h:41
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
glob_error_args::path
const char * path
Definition: dir.c:1955
brace_args
Definition: dir.c:2631
glob_args::func
void(* func)(const char *, VALUE, void *)
Definition: dir.c:1935
chdir_data::old_path
VALUE old_path
Definition: dir.c:1006
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
rb_thread_call_with_gvl
RUBY_SYMBOL_EXPORT_BEGIN void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
Definition: thread.c:1662
rb_w32_conv_from_wchar
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
Definition: win32.c:2229
RUBY_TYPED_WB_PROTECTED
#define RUBY_TYPED_WB_PROTECTED
Definition: ruby.h:1208
rb_enc_associate_index
VALUE rb_enc_associate_index(VALUE obj, int idx)
Definition: encoding.c:838
rb_usascii_encoding
rb_encoding * rb_usascii_encoding(void)
Definition: encoding.c:1340
rb_syserr_fail_str
void rb_syserr_fail_str(int e, VALUE mesg)
Definition: error.c:2787
rb_w32_mbstr_to_wstr
WCHAR * rb_w32_mbstr_to_wstr(UINT, const char *, int, long *)
Definition: win32.c:2149
chdir
int chdir(const char *__path)
name
const char * name
Definition: nkf.c:208
glob_error_args::error
int error
Definition: dir.c:1957