diff -r d33b9fd46cef Lib/shutil.py --- a/Lib/shutil.py Sun Nov 06 18:47:35 2016 +0200 +++ b/Lib/shutil.py Mon Nov 07 19:24:17 2016 +0200 @@ -388,22 +388,25 @@ def _rmtree_unsafe(path, onerror): # Version using fd-based APIs to protect against races def _rmtree_safe_fd(topfd, path, onerror): - names = [] try: - names = os.listdir(topfd) + with os.scandir(topfd) as scandir_it: + entries = list(scandir_it) except OSError as err: err.filename = path - onerror(os.listdir, path, sys.exc_info()) - for name in names: - fullname = os.path.join(path, name) + onerror(os.scandir, path, sys.exc_info()) + return + for entry in entries: + fullname = os.path.join(path, entry.name) try: - orig_st = os.stat(name, dir_fd=topfd, follow_symlinks=False) - mode = orig_st.st_mode + is_dir = entry.is_dir(follow_symlinks=False) + if is_dir: + orig_st = entry.stat(follow_symlinks=False) + is_dir = stat.S_ISDIR(orig_st.st_mode) except OSError: - mode = 0 - if stat.S_ISDIR(mode): + is_dir = False + if is_dir: try: - dirfd = os.open(name, os.O_RDONLY, dir_fd=topfd) + dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd) except OSError: onerror(os.open, fullname, sys.exc_info()) else: @@ -411,7 +414,7 @@ def _rmtree_safe_fd(topfd, path, onerror if os.path.samestat(orig_st, os.fstat(dirfd)): _rmtree_safe_fd(dirfd, fullname, onerror) try: - os.rmdir(name, dir_fd=topfd) + os.rmdir(entry.name, dir_fd=topfd) except OSError: onerror(os.rmdir, fullname, sys.exc_info()) else: @@ -427,13 +430,13 @@ def _rmtree_safe_fd(topfd, path, onerror os.close(dirfd) else: try: - os.unlink(name, dir_fd=topfd) + os.unlink(entry.name, dir_fd=topfd) except OSError: onerror(os.unlink, fullname, sys.exc_info()) _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <= os.supports_dir_fd and - os.listdir in os.supports_fd and + os.scandir in os.supports_fd and os.stat in os.supports_follow_symlinks) def rmtree(path, ignore_errors=False, onerror=None): diff -r d33b9fd46cef Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py Sun Nov 06 18:47:35 2016 +0200 +++ b/Lib/test/test_shutil.py Mon Nov 07 19:24:17 2016 +0200 @@ -201,7 +201,7 @@ class TestShutil(unittest.TestCase): errors.append(args) shutil.rmtree(filename, onerror=onerror) self.assertEqual(len(errors), 2) - self.assertIs(errors[0][0], os.listdir) + self.assertIs(errors[0][0], os.scandir) self.assertEqual(errors[0][1], filename) self.assertIsInstance(errors[0][2][1], NotADirectoryError) self.assertIn(errors[0][2][1].filename, possible_args)