Ruby  1.9.3p551(2014-11-13revision48407)
dir.c
Go to the documentation of this file.
1 /**********************************************************************
2 
3  dir.c -
4 
5  $Author: usa $
6  created at: Wed Jan 5 09:51:01 JST 1994
7 
8  Copyright (C) 1993-2007 Yukihiro Matsumoto
9  Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10  Copyright (C) 2000 Information-technology Promotion Agency, Japan
11 
12 **********************************************************************/
13 
14 #include "ruby/ruby.h"
15 #include "ruby/encoding.h"
16 #include "internal.h"
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24 
25 #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 # if !defined __NeXT__
34 # define NAMLEN(dirent) (dirent)->d_namlen
35 # else
36 # /* On some versions of NextStep, d_namlen is always zero, so avoid it. */
37 # define NAMLEN(dirent) strlen((dirent)->d_name)
38 # endif
39 # if HAVE_SYS_NDIR_H
40 # include <sys/ndir.h>
41 # endif
42 # if HAVE_SYS_DIR_H
43 # include <sys/dir.h>
44 # endif
45 # if HAVE_NDIR_H
46 # include <ndir.h>
47 # endif
48 # ifdef _WIN32
49 # include "win32/dir.h"
50 # endif
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 #if !defined HAVE_LSTAT && !defined lstat
68 #define lstat stat
69 #endif
70 
71 /* define system APIs */
72 #ifdef _WIN32
73 #undef chdir
74 #define chdir(p) rb_w32_uchdir(p)
75 #undef mkdir
76 #define mkdir(p, m) rb_w32_umkdir((p), (m))
77 #undef rmdir
78 #define rmdir(p) rb_w32_urmdir(p)
79 #undef opendir
80 #define opendir(p) rb_w32_uopendir(p)
81 #endif
82 
83 #define rb_sys_fail_path(path) rb_sys_fail_str(path)
84 
85 #define FNM_NOESCAPE 0x01
86 #define FNM_PATHNAME 0x02
87 #define FNM_DOTMATCH 0x04
88 #define FNM_CASEFOLD 0x08
89 #if CASEFOLD_FILESYSTEM
90 #define FNM_SYSCASE FNM_CASEFOLD
91 #else
92 #define FNM_SYSCASE 0
93 #endif
94 
95 #define FNM_NOMATCH 1
96 #define FNM_ERROR 2
97 
98 # define Next(p, e, enc) ((p)+ rb_enc_mbclen((p), (e), (enc)))
99 # define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
100 
101 static char *
103  const char *p, /* pattern (next to '[') */
104  const char *pend,
105  const char *s, /* string */
106  const char *send,
107  int flags,
108  rb_encoding *enc)
109 {
110  const int nocase = flags & FNM_CASEFOLD;
111  const int escape = !(flags & FNM_NOESCAPE);
112  unsigned int c1, c2;
113  int r;
114  int ok = 0, not = 0;
115 
116  if (p >= pend) return NULL;
117  if (*p == '!' || *p == '^') {
118  not = 1;
119  p++;
120  }
121 
122  while (*p != ']') {
123  const char *t1 = p;
124  if (escape && *t1 == '\\')
125  t1++;
126  if (!*t1)
127  return NULL;
128  p = t1 + (r = rb_enc_mbclen(t1, pend, enc));
129  if (p >= pend) return NULL;
130  if (p[0] == '-' && p[1] != ']') {
131  const char *t2 = p + 1;
132  int r2;
133  if (escape && *t2 == '\\')
134  t2++;
135  if (!*t2)
136  return NULL;
137  p = t2 + (r2 = rb_enc_mbclen(t2, pend, enc));
138  if (ok) continue;
139  if ((r <= (send-s) && memcmp(t1, s, r) == 0) ||
140  (r2 <= (send-s) && memcmp(t2, s, r) == 0)) {
141  ok = 1;
142  continue;
143  }
144  c1 = rb_enc_codepoint(s, send, enc);
145  if (nocase) c1 = rb_enc_toupper(c1, enc);
146  c2 = rb_enc_codepoint(t1, pend, enc);
147  if (nocase) c2 = rb_enc_toupper(c2, enc);
148  if (c1 < c2) continue;
149  c2 = rb_enc_codepoint(t2, pend, enc);
150  if (nocase) c2 = rb_enc_toupper(c2, enc);
151  if (c1 > c2) continue;
152  }
153  else {
154  if (ok) continue;
155  if (r <= (send-s) && memcmp(t1, s, r) == 0) {
156  ok = 1;
157  continue;
158  }
159  if (!nocase) continue;
160  c1 = rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc);
161  c2 = rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc);
162  if (c1 != c2) continue;
163  }
164  ok = 1;
165  }
166 
167  return ok == not ? NULL : (char *)p + 1;
168 }
169 
170 /* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0')
171  Otherwise, entire string will be matched.
172  End marker itself won't be compared.
173  And if function succeeds, *pcur reaches end marker.
174 */
175 #define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p))
176 #define ISEND(p) (!*(p) || (pathname && *(p) == '/'))
177 #define RETURN(val) return *pcur = p, *scur = s, (val);
178 
179 static int
181  const char **pcur, /* pattern */
182  const char **scur, /* string */
183  int flags,
184  rb_encoding *enc)
185 {
186  const int period = !(flags & FNM_DOTMATCH);
187  const int pathname = flags & FNM_PATHNAME;
188  const int escape = !(flags & FNM_NOESCAPE);
189  const int nocase = flags & FNM_CASEFOLD;
190 
191  const char *ptmp = 0;
192  const char *stmp = 0;
193 
194  const char *p = *pcur;
195  const char *pend = p + strlen(p);
196  const char *s = *scur;
197  const char *send = s + strlen(s);
198 
199  int r;
200 
201  if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */
203 
204  while (1) {
205  switch (*p) {
206  case '*':
207  do { p++; } while (*p == '*');
208  if (ISEND(UNESCAPE(p))) {
209  p = UNESCAPE(p);
210  RETURN(0);
211  }
212  if (ISEND(s))
214  ptmp = p;
215  stmp = s;
216  continue;
217 
218  case '?':
219  if (ISEND(s))
221  p++;
222  Inc(s, send, enc);
223  continue;
224 
225  case '[': {
226  const char *t;
227  if (ISEND(s))
229  if ((t = bracket(p + 1, pend, s, send, flags, enc)) != 0) {
230  p = t;
231  Inc(s, send, enc);
232  continue;
233  }
234  goto failed;
235  }
236  }
237 
238  /* ordinary */
239  p = UNESCAPE(p);
240  if (ISEND(s))
241  RETURN(ISEND(p) ? 0 : FNM_NOMATCH);
242  if (ISEND(p))
243  goto failed;
244  r = rb_enc_precise_mbclen(p, pend, enc);
245  if (!MBCLEN_CHARFOUND_P(r))
246  goto failed;
247  if (r <= (send-s) && memcmp(p, s, r) == 0) {
248  p += r;
249  s += r;
250  continue;
251  }
252  if (!nocase) goto failed;
253  if (rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc) !=
254  rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc))
255  goto failed;
256  p += r;
257  Inc(s, send, enc);
258  continue;
259 
260  failed: /* try next '*' position */
261  if (ptmp && stmp) {
262  p = ptmp;
263  Inc(stmp, send, enc); /* !ISEND(*stmp) */
264  s = stmp;
265  continue;
266  }
267  RETURN(FNM_NOMATCH);
268  }
269 }
270 
271 static int
273  const char *pattern,
274  rb_encoding *enc,
275  const char *string,
276  int flags)
277 {
278  const char *p = pattern;
279  const char *s = string;
280  const char *send = s + strlen(string);
281  const int period = !(flags & FNM_DOTMATCH);
282  const int pathname = flags & FNM_PATHNAME;
283 
284  const char *ptmp = 0;
285  const char *stmp = 0;
286 
287  if (pathname) {
288  while (1) {
289  if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
290  do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
291  ptmp = p;
292  stmp = s;
293  }
294  if (fnmatch_helper(&p, &s, flags, enc) == 0) {
295  while (*s && *s != '/') Inc(s, send, enc);
296  if (*p && *s) {
297  p++;
298  s++;
299  continue;
300  }
301  if (!*p && !*s)
302  return 0;
303  }
304  /* failed : try next recursion */
305  if (ptmp && stmp && !(period && *stmp == '.')) {
306  while (*stmp && *stmp != '/') Inc(stmp, send, enc);
307  if (*stmp) {
308  p = ptmp;
309  stmp++;
310  s = stmp;
311  continue;
312  }
313  }
314  return FNM_NOMATCH;
315  }
316  }
317  else
318  return fnmatch_helper(&p, &s, flags, enc);
319 }
320 
322 
323 struct dir_data {
327 };
328 
329 static void
330 dir_mark(void *ptr)
331 {
332  struct dir_data *dir = ptr;
333  rb_gc_mark(dir->path);
334 }
335 
336 static void
337 dir_free(void *ptr)
338 {
339  struct dir_data *dir = ptr;
340  if (dir) {
341  if (dir->dir) closedir(dir->dir);
342  }
343  xfree(dir);
344 }
345 
346 static size_t
347 dir_memsize(const void *ptr)
348 {
349  return ptr ? sizeof(struct dir_data) : 0;
350 }
351 
353  "dir",
355 };
356 
357 static VALUE dir_close(VALUE);
358 
359 #define GlobPathValue(str, safe) \
360  /* can contain null bytes as separators */ \
361  (!RB_TYPE_P((str), T_STRING) ? \
362  (void)FilePathValue(str) : \
363  (void)(check_safe_glob((str), (safe)), \
364  check_glob_encoding(str), (str)))
365 #define check_safe_glob(str, safe) ((safe) ? rb_check_safe_obj(str) : (void)0)
366 #define check_glob_encoding(str) rb_enc_check((str), rb_enc_from_encoding(rb_usascii_encoding()))
367 
368 static VALUE
370 {
371  struct dir_data *dirp;
372  VALUE obj = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dirp);
373 
374  dirp->dir = NULL;
375  dirp->path = Qnil;
376  dirp->enc = NULL;
377 
378  return obj;
379 }
380 
381 /*
382  * call-seq:
383  * Dir.new( string ) -> aDir
384  *
385  * Returns a new directory object for the named directory.
386  */
387 static VALUE
389 {
390  struct dir_data *dp;
391  rb_encoding *fsenc;
392  VALUE dirname, opt, orig;
393  static VALUE sym_enc;
394 
395  if (!sym_enc) {
396  sym_enc = ID2SYM(rb_intern("encoding"));
397  }
398  fsenc = rb_filesystem_encoding();
399 
400  argc = rb_scan_args(argc, argv, "1:", &dirname, &opt);
401 
402  if (!NIL_P(opt)) {
403  VALUE enc = rb_hash_aref(opt, sym_enc);
404  if (!NIL_P(enc)) {
405  fsenc = rb_to_encoding(enc);
406  }
407  }
408 
409  GlobPathValue(dirname, FALSE);
410  orig = rb_str_dup_frozen(dirname);
411  dirname = rb_str_encode_ospath(dirname);
412  dirname = rb_str_dup_frozen(dirname);
413 
414  TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dp);
415  if (dp->dir) closedir(dp->dir);
416  dp->dir = NULL;
417  dp->path = Qnil;
418  dp->enc = fsenc;
419  dp->dir = opendir(RSTRING_PTR(dirname));
420  if (dp->dir == NULL) {
421  if (errno == EMFILE || errno == ENFILE) {
422  rb_gc();
423  dp->dir = opendir(RSTRING_PTR(dirname));
424  }
425  if (dp->dir == NULL) {
426  rb_sys_fail_path(orig);
427  }
428  }
429  dp->path = orig;
430 
431  return dir;
432 }
433 
434 /*
435  * call-seq:
436  * Dir.open( string ) -> aDir
437  * Dir.open( string ) {| aDir | block } -> anObject
438  *
439  * With no block, <code>open</code> is a synonym for
440  * <code>Dir::new</code>. If a block is present, it is passed
441  * <i>aDir</i> as a parameter. The directory is closed at the end of
442  * the block, and <code>Dir::open</code> returns the value of the
443  * block.
444  */
445 static VALUE
447 {
448  struct dir_data *dp;
449  VALUE dir = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dp);
450 
451  dir_initialize(argc, argv, dir);
452  if (rb_block_given_p()) {
453  return rb_ensure(rb_yield, dir, dir_close, dir);
454  }
455 
456  return dir;
457 }
458 
459 static void
461 {
462  rb_raise(rb_eIOError, "closed directory");
463 }
464 
465 static struct dir_data *
467 {
468  struct dir_data *dirp;
469  if (!OBJ_UNTRUSTED(dir) && rb_safe_level() >= 4)
470  rb_raise(rb_eSecurityError, "Insecure: operation on trusted Dir");
471  rb_check_frozen(dir);
472  dirp = rb_check_typeddata(dir, &dir_data_type);
473  if (!dirp->dir) dir_closed();
474  return dirp;
475 }
476 
477 #define GetDIR(obj, dirp) ((dirp) = dir_check(obj))
478 
479 
480 /*
481  * call-seq:
482  * dir.inspect -> string
483  *
484  * Return a string describing this Dir object.
485  */
486 static VALUE
488 {
489  struct dir_data *dirp;
490 
491  TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
492  if (!NIL_P(dirp->path)) {
493  VALUE str = rb_str_new_cstr("#<");
495  rb_str_cat2(str, ":");
496  rb_str_append(str, dirp->path);
497  rb_str_cat2(str, ">");
498  return str;
499  }
500  return rb_funcall(dir, rb_intern("to_s"), 0, 0);
501 }
502 
503 /*
504  * call-seq:
505  * dir.path -> string or nil
506  *
507  * Returns the path parameter passed to <em>dir</em>'s constructor.
508  *
509  * d = Dir.new("..")
510  * d.path #=> ".."
511  */
512 static VALUE
514 {
515  struct dir_data *dirp;
516 
517  TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
518  if (NIL_P(dirp->path)) return Qnil;
519  return rb_str_dup(dirp->path);
520 }
521 
522 #if defined HAVE_READDIR_R
523 # define READDIR(dir, enc, entry, dp) (readdir_r((dir), (entry), &(dp)) == 0 && (dp) != 0)
524 #elif defined _WIN32
525 # define READDIR(dir, enc, entry, dp) (((dp) = rb_w32_readdir_with_enc((dir), (enc))) != 0)
526 #else
527 # define READDIR(dir, enc, entry, dp) (((dp) = readdir(dir)) != 0)
528 #endif
529 #if defined HAVE_READDIR_R
530 # define IF_HAVE_READDIR_R(something) something
531 #else
532 # define IF_HAVE_READDIR_R(something) /* nothing */
533 #endif
534 
535 #if defined SIZEOF_STRUCT_DIRENT_TOO_SMALL
536 # include <limits.h>
537 # define NAME_MAX_FOR_STRUCT_DIRENT 255
538 # if defined NAME_MAX
539 # if NAME_MAX_FOR_STRUCT_DIRENT < NAME_MAX
540 # undef NAME_MAX_FOR_STRUCT_DIRENT
541 # define NAME_MAX_FOR_STRUCT_DIRENT NAME_MAX
542 # endif
543 # endif
544 # if defined _POSIX_NAME_MAX
545 # if NAME_MAX_FOR_STRUCT_DIRENT < _POSIX_NAME_MAX
546 # undef NAME_MAX_FOR_STRUCT_DIRENT
547 # define NAME_MAX_FOR_STRUCT_DIRENT _POSIX_NAME_MAX
548 # endif
549 # endif
550 # if defined _XOPEN_NAME_MAX
551 # if NAME_MAX_FOR_STRUCT_DIRENT < _XOPEN_NAME_MAX
552 # undef NAME_MAX_FOR_STRUCT_DIRENT
553 # define NAME_MAX_FOR_STRUCT_DIRENT _XOPEN_NAME_MAX
554 # endif
555 # endif
556 # define DEFINE_STRUCT_DIRENT \
557  union { \
558  struct dirent dirent; \
559  char dummy[offsetof(struct dirent, d_name) + \
560  NAME_MAX_FOR_STRUCT_DIRENT + 1]; \
561  }
562 # define STRUCT_DIRENT(entry) ((entry).dirent)
563 #else
564 # define DEFINE_STRUCT_DIRENT struct dirent
565 # define STRUCT_DIRENT(entry) (entry)
566 #endif
567 
568 /*
569  * call-seq:
570  * dir.read -> string or nil
571  *
572  * Reads the next entry from <em>dir</em> and returns it as a string.
573  * Returns <code>nil</code> at the end of the stream.
574  *
575  * d = Dir.new("testdir")
576  * d.read #=> "."
577  * d.read #=> ".."
578  * d.read #=> "config.h"
579  */
580 static VALUE
582 {
583  struct dir_data *dirp;
584  struct dirent *dp;
586 
587  GetDIR(dir, dirp);
588  errno = 0;
589  if (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
590  return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc);
591  }
592  else if (errno == 0) { /* end of stream */
593  return Qnil;
594  }
595  else {
596  rb_sys_fail(0);
597  }
598  return Qnil; /* not reached */
599 }
600 
601 /*
602  * call-seq:
603  * dir.each { |filename| block } -> dir
604  * dir.each -> an_enumerator
605  *
606  * Calls the block once for each entry in this directory, passing the
607  * filename of each entry as a parameter to the block.
608  *
609  * If no block is given, an enumerator is returned instead.
610  *
611  * d = Dir.new("testdir")
612  * d.each {|x| puts "Got #{x}" }
613  *
614  * <em>produces:</em>
615  *
616  * Got .
617  * Got ..
618  * Got config.h
619  * Got main.rb
620  */
621 static VALUE
623 {
624  struct dir_data *dirp;
625  struct dirent *dp;
627 
628  RETURN_ENUMERATOR(dir, 0, 0);
629  GetDIR(dir, dirp);
630  rewinddir(dirp->dir);
631  while (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
632  rb_yield(rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc));
633  if (dirp->dir == NULL) dir_closed();
634  }
635  return dir;
636 }
637 
638 #ifdef HAVE_TELLDIR
639 /*
640  * call-seq:
641  * dir.pos -> integer
642  * dir.tell -> integer
643  *
644  * Returns the current position in <em>dir</em>. See also
645  * <code>Dir#seek</code>.
646  *
647  * d = Dir.new("testdir")
648  * d.tell #=> 0
649  * d.read #=> "."
650  * d.tell #=> 12
651  */
652 static VALUE
653 dir_tell(VALUE dir)
654 {
655  struct dir_data *dirp;
656  long pos;
657 
658  GetDIR(dir, dirp);
659  pos = telldir(dirp->dir);
660  return rb_int2inum(pos);
661 }
662 #else
663 #define dir_tell rb_f_notimplement
664 #endif
665 
666 #ifdef HAVE_SEEKDIR
667 /*
668  * call-seq:
669  * dir.seek( integer ) -> dir
670  *
671  * Seeks to a particular location in <em>dir</em>. <i>integer</i>
672  * must be a value returned by <code>Dir#tell</code>.
673  *
674  * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
675  * d.read #=> "."
676  * i = d.tell #=> 12
677  * d.read #=> ".."
678  * d.seek(i) #=> #<Dir:0x401b3c40>
679  * d.read #=> ".."
680  */
681 static VALUE
682 dir_seek(VALUE dir, VALUE pos)
683 {
684  struct dir_data *dirp;
685  long p = NUM2LONG(pos);
686 
687  GetDIR(dir, dirp);
688  seekdir(dirp->dir, p);
689  return dir;
690 }
691 #else
692 #define dir_seek rb_f_notimplement
693 #endif
694 
695 /*
696  * call-seq:
697  * dir.pos( integer ) -> integer
698  *
699  * Synonym for <code>Dir#seek</code>, but returns the position
700  * parameter.
701  *
702  * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
703  * d.read #=> "."
704  * i = d.pos #=> 12
705  * d.read #=> ".."
706  * d.pos = i #=> 12
707  * d.read #=> ".."
708  */
709 static VALUE
711 {
712  dir_seek(dir, pos);
713  return pos;
714 }
715 
716 /*
717  * call-seq:
718  * dir.rewind -> dir
719  *
720  * Repositions <em>dir</em> to the first entry.
721  *
722  * d = Dir.new("testdir")
723  * d.read #=> "."
724  * d.rewind #=> #<Dir:0x401b3fb0>
725  * d.read #=> "."
726  */
727 static VALUE
729 {
730  struct dir_data *dirp;
731 
732  if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(dir)) {
733  rb_raise(rb_eSecurityError, "Insecure: can't close");
734  }
735  GetDIR(dir, dirp);
736  rewinddir(dirp->dir);
737  return dir;
738 }
739 
740 /*
741  * call-seq:
742  * dir.close -> nil
743  *
744  * Closes the directory stream. Any further attempts to access
745  * <em>dir</em> will raise an <code>IOError</code>.
746  *
747  * d = Dir.new("testdir")
748  * d.close #=> nil
749  */
750 static VALUE
752 {
753  struct dir_data *dirp;
754 
755  GetDIR(dir, dirp);
756  closedir(dirp->dir);
757  dirp->dir = NULL;
758 
759  return Qnil;
760 }
761 
762 static void
764 {
765  if (chdir(RSTRING_PTR(path)) < 0)
766  rb_sys_fail_path(path);
767 }
768 
769 static int chdir_blocking = 0;
771 
772 struct chdir_data {
774  int done;
775 };
776 
777 static VALUE
779 {
780  dir_chdir(args->new_path);
781  args->done = TRUE;
782  chdir_blocking++;
783  if (chdir_thread == Qnil)
784  chdir_thread = rb_thread_current();
785  return rb_yield(args->new_path);
786 }
787 
788 static VALUE
790 {
791  if (args->done) {
792  chdir_blocking--;
793  if (chdir_blocking == 0)
794  chdir_thread = Qnil;
795  dir_chdir(args->old_path);
796  }
797  return Qnil;
798 }
799 
800 /*
801  * call-seq:
802  * Dir.chdir( [ string] ) -> 0
803  * Dir.chdir( [ string] ) {| path | block } -> anObject
804  *
805  * Changes the current working directory of the process to the given
806  * string. When called without an argument, changes the directory to
807  * the value of the environment variable <code>HOME</code>, or
808  * <code>LOGDIR</code>. <code>SystemCallError</code> (probably
809  * <code>Errno::ENOENT</code>) if the target directory does not exist.
810  *
811  * If a block is given, it is passed the name of the new current
812  * directory, and the block is executed with that as the current
813  * directory. The original working directory is restored when the block
814  * exits. The return value of <code>chdir</code> is the value of the
815  * block. <code>chdir</code> blocks can be nested, but in a
816  * multi-threaded program an error will be raised if a thread attempts
817  * to open a <code>chdir</code> block while another thread has one
818  * open.
819  *
820  * Dir.chdir("/var/spool/mail")
821  * puts Dir.pwd
822  * Dir.chdir("/tmp") do
823  * puts Dir.pwd
824  * Dir.chdir("/usr") do
825  * puts Dir.pwd
826  * end
827  * puts Dir.pwd
828  * end
829  * puts Dir.pwd
830  *
831  * <em>produces:</em>
832  *
833  * /var/spool/mail
834  * /tmp
835  * /usr
836  * /tmp
837  * /var/spool/mail
838  */
839 static VALUE
841 {
842  VALUE path = Qnil;
843 
844  rb_secure(2);
845  if (rb_scan_args(argc, argv, "01", &path) == 1) {
846  FilePathValue(path);
847  path = rb_str_encode_ospath(path);
848  }
849  else {
850  const char *dist = getenv("HOME");
851  if (!dist) {
852  dist = getenv("LOGDIR");
853  if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
854  }
855  path = rb_str_new2(dist);
856  }
857 
858  if (chdir_blocking > 0) {
859  if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
860  rb_warn("conflicting chdir during another chdir block");
861  }
862 
863  if (rb_block_given_p()) {
864  struct chdir_data args;
865 
867  args.new_path = path;
868  args.done = FALSE;
869  return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
870  }
871  dir_chdir(path);
872 
873  return INT2FIX(0);
874 }
875 
876 VALUE
878 {
879  char *path;
880  VALUE cwd;
881 
882  rb_secure(4);
883  path = my_getcwd();
884  cwd = rb_tainted_str_new2(path);
886 
887  xfree(path);
888  return cwd;
889 }
890 
891 /*
892  * call-seq:
893  * Dir.getwd -> string
894  * Dir.pwd -> string
895  *
896  * Returns the path to the current working directory of this process as
897  * a string.
898  *
899  * Dir.chdir("/tmp") #=> 0
900  * Dir.getwd #=> "/tmp"
901  */
902 static VALUE
904 {
905  return rb_dir_getwd();
906 }
907 
908 static void
909 check_dirname(volatile VALUE *dir)
910 {
911  VALUE d = *dir;
912  char *path, *pend;
913  long len;
914  rb_encoding *enc;
915 
916  rb_secure(2);
917  FilePathValue(d);
918  enc = rb_enc_get(d);
919  RSTRING_GETMEM(d, path, len);
920  pend = path + len;
921  pend = rb_enc_path_end(rb_enc_path_skip_prefix(path, pend, enc), pend, enc);
922  if (pend - path < len) {
923  d = rb_str_subseq(d, 0, pend - path);
924  }
925  *dir = rb_str_encode_ospath(d);
926 }
927 
928 #if defined(HAVE_CHROOT)
929 /*
930  * call-seq:
931  * Dir.chroot( string ) -> 0
932  *
933  * Changes this process's idea of the file system root. Only a
934  * privileged process may make this call. Not available on all
935  * platforms. On Unix systems, see <code>chroot(2)</code> for more
936  * information.
937  */
938 static VALUE
939 dir_s_chroot(VALUE dir, VALUE path)
940 {
941  check_dirname(&path);
942  if (chroot(RSTRING_PTR(path)) == -1)
943  rb_sys_fail_path(path);
944 
945  return INT2FIX(0);
946 }
947 #else
948 #define dir_s_chroot rb_f_notimplement
949 #endif
950 
951 /*
952  * call-seq:
953  * Dir.mkdir( string [, integer] ) -> 0
954  *
955  * Makes a new directory named by <i>string</i>, with permissions
956  * specified by the optional parameter <i>anInteger</i>. The
957  * permissions may be modified by the value of
958  * <code>File::umask</code>, and are ignored on NT. Raises a
959  * <code>SystemCallError</code> if the directory cannot be created. See
960  * also the discussion of permissions in the class documentation for
961  * <code>File</code>.
962  *
963  * Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0
964  *
965  */
966 static VALUE
968 {
969  VALUE path, vmode;
970  int mode;
971 
972  if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
973  mode = NUM2INT(vmode);
974  }
975  else {
976  mode = 0777;
977  }
978 
979  check_dirname(&path);
980  if (mkdir(RSTRING_PTR(path), mode) == -1)
981  rb_sys_fail_path(path);
982 
983  return INT2FIX(0);
984 }
985 
986 /*
987  * call-seq:
988  * Dir.delete( string ) -> 0
989  * Dir.rmdir( string ) -> 0
990  * Dir.unlink( string ) -> 0
991  *
992  * Deletes the named directory. Raises a subclass of
993  * <code>SystemCallError</code> if the directory isn't empty.
994  */
995 static VALUE
997 {
998  check_dirname(&dir);
999  if (rmdir(RSTRING_PTR(dir)) < 0)
1000  rb_sys_fail_path(dir);
1001 
1002  return INT2FIX(0);
1003 }
1004 
1005 static VALUE
1007 {
1008  rb_sys_warning("%s:%s", strerror(errno), (const char *)mesg);
1009  return Qnil;
1010 }
1011 
1012 #define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1))
1013 #define sys_warning(val) \
1014  (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0))
1015 
1016 #define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
1017 #define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n)))
1018 #define GLOB_FREE(ptr) free(ptr)
1019 #define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
1020 
1021 /*
1022  * ENOTDIR can be returned by stat(2) if a non-leaf element of the path
1023  * is not a directory.
1024  */
1025 #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
1026 
1027 /* System call with warning */
1028 static int
1029 do_stat(const char *path, struct stat *pst, int flags)
1030 
1031 {
1032  int ret = stat(path, pst);
1033  if (ret < 0 && !to_be_ignored(errno))
1034  sys_warning(path);
1035 
1036  return ret;
1037 }
1038 
1039 static int
1040 do_lstat(const char *path, struct stat *pst, int flags)
1041 {
1042  int ret = lstat(path, pst);
1043  if (ret < 0 && !to_be_ignored(errno))
1044  sys_warning(path);
1045 
1046  return ret;
1047 }
1048 
1049 static DIR *
1050 do_opendir(const char *path, int flags, rb_encoding *enc)
1051 {
1052  DIR *dirp;
1053 #ifdef _WIN32
1054  volatile VALUE tmp;
1055  if (enc != rb_usascii_encoding() &&
1056  enc != rb_ascii8bit_encoding() &&
1057  enc != rb_utf8_encoding()) {
1058  tmp = rb_enc_str_new(path, strlen(path), enc);
1059  tmp = rb_str_encode_ospath(tmp);
1060  path = RSTRING_PTR(tmp);
1061  }
1062 #endif
1063  dirp = opendir(path);
1064  if (dirp == NULL && !to_be_ignored(errno))
1065  sys_warning(path);
1066 
1067  return dirp;
1068 }
1069 
1070 /* Return nonzero if S has any special globbing chars in it. */
1071 static int
1072 has_magic(const char *p, const char *pend, int flags, rb_encoding *enc)
1073 {
1074  const int escape = !(flags & FNM_NOESCAPE);
1075  const int nocase = flags & FNM_CASEFOLD;
1076 
1077  register char c;
1078 
1079  while (p < pend && (c = *p++) != 0) {
1080  switch (c) {
1081  case '*':
1082  case '?':
1083  case '[':
1084  return 1;
1085 
1086  case '\\':
1087  if (escape && !(c = *p++))
1088  return 0;
1089  continue;
1090 
1091  default:
1092  if (!FNM_SYSCASE && ISALPHA(c) && nocase)
1093  return 1;
1094  }
1095 
1096  p = Next(p-1, pend, enc);
1097  }
1098 
1099  return 0;
1100 }
1101 
1102 /* Find separator in globbing pattern. */
1103 static char *
1104 find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc)
1105 {
1106  const int escape = !(flags & FNM_NOESCAPE);
1107 
1108  register char c;
1109  int open = 0;
1110 
1111  while ((c = *p++) != 0) {
1112  switch (c) {
1113  case '[':
1114  open = 1;
1115  continue;
1116  case ']':
1117  open = 0;
1118  continue;
1119 
1120  case '/':
1121  if (!open)
1122  return (char *)p-1;
1123  continue;
1124 
1125  case '\\':
1126  if (escape && !(c = *p++))
1127  return (char *)p-1;
1128  continue;
1129  }
1130 
1131  p = Next(p-1, pend, enc);
1132  }
1133 
1134  return (char *)p-1;
1135 }
1136 
1137 /* Remove escaping backslashes */
1138 static void
1140 {
1141  register const char *pend = p + strlen(p);
1142  char *t = p;
1143  char *s = p;
1144 
1145  while (*p) {
1146  if (*p == '\\') {
1147  if (t != s)
1148  memmove(t, s, p - s);
1149  t += p - s;
1150  s = ++p;
1151  if (!*p) break;
1152  }
1153  Inc(p, pend, enc);
1154  }
1155 
1156  while (*p++);
1157 
1158  if (t != s)
1159  memmove(t, s, p - s); /* move '\0' too */
1160 }
1161 
1162 /* Globing pattern */
1164 
1166  char *str;
1169 };
1170 
1171 static void glob_free_pattern(struct glob_pattern *list);
1172 
1173 static struct glob_pattern *
1174 glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
1175 {
1176  struct glob_pattern *list, *tmp, **tail = &list;
1177  int dirsep = 0; /* pattern is terminated with '/' */
1178  int recursive = 0;
1179 
1180  while (p < e && *p) {
1181  tmp = GLOB_ALLOC(struct glob_pattern);
1182  if (!tmp) goto error;
1183  if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
1184  /* fold continuous RECURSIVEs (needed in glob_helper) */
1185  do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
1186  tmp->type = RECURSIVE;
1187  tmp->str = 0;
1188  dirsep = 1;
1189  recursive = 1;
1190  }
1191  else {
1192  const char *m = find_dirsep(p, e, flags, enc);
1193  int magic = has_magic(p, m, flags, enc);
1194  char *buf;
1195 
1196  if (!magic && !recursive && *m) {
1197  const char *m2;
1198  while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) &&
1199  *m2) {
1200  m = m2;
1201  }
1202  }
1203  buf = GLOB_ALLOC_N(char, m-p+1);
1204  if (!buf) {
1205  GLOB_FREE(tmp);
1206  goto error;
1207  }
1208  memcpy(buf, p, m-p);
1209  buf[m-p] = '\0';
1210  tmp->type = magic ? MAGICAL : PLAIN;
1211  tmp->str = buf;
1212  if (*m) {
1213  dirsep = 1;
1214  p = m + 1;
1215  }
1216  else {
1217  dirsep = 0;
1218  p = m;
1219  }
1220  }
1221  *tail = tmp;
1222  tail = &tmp->next;
1223  }
1224 
1225  tmp = GLOB_ALLOC(struct glob_pattern);
1226  if (!tmp) {
1227  error:
1228  *tail = 0;
1229  glob_free_pattern(list);
1230  return 0;
1231  }
1232  tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
1233  tmp->str = 0;
1234  *tail = tmp;
1235  tmp->next = 0;
1236 
1237  return list;
1238 }
1239 
1240 static void
1242 {
1243  while (list) {
1244  struct glob_pattern *tmp = list;
1245  list = list->next;
1246  if (tmp->str)
1247  GLOB_FREE(tmp->str);
1248  GLOB_FREE(tmp);
1249  }
1250 }
1251 
1252 static char *
1253 join_path(const char *path, int dirsep, const char *name)
1254 {
1255  long len = strlen(path);
1256  long len2 = strlen(name)+(dirsep?1:0)+1;
1257  char *buf = GLOB_ALLOC_N(char, len+len2);
1258 
1259  if (!buf) return 0;
1260  memcpy(buf, path, len);
1261  if (dirsep) {
1262  buf[len++] = '/';
1263  }
1264  buf[len] = '\0';
1265  strlcat(buf+len, name, len2);
1266  return buf;
1267 }
1268 
1269 enum answer { YES, NO, UNKNOWN };
1270 
1271 #ifndef S_ISDIR
1272 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1273 #endif
1274 
1275 #ifndef S_ISLNK
1276 # ifndef S_IFLNK
1277 # define S_ISLNK(m) (0)
1278 # else
1279 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1280 # endif
1281 #endif
1282 
1283 struct glob_args {
1284  void (*func)(const char *, VALUE, void *);
1285  const char *path;
1288 };
1289 
1290 static VALUE
1292 {
1293  struct glob_args *args = (struct glob_args *)val;
1294 
1295  (*args->func)(args->path, args->value, args->enc);
1296  return Qnil;
1297 }
1298 
1299 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc))
1300 
1301 static int
1303  const char *path,
1304  int dirsep, /* '/' should be placed before appending child entry's name to 'path'. */
1305  enum answer exist, /* Does 'path' indicate an existing entry? */
1306  enum answer isdir, /* Does 'path' indicate a directory or a symlink to a directory? */
1307  struct glob_pattern **beg,
1308  struct glob_pattern **end,
1309  int flags,
1311  VALUE arg,
1312  rb_encoding *enc)
1313 {
1314  struct stat st;
1315  int status = 0;
1316  struct glob_pattern **cur, **new_beg, **new_end;
1317  int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
1318  int escape = !(flags & FNM_NOESCAPE);
1319 
1320  for (cur = beg; cur < end; ++cur) {
1321  struct glob_pattern *p = *cur;
1322  if (p->type == RECURSIVE) {
1323  recursive = 1;
1324  p = p->next;
1325  }
1326  switch (p->type) {
1327  case PLAIN:
1328  plain = 1;
1329  break;
1330  case MAGICAL:
1331  magical = 1;
1332  break;
1333  case MATCH_ALL:
1334  match_all = 1;
1335  break;
1336  case MATCH_DIR:
1337  match_dir = 1;
1338  break;
1339  case RECURSIVE:
1340  rb_bug("continuous RECURSIVEs");
1341  }
1342  }
1343 
1344  if (*path) {
1345  if (match_all && exist == UNKNOWN) {
1346  if (do_lstat(path, &st, flags) == 0) {
1347  exist = YES;
1348  isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
1349  }
1350  else {
1351  exist = NO;
1352  isdir = NO;
1353  }
1354  }
1355  if (match_dir && isdir == UNKNOWN) {
1356  if (do_stat(path, &st, flags) == 0) {
1357  exist = YES;
1358  isdir = S_ISDIR(st.st_mode) ? YES : NO;
1359  }
1360  else {
1361  exist = NO;
1362  isdir = NO;
1363  }
1364  }
1365  if (match_all && exist == YES) {
1366  status = glob_call_func(func, path, arg, enc);
1367  if (status) return status;
1368  }
1369  if (match_dir && isdir == YES) {
1370  char *tmp = join_path(path, dirsep, "");
1371  if (!tmp) return -1;
1372  status = glob_call_func(func, tmp, arg, enc);
1373  GLOB_FREE(tmp);
1374  if (status) return status;
1375  }
1376  }
1377 
1378  if (exist == NO || isdir == NO) return 0;
1379 
1380  if (magical || recursive) {
1381  struct dirent *dp;
1382  DIR *dirp;
1384  dirp = do_opendir(*path ? path : ".", flags, enc);
1385  if (dirp == NULL) return 0;
1386 
1387  while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) {
1388  char *buf = join_path(path, dirsep, dp->d_name);
1389  enum answer new_isdir = UNKNOWN;
1390 
1391  if (!buf) {
1392  status = -1;
1393  break;
1394  }
1395  if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0
1396  && fnmatch("*", rb_usascii_encoding(), dp->d_name, flags) == 0) {
1397 #ifndef _WIN32
1398  if (do_lstat(buf, &st, flags) == 0)
1399  new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
1400  else
1401  new_isdir = NO;
1402 #else
1403  new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
1404 #endif
1405  }
1406 
1407  new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
1408  if (!new_beg) {
1409  GLOB_FREE(buf);
1410  status = -1;
1411  break;
1412  }
1413 
1414  for (cur = beg; cur < end; ++cur) {
1415  struct glob_pattern *p = *cur;
1416  if (p->type == RECURSIVE) {
1417  if (new_isdir == YES) /* not symlink but real directory */
1418  *new_end++ = p; /* append recursive pattern */
1419  p = p->next; /* 0 times recursion */
1420  }
1421  if (p->type == PLAIN || p->type == MAGICAL) {
1422  if (fnmatch(p->str, enc, dp->d_name, flags) == 0)
1423  *new_end++ = p->next;
1424  }
1425  }
1426 
1427  status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end,
1428  flags, func, arg, enc);
1429  GLOB_FREE(buf);
1430  GLOB_FREE(new_beg);
1431  if (status) break;
1432  }
1433 
1434  closedir(dirp);
1435  }
1436  else if (plain) {
1437  struct glob_pattern **copy_beg, **copy_end, **cur2;
1438 
1439  copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
1440  if (!copy_beg) return -1;
1441  for (cur = beg; cur < end; ++cur)
1442  *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
1443 
1444  for (cur = copy_beg; cur < copy_end; ++cur) {
1445  if (*cur) {
1446  char *buf;
1447  char *name;
1448  size_t len = strlen((*cur)->str) + 1;
1449  name = GLOB_ALLOC_N(char, len);
1450  if (!name) {
1451  status = -1;
1452  break;
1453  }
1454  memcpy(name, (*cur)->str, len);
1455  if (escape) remove_backslashes(name, enc);
1456 
1457  new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
1458  if (!new_beg) {
1459  GLOB_FREE(name);
1460  status = -1;
1461  break;
1462  }
1463  *new_end++ = (*cur)->next;
1464  for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
1465  if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
1466  *new_end++ = (*cur2)->next;
1467  *cur2 = 0;
1468  }
1469  }
1470 
1471  buf = join_path(path, dirsep, name);
1472  GLOB_FREE(name);
1473  if (!buf) {
1474  GLOB_FREE(new_beg);
1475  status = -1;
1476  break;
1477  }
1478  status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
1479  new_end, flags, func, arg, enc);
1480  GLOB_FREE(buf);
1481  GLOB_FREE(new_beg);
1482  if (status) break;
1483  }
1484  }
1485 
1486  GLOB_FREE(copy_beg);
1487  }
1488 
1489  return status;
1490 }
1491 
1492 static int
1493 ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
1494 {
1495  struct glob_pattern *list;
1496  const char *root, *start;
1497  char *buf;
1498  size_t n;
1499  int status;
1500 
1501  start = root = path;
1502  flags |= FNM_SYSCASE;
1503 #if defined DOSISH
1504  root = rb_enc_path_skip_prefix(root, root + strlen(root), enc);
1505 #endif
1506 
1507  if (root && *root == '/') root++;
1508 
1509  n = root - start;
1510  buf = GLOB_ALLOC_N(char, n + 1);
1511  if (!buf) return -1;
1512  MEMCPY(buf, start, char, n);
1513  buf[n] = '\0';
1514 
1515  list = glob_make_pattern(root, root + strlen(root), flags, enc);
1516  if (!list) {
1517  GLOB_FREE(buf);
1518  return -1;
1519  }
1520  status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc);
1521  glob_free_pattern(list);
1522  GLOB_FREE(buf);
1523 
1524  return status;
1525 }
1526 
1527 int
1528 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
1529 {
1530  return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
1532 }
1533 
1534 static int
1535 rb_glob_caller(const char *path, VALUE a, void *enc)
1536 {
1537  int status;
1538  struct glob_args *args = (struct glob_args *)a;
1539 
1540  args->path = path;
1541  rb_protect(glob_func_caller, a, &status);
1542  return status;
1543 }
1544 
1545 static int
1546 rb_glob2(const char *path, int flags,
1547  void (*func)(const char *, VALUE, void *), VALUE arg,
1548  rb_encoding* enc)
1549 {
1550  struct glob_args args;
1551 
1552  args.func = func;
1553  args.value = arg;
1554  args.enc = enc;
1555 
1556  if (flags & FNM_SYSCASE) {
1557  rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
1558  }
1559 
1560  return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
1561  enc);
1562 }
1563 
1564 void
1565 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
1566 {
1567  int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding());
1568  if (status) GLOB_JUMP_TAG(status);
1569 }
1570 
1571 static void
1572 push_pattern(const char *path, VALUE ary, void *enc)
1573 {
1574  rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc));
1575 }
1576 
1577 static int
1578 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
1579  rb_encoding *enc)
1580 {
1581  const int escape = !(flags & FNM_NOESCAPE);
1582  const char *p = str;
1583  const char *pend = p + strlen(p);
1584  const char *s = p;
1585  const char *lbrace = 0, *rbrace = 0;
1586  int nest = 0, status = 0;
1587 
1588  while (*p) {
1589  if (*p == '{' && nest++ == 0) {
1590  lbrace = p;
1591  }
1592  if (*p == '}' && --nest <= 0) {
1593  rbrace = p;
1594  break;
1595  }
1596  if (*p == '\\' && escape) {
1597  if (!*++p) break;
1598  }
1599  Inc(p, pend, enc);
1600  }
1601 
1602  if (lbrace && rbrace) {
1603  size_t len = strlen(s) + 1;
1604  char *buf = GLOB_ALLOC_N(char, len);
1605  long shift;
1606 
1607  if (!buf) return -1;
1608  memcpy(buf, s, lbrace-s);
1609  shift = (lbrace-s);
1610  p = lbrace;
1611  while (p < rbrace) {
1612  const char *t = ++p;
1613  nest = 0;
1614  while (p < rbrace && !(*p == ',' && nest == 0)) {
1615  if (*p == '{') nest++;
1616  if (*p == '}') nest--;
1617  if (*p == '\\' && escape) {
1618  if (++p == rbrace) break;
1619  }
1620  Inc(p, pend, enc);
1621  }
1622  memcpy(buf+shift, t, p-t);
1623  strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
1624  status = ruby_brace_expand(buf, flags, func, arg, enc);
1625  if (status) break;
1626  }
1627  GLOB_FREE(buf);
1628  }
1629  else if (!lbrace && !rbrace) {
1630  status = (*func)(s, arg, enc);
1631  }
1632 
1633  return status;
1634 }
1635 
1636 struct brace_args {
1639  int flags;
1640 };
1641 
1642 static int
1643 glob_brace(const char *path, VALUE val, void *enc)
1644 {
1645  struct brace_args *arg = (struct brace_args *)val;
1646 
1647  return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
1648 }
1649 
1650 static int
1651 ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg,
1652  rb_encoding* enc)
1653 {
1654  struct brace_args args;
1655 
1656  args.func = func;
1657  args.value = arg;
1658  args.flags = flags;
1659  return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
1660 }
1661 
1662 int
1663 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
1664 {
1665  return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg,
1667 }
1668 
1669 int
1670 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
1671 {
1672  return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc);
1673 }
1674 
1675 static int
1676 push_glob(VALUE ary, VALUE str, int flags)
1677 {
1678  struct glob_args args;
1679  rb_encoding *enc = rb_enc_get(str);
1680 
1681  if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding();
1682  args.func = push_pattern;
1683  args.value = ary;
1684  args.enc = enc;
1685 
1686  RB_GC_GUARD(str);
1687  return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE,
1688  rb_glob_caller, (VALUE)&args, enc);
1689 }
1690 
1691 static VALUE
1692 rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
1693 {
1694  long offset = 0;
1695  VALUE ary;
1696 
1697  GlobPathValue(str, TRUE);
1698  ary = rb_ary_new();
1699 
1700  while (offset < RSTRING_LEN(str)) {
1701  char *p, *pend;
1702  int status;
1703  p = RSTRING_PTR(str) + offset;
1704  status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
1705  flags);
1706  if (status) GLOB_JUMP_TAG(status);
1707  if (offset >= RSTRING_LEN(str)) break;
1708  p += strlen(p) + 1;
1709  pend = RSTRING_PTR(str) + RSTRING_LEN(str);
1710  while (p < pend && !*p)
1711  p++;
1712  offset = p - RSTRING_PTR(str);
1713  }
1714 
1715  return ary;
1716 }
1717 
1718 static VALUE
1719 dir_globs(long argc, VALUE *argv, int flags)
1720 {
1721  VALUE ary = rb_ary_new();
1722  long i;
1723 
1724  for (i = 0; i < argc; ++i) {
1725  int status;
1726  VALUE str = argv[i];
1727  GlobPathValue(str, TRUE);
1728  status = push_glob(ary, str, flags);
1729  if (status) GLOB_JUMP_TAG(status);
1730  }
1731 
1732  return ary;
1733 }
1734 
1735 /*
1736  * call-seq:
1737  * Dir[ array ] -> array
1738  * Dir[ string [, string ...] ] -> array
1739  *
1740  * Equivalent to calling
1741  * <code>Dir.glob(</code><i>array,</i><code>0)</code> and
1742  * <code>Dir.glob([</code><i>string,...</i><code>],0)</code>.
1743  *
1744  */
1745 static VALUE
1747 {
1748  if (argc == 1) {
1749  return rb_push_glob(argv[0], 0);
1750  }
1751  return dir_globs(argc, argv, 0);
1752 }
1753 
1754 /*
1755  * call-seq:
1756  * Dir.glob( pattern, [flags] ) -> array
1757  * Dir.glob( pattern, [flags] ) {| filename | block } -> nil
1758  *
1759  * Returns the filenames found by expanding <i>pattern</i> which is
1760  * an +Array+ of the patterns or the pattern +String+, either as an
1761  * <i>array</i> or as parameters to the block. Note that this pattern
1762  * is not a regexp (it's closer to a shell glob). See
1763  * <code>File::fnmatch</code> for the meaning of the <i>flags</i>
1764  * parameter. Note that case sensitivity depends on your system (so
1765  * <code>File::FNM_CASEFOLD</code> is ignored), as does the order
1766  * in which the results are returned.
1767  *
1768  * <code>*</code>:: Matches any file. Can be restricted by
1769  * other values in the glob. <code>*</code>
1770  * will match all files; <code>c*</code> will
1771  * match all files beginning with
1772  * <code>c</code>; <code>*c</code> will match
1773  * all files ending with <code>c</code>; and
1774  * <code>\*c\*</code> will match all files that
1775  * have <code>c</code> in them (including at
1776  * the beginning or end). Equivalent to
1777  * <code>/ .* /x</code> in regexp. Note, this
1778  * will not match Unix-like hidden files (dotfiles).
1779  * In order to include those in the match results,
1780  * you must use something like "{*,.*}".
1781  * <code>**</code>:: Matches directories recursively.
1782  * <code>?</code>:: Matches any one character. Equivalent to
1783  * <code>/.{1}/</code> in regexp.
1784  * <code>[set]</code>:: Matches any one character in +set+.
1785  * Behaves exactly like character sets in
1786  * Regexp, including set negation
1787  * (<code>[^a-z]</code>).
1788  * <code>{p,q}</code>:: Matches either literal <code>p</code> or
1789  * literal <code>q</code>. Matching literals
1790  * may be more than one character in length.
1791  * More than two literals may be specified.
1792  * Equivalent to pattern alternation in
1793  * regexp.
1794  * <code></code>:: Escapes the next metacharacter.
1795  * Note that this means you cannot use backslash in windows
1796  * as part of a glob, i.e. Dir["c:\\foo*"] will not work
1797  * use Dir["c:/foo*"] instead
1798  *
1799  * Dir["config.?"] #=> ["config.h"]
1800  * Dir.glob("config.?") #=> ["config.h"]
1801  * Dir.glob("*.[a-z][a-z]") #=> ["main.rb"]
1802  * Dir.glob("*.[^r]*") #=> ["config.h"]
1803  * Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"]
1804  * Dir.glob("*") #=> ["config.h", "main.rb"]
1805  * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"]
1806  *
1807  * rbfiles = File.join("**", "*.rb")
1808  * Dir.glob(rbfiles) #=> ["main.rb",
1809  * # "lib/song.rb",
1810  * # "lib/song/karaoke.rb"]
1811  * libdirs = File.join("**", "lib")
1812  * Dir.glob(libdirs) #=> ["lib"]
1813  *
1814  * librbfiles = File.join("**", "lib", "**", "*.rb")
1815  * Dir.glob(librbfiles) #=> ["lib/song.rb",
1816  * # "lib/song/karaoke.rb"]
1817  *
1818  * librbfiles = File.join("**", "lib", "*.rb")
1819  * Dir.glob(librbfiles) #=> ["lib/song.rb"]
1820  */
1821 static VALUE
1823 {
1824  VALUE str, rflags, ary;
1825  int flags;
1826 
1827  if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
1828  flags = NUM2INT(rflags);
1829  else
1830  flags = 0;
1831 
1832  ary = rb_check_array_type(str);
1833  if (NIL_P(ary)) {
1834  ary = rb_push_glob(str, flags);
1835  }
1836  else {
1837  volatile VALUE v = ary;
1838  ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
1839  }
1840 
1841  if (rb_block_given_p()) {
1842  rb_ary_each(ary);
1843  return Qnil;
1844  }
1845  return ary;
1846 }
1847 
1848 static VALUE
1850 {
1851  VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv);
1852  struct dir_data *dirp;
1853 
1854  TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
1855  return dir;
1856 }
1857 
1858 
1859 /*
1860  * call-seq:
1861  * Dir.foreach( dirname ) {| filename | block } -> nil
1862  * Dir.foreach( dirname ) -> an_enumerator
1863  *
1864  * Calls the block once for each entry in the named directory, passing
1865  * the filename of each entry as a parameter to the block.
1866  *
1867  * If no block is given, an enumerator is returned instead.
1868  *
1869  * Dir.foreach("testdir") {|x| puts "Got #{x}" }
1870  *
1871  * <em>produces:</em>
1872  *
1873  * Got .
1874  * Got ..
1875  * Got config.h
1876  * Got main.rb
1877  *
1878  */
1879 static VALUE
1881 {
1882  VALUE dir;
1883 
1884  RETURN_ENUMERATOR(io, argc, argv);
1885  dir = dir_open_dir(argc, argv);
1886  rb_ensure(dir_each, dir, dir_close, dir);
1887  return Qnil;
1888 }
1889 
1890 /*
1891  * call-seq:
1892  * Dir.entries( dirname ) -> array
1893  *
1894  * Returns an array containing all of the filenames in the given
1895  * directory. Will raise a <code>SystemCallError</code> if the named
1896  * directory doesn't exist.
1897  *
1898  * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"]
1899  *
1900  */
1901 static VALUE
1903 {
1904  VALUE dir;
1905 
1906  dir = dir_open_dir(argc, argv);
1907  return rb_ensure(rb_Array, dir, dir_close, dir);
1908 }
1909 
1910 /*
1911  * call-seq:
1912  * File.fnmatch( pattern, path, [flags] ) -> (true or false)
1913  * File.fnmatch?( pattern, path, [flags] ) -> (true or false)
1914  *
1915  * Returns true if <i>path</i> matches against <i>pattern</i> The
1916  * pattern is not a regular expression; instead it follows rules
1917  * similar to shell filename globbing. It may contain the following
1918  * metacharacters:
1919  *
1920  * <code>*</code>:: Matches any file. Can be restricted by
1921  * other values in the glob. <code>*</code>
1922  * will match all files; <code>c*</code> will
1923  * match all files beginning with
1924  * <code>c</code>; <code>*c</code> will match
1925  * all files ending with <code>c</code>; and
1926  * <code>\*c*</code> will match all files that
1927  * have <code>c</code> in them (including at
1928  * the beginning or end). Equivalent to
1929  * <code>/ .* /x</code> in regexp.
1930  * <code>**</code>:: Matches directories recursively or files
1931  * expansively.
1932  * <code>?</code>:: Matches any one character. Equivalent to
1933  * <code>/.{1}/</code> in regexp.
1934  * <code>[set]</code>:: Matches any one character in +set+.
1935  * Behaves exactly like character sets in
1936  * Regexp, including set negation
1937  * (<code>[^a-z]</code>).
1938  * <code></code>:: Escapes the next metacharacter.
1939  *
1940  * <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code>
1941  * parameters. The same glob pattern and flags are used by
1942  * <code>Dir::glob</code>.
1943  *
1944  * File.fnmatch('cat', 'cat') #=> true # match entire string
1945  * File.fnmatch('cat', 'category') #=> false # only match partial string
1946  * File.fnmatch('c{at,ub}s', 'cats') #=> false # { } isn't supported
1947  *
1948  * File.fnmatch('c?t', 'cat') #=> true # '?' match only 1 character
1949  * File.fnmatch('c??t', 'cat') #=> false # ditto
1950  * File.fnmatch('c*', 'cats') #=> true # '*' match 0 or more characters
1951  * File.fnmatch('c*t', 'c/a/b/t') #=> true # ditto
1952  * File.fnmatch('ca[a-z]', 'cat') #=> true # inclusive bracket expression
1953  * File.fnmatch('ca[^t]', 'cat') #=> false # exclusive bracket expression ('^' or '!')
1954  *
1955  * File.fnmatch('cat', 'CAT') #=> false # case sensitive
1956  * File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true # case insensitive
1957  *
1958  * File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false # wildcard doesn't match '/' on FNM_PATHNAME
1959  * File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false # ditto
1960  * File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false # ditto
1961  *
1962  * File.fnmatch('\?', '?') #=> true # escaped wildcard becomes ordinary
1963  * File.fnmatch('\a', 'a') #=> true # escaped ordinary remains ordinary
1964  * File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true # FNM_NOESACPE makes '\' ordinary
1965  * File.fnmatch('[\?]', '?') #=> true # can escape inside bracket expression
1966  *
1967  * File.fnmatch('*', '.profile') #=> false # wildcard doesn't match leading
1968  * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true # period by default.
1969  * File.fnmatch('.*', '.profile') #=> true
1970  *
1971  * rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string.
1972  * File.fnmatch(rbfiles, 'main.rb') #=> false
1973  * File.fnmatch(rbfiles, './main.rb') #=> false
1974  * File.fnmatch(rbfiles, 'lib/song.rb') #=> true
1975  * File.fnmatch('**.rb', 'main.rb') #=> true
1976  * File.fnmatch('**.rb', './main.rb') #=> false
1977  * File.fnmatch('**.rb', 'lib/song.rb') #=> true
1978  * File.fnmatch('*', 'dave/.profile') #=> true
1979  *
1980  * pattern = '*' '/' '*'
1981  * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME) #=> false
1982  * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
1983  *
1984  * pattern = '**' '/' 'foo'
1985  * File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME) #=> true
1986  * File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME) #=> true
1987  * File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true
1988  * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME) #=> false
1989  * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
1990  */
1991 static VALUE
1993 {
1994  VALUE pattern, path;
1995  VALUE rflags;
1996  int flags;
1997 
1998  if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
1999  flags = NUM2INT(rflags);
2000  else
2001  flags = 0;
2002 
2003  StringValue(pattern);
2004  FilePathStringValue(path);
2005 
2006  if (fnmatch(RSTRING_PTR(pattern), rb_enc_get(pattern), RSTRING_PTR(path),
2007  flags) == 0)
2008  return Qtrue;
2009 
2010  return Qfalse;
2011 }
2012 
2013 /*
2014  * call-seq:
2015  * Dir.home() -> "/home/me"
2016  * Dir.home("root") -> "/root"
2017  *
2018  * Returns the home directory of the current user or the named user
2019  * if given.
2020  */
2021 static VALUE
2023 {
2024  VALUE user;
2025  const char *u = 0;
2026 
2027  rb_scan_args(argc, argv, "01", &user);
2028  if (!NIL_P(user)) {
2029  SafeStringValue(user);
2030  u = StringValueCStr(user);
2031  }
2032  return rb_home_dir(u, rb_str_new(0, 0));
2033 }
2034 
2035 /*
2036  * Objects of class <code>Dir</code> are directory streams representing
2037  * directories in the underlying file system. They provide a variety of
2038  * ways to list directories and their contents. See also
2039  * <code>File</code>.
2040  *
2041  * The directory used in these examples contains the two regular files
2042  * (<code>config.h</code> and <code>main.rb</code>), the parent
2043  * directory (<code>..</code>), and the directory itself
2044  * (<code>.</code>).
2045  */
2046 void
2048 {
2050 
2052 
2057 
2058  rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
2059  rb_define_method(rb_cDir,"path", dir_path, 0);
2060  rb_define_method(rb_cDir,"to_path", dir_path, 0);
2061  rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
2062  rb_define_method(rb_cDir,"read", dir_read, 0);
2063  rb_define_method(rb_cDir,"each", dir_each, 0);
2064  rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
2065  rb_define_method(rb_cDir,"tell", dir_tell, 0);
2066  rb_define_method(rb_cDir,"seek", dir_seek, 1);
2067  rb_define_method(rb_cDir,"pos", dir_tell, 0);
2068  rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
2069  rb_define_method(rb_cDir,"close", dir_close, 0);
2070 
2080 
2083  rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1); /* in file.c */
2084  rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1); /* in file.c */
2085 
2088 
2089  rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
2090  rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
2091  rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
2092  rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
2093  rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
2094 }
2095