From c8c0249c9e8f61ab7670119a5a5278354df27bbb Mon Sep 17 00:00:00 2001 From: Joe Pamer Date: Tue, 25 Sep 2018 10:57:36 -0400 Subject: [PATCH] bpo-32557: allow shutil.disk_usage to take a file path on Windows also (GH-9372) https://bugs.python.org/issue32557 --- Doc/library/shutil.rst | 7 +++-- Lib/test/test_shutil.py | 1 + .../2018-09-25-10-39-27.bpo-32557.Rs1bf9.rst | 1 + Modules/posixmodule.c | 29 +++++++++++++++++-- 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2018-09-25-10-39-27.bpo-32557.Rs1bf9.rst diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index c692cf43b6d..d8826277a46 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 a169c3684f2..9db6aec1920 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 00000000000..d93c55ac62f --- /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 400ed979821..c7223ab5205 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 */