Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Lib/test/test_os/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,30 @@ def test_fchmod_file(self):
self.check_chmod(posix.fchmod, f.fileno())
self.check_chmod(posix.chmod, f.fileno())

@os_helper.skip_unless_working_chmod
@unittest.skipUnless(os.chmod in os.supports_fd,
"test needs fd support in os.chmod()")
@unittest.skipUnless(os.chmod in os.supports_dir_fd,
"test needs dir_fd support in os.chmod()")
def test_chmod_fd_with_dir_fd(self):
with open(os_helper.TESTFN, 'wb+') as f:
dir_fd = os.open(os.curdir, os.O_RDONLY)
self.addCleanup(os.close, dir_fd)
with self.assertRaisesRegex(ValueError,
'can\'t specify both dir_fd and fd'):
posix.chmod(f.fileno(), 0o600, dir_fd=dir_fd)

@os_helper.skip_unless_working_chmod
@unittest.skipUnless(os.chmod in os.supports_fd,
"test needs fd support in os.chmod()")
@unittest.skipIf(os.name == 'nt',
'follow_symlinks defaults to False on Windows')
def test_chmod_fd_follow_symlinks(self):
with open(os_helper.TESTFN, 'wb+') as f:
with self.assertRaisesRegex(ValueError,
'cannot use fd and follow_symlinks together'):
posix.chmod(f.fileno(), 0o600, follow_symlinks=False)

@unittest.skipUnless(hasattr(posix, 'lchmod'), 'test needs os.lchmod()')
def test_lchmod_file(self):
self.check_chmod(posix.lchmod, os_helper.TESTFN)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:func:`os.chmod` now raises :exc:`ValueError` when *dir_fd* or
*follow_symlinks* is used together with a file descriptor *path*, matching
the documented behaviour and :func:`os.chown`.
9 changes: 9 additions & 0 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -4113,6 +4113,15 @@ os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd,
return NULL;
#endif

if (dir_fd_and_fd_invalid("chmod", dir_fd, path->fd))
return NULL;
#ifndef MS_WINDOWS
/* On Windows, follow_symlinks defaults to False, so doing this check
would reject the valid os.chmod(fd, mode). */
if (fd_and_follow_symlinks_invalid("chmod", path->is_fd, follow_symlinks))
return NULL;
#endif

if (PySys_Audit("os.chmod", "Oii", path->object, mode,
dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
return NULL;
Expand Down
Loading