Skip to content

Commit 35605cc

Browse files
[3.15] gh-158998: Fix os.statx() ignoring follow_symlinks=False (GH-158999) (#160996)
(cherry picked from commit b84e0b7) Co-authored-by: Jonathan J. Helmus <jjhelmus@gmail.com>
1 parent 848e717 commit 35605cc

3 files changed

Lines changed: 29 additions & 3 deletions

File tree

‎Lib/test/test_os/test_os.py‎

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -752,13 +752,13 @@ def test_stat_result_pickle(self):
752752
unpickled = pickle.loads(p)
753753
self.assertEqual(result, unpickled)
754754

755-
def check_statx_attributes(self, filename):
755+
def check_statx_attributes(self, filename, follow_symlinks=True):
756756
maximal_mask = 0
757757
for name in dir(os):
758758
if name.startswith('STATX_'):
759759
maximal_mask |= getattr(os, name)
760-
result = os.statx(filename, maximal_mask)
761-
stat_result = os.stat(filename)
760+
result = os.statx(filename, maximal_mask, follow_symlinks=follow_symlinks)
761+
stat_result = os.stat(filename, follow_symlinks=follow_symlinks)
762762

763763
time_attributes = ('stx_atime', 'stx_btime', 'stx_ctime', 'stx_mtime')
764764
# gh-83714: stx_btime can be None on tmpfs even if STATX_BTIME mask
@@ -873,6 +873,28 @@ def getmask(name):
873873
def test_statx_attributes(self):
874874
self.check_statx_attributes(self.fname)
875875

876+
@unittest.skipUnless(hasattr(os, 'statx'), 'test needs os.statx()')
877+
@os_helper.skip_unless_symlink
878+
def test_statx_attributes_symlink(self):
879+
link = self.fname + '-link'
880+
os.symlink(os.path.basename(self.fname), link)
881+
self.addCleanup(os_helper.unlink, link)
882+
883+
with self.subTest(broken=False, follow_symlinks=True):
884+
self.check_statx_attributes(link, follow_symlinks=True)
885+
886+
with self.subTest(broken=False, follow_symlinks=False):
887+
self.check_statx_attributes(link, follow_symlinks=False)
888+
889+
# break the symlink
890+
os.unlink(self.fname)
891+
with self.subTest(broken=True, follow_symlinks=True):
892+
with self.assertRaises(FileNotFoundError):
893+
os.statx(link, os.STATX_BASIC_STATS, follow_symlinks=True)
894+
895+
with self.subTest(broken=True, follow_symlinks=False):
896+
self.check_statx_attributes(link, follow_symlinks=False)
897+
876898
@unittest.skipUnless(hasattr(os, 'statx'), 'test needs os.statx()')
877899
def test_statx_attributes_bytes(self):
878900
try:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix :func:`os.statx` ignoring the *follow_symlinks* argument.

‎Modules/posixmodule.c‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3709,6 +3709,9 @@ os_statx_impl(PyObject *module, path_t *path, unsigned int mask, int flags,
37093709
"use dir_fd kwarg instead of AT_EMPTY_PATH flag");
37103710
return NULL;
37113711
}
3712+
if (!follow_symlinks) {
3713+
flags |= AT_SYMLINK_NOFOLLOW;
3714+
}
37123715

37133716
/* Future bits may refer to members beyond the current size of struct
37143717
statx, so we need to mask them off to prevent memory corruption. */

0 commit comments

Comments
 (0)