8000 bpo-46245: Add optional parameter dir_fd in shutil.rmtree() (GH-30365) · python-docs-tr/cpython@02fbaf4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 02fbaf4

Browse files
bpo-46245: Add optional parameter dir_fd in shutil.rmtree() (pythonGH-30365)
1 parent 5eb03b1 commit 02fbaf4

File tree

5 files changed

+49
-7
lines changed

5 files changed

+49
-7
lines changed

Doc/library/shutil.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ Directory and files operations
286286
.. versionadded:: 3.8
287287
The *dirs_exist_ok* parameter.
288288

289-
.. function:: rmtree(path, ignore_errors=False, onerror=None)
289+
.. function:: rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None)
290290

291291
.. index:: single: directory; deleting
292292

@@ -296,6 +296,9 @@ Directory and files operations
296296
handled by calling a handler specified by *onerror* or, if that is omitted,
297297
they raise an exception.
298298

299+
This function can support :ref:`paths relative to directory descriptors
300+
<dir_fd>`.
301+
299302
.. note::
300303

301304
On platforms that support the necessary fd-based functions a symlink
@@ -315,7 +318,7 @@ Directory and files operations
315318
*excinfo*, will be the exception information returned by
316319
:func:`sys.exc_info`. Exceptions raised by *onerror* will not be caught.
317320

318-
.. audit-event:: shutil.rmtree path shutil.rmtree
321+
.. audit-event:: shutil.rmtree path,dir_fd shutil.rmtree
319322

320323
.. versionchanged:: 3.3
321324
Added a symlink attack resistant version that is used automatically
@@ -325,6 +328,9 @@ Directory and files operations
325328
On Windows, will no longer delete the contents of a directory junction
326329
before removing the junction.
327330

331+
.. versionchanged:: 3.11
332+
The *dir_fd* parameter.
333+
328334
.. attribute:: rmtree.avoids_symlink_attacks
329335

330336
Indicates whether the current platform and implementation provides a

Doc/whatsnew/3.11.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,13 @@ os
283283
(Contributed by Dong-hee Na in :issue:`44611`.)
284284

285285

286+
shutil
287+
------
288+
289+
* Add optional parameter *dir_fd* in :func:`shutil.rmtree`.
290+
(Contributed by Serhiy Storchaka in :issue:`46245`.)
291+
292+
286293
socket
287294
------
288295

Lib/shutil.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -684,9 +684,14 @@ def _rmtree_safe_fd(topfd, path, onerror):
684684
os.scandir in os.supports_fd and
685685
os.stat in os.supports_follow_symlinks)
686686

687-
def rmtree(path, ignore_errors=False, onerror=None):
687+
def rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None):
688688
"""Recursively delete a directory tree.
689689
690+
If dir_fd is not None, it should be a file descriptor open to a directory;
691+
path will then be relative to that directory.
692+
dir_fd may not be implemented on your platform.
693+
If it is unavailable, using it will raise a NotImplementedError.
694+
690695
If ignore_errors is set, errors are ignored; otherwise, if onerror
691696
is set, it is called to handle the error with arguments (func,
692697
path, exc_info) where func is platform and implementation dependent;
@@ -695,7 +700,7 @@ def rmtree(path, ignore_errors=False, onerror=None):
695700
is false and onerror is None, an exception is raised.
696701
697702
"""
698-
sys.audit("shutil.rmtree", path)
703+
sys.audit("shutil.rmtree", path, dir_fd)
699704
if ignore_errors:
700705
def onerror(*args):
701706
pass
@@ -709,12 +714,12 @@ def onerror(*args):
709714
# Note: To guard against symlink races, we use the standard
710715
# lstat()/open()/fstat() trick.
711716
try:
712-
orig_st = os.lstat(path)
717+
orig_st = os.lstat(path, dir_fd=dir_fd)
713718
except Exception:
714719
onerror(os.lstat, path, sys.exc_info())
715720
return
716721
try:
717-
fd = os.open(path, os.O_RDONLY)
722+
fd = os.open(path, os.O_RDONLY, dir_fd=dir_fd)
718723
fd_closed = False
719724
except Exception:
720725
onerror(os.open, path, sys.exc_info())
@@ -725,7 +730,7 @@ def onerror(*args):
725730
try:
726731
os.close(fd)
727732
fd_closed = True
728-
os.rmdir(path)
733+
os.rmdir(path, dir_fd=dir_fd)
729734
except OSError:
730735
onerror(os.rmdir, path, sys.exc_info())
731736
else:
@@ -738,6 +743,8 @@ def onerror(*args):
738743
if not fd_closed:
739744
os.close(fd)
740745
else:
746+
if dir_fd is not None:
747+
raise NotImplementedError("dir_fd unavailable on this platform")
741748
try:
742749
if _rmtree_islink(path):
743750
# symlinks to directories are forbidden, see bug #1669

Lib/test/test_shutil.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,27 @@ def _raiser(*args, **kwargs):
405405
self.assertFalse(shutil._use_fd_functions)
406406
self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
407407

408+
@unittest.skipUnless(shutil._use_fd_functions, "dir_fd is not supported")
409+
def test_rmtree_with_dir_fd(self):
410+
tmp_dir = self.mkdtemp()
411+
victim = 'killme'
412+
fullname = os.path.join(tmp_dir, victim)
413+
dir_fd = os.open(tmp_dir, os.O_RDONLY)
414+
self.addCleanup(os.close, dir_fd)
415+
os.mkdir(fullname)
416+
os.mkdir(os.path.join(fullname, 'subdir'))
417+
write_file(os.path.join(fullname, 'subdir', 'somefile'), 'foo')
418+
self.assertTrue(os.path.exists(fullname))
419+
shutil.rmtree(victim, dir_fd=dir_fd)
420+
self.assertFalse(os.path.exists(fullname))
421+
422+
@unittest.skipIf(shutil._use_fd_functions, "dir_fd is supported")
423+
def test_rmtree_with_dir_fd_unsupported( 8AE1 self):
424+
tmp_dir = self.mkdtemp()
425+
with self.assertRaises(NotImplementedError):
426+
shutil.rmtree(tmp_dir, dir_fd=0)
427+
self.assertTrue(os.path.exists(tmp_dir))
428+
408429
def test_rmtree_dont_delete_file(self):
409430
# When called on a file instead of a directory, don't delete it.
410431
handle, path = tempfile.mkstemp(dir=self.mkdtemp())
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add optional parameter *dir_fd* in :func:`shutil.rmtree`.

0 commit comments

Comments
 (0)
0