summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorshirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-08-09 11:34:48 +0000
committershirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-08-09 11:34:48 +0000
commitdcd7f09be26dd85247f58354709e50e97b9c2291 (patch)
treefefdff489cb0a44a37bba46faae249fc802dfed0 /win32
parent0e92dc4b729970112e8205fa1dd55b17af38d27a (diff)
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.c54
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':') ?