bpo-32557: allow shutil.disk_usage to take a file path on Windows als… · python/cpython@c8c0249 (original) (raw)
4 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -343,11 +343,14 @@ Directory and files operations | ||
343 | 343 | |
344 | 344 | Return disk usage statistics about the given path as a :term:`named tuple` |
345 | 345 | 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. | |
348 | 348 | |
349 | 349 | .. versionadded:: 3.3 |
350 | 350 | |
351 | + .. versionchanged:: 3.8 | |
352 | + On Windows, *path* can now be a file or directory. | |
353 | + | |
351 | 354 | Availability: Unix, Windows. |
352 | 355 | |
353 | 356 | .. function:: chown(path, user=None, group=None) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1363,6 +1363,7 @@ def _boo(filename, extract_dir, extra): | ||
1363 | 1363 | "disk_usage not available on this platform") |
1364 | 1364 | def test_disk_usage(self): |
1365 | 1365 | usage = shutil.disk_usage(os.path.dirname(__file__)) |
1366 | +self.assertEqual(usage, shutil.disk_usage(__file__)) | |
1366 | 1367 | self.assertGreater(usage.total, 0) |
1367 | 1368 | self.assertGreater(usage.used, 0) |
1368 | 1369 | self.assertGreaterEqual(usage.free, 0) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1 | +Allow shutil.disk_usage to take a file path on Windows |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -10079,13 +10079,38 @@ os__getdiskusage_impl(PyObject *module, path_t *path) | ||
10079 | 10079 | { |
10080 | 10080 | BOOL retval; |
10081 | 10081 | ULARGE_INTEGER _, total, free; |
10082 | +DWORD err = 0; | |
10082 | 10083 | |
10083 | 10084 | Py_BEGIN_ALLOW_THREADS |
10084 | 10085 | retval = GetDiskFreeSpaceExW(path->wide, &_, &total, &free); |
10085 | 10086 | 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 | + } | |
10088 | 10112 | |
10113 | +success: | |
10089 | 10114 | return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); |
10090 | 10115 | } |
10091 | 10116 | #endif /* MS_WINDOWS */ |