Skip to content

Instantly share code, notes, and snippets.

@shirosaki
Created August 6, 2012 22:12
Show Gist options
  • Save shirosaki/3278908 to your computer and use it in GitHub Desktop.
Save shirosaki/3278908 to your computer and use it in GitHub Desktop.
Winstat patch which adds root path check
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