PageRenderTime 56ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/dir.c

https://github.com/diabolo/ruby
C | 2063 lines | 1386 code | 233 blank | 444 comment | 371 complexity | f0159521cc534e45645664bc2782641a MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file