]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-18108: Adding dir_fd and follow_symlinks keyword args to shutil.chown (GH-15811)
authortahia <tahia.khan@gmail.com>
Mon, 22 Apr 2024 18:23:36 +0000 (14:23 -0400)
committerGitHub <noreply@github.com>
Mon, 22 Apr 2024 18:23:36 +0000 (18:23 +0000)
* Adding dir_fd and follow_symlinks keyword args to shutil.chown
* Extending test_shutil.TestShutil.test_chown to include new kwargs
* Updating shutil.chown documentation

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Berker Peksag <berker.peksag@gmail.com>
Co-authored-by: Zachary Ware <zachary.ware@gmail.com>
Doc/library/shutil.rst
Doc/whatsnew/3.13.rst
Lib/shutil.py
Lib/test/test_shutil.py
Misc/NEWS.d/next/Library/2019-09-09-18-18-34.bpo-18108.ajPLAO.rst [new file with mode: 0644]

index 4f07b9f6040d24025a892e2b4c67c333af45a8d3..8e5828c789e4e239793ea3b95996f6270484c247 100644 (file)
@@ -421,7 +421,8 @@ Directory and files operations
 
    .. availability:: Unix, Windows.
 
-.. function:: chown(path, user=None, group=None)
+.. function:: chown(path, user=None, group=None, *, dir_fd=None, \
+                    follow_symlinks=True)
 
    Change owner *user* and/or *group* of the given *path*.
 
@@ -436,6 +437,9 @@ Directory and files operations
 
    .. versionadded:: 3.3
 
+   .. versionchanged:: 3.13
+      Added *dir_fd* and *follow_symlinks* parameters.
+
 
 .. function:: which(cmd, mode=os.F_OK | os.X_OK, path=None)
 
index 5be562030b507b26e6ac78391ade5830fe58d937..c04dc924d1efa535b3c859504a1937196722b023 100644 (file)
@@ -594,6 +594,10 @@ os.path
   exactly one (back)slash to be absolute.
   (Contributed by Barney Gale and Jon Foster in :gh:`44626`.)
 
+* Add support of *dir_fd* and *follow_symlinks* keyword arguments in
+  :func:`shutil.chown`.
+  (Contributed by Berker Peksag and Tahia K in :gh:`62308`)
+
 pathlib
 -------
 
index 94b09509008b0bb2151d37d28f40d66a7d76d577..910d6b6c63ac088214c0abd386d293bdb0a92f27 100644 (file)
@@ -1442,11 +1442,18 @@ elif _WINDOWS:
         return _ntuple_diskusage(total, used, free)
 
 
-def chown(path, user=None, group=None):
+def chown(path, user=None, group=None, *, dir_fd=None, follow_symlinks=True):
     """Change owner user and group of the given path.
 
     user and group can be the uid/gid or the user/group names, and in that case,
     they are converted to their respective uid/gid.
+
+    If dir_fd is set, it should be an open file descriptor to the directory to
+    be used as the root of *path* if it is relative.
+
+    If follow_symlinks is set to False and the last element of the path is a
+    symbolic link, chown will modify the link itself and not the file being
+    referenced by the link.
     """
     sys.audit('shutil.chown', path, user, group)
 
@@ -1472,7 +1479,8 @@ def chown(path, user=None, group=None):
         if _group is None:
             raise LookupError("no such group: {!r}".format(group))
 
-    os.chown(path, _user, _group)
+    os.chown(path, _user, _group, dir_fd=dir_fd,
+             follow_symlinks=follow_symlinks)
 
 def get_terminal_size(fallback=(80, 24)):
     """Get the size of the terminal window.
index 3aa0ec6952339baff28d7be4ddfc6ca21b741c83..5b0aac67a0adeb5d322075c2821df3837b5eb095 100644 (file)
@@ -2212,7 +2212,9 @@ class TestMisc(BaseTest, unittest.TestCase):
     def test_chown(self):
         dirname = self.mkdtemp()
         filename = tempfile.mktemp(dir=dirname)
+        linkname = os.path.join(dirname, "chown_link")
         write_file(filename, 'testing chown function')
+        os.symlink(filename, linkname)
 
         with self.assertRaises(ValueError):
             shutil.chown(filename)
@@ -2233,7 +2235,7 @@ class TestMisc(BaseTest, unittest.TestCase):
         gid = os.getgid()
 
         def check_chown(path, uid=None, gid=None):
-            s = os.stat(filename)
+            s = os.stat(path)
             if uid is not None:
                 self.assertEqual(uid, s.st_uid)
             if gid is not None:
@@ -2269,6 +2271,36 @@ class TestMisc(BaseTest, unittest.TestCase):
             shutil.chown(dirname, user, group)
             check_chown(dirname, uid, gid)
 
+        dirfd = os.open(dirname, os.O_RDONLY)
+        self.addCleanup(os.close, dirfd)
+        basename = os.path.basename(filename)
+        baselinkname = os.path.basename(linkname)
+        shutil.chown(basename, uid, gid, dir_fd=dirfd)
+        check_chown(filename, uid, gid)
+        shutil.chown(basename, uid, dir_fd=dirfd)
+        check_chown(filename, uid)
+        shutil.chown(basename, group=gid, dir_fd=dirfd)
+        check_chown(filename, gid=gid)
+        shutil.chown(basename, uid, gid, dir_fd=dirfd, follow_symlinks=True)
+        check_chown(filename, uid, gid)
+        shutil.chown(basename, uid, gid, dir_fd=dirfd, follow_symlinks=False)
+        check_chown(filename, uid, gid)
+        shutil.chown(linkname, uid, follow_symlinks=True)
+        check_chown(filename, uid)
+        shutil.chown(baselinkname, group=gid, dir_fd=dirfd, follow_symlinks=False)
+        check_chown(filename, gid=gid)
+        shutil.chown(baselinkname, uid, gid, dir_fd=dirfd, follow_symlinks=True)
+        check_chown(filename, uid, gid)
+
+        with self.assertRaises(TypeError):
+            shutil.chown(filename, uid, dir_fd=dirname)
+
+        with self.assertRaises(FileNotFoundError):
+            shutil.chown('missingfile', uid, gid, dir_fd=dirfd)
+
+        with self.assertRaises(ValueError):
+            shutil.chown(filename, dir_fd=dirfd)
+
 
 @support.requires_subprocess()
 class TestWhich(BaseTest, unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Library/2019-09-09-18-18-34.bpo-18108.ajPLAO.rst b/Misc/NEWS.d/next/Library/2019-09-09-18-18-34.bpo-18108.ajPLAO.rst
new file mode 100644 (file)
index 0000000..70ff76a
--- /dev/null
@@ -0,0 +1 @@
+:func:`shutil.chown` now supports *dir_fd* and *follow_symlinks* keyword arguments.