Skip to content

Commit c8c0249

Browse files
jopamermiss-islington
authored andcommitted
bpo-32557: allow shutil.disk_usage to take a file path on Windows also (GH-9372)
https://bugs.python.org/issue32557
1 parent 604e7b9 commit c8c0249

4 files changed

Lines changed: 34 additions & 4 deletions

File tree

Doc/library/shutil.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,11 +343,14 @@ Directory and files operations
343343

344344
Return disk usage statistics about the given path as a :term:`named tuple`
345345
with the attributes *total*, *used* and *free*, which are the amount of
346-
total, used and free space, in bytes. On Windows, *path* must be a
347-
directory; on Unix, it can be a file or directory.
346+
total, used and free space, in bytes. *path* may be a file or a
347+
directory.
348348

349349
.. versionadded:: 3.3
350350

351+
.. versionchanged:: 3.8
352+
On Windows, *path* can now be a file or directory.
353+
351354
Availability: Unix, Windows.
352355

353356
.. function:: chown(path, user=None, group=None)

Lib/test/test_shutil.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,7 @@ def _boo(filename, extract_dir, extra):
13631363
"disk_usage not available on this platform")
13641364
def test_disk_usage(self):
13651365
usage = shutil.disk_usage(os.path.dirname(__file__))
1366+
self.assertEqual(usage, shutil.disk_usage(__file__))
13661367
self.assertGreater(usage.total, 0)
13671368
self.assertGreater(usage.used, 0)
13681369
self.assertGreaterEqual(usage.free, 0)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Allow shutil.disk_usage to take a file path on Windows

Modules/posixmodule.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10079,13 +10079,38 @@ os__getdiskusage_impl(PyObject *module, path_t *path)
1007910079
{
1008010080
BOOL retval;
1008110081
ULARGE_INTEGER _, total, free;
10082+
DWORD err = 0;
1008210083

1008310084
Py_BEGIN_ALLOW_THREADS
1008410085
retval = GetDiskFreeSpaceExW(path->wide, &_, &total, &free);
1008510086
Py_END_ALLOW_THREADS
10086-
if (retval == 0)
10087-
return PyErr_SetFromWindowsErr(0);
10087+
if (retval == 0) {
10088+
if (GetLastError() == ERROR_DIRECTORY) {
10089+
wchar_t *dir_path = NULL;
10090+
10091+
dir_path = PyMem_New(wchar_t, path->length + 1);
10092+
if (dir_path == NULL) {
10093+
return PyErr_NoMemory();
10094+
}
10095+
10096+
wcscpy_s(dir_path, path->length + 1, path->wide);
10097+
10098+
if (_dirnameW(dir_path) != -1) {
10099+
Py_BEGIN_ALLOW_THREADS
10100+
retval = GetDiskFreeSpaceExW(dir_path, &_, &total, &free);
10101+
Py_END_ALLOW_THREADS
10102+
}
10103+
/* Record the last error in case it's modified by PyMem_Free. */
10104+
err = GetLastError();
10105+
PyMem_Free(dir_path);
10106+
if (retval) {
10107+
goto success;
10108+
}
10109+
}
10110+
return PyErr_SetFromWindowsErr(err);
10111+
}
1008810112

10113+
success:
1008910114
return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart);
1009010115
}
1009110116
#endif /* MS_WINDOWS */

0 commit comments

Comments
 (0)