[前][次][番号順一覧][スレッド一覧]

ruby-changes:24617

From: shirosaki <ko1@a...>
Date: Thu, 9 Aug 2012 20:35:13 +0900 (JST)
Subject: [ruby-changes:24617] shirosaki:r36668 (trunk): Optimize winnt_stat

shirosaki	2012-08-09 20:34:48 +0900 (Thu, 09 Aug 2012)

  New Revision: 36668

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=36668

  Log:
    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]

  Modified files:
    trunk/ChangeLog
    trunk/test/ruby/test_file_exhaustive.rb
    trunk/win32/win32.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 36667)
+++ ChangeLog	(revision 36668)
@@ -1,3 +1,18 @@
+Thu Aug  9 20:03:11 2012  Hiroshi Shirosaki  <h.shirosaki@g...>
+
+	* 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]
+
 Thu Aug  9 18:33:46 2012  Nobuyoshi Nakada  <nobu@r...>
 
 	* ruby.c (proc_options): show version only once even if -v and
Index: win32/win32.c
===================================================================
--- win32/win32.c	(revision 36667)
+++ win32/win32.c	(revision 36668)
@@ -4557,6 +4557,11 @@
     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 @@
 {
     HANDLE h;
     WIN32_FIND_DATAW wfd;
+    WIN32_FILE_ATTRIBUTE_DATA wfa;
     const WCHAR *p = path;
 
     memset(st, 0, sizeof(*st));
@@ -4589,27 +4595,43 @@
 	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) {
+	/* 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 */
+	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;
 	}
-	if (attr & FILE_ATTRIBUTE_DIRECTORY) {
-	    if (check_valid_dir(path)) return -1;
-	}
-	st->st_mode  = fileattr_to_unixmode(attr, path);
     }
 
     st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ?
Index: test/ruby/test_file_exhaustive.rb
===================================================================
--- test/ruby/test_file_exhaustive.rb	(revision 36667)
+++ test/ruby/test_file_exhaustive.rb	(revision 36668)
@@ -819,6 +819,13 @@
     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

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]