@@ -4621,9 +4621,15 @@ def test_sneaky_hardlink_fallback(self):
46214621 for filter in 'tar', 'fully_trusted':
46224622 with self.subTest(filter), self.check_context(arc.open(), filter):
46234623 if not os_helper.can_symlink():
4624- self.expect_file("a/t/dummy")
4625- self.expect_file("b/")
4626- self.expect_file("c/")
4624+ if filter == 'tar':
4625+ self.expect_exception(
4626+ tarfile.LinkFallbackError,
4627+ "link 'boom' would be extracted as a copy of "
4628+ + "'c/escape', which was rejected")
4629+ else:
4630+ self.expect_file("a/t/dummy")
4631+ self.expect_file("b/")
4632+ self.expect_file("c/")
46274633 else:
46284634 self.expect_file("a/t/dummy")
46294635 self.expect_file("b/")
@@ -4820,6 +4826,25 @@ def testing_filter(member, path):
48204826 if os_helper.can_chmod():
48214827 self.assertFalse(path.stat().st_mode & stat.S_IWUSR)
48224828
4829+ @symlink_test
4830+ def test_extract_filters_target_none(self):
4831+ # Test that when extract() falls back to extracting (rather than
4832+ # linking) a hardlink target, the member is skipped if the filter
4833+ # returns None.
4834+ with ArchiveMaker() as arc:
4835+ arc.add('a/b/s', symlink_to='../escape')
4836+ arc.add('q', hardlink_to='a/b/s')
4837+ def filter_unsafe_members(member, path):
4838+ try:
4839+ return tarfile.data_filter(member, path)
4840+ except tarfile.FilterError as error:
4841+ return None
4842+ with self.check_context(arc.open(), filter_unsafe_members):
4843+ if os_helper.can_symlink():
4844+ self.expect_file('a/b/s', symlink_to='../escape')
4845+ else:
4846+ self.expect_file('a/b/') # symlink is not extracted
4847+
48234848 def test_link_fallback_normalizes(self):
48244849 # Make sure hardlink fallbacks work for non-normalized paths for all
48254850 # filters
0 commit comments