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