なかだです。

At Thu, 8 Jan 2004 13:49:40 +0900,
H.Yamamoto wrote:
> もしも **/ とシンボリックリンクのチェックがタイムリーでなくていいのなら、
> 上からマッチする順が下からマッチする順と同様に高速で、
> デフォルトが上からマッチなので互換性も取れて、
> Win32のパッチも今のままで問題なくなって、
> なかださんのパッチでよさそうなんですけど、どうなんでしょうか。
> (ただ、_WIN32のコードは外にだせるかも)

名前を先にyieldしてからその中身を読むという動作上、ある程度はしょ
うがないような気がします。これをどうしても避けたいなら、今
rb_w32_opendir()でやっているように一度全部読んでしまう以外には
ないかも知れません。しかし今度は、readdir()したときにはあったファ
イルがなくなったり、なかったものが増えていたりという可能性もで
てくるでしょうし。

> Dir.glob("hoge/**/*") do |path|
>     # path のディレクトリを削除
>     # path にディレクトリへのシンボリックリンクを作成
> end
> 
> みたいなコードを走らせた場合にとんでもないことになりそうなのが
> 怖いんですが・・・

結局、そういう元のディレクトリを変更するような場合にはPOSTORDER
を使うべし、ということになるのでは。その例では、(_WIN32以外では)
再帰する前にopendir()することでちょっとマシになるかも知れません。

_WIN32のコードについては、プラットフォームによってロジックが微
妙に異なるという状態はできれば避けたいという気もしますが。


Index: dir.c =================================================================== RCS file: /cvs/ruby/src/ruby/dir.c,v retrieving revision 1.96 diff -u -2 -p -r1.96 dir.c --- dir.c 8 Jan 2004 09:25:32 -0000 1.96 +++ dir.c 8 Jan 2004 09:26:54 -0000 @@ -72,4 +72,5 @@ char *strchr _((char*,char)); #define FNM_DOTMATCH 0x04 #define FNM_CASEFOLD 0x08 +#define GLOB_POSTORDER 0x0100 #define FNM_NOMATCH 1 @@ -1002,4 +1003,5 @@ glob_helper(path, sub, separator, flags, int recursive = 0; int magical = 1; + int n1, mlen; struct d_link { @@ -1050,4 +1052,7 @@ glob_helper(path, sub, separator, flags, } + n1 = p - path; + mlen = strlen(m); + if (path == p) { dirp = do_opendir("."); @@ -1063,13 +1068,16 @@ glob_helper(path, sub, separator, flags, } + if (!magical && !(flags & GLOB_POSTORDER)) { + status = glob_helper(path, p, separator, flags, func, arg); + if (status) return status; + } + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { - const int n1 = p - path; const int n2 = n1 + NAMLEN(dp); - const int ok = 0; - const int ln = 1; - const int no = 2; - int is_dir = -1; /* not checked yet */ + enum {unknown = -1, nodir, symlnk, dir} dirtype = unknown; + int down = 0; + #ifdef _WIN32 - is_dir = dp->d_isdir ? (dp->d_isrep ? ln : ok) : no; + dirtype = dp->d_isdir ? (dp->d_isrep ? symlnk : dir) : nodir; #endif if (recursive && strcmp(".", dp->d_name) != 0 && strcmp("..", dp->d_name) != 0) { @@ -1078,33 +1086,46 @@ glob_helper(path, sub, separator, flags, strcpy(buf+n1, dp->d_name); #ifndef _WIN32 - is_dir = no; + dirtype = nodir; if (do_lstat(buf, &st) == 0) { if (S_ISDIR(st.st_mode)) - is_dir = ok; + dirtype = dir; else if (S_ISLNK(st.st_mode) && do_stat(buf, &st) == 0 && S_ISDIR(st.st_mode)) - is_dir = ln; + dirtype = symlnk; } #endif - if (is_dir == ok) { - strcpy(buf+n2, "/**/"); - strcpy(buf+n2+4, p); - status = glob_helper(buf, buf+n2+1, 1, flags, func, arg); + if (dirtype == dir) { + if (flags & GLOB_POSTORDER) { + strcpy(buf+n2, "/**/"); + strcpy(buf+n2+4, p); + status = glob_helper(buf, buf+n2+1, 1, flags, func, arg); + } + else { + down = 1; + } } free(buf); if (status) break; } - if (is_dir == no && *m == '/') { + if (dirtype == nodir && *m == '/') { continue; } if (magical && do_fnmatch(p, m, dp->d_name, flags) == 0) { - buf = ALLOC_N(char, n2+1+1); - memcpy(buf, path, n1); - strcpy(buf+n1, dp->d_name); - if (*m == '\0') { + if (mlen == 0 || mlen == 1 && (dirtype >= symlnk)) { + buf = ALLOC_N(char, n2+mlen+1); + memcpy(buf, path, n1); + strcpy(buf+n1, dp->d_name); + strcpy(buf+n2, m); status = glob_call_func(func, buf, arg); + free(buf); + if (status) break; } - else if (m[1] == '\0' && (is_dir == ok || is_dir == ln)) { /* *m == '/' */ - strcpy(buf+n2, "/"); - status = glob_call_func(func, buf, arg); + else if (!(flags & GLOB_POSTORDER)) { + buf = ALLOC_N(char, n2+mlen+1); + memcpy(buf, path, n1); + strcpy(buf+n1, dp->d_name); + strcpy(buf+n2, m); + status = glob_helper(buf, buf+n2+1, 1, flags, func, arg); + free(buf); + if (status) break; } else { @@ -1115,4 +1136,12 @@ glob_helper(path, sub, separator, flags, tail = &tmp->next; } + } + if (down) { + buf = ALLOC_N(char, n2+4+strlen(p)+1); + memcpy(buf, path, n1); + strcpy(buf+n1, dp->d_name); + strcpy(buf+n2, "/**/"); + strcpy(buf+n2+4, p); + status = glob_helper(buf, buf+n2+1, 1, flags, func, arg); free(buf); if (status) break; @@ -1124,7 +1153,6 @@ glob_helper(path, sub, separator, flags, while (link) { if (status == 0) { - const int n1 = p - path; const int n2 = n1 + strlen(link->name); - buf = ALLOC_N(char, n2+strlen(m)+1); + buf = ALLOC_N(char, n2+mlen+1); memcpy(buf, path, n1); strcpy(buf+n1, link->name); @@ -1139,5 +1167,5 @@ glob_helper(path, sub, separator, flags, } - if (status == 0 && !magical) { + if (status == 0 && !magical && (flags & GLOB_POSTORDER)) { status = glob_helper(path, p, separator, flags, func, arg); } @@ -1531,3 +1559,5 @@ Init_Dir() rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH)); rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD)); + + rb_define_const(rb_cDir, "GLOB_POSTORDER", INT2FIX(GLOB_POSTORDER)); }
-- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦