Created
August 6, 2012 22:12
-
-
Save shirosaki/3278908 to your computer and use it in GitHub Desktop.
Winstat patch which adds root path check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb | |
index a19fcd9..7d1716b 100644 | |
--- a/test/ruby/test_file_exhaustive.rb | |
+++ b/test/ruby/test_file_exhaustive.rb | |
@@ -813,6 +813,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("#{DRIVE}/*.sys") {|f| File::Stat.new(f) } | |
+ end | |
+ end if DRIVE | |
+ | |
def test_path_check | |
assert_nothing_raised { ENV["PATH"] } | |
end | |
diff --git a/win32/win32.c b/win32/win32.c | |
index 458b613..952b3a9 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,57 @@ 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) { | |
+ WCHAR full[MAX_PATH]; | |
+ WCHAR *dmy; | |
+ | |
+ /* 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 */ | |
+ /* if the path is not root directory */ | |
+ if (!GetFullPathNameW(path, sizeof(full) / sizeof(WCHAR), full, &dmy)) { | |
errno = map_errno(GetLastError()); | |
return -1; | |
} | |
- if (attr & FILE_ATTRIBUTE_DIRECTORY) { | |
- if (check_valid_dir(path)) return -1; | |
+ if (full[1] == L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR) { | |
+ /* root directory */ | |
+ errno = map_errno(e); | |
+ 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; | |
+ } | |
+ 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':') ? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment