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