From: "H.Yamamoto" Date: 2005-11-16T16:12:07+09:00 Subject: [ruby-dev:27721] Re: [ruby-list:41557] Re:Windowsにおける共有フォルダーでのDir.globは一覧を返さない? 山本です。 >いま色々試していて、私も誤解していたことに気付きました。 >共有フォルダに対する . も .. も(rb_w32_)stat()は成功するべき >ですねえ。 ># Dir.glob('*') が . で始まるファイルを取ってこないことを忘れ ># てました。 > >というわけなので山本さんにお願いしてしまいましょうかねえ。 >bcc32の問題もあるし。 昔の実装を流用しただけですが、とりあえず一つ形になったので流してみます。 メリット: * st_dev, st_rdev に stat と fstat で同じ値が得られる(test_pathname が通る) * st_nlink に正しい値が入る デメリット: * WinNT でしか動かない(FILE_FLAG_BACKUP_SEMANTICS がないため) * 共有フォルダ上のファイルに対する動作が遅い(2倍強) まだ手をつけていないところ: * アクセス権の設定。0x777 となるべきところが 0x700 になっていたりとか * 64bit ファイルサイズサポート 共有フォルダに対する動作が遅いのは難点なので、FindFirstFile を使う(ライブラリ のしている実装)方法を含めて、色々試してみようと思います。気長にお待ちを。 Index: win32.c =================================================================== RCS file: /src/ruby/win32/win32.c,v retrieving revision 1.178 diff -u -w -b -p -r1.178 win32.c --- win32.c 5 Nov 2005 04:43:46 -0000 1.178 +++ win32.c 16 Nov 2005 06:13:02 -0000 @@ -3164,23 +3164,82 @@ isUNCRoot(const char *path) return 0; } -#ifdef __BORLANDC__ -#undef fstat -int -rb_w32_fstat(int fd, struct stat *st) +static time_t +filetime_to_unixtime(const FILETIME *ft) { - BY_HANDLE_FILE_INFORMATION info; - int ret = fstat(fd, st); + FILETIME loc; + SYSTEMTIME st; + struct tm tm; + time_t t; - if (ret) return ret; - st->st_mode &= ~(S_IWGRP | S_IWOTH); - if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info) && - !(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { - st->st_mode |= S_IWUSR; + if (!FileTimeToLocalFileTime(ft, &loc)) { + return 0; } - return ret; + if (!FileTimeToSystemTime(&loc, &st)) { + return 0; + } + memset(&tm, 0, sizeof(tm)); + tm.tm_year = st.wYear - 1900; + tm.tm_mon = st.wMonth - 1; + tm.tm_mday = st.wDay; + tm.tm_hour = st.wHour; + tm.tm_min = st.wMinute; + tm.tm_sec = st.wSecond; + t = mktime(&tm); + return t == -1 ? 0 : t; +} + +static int +os_stat(HANDLE h, struct stat *st) + { + BY_HANDLE_FILE_INFORMATION info; + + memset(st, 0, sizeof(struct stat)); + switch (GetFileType(h)) { + case FILE_TYPE_DISK: + if (!GetFileInformationByHandle(h, &info)) { + errno = map_errno(GetLastError()); + return -1; } + st->st_mode = S_IREAD; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + st->st_mode |= (S_IFDIR | S_IWRITE | S_IWUSR | S_IEXEC); + else if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + st->st_mode |= (S_IFREG); + else + st->st_mode |= (S_IFREG | S_IWRITE | S_IWUSR); + st->st_nlink = info.nNumberOfLinks; + st->st_dev = st->st_rdev = info.dwVolumeSerialNumber; + st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime); + st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime); + st->st_ctime = filetime_to_unixtime(&info.ftCreationTime); + st->st_size = info.nFileSizeLow; +// st->st_size = info.nFileSizeHigh; +// st->st_size << 32; +// st->st_size += info.nFileSizeLow; + break; + case FILE_TYPE_CHAR: + st->st_mode = S_IFCHR; + break; +#ifdef S_IFFIFO + case FILE_TYPE_PIPE: + st->st_mode = S_IFIFO; + break; #endif + } + return 0; +} + +int +rb_w32_fstat(int fd, struct stat *st) +{ + long h = _get_osfhandle(fd); + + if (h < 0) + return -1; + else + return os_stat((HANDLE)h, st); +} int rb_w32_stat(const char *path, struct stat *st) @@ -3189,6 +3248,7 @@ rb_w32_stat(const char *path, struct sta char *buf1, *s, *end; int len; int ret; + HANDLE h; if (!path || !st) { errno = EFAULT; @@ -3217,9 +3277,36 @@ rb_w32_stat(const char *path, struct sta } else if (*end == '\\' || (buf1 + 1 == end && *end == ':')) strcat(buf1, "."); - ret = stat(buf1, st); - if (ret == 0) { - st->st_mode &= ~(S_IWGRP | S_IWOTH); + h = CreateFile( + buf1, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + if (h == INVALID_HANDLE_VALUE) { + errno = map_errno(GetLastError()); + return -1; + } + ret = os_stat(h, st); + CloseHandle(h); + + if (ret == 0 && (st->st_mode & S_IFREG)) { + end = buf1 + strlen(buf1); + while (buf1 < end) { + end = CharPrev(buf1, end); + if (*end == '.') { + if ((strcmpi(end, ".bat") == 0) || + (strcmpi(end, ".cmd") == 0) || + (strcmpi(end, ".com") == 0) || + (strcmpi(end, ".exe") == 0)) { + st->st_mode |= S_IEXEC; + } + break; + } + } } return ret; } Index: win32.h =================================================================== RCS file: /src/ruby/win32/win32.h,v retrieving revision 1.74 diff -u -w -b -p -r1.74 win32.h --- win32.h 5 Nov 2005 04:43:46 -0000 1.74 +++ win32.h 16 Nov 2005 05:33:53 -0000 @@ -105,8 +105,6 @@ extern "C++" { #define write(h, b, l) _write(h, b, l) #define _open _sopen #define sopen _sopen -#undef fstat -#define fstat(fd,st) rb_w32_fstat(fd,st) #undef fopen #define fopen(p, m) rb_w32_fopen(p, m) #undef fdopen @@ -117,6 +115,8 @@ extern "C++" { #undef stat #define stat(path,st) rb_w32_stat(path,st) +#undef fstat +#define fstat(fd,st) rb_w32_fstat(fd,st) #undef execv #define execv(path,argv) rb_w32_aspawn(P_OVERLAY,path,argv) #if !defined(__BORLANDC__) && !defined(_WIN32_WCE)