diff options
author | shirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-08-09 11:34:48 +0000 |
---|---|---|
committer | shirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-08-09 11:34:48 +0000 |
commit | dcd7f09be26dd85247f58354709e50e97b9c2291 (patch) | |
tree | fefdff489cb0a44a37bba46faae249fc802dfed0 /win32 | |
parent | 0e92dc4b729970112e8205fa1dd55b17af38d27a (diff) | |
download | ruby-dcd7f09be26dd85247f58354709e50e97b9c2291.tar.gz |
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
Diffstat (limited to 'win32')
-rw-r--r-- | win32/win32.c | 54 |
1 files changed, 38 insertions, 16 deletions
diff --git a/win32/win32.c b/win32/win32.c index 458b613756..de655df8b3 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -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) { - errno = map_errno(GetLastError()); + /* 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; } - if (attr & FILE_ATTRIBUTE_DIRECTORY) { - if (check_valid_dir(path)) 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; } - st->st_mode = fileattr_to_unixmode(attr, path); } st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ? |