Optimize winnt_stat

* test/ruby/test_file_exhaustive.rb
  (TestFileExhaustive#test_stat_special_file): add a test.
  GetFileAttributesExW fails to get attributes of special files
  such as pagefile.sys.

* win32/win32.c (check_valid_dir): for performance, check the path
  by FindFirstFileW only if the path containts "..."

* win32/win32.c (winnt_stat): use GetFileAttributesExW instead of
  FindFirstFileW since GetFileAttributesExW is faster.
  Based on the patch by Dusan D. Majkic.
  [ruby-core:47083] [Feature #6845]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36668 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shirosaki 2012-08-09 11:34:48 +00:00
parent 0e92dc4b72
commit dcd7f09be2
3 changed files with 60 additions and 16 deletions

View File

@ -1,3 +1,18 @@
Thu Aug 9 20:03:11 2012 Hiroshi Shirosaki <h.shirosaki@gmail.com>
* test/ruby/test_file_exhaustive.rb
(TestFileExhaustive#test_stat_special_file): add a test.
GetFileAttributesExW fails to get attributes of special files
such as pagefile.sys.
* win32/win32.c (check_valid_dir): for performance, check the path
by FindFirstFileW only if the path containts "..."
* win32/win32.c (winnt_stat): use GetFileAttributesExW instead of
FindFirstFileW since GetFileAttributesExW is faster.
Based on the patch by Dusan D. Majkic.
[ruby-core:47083] [Feature #6845]
Thu Aug 9 18:33:46 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ruby.c (proc_options): show version only once even if -v and

View File

@ -819,6 +819,13 @@ class TestFileExhaustive < Test::Unit::TestCase
assert_equal(0, File::Stat.new(@zerofile).size)
end
def test_stat_special_file
# test for special files such as pagefile.sys on Windows
assert_nothing_raised do
Dir::glob("C:/*.sys") {|f| File::Stat.new(f) }
end
end if DRIVE
def test_path_check
assert_nothing_raised { ENV["PATH"] }
end

View File

@ -4557,6 +4557,11 @@ check_valid_dir(const WCHAR *path)
WCHAR full[MAX_PATH];
WCHAR *dmy;
/* GetFileAttributes() determines "..." as directory. */
/* We recheck it by FindFirstFile(). */
if (wcsstr(path, L"...") == NULL)
return 0;
/* if the specified path is the root of a drive and the drive is empty, */
/* FindFirstFile() returns INVALID_HANDLE_VALUE. */
if (!GetFullPathNameW(path, sizeof(full) / sizeof(WCHAR), full, &dmy)) {
@ -4579,6 +4584,7 @@ winnt_stat(const WCHAR *path, struct stati64 *st)
{
HANDLE h;
WIN32_FIND_DATAW wfd;
WIN32_FILE_ATTRIBUTE_DATA wfa;
const WCHAR *p = path;
memset(st, 0, sizeof(*st));
@ -4589,27 +4595,43 @@ winnt_stat(const WCHAR *path, struct stati64 *st)
errno = ENOENT;
return -1;
}
h = FindFirstFileW(path, &wfd);
if (h != INVALID_HANDLE_VALUE) {
FindClose(h);
st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
if (GetFileAttributesExW(path, GetFileExInfoStandard, (void*)&wfa)) {
if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (check_valid_dir(path)) return -1;
st->st_size = 0;
}
else {
st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow;
}
st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path);
st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime);
st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime);
st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime);
}
else {
// If runtime stat(2) is called for network shares, it fails on WinNT.
// Because GetDriveType returns 1 for network shares. (Win98 returns 4)
DWORD attr = GetFileAttributesW(path);
if (attr == (DWORD)-1L) {
/* GetFileAttributesEx failed; check why. */
int e = GetLastError();
if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
|| (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
errno = map_errno(e);
return -1;
}
/* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */
h = FindFirstFileW(path, &wfd);
if (h != INVALID_HANDLE_VALUE) {
FindClose(h);
st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
}
else {
errno = map_errno(GetLastError());
return -1;
}
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
if (check_valid_dir(path)) return -1;
}
st->st_mode = fileattr_to_unixmode(attr, path);
}
st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ?