diff options
-rw-r--r-- | Doc/library/shutil.rst | 7 | ||||
-rw-r--r-- | Lib/test/test_shutil.py | 1 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Windows/2018-09-25-10-39-27.bpo-32557.Rs1bf9.rst | 1 | ||||
-rw-r--r-- | Modules/posixmodule.c | 29 |
4 files changed, 34 insertions, 4 deletions
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index c692cf4..d882627 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -343,11 +343,14 @@ Directory and files operations Return disk usage statistics about the given path as a :term:`named tuple` with the attributes *total*, *used* and *free*, which are the amount of - total, used and free space, in bytes. On Windows, *path* must be a - directory; on Unix, it can be a file or directory. + total, used and free space, in bytes. *path* may be a file or a + directory. .. versionadded:: 3.3 + .. versionchanged:: 3.8 + On Windows, *path* can now be a file or directory. + Availability: Unix, Windows. .. function:: chown(path, user=None, group=None) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index a169c36..9db6aec 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1363,6 +1363,7 @@ class TestShutil(unittest.TestCase): "disk_usage not available on this platform") def test_disk_usage(self): usage = shutil.disk_usage(os.path.dirname(__file__)) + self.assertEqual(usage, shutil.disk_usage(__file__)) self.assertGreater(usage.total, 0) self.assertGreater(usage.used, 0) self.assertGreaterEqual(usage.free, 0) diff --git a/Misc/NEWS.d/next/Windows/2018-09-25-10-39-27.bpo-32557.Rs1bf9.rst b/Misc/NEWS.d/next/Windows/2018-09-25-10-39-27.bpo-32557.Rs1bf9.rst new file mode 100644 index 0000000..d93c55a --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2018-09-25-10-39-27.bpo-32557.Rs1bf9.rst @@ -0,0 +1 @@ +Allow shutil.disk_usage to take a file path on Windows diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 400ed97..c7223ab 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10079,13 +10079,38 @@ os__getdiskusage_impl(PyObject *module, path_t *path) { BOOL retval; ULARGE_INTEGER _, total, free; + DWORD err = 0; Py_BEGIN_ALLOW_THREADS retval = GetDiskFreeSpaceExW(path->wide, &_, &total, &free); Py_END_ALLOW_THREADS - if (retval == 0) - return PyErr_SetFromWindowsErr(0); + if (retval == 0) { + if (GetLastError() == ERROR_DIRECTORY) { + wchar_t *dir_path = NULL; + + dir_path = PyMem_New(wchar_t, path->length + 1); + if (dir_path == NULL) { + return PyErr_NoMemory(); + } + + wcscpy_s(dir_path, path->length + 1, path->wide); + + if (_dirnameW(dir_path) != -1) { + Py_BEGIN_ALLOW_THREADS + retval = GetDiskFreeSpaceExW(dir_path, &_, &total, &free); + Py_END_ALLOW_THREADS + } + /* Record the last error in case it's modified by PyMem_Free. */ + err = GetLastError(); + PyMem_Free(dir_path); + if (retval) { + goto success; + } + } + return PyErr_SetFromWindowsErr(err); + } +success: return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); } #endif /* MS_WINDOWS */ |