]> granicus.if.org Git - python/commitdiff
Bug #1686475: Support stat'ing open files on Windows again.
authorMartin v. Löwis <martin@v.loewis.de>
Wed, 4 Apr 2007 18:30:36 +0000 (18:30 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Wed, 4 Apr 2007 18:30:36 +0000 (18:30 +0000)
Will backport to 2.5.

Lib/test/test_os.py
Misc/NEWS
Modules/posixmodule.c

index 40d7c3e7d3d2ecbaf37646c66f1a05f6ac5ff3b9..51fdc8a78c2545cdbde0aa3b6397cbe7cb7ae77e 100644 (file)
@@ -240,6 +240,15 @@ class StatAttributeTests(unittest.TestCase):
             os.utime(self.fname, (t1, t1))
             self.assertEquals(os.stat(self.fname).st_mtime, t1)
 
+        def test_1686475(self):
+            # Verify that an open file can be stat'ed
+            try:
+                os.stat(r"c:\pagefile.sys")
+            except WindowsError, e:
+                if e == 2: # file does not exist; cannot run test
+                    return
+                self.fail("Could not stat pagefile.sys")
+
 from test import mapping_tests
 
 class EnvironTests(mapping_tests.BasicTestMappingProtocol):
index d8f51bcd85f85656fbe6a8e55c4442f7064ebea8..12d4413244650c031ce31dbbdf32d1360696c0f0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -589,6 +589,8 @@ Library
 Extension Modules
 -----------------
 
+- Bug #1686475: Support stat'ing open files on Windows again.
+
 - Patch #1185447: binascii.b2a_qp() now correctly quotes binary characters
   with ASCII value less than 32. Also, it correctly quotes dots only if
   they occur on a single line, as opposed to the previous behavior of
index b9572cfa01e29ef133672e2bdda8ba404d317653..8fc9fa9b2fd62147eed6997be3df5cd97463c705 100644 (file)
@@ -844,14 +844,48 @@ check_gfax()
        *(FARPROC*)&gfaxw = GetProcAddress(hKernel32, "GetFileAttributesExW");
 }
 
+static BOOL
+attributes_from_dir(LPCSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
+{
+       HANDLE hFindFile;
+       WIN32_FIND_DATAA FileData;
+       hFindFile = FindFirstFileA(pszFile, &FileData);
+       if (hFindFile == INVALID_HANDLE_VALUE)
+               return FALSE;
+       FindClose(hFindFile);
+       pfad->dwFileAttributes = FileData.dwFileAttributes;
+       pfad->ftCreationTime   = FileData.ftCreationTime;
+       pfad->ftLastAccessTime = FileData.ftLastAccessTime;
+       pfad->ftLastWriteTime  = FileData.ftLastWriteTime;
+       pfad->nFileSizeHigh    = FileData.nFileSizeHigh;
+       pfad->nFileSizeLow     = FileData.nFileSizeLow;
+       return TRUE;
+}
+
+static BOOL
+attributes_from_dir_w(LPCWSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
+{
+       HANDLE hFindFile;
+       WIN32_FIND_DATAW FileData;
+       hFindFile = FindFirstFileW(pszFile, &FileData);
+       if (hFindFile == INVALID_HANDLE_VALUE)
+               return FALSE;
+       FindClose(hFindFile);
+       pfad->dwFileAttributes = FileData.dwFileAttributes;
+       pfad->ftCreationTime   = FileData.ftCreationTime;
+       pfad->ftLastAccessTime = FileData.ftLastAccessTime;
+       pfad->ftLastWriteTime  = FileData.ftLastWriteTime;
+       pfad->nFileSizeHigh    = FileData.nFileSizeHigh;
+       pfad->nFileSizeLow     = FileData.nFileSizeLow;
+       return TRUE;
+}
+
 static BOOL WINAPI
 Py_GetFileAttributesExA(LPCSTR pszFile, 
                       GET_FILEEX_INFO_LEVELS level,
                        LPVOID pv)
 {
        BOOL result;
-       HANDLE hFindFile;
-       WIN32_FIND_DATAA FileData;
        LPWIN32_FILE_ATTRIBUTE_DATA pfad = pv;
        /* First try to use the system's implementation, if that is
           available and either succeeds to gives an error other than
@@ -873,17 +907,7 @@ Py_GetFileAttributesExA(LPCSTR pszFile,
           accept). */
        if (GetFileAttributesA(pszFile) == 0xFFFFFFFF)
                return FALSE;
-       hFindFile = FindFirstFileA(pszFile, &FileData);
-       if (hFindFile == INVALID_HANDLE_VALUE)
-               return FALSE;
-       FindClose(hFindFile);
-       pfad->dwFileAttributes = FileData.dwFileAttributes;
-       pfad->ftCreationTime   = FileData.ftCreationTime;
-       pfad->ftLastAccessTime = FileData.ftLastAccessTime;
-       pfad->ftLastWriteTime  = FileData.ftLastWriteTime;
-       pfad->nFileSizeHigh    = FileData.nFileSizeHigh;
-       pfad->nFileSizeLow     = FileData.nFileSizeLow;
-       return TRUE;
+       return attributes_from_dir(pszFile, pfad);
 }
 
 static BOOL WINAPI
@@ -892,8 +916,6 @@ Py_GetFileAttributesExW(LPCWSTR pszFile,
                        LPVOID pv)
 {
        BOOL result;
-       HANDLE hFindFile;
-       WIN32_FIND_DATAW FileData;
        LPWIN32_FILE_ATTRIBUTE_DATA pfad = pv;
        /* First try to use the system's implementation, if that is
           available and either succeeds to gives an error other than
@@ -915,17 +937,7 @@ Py_GetFileAttributesExW(LPCWSTR pszFile,
           accept). */
        if (GetFileAttributesW(pszFile) == 0xFFFFFFFF)
                return FALSE;
-       hFindFile = FindFirstFileW(pszFile, &FileData);
-       if (hFindFile == INVALID_HANDLE_VALUE)
-               return FALSE;
-       FindClose(hFindFile);
-       pfad->dwFileAttributes = FileData.dwFileAttributes;
-       pfad->ftCreationTime   = FileData.ftCreationTime;
-       pfad->ftLastAccessTime = FileData.ftLastAccessTime;
-       pfad->ftLastWriteTime  = FileData.ftLastWriteTime;
-       pfad->nFileSizeHigh    = FileData.nFileSizeHigh;
-       pfad->nFileSizeLow     = FileData.nFileSizeLow;
-       return TRUE;
+       return attributes_from_dir_w(pszFile, pfad);
 }
 
 static int 
@@ -936,10 +948,20 @@ win32_stat(const char* path, struct win32_stat *result)
        char *dot;
        /* XXX not supported on Win95 and NT 3.x */
        if (!Py_GetFileAttributesExA(path, GetFileExInfoStandard, &info)) {
-               /* Protocol violation: we explicitly clear errno, instead of
-                  setting it to a POSIX error. Callers should use GetLastError. */
-               errno = 0;
-               return -1;
+               if (GetLastError() != ERROR_SHARING_VIOLATION) {
+                       /* Protocol violation: we explicitly clear errno, instead of
+                          setting it to a POSIX error. Callers should use GetLastError. */
+                       errno = 0;
+                       return -1;
+               } else {
+                       /* Could not get attributes on open file. Fall back to
+                          reading the directory. */
+                       if (!attributes_from_dir(path, &info)) {
+                               /* Very strange. This should not fail now */
+                               errno = 0;
+                               return -1;
+                       }
+               }
        }
        code = attribute_data_to_stat(&info, result);
        if (code != 0)
@@ -964,10 +986,20 @@ win32_wstat(const wchar_t* path, struct win32_stat *result)
        WIN32_FILE_ATTRIBUTE_DATA info;
        /* XXX not supported on Win95 and NT 3.x */
        if (!Py_GetFileAttributesExW(path, GetFileExInfoStandard, &info)) {
-               /* Protocol violation: we explicitly clear errno, instead of
-                  setting it to a POSIX error. Callers should use GetLastError. */
-               errno = 0;
-               return -1;
+               if (GetLastError() != ERROR_SHARING_VIOLATION) {
+                       /* Protocol violation: we explicitly clear errno, instead of
+                          setting it to a POSIX error. Callers should use GetLastError. */
+                       errno = 0;
+                       return -1;
+               } else {
+                       /* Could not get attributes on open file. Fall back to
+                          reading the directory. */
+                       if (!attributes_from_dir_w(path, &info)) {
+                               /* Very strange. This should not fail now */
+                               errno = 0;
+                               return -1;
+                       }
+               }
        }
        code = attribute_data_to_stat(&info, result);
        if (code < 0)