Skip to content

Instantly share code, notes, and snippets.

@shirosaki
Created August 7, 2012 13:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shirosaki/3285446 to your computer and use it in GitHub Desktop.
Save shirosaki/3285446 to your computer and use it in GitHub Desktop.
winnt_stat optimize patch
diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb
index de17d7e..434c93c 100644
--- a/test/ruby/test_file_exhaustive.rb
+++ b/test/ruby/test_file_exhaustive.rb
@@ -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
diff --git a/win32/win32.c b/win32/win32.c
index 458b613..de655df 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':') ?

Benchmark of require

Best result of several trials.

Trunk

X:\measurements>rci bench core_require_empty
ruby 2.0.0dev (2012-08-07 trunk 36652) [i386-mingw32]
Rehearsal ------------------------------------------------------
core_require_empty   0.858000   2.043000   2.901000 (  2.995205)
--------------------------------------------- total: 2.901000sec

                         user     system      total        real
core_require_empty   0.967000   1.904000   2.871000 (  2.932805)


X:\measurements>rci bench core_require_nested
ruby 2.0.0dev (2012-08-07 trunk 36652) [i386-mingw32]
Rehearsal -------------------------------------------------------
core_require_nested   1.014000   2.324000   3.338000 (  3.432006)
---------------------------------------------- total: 3.338000sec

                          user     system      total        real
core_require_nested   0.998000   2.371000   3.369000 (  3.416406)

Patched

X:\measurements>rci bench core_require_empty
ruby 2.0.0dev (2012-08-07 trunk 36652) [i386-mingw32]
Rehearsal ------------------------------------------------------
core_require_empty   0.795000   1.825000   2.620000 (  2.870405)
--------------------------------------------- total: 2.620000sec

                         user     system      total        real
core_require_empty   0.733000   1.934000   2.667000 (  2.792405)


X:\measurements>rci bench core_require_nested
ruby 2.0.0dev (2012-08-07 trunk 36652) [i386-mingw32]
Rehearsal -------------------------------------------------------
core_require_nested   1.014000   1.935000   2.949000 (  2.995206)
---------------------------------------------- total: 2.949000sec

                          user     system      total        real
core_require_nested   1.092000   1.809000   2.901000 (  2.964005)

Rails start up time

Rails 3.2.7 empty app

trunk

X:\a\b\c\d\e\f\g\empty>timer ruby script\rails r 'p $:.size, $".size'
57
759
real    4.040
system  2.433
user    1.560

patched

X:\a\b\c\d\e\f\g\empty>timer ruby script\rails r 'p $:.size, $".size'
57
759
real    3.900
system  2.199
user    1.606
@shirosaki
Copy link
Author

bench

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment