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