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