Ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5ad0e4688e963d9de019557c78feed9)
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
74char *getenv();
75#endif
76
77#ifndef HAVE_STRING_H
78char *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
140static inline int
141need_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
163static inline int
164has_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
179#ifndef IFTODT
180# define IFTODT(m) (((m) & S_IFMT) / ((~S_IFMT & (S_IFMT-1)) + 1))
181#endif
182
183typedef enum {
184#ifdef DT_UNKNOWN
189#else
194#endif
196 path_unknown = -2
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
215#define FNM_NOMATCH 1
216#define FNM_ERROR 2
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
221static char *
222bracket(
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.
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
299static int
300fnmatch_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 */
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))
334 ptmp = p;
335 stmp = s;
336 continue;
337
338 case '?':
339 if (ISEND(s))
341 p++;
342 Inc(s, send, enc);
343 continue;
344
345 case '[': {
346 const char *t;
347 if (ISEND(s))
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 }
388 }
389}
390
391static int
392fnmatch(
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);
440
443struct dir_data {
445 const VALUE path;
447};
448
449static void
450dir_mark(void *ptr)
451{
452 struct dir_data *dir = ptr;
453 rb_gc_mark(dir->path);
454}
455
456static void
457dir_free(void *ptr)
458{
459 struct dir_data *dir = ptr;
460
461 if (dir->dir) closedir(dir->dir);
462 xfree(dir);
463}
464
465static size_t
466dir_memsize(const void *ptr)
467{
468 return sizeof(struct dir_data);
469}
470
471static const rb_data_type_t dir_data_type = {
472 "dir",
473 {dir_mark, dir_free, dir_memsize,},
475};
476
477static VALUE dir_close(VALUE);
478
479static VALUE
480dir_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
492static void *
493nogvl_opendir(void *ptr)
494{
495 const char *path = ptr;
496
497 return (void *)opendir(path);
498}
499
500static DIR *
501opendir_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 */
524static VALUE
525dir_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 */
600static VALUE
601dir_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;
613
614NORETURN(static void dir_closed(void));
615
616static void
617dir_closed(void)
618{
619 rb_raise(rb_eIOError, "closed directory");
620}
621
622static struct dir_data *
623dir_get(VALUE dir)
624{
626 return rb_check_typeddata(dir, &dir_data_type);
627}
628
629static struct dir_data *
630dir_check(VALUE dir)
631{
632 struct dir_data *dirp = dir_get(dir);
633 if (!dirp->dir) dir_closed();
634 return dirp;
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 */
646static VALUE
647dir_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("#<");
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 */
691static VALUE
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);
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 */
717static VALUE
718dir_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
728static int
729fundamental_encoding_p(rb_encoding *enc)
730{
731 switch (rb_enc_to_index(enc)) {
732 case ENCINDEX_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 */
746static int
747to_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 */
780static VALUE
781dir_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
798static VALUE dir_each_entry(VALUE, VALUE (*)(VALUE, VALUE), VALUE, int);
799
800static VALUE
801dir_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 */
826static VALUE
827dir_each(VALUE dir)
828{
829 RETURN_ENUMERATOR(dir, 0, 0);
830 return dir_each_entry(dir, dir_yield, Qnil, FALSE);
831}
832
833static VALUE
834dir_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))) {
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 */
878static VALUE
879dir_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);
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 */
907static VALUE
909{
910 struct dir_data *dirp;
911 long p = NUM2LONG(pos);
912
913 GetDIR(dir, dirp);
914 seekdir(dirp->dir, p);
915 return dir;
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 */
935static VALUE
937{
938 dir_seek(dir, pos);
939 return pos;
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 */
956static VALUE
957dir_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 */
976static VALUE
977dir_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
989static void *
990nogvl_chdir(void *ptr)
991{
992 const char *path = ptr;
993
994 return (void *)(VALUE)chdir(path);
995}
996
997static void
998dir_chdir(VALUE path)
999{
1000 if (chdir(RSTRING_PTR(path)) < 0)
1002}
1003
1004static int chdir_blocking = 0;
1005static VALUE chdir_thread = Qnil;
1009 int done;
1010};
1011
1012static VALUE
1013chdir_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
1024static VALUE
1025chdir_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 */
1076static VALUE
1077dir_s_chdir(int argc, VALUE *argv, VALUE obj)
1078{
1079 VALUE path = Qnil;
1080
1081 if (rb_check_arity(argc, 0, 1) == 1) {
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
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)
1112 }
1113
1114 return INT2FIX(0);
1115}
1116
1117#ifndef _WIN32
1118VALUE
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
1142VALUE
1143rb_dir_getwd(void)
1144{
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 */
1174static VALUE
1175dir_s_getwd(VALUE dir)
1176{
1177 return rb_dir_getwd();
1178}
1179
1180static VALUE
1181check_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 */
1210static VALUE
1212{
1213 path = check_dirname(path);
1214 if (chroot(RSTRING_PTR(path)) == -1)
1216
1217 return INT2FIX(0);
1219#else
1220#define dir_s_chroot rb_f_notimplement
1221#endif
1224 const char *path;
1225 mode_t mode;
1226};
1227
1228static void *
1229nogvl_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 */
1250static VALUE
1251dir_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)
1269
1270 return INT2FIX(0);
1271}
1272
1273static void *
1274nogvl_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 */
1290static VALUE
1291dir_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);
1304
1305struct warning_args {
1306#ifdef RUBY_FUNCTION_NAME_STRING
1307 const char *func;
1308#endif
1309 const char *mesg;
1311};
1313#ifndef RUBY_FUNCTION_NAME_STRING
1314#define sys_enc_warning_in(func, mesg, enc) sys_enc_warning(mesg, enc)
1315#endif
1316
1317static VALUE
1318sys_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
1329static void
1330sys_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);
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
1345static inline void *
1346glob_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 }
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 */
1367ALWAYS_INLINE(static int to_be_ignored(int e));
1368static inline int
1369to_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
1382typedef int ruby_glob_errfunc(const char*, VALUE, const void*, int);
1383typedef struct {
1384 ruby_glob_func *match;
1387
1388static const char *
1389at_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 */
1401static int
1402do_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
1416static int
1417do_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;
1429#else
1430#define do_lstat do_stat
1431#endif
1434 int basefd;
1435 const char *path;
1436};
1437
1438static void *
1439with_gvl_gc_for_fd(void *ptr)
1440{
1441 int *e = ptr;
1442
1443 return (void *)(rb_gc_for_fd(*e) ? Qtrue : Qfalse);
1444}
1445
1446static int
1447gc_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
1455static void *
1456nogvl_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
1495static DIR *
1496opendir_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
1509static DIR *
1510do_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}
1543/* Globing pattern */
1545
1546/* Return nonzero if S has any special globbing chars in it. */
1547static enum glob_pattern_type
1548has_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. */
1594static char *
1595find_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 */
1636static char *
1637remove_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;
1662 char *str;
1664 struct glob_pattern *next;
1665};
1666
1667static void glob_free_pattern(struct glob_pattern *list);
1668
1669static struct glob_pattern *
1670glob_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
1737static void
1738glob_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
1749static char *
1750join_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
1770static int
1771is_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
1794static char *
1795replace_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
1846VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
1847int rb_w32_reparse_symlink_p(const WCHAR *path);
1848
1849static char *
1850replace_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 :
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
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
1937 void (*func)(const char *, VALUE, void *);
1938 const char *path;
1939 const char *base;
1940 size_t baselen;
1941 VALUE value;
1944
1945#define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (void *)(enc))
1946
1947static VALUE
1948glob_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;
1957 const char *path;
1959 int error;
1960};
1961
1962static VALUE
1963glob_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
1971static int
1972rb_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
1985static VALUE
1986glob_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
1994static int
1995rb_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
2011static inline int
2012dirent_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;
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' */
2031 const ruby_glob_funcs_t *funcs;
2032 VALUE arg;
2036 const char *name;
2037 const struct dirent *dp;
2038 int flags;
2039};
2040
2041static int
2042dirent_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() */
2050static char*
2051join_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
2095static int push_caller(const char *path, VALUE val, void *enc);
2096
2097static int ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
2098 rb_encoding *enc, VALUE var);
2099
2100static int
2101glob_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 {
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 {
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,
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
2428static int
2429push_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
2446static int ruby_glob0(const char *path, int fd, const char *base, int flags,
2450 int fd;
2451 const char *base;
2453 const ruby_glob_funcs_t *funcs;
2454 VALUE arg;
2455};
2456
2457static int
2458push_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
2464static int
2465ruby_glob0(const char *path, int fd, const char *base, int flags,
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}
2520int
2521ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
2522{
2524 funcs.match = func;
2525 funcs.error = NULL;
2526 return ruby_glob0(path, AT_FDCWD, 0, flags & ~GLOB_VERBOSE,
2528}
2529
2530static int
2531rb_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
2541static const ruby_glob_funcs_t rb_glob_funcs = {
2542 rb_glob_caller, rb_glob_error,
2543};
2545void
2546rb_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
2560static void
2561push_pattern(const char *path, VALUE ary, void *enc)
2562{
2563#if defined _WIN32 || defined __APPLE__
2566 name = rb_str_conv_enc(name, NULL, eenc ? eenc : enc);
2567#else
2569#endif
2570 rb_ary_push(ary, name);
2571}
2572
2573static int
2574ruby_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;
2635 VALUE value;
2636 int flags;
2637};
2638
2639static int
2640glob_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}
2647int
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}
2660int
2661ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
2662{
2664}
2665
2666static int
2667push_glob(VALUE ary, VALUE str, VALUE base, int flags)
2668{
2669 struct glob_args args;
2670 int fd;
2672
2673#if defined _WIN32 || defined __APPLE__
2675#endif
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__
2700#endif
2701
2702 return ruby_glob0(RSTRING_PTR(str), fd, args.base, flags, &rb_glob_funcs,
2703 (VALUE)&args, enc);
2704}
2705
2706static VALUE
2707rb_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)) {
2715 }
2716 else if (!rb_str_to_cstr(str)) {
2717 rb_raise(rb_eArgError, "nul-separated glob pattern is deprecated");
2718 }
2719 else {
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
2730static VALUE
2731dir_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];
2740 status = push_glob(ary, str, base, flags);
2741 if (status) GLOB_JUMP_TAG(status);
2742 }
2743
2744 return ary;
2745}
2746
2747static void
2748dir_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 */
2781static VALUE
2782dir_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 */
2881static VALUE
2882dir_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
2911static VALUE
2912dir_open_dir(int argc, VALUE *argv)
2913{
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 */
2943static VALUE
2944dir_foreach(int argc, VALUE *argv, VALUE io)
2945{
2946 VALUE dir;
2947
2949 dir = dir_open_dir(argc, argv);
2950 rb_ensure(dir_each, dir, dir_close, dir);
2951 return Qnil;
2952}
2953
2954static VALUE
2955dir_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 */
2977static VALUE
2978dir_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
2986static VALUE
2987dir_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 */
3013static VALUE
3014dir_s_each_child(int argc, VALUE *argv, VALUE io)
3015{
3016 VALUE dir;
3017
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 */
3044static VALUE
3045dir_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 */
3062static VALUE
3063dir_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 */
3085static VALUE
3086dir_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
3094static int
3095fnmatch_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;
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 */
3214static VALUE
3215file_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);
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 */
3257static VALUE
3258dir_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 */
3286VALUE
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 */
3298static VALUE
3299rb_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
3305static void *
3306nogvl_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 */
3344static VALUE
3345rb_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>).
3394void
3395Init_Dir(void)
3396{
3398
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);
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);
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);
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}
int errno
enum @73::@75::@76 mask
struct RIMemo * ptr
Definition: debug.c:65
VALUE rb_dir_getwd(void)
Definition: dir.c:1141
#define FNM_NOESCAPE
Definition: dir.c:197
NORETURN(static void dir_closed(void))
#define USE_NAME_ON_FS
Definition: dir.c:119
#define STAT(p, s)
Definition: dir.c:1377
VALUE rb_dir_getwd_ospath(void)
Definition: dir.c:1117
char * strchr(char *, char)
VALUE rb_cDir
Definition: dir.c:439
#define READDIR(dir, enc)
Definition: dir.c:740
#define AT_FDCWD
Definition: dir.c:43
#define GLOB_JUMP_TAG(status)
Definition: dir.c:1359
#define Next(p, e, enc)
Definition: dir.c:216
#define sys_enc_warning_in(func, mesg, enc)
Definition: dir.c:1312
#define glob_call_func(func, path, arg, enc)
Definition: dir.c:1943
#define GLOB_ALLOC_N(type, n)
Definition: dir.c:1356
#define FNM_EXTGLOB
Definition: dir.c:201
ALWAYS_INLINE(static int to_be_ignored(int e))
int ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
Definition: dir.c:2646
#define IF_NORMALIZE_UTF8PATH(something)
Definition: dir.c:174
#define GLOB_ALLOC(type)
Definition: dir.c:1355
#define RETURN(val)
Definition: dir.c:295
int ruby_glob_errfunc(const char *, VALUE, const void *, int)
Definition: dir.c:1380
#define UNESCAPE(p)
Definition: dir.c:293
#define do_lstat
Definition: dir.c:1428
#define ISEND(p)
Definition: dir.c:294
#define dirent
Definition: dir.c:54
#define GLOB_FREE(ptr)
Definition: dir.c:1358
#define GLOB_REALLOC(ptr, size)
Definition: dir.c:1357
#define FNM_SYSCASE
Definition: dir.c:205
#define vm_initialized
Definition: dir.c:85
void Init_Dir(void)
Definition: dir.c:3393
rb_pathtype_t
Definition: dir.c:181
@ path_noent
Definition: dir.c:193
@ path_symlink
Definition: dir.c:191
@ path_exist
Definition: dir.c:188
@ path_regular
Definition: dir.c:190
@ path_directory
Definition: dir.c:189
@ path_unknown
Definition: dir.c:194
#define sys_warning(val, enc)
Definition: dir.c:1340
#define GetDIR(obj, dirp)
Definition: dir.c:635
#define Inc(p, e, enc)
Definition: dir.c:217
#define GLOB_VERBOSE
Definition: dir.c:1339
glob_pattern_type
Definition: dir.c:1542
@ MATCH_ALL
Definition: dir.c:1542
@ MATCH_DIR
Definition: dir.c:1542
@ ALPHA
Definition: dir.c:1542
@ MAGICAL
Definition: dir.c:1542
@ RECURSIVE
Definition: dir.c:1542
@ PLAIN
Definition: dir.c:1542
@ BRACE
Definition: dir.c:1542
#define NAMLEN(dirent)
Definition: dir.c:55
char * getenv()
#define IS_WIN32
Definition: dir.c:100
#define FNM_CASEFOLD
Definition: dir.c:200
#define O_CLOEXEC
Definition: dir.c:28
#define dir_fileno
Definition: dir.c:702
#define dir_s_chroot
Definition: dir.c:1218
#define dir_set_pos
Definition: dir.c:940
#define IFTODT(m)
Definition: dir.c:178
#define FNM_DOTMATCH
Definition: dir.c:199
#define FNM_PATHNAME
Definition: dir.c:198
#define dir_seek
Definition: dir.c:916
#define FNM_SHORTNAME
Definition: dir.c:210
#define FNM_NOMATCH
Definition: dir.c:213
#define dir_tell
Definition: dir.c:887
#define DT_DIR
Definition: dir.h:5
#define DT_UNKNOWN
Definition: dir.h:4
#define rewinddir(d)
Definition: dir.h:42
#define seekdir(d, l)
Definition: dir.h:41
#define DT_REG
Definition: dir.h:6
#define DT_LNK
Definition: dir.h:7
#define opendir(s)
Definition: dir.h:38
#define telldir(d)
Definition: dir.h:40
#define closedir(d)
Definition: dir.h:43
#define free(x)
Definition: dln.c:52
#define ENCINDEX_UTF_8
Definition: encindex.h:43
#define ENCINDEX_US_ASCII
Definition: encindex.h:44
#define ENCINDEX_ASCII
Definition: encindex.h:42
struct rb_encoding_entry * list
Definition: encoding.c:56
int rb_enc_precise_mbclen(const char *p, const char *e, rb_encoding *enc)
Definition: encoding.c:1032
rb_encoding * rb_utf8_encoding(void)
Definition: encoding.c:1328
rb_encoding * rb_ascii8bit_encoding(void)
Definition: encoding.c:1316
rb_encoding * rb_filesystem_encoding(void)
Definition: encoding.c:1387
rb_encoding * rb_default_internal_encoding(void)
Definition: encoding.c:1512
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:872
int rb_enc_to_index(rb_encoding *enc)
Definition: encoding.c:125
rb_encoding * rb_enc_check(VALUE str1, VALUE str2)
Definition: encoding.c:891
int rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc)
Definition: encoding.c:1020
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Definition: encoding.c:974
rb_encoding * rb_to_encoding(VALUE enc)
Definition: encoding.c:245
int rb_enc_toupper(int c, rb_encoding *enc)
Definition: encoding.c:1106
rb_encoding * rb_usascii_encoding(void)
Definition: encoding.c:1340
VALUE rb_enc_from_encoding(rb_encoding *encoding)
Definition: encoding.c:116
VALUE rb_enc_associate_index(VALUE obj, int idx)
Definition: encoding.c:838
#define ENC_CODERANGE_7BIT
Definition: encoding.h:104
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Definition: string.c:1030
VALUE rb_enc_str_new_cstr(const char *, rb_encoding *)
Definition: string.c:836
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:796
#define rb_enc_asciicompat(enc)
Definition: encoding.h:245
#define rb_enc_codepoint(p, e, enc)
Definition: encoding.h:207
int rb_enc_str_asciionly_p(VALUE)
Definition: string.c:678
long rb_str_coderange_scan_restartable(const char *, const char *, rb_encoding *, int *)
Definition: string.c:567
#define MBCLEN_CHARFOUND_P(ret)
Definition: encoding.h:191
VALUE rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *)
Definition: string.c:1036
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
char * rb_enc_path_end(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:3480
char * rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:3412
void rb_memerror(void)
Definition: gc.c:9611
void rb_include_module(VALUE, VALUE)
Definition: class.c:882
VALUE rb_define_class(const char *, VALUE)
Defines a top-level class.
Definition: class.c:662
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:898
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *)
Definition: class.c:1904
void rb_glob(const char *path, void(*func)(const char *, VALUE, void *), VALUE arg)
Definition: dir.c:2544
VALUE rb_cFile
Definition: file.c:159
VALUE rb_cObject
Object class.
Definition: ruby.h:2012
int ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
Definition: dir.c:2659
int ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
Definition: dir.c:2519
VALUE rb_eIOError
Definition: ruby.h:2066
VALUE rb_mEnumerable
Definition: enum.c:20
void rb_syserr_fail(int e, const char *mesg)
Definition: error.c:2783
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
void rb_sys_enc_warning(rb_encoding *enc, const char *fmt,...)
Definition: error.c:2945
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:874
void rb_bug(const char *fmt,...)
Definition: error.c:636
void rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt,...)
Definition: error.c:2957
void rb_syserr_fail_str(int e, VALUE mesg)
Definition: error.c:2789
VALUE rb_protect(VALUE(*)(VALUE), VALUE, int *)
Protects a function call from potential global escapes from the function.
Definition: eval.c:1072
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:891
void rb_warn(const char *fmt,...)
Definition: error.c:315
VALUE rb_eArgError
Definition: error.c:925
VALUE rb_ensure(VALUE(*)(VALUE), VALUE, VALUE(*)(VALUE), VALUE)
An equivalent to ensure clause.
Definition: eval.c:1115
void rb_sys_fail(const char *mesg)
Definition: error.c:2795
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
const char * name
Definition: nkf.c:208
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4322
VALUE rb_class_name(VALUE)
Definition: variable.c:274
#define RARRAY_LEN(a)
__uint32_t uint32_t
#define SafeStringValue(v)
#define rb_str_new2
#define ENOENT
#define MEMCPY(p1, p2, type, n)
#define NULL
#define rb_funcallv(recv, mid, argc, argv)
int memcmp(const void *, const void *, size_t)
Definition: memcmp.c:7
void rb_file_const(const char *, VALUE)
Definition: file.c:6144
#define dp(v)
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2709
#define RSTRING_LEN(str)
#define S_IFDIR
VALUE rb_int2inum(intptr_t)
Definition: bignum.c:3208
#define S_IFREG
enum ruby_tag_type st
#define rb_syserr_fail_path(err, path)
void rb_must_asciicompat(VALUE)
Definition: string.c:2166
int rmdir(const char *__path)
size_t strlen(const char *)
#define T_STRING
#define rb_utf8_str_new_cstr(str)
void * malloc(size_t) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__alloc_size__(1)))
VALUE rb_str_encode_ospath(VALUE)
Definition: file.c:236
#define Data_Wrap_Struct(klass, mark, free, sval)
int close(int __fildes)
#define xfree
#define SSIZE_MAX
#define RUBY_TYPED_WB_PROTECTED
#define Qundef
#define rb_str_cat2
#define rb_sys_fail_path(path)
const VALUE VALUE obj
#define rb_check_frozen(obj)
VALUE rb_ary_each(VALUE)
Definition: array.c:2129
int chroot(const char *__path)
VALUE rb_funcallv_kw(VALUE, ID, int, const VALUE *, int)
Definition: vm_eval.c:962
VALUE rb_file_directory_p(VALUE, VALUE)
Definition: file.c:1617
#define RSTRING_PTR(str)
const rb_iseq_t const char * error
#define RUBY_UBF_IO
#define rb_str_new(str, len)
#define NIL_P(v)
const char size_t n
#define basename
const char const char *typedef unsigned long VALUE
VALUE rb_ary_push(VALUE, VALUE)
Definition: array.c:1195
size_t strlcpy(char *, const char *, size_t)
Definition: strlcpy.c:29
int rb_gc_for_fd(int err)
Definition: io.c:953
#define FilePathValue(v)
() void(cc->call !=vm_call_general)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
uint32_t i
#define RSTRING_GETMEM(str, ptrvar, lenvar)
__inline__ const void *__restrict__ size_t len
int lstat(const char *__restrict__ __path, struct stat *__restrict__ __buf)
#define INT2NUM(x)
#define RB_OBJ_WRITE(a, slot, b)
#define NUM2INT(x)
void rb_define_singleton_method(VALUE, const char *, VALUE(*)(), int)
#define RB_GC_GUARD(v)
#define RUBY_TYPED_FREE_IMMEDIATELY
#define TypedData_Get_Struct(obj, type, data_type, sval)
#define ENOTDIR
int VALUE v
VALUE rb_ary_new(void)
Definition: array.c:723
ID rb_id_encoding(void)
Definition: encoding.c:759
#define rb_scan_args(argc, argvp, fmt,...)
#define RB_PASS_CALLED_KEYWORDS
void rb_gc_mark(VALUE)
Definition: gc.c:5228
#define rb_intern(str)
#define NUM2MODET(v)
#define TRUE
#define FALSE
#define Qtrue
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:2474
int ruby_glob_func(const char *, VALUE, void *)
#define memmove(dst, src, len)
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2965
#define Qnil
#define Qfalse
__uint32_t u_int32_t
#define DATA_PTR(dta)
#define RUBY_DEFAULT_FREE
void * memcpy(void *__restrict__, const void *__restrict__, size_t)
#define EACCES
VALUE rb_thread_current(void)
Definition: thread.c:2675
#define RB_TYPE_P(obj, type)
#define INT2FIX(i)
VALUE rb_check_array_type(VALUE)
Definition: array.c:909
#define rb_str_dup_frozen
#define TypedData_Make_Struct(klass, type, data_type, sval)
const VALUE * argv
char * rb_str_to_cstr(VALUE str)
Definition: string.c:2284
int fstatat(int, const char *__restrict__, struct stat *__restrict__, int)
VALUE rb_get_path(VALUE)
Definition: file.c:230
__inline__ int
#define CLASS_OF(v)
#define RETURN_ENUMERATOR(obj, argc, argv)
#define rb_check_arity
#define FilePathStringValue(v)
#define MAXPATHLEN
VALUE rb_home_dir_of(VALUE user, VALUE result)
Definition: file.c:3576
VALUE rb_str_dup(VALUE)
Definition: string.c:1516
unsigned long ID
rb_control_frame_t * __attribute__((__fastcall__)) *rb_insn_func_t)(rb_execution_context_t *
int chdir(const char *__path)
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1237
const char *void rb_warning(const char *,...) __attribute__((format(printf
size_t st_index_t h
__mode_t mode_t
#define NUM2LONG(x)
void rb_define_method(VALUE, const char *, VALUE(*)(), int)
#define rb_str_new_cstr(str)
#define RARRAY_CONST_PTR(a)
#define ISASCII(c)
int mkdir(const char *_path, mode_t __mode)
#define StringValueCStr(v)
#define ISALPHA(c)
#define S_IFLNK
VALUE rb_default_home_dir(VALUE result)
Definition: file.c:3616
unsigned long VALUE
Definition: ruby.h:102
#define r2
VALUE rb_external_str_with_enc(VALUE str, rb_encoding *eenc)
Definition: string.c:1074
Definition: dir.h:18
int flags
Definition: dir.c:2634
VALUE value
Definition: dir.c:2633
ruby_glob_funcs_t funcs
Definition: dir.c:2632
VALUE old_path
Definition: dir.c:1006
VALUE new_path
Definition: dir.c:1006
int done
Definition: dir.c:1007
Definition: dir.c:441
rb_encoding * enc
Definition: dir.c:444
const VALUE path
Definition: dir.c:443
DIR * dir
Definition: dir.c:442
const char * name
Definition: dir.c:2034
const struct dirent * dp
Definition: dir.c:2035
const char * path
Definition: dir.c:1936
rb_encoding * enc
Definition: dir.c:1940
VALUE value
Definition: dir.c:1939
const char * base
Definition: dir.c:1937
size_t baselen
Definition: dir.c:1938
void(* func)(const char *, VALUE, void *)
Definition: dir.c:1935
rb_encoding * enc
Definition: dir.c:1956
const char * path
Definition: dir.c:1955
char * str
Definition: dir.c:1660
struct glob_pattern * next
Definition: dir.c:1662
enum glob_pattern_type type
Definition: dir.c:1661
const char * path
Definition: dir.c:1222
mode_t mode
Definition: dir.c:1223
int basefd
Definition: dir.c:1432
const char * path
Definition: dir.c:1433
VALUE arg
Definition: dir.c:2452
const char * base
Definition: dir.c:2449
const ruby_glob_funcs_t * funcs
Definition: dir.c:2451
const ruby_glob_funcs_t * funcs
Definition: dir.c:2029
int flags
Definition: dir.c:2028
size_t namelen
Definition: dir.c:2025
const char * path
Definition: dir.c:2023
VALUE arg
Definition: dir.c:2030
size_t baselen
Definition: dir.c:2024
rb_pathtype_t pathtype
Definition: dir.c:2027
int dirsep
Definition: dir.c:2026
ruby_glob_func * match
Definition: dir.c:1382
ruby_glob_errfunc * error
Definition: dir.c:1383
const char * mesg
Definition: dir.c:1307
rb_encoding * enc
Definition: dir.c:1308
RUBY_SYMBOL_EXPORT_BEGIN void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
Definition: thread.c:1661
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
char * ruby_getcwd(void)
Definition: util.c:539
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
Definition: win32.c:2259
int rb_w32_reparse_symlink_p(const WCHAR *path)
Definition: win32.c:5017
int rb_w32_map_errno(DWORD)
Definition: win32.c:273
WCHAR * rb_w32_mbstr_to_wstr(UINT, const char *, int, long *)
Definition: win32.c:2179