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