Commits

Martin von Löwis committed b001b65

Bug #1686475: Support stat'ing open files on Windows again.

Comments (0)

Files changed (3)

Lib/test/test_os.py

             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):
 Extension Modules
 -----------------
 
+- Bug #1686475: Support stat'ing open files on Windows again.
+
 - Bug #1647541: Array module's buffer interface can now handle empty arrays.
 
 - Bug #1693079: The array module can now successfully pickle empty arrays.

Modules/posixmodule.c

 	*(FARPROC*)&gfaxw = GetProcAddress(hKernel32, "GetFileAttributesExW");
 }
 
-static BOOL WINAPI
-Py_GetFileAttributesExA(LPCSTR pszFile, 
-		       GET_FILEEX_INFO_LEVELS level,
-                       LPVOID pv)
-{
-	BOOL result;
+static BOOL
+attributes_from_dir(LPCSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
+{
 	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
-	   that it isn't implemented. */
-	check_gfax();
-	if (gfaxa) {
-		result = gfaxa(pszFile, level, pv);
-		if (result || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
-			return result;
-	}
-	/* It's either not present, or not implemented.
-	   Emulate using FindFirstFile. */
-	if (level != GetFileExInfoStandard) {
-		SetLastError(ERROR_INVALID_PARAMETER);
-		return FALSE;
-	}
-	/* Use GetFileAttributes to validate that the file name
-	   does not contain wildcards (which FindFirstFile would
-	   accept). */
-	if (GetFileAttributesA(pszFile) == 0xFFFFFFFF)
-		return FALSE;
 	hFindFile = FindFirstFileA(pszFile, &FileData);
 	if (hFindFile == INVALID_HANDLE_VALUE)
 		return FALSE;
 	return TRUE;
 }
 
-static BOOL WINAPI
-Py_GetFileAttributesExW(LPCWSTR pszFile, 
-		       GET_FILEEX_INFO_LEVELS level,
-                       LPVOID pv)
-{
-	BOOL result;
+static BOOL
+attributes_from_dir_w(LPCWSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
+{
 	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
-	   that it isn't implemented. */
-	check_gfax();
-	if (gfaxa) {
-		result = gfaxw(pszFile, level, pv);
-		if (result || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
-			return result;
-	}
-	/* It's either not present, or not implemented.
-	   Emulate using FindFirstFile. */
-	if (level != GetFileExInfoStandard) {
-		SetLastError(ERROR_INVALID_PARAMETER);
-		return FALSE;
-	}
-	/* Use GetFileAttributes to validate that the file name
-	   does not contain wildcards (which FindFirstFile would
-	   accept). */
-	if (GetFileAttributesW(pszFile) == 0xFFFFFFFF)
-		return FALSE;
 	hFindFile = FindFirstFileW(pszFile, &FileData);
 	if (hFindFile == INVALID_HANDLE_VALUE)
 		return FALSE;
 	return TRUE;
 }
 
+static BOOL WINAPI
+Py_GetFileAttributesExA(LPCSTR pszFile, 
+		       GET_FILEEX_INFO_LEVELS level,
+                       LPVOID pv)
+{
+	BOOL result;
+	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
+	   that it isn't implemented. */
+	check_gfax();
+	if (gfaxa) {
+		result = gfaxa(pszFile, level, pv);
+		if (result || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+			return result;
+	}
+	/* It's either not present, or not implemented.
+	   Emulate using FindFirstFile. */
+	if (level != GetFileExInfoStandard) {
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	/* Use GetFileAttributes to validate that the file name
+	   does not contain wildcards (which FindFirstFile would
+	   accept). */
+	if (GetFileAttributesA(pszFile) == 0xFFFFFFFF)
+		return FALSE;
+	return attributes_from_dir(pszFile, pfad);
+}
+
+static BOOL WINAPI
+Py_GetFileAttributesExW(LPCWSTR pszFile, 
+		       GET_FILEEX_INFO_LEVELS level,
+                       LPVOID pv)
+{
+	BOOL result;
+	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
+	   that it isn't implemented. */
+	check_gfax();
+	if (gfaxa) {
+		result = gfaxw(pszFile, level, pv);
+		if (result || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+			return result;
+	}
+	/* It's either not present, or not implemented.
+	   Emulate using FindFirstFile. */
+	if (level != GetFileExInfoStandard) {
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	/* Use GetFileAttributes to validate that the file name
+	   does not contain wildcards (which FindFirstFile would
+	   accept). */
+	if (GetFileAttributesW(pszFile) == 0xFFFFFFFF)
+		return FALSE;
+	return attributes_from_dir_w(pszFile, pfad);
+}
+
 static int 
 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)
 	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)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.