diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index 44f967eb12dd4f..c03a010aa96915 100644 --- a/Lib/pathlib/__init__.py +++ b/Lib/pathlib/__init__.py @@ -1328,8 +1328,13 @@ def _copy_from(self, source, follow_symlinks=True, preserve_metadata=False): child, follow_symlinks, preserve_metadata) if preserve_metadata: _copy_info(source.info, self) - else: + elif source.info.is_file(): + self._copy_from_file(source, preserve_metadata) + elif not source.info.exists(follow_symlinks=follow_symlinks): self._copy_from_file(source, preserve_metadata) + else: + raise io.UnsupportedOperation( + f"{source!r} is a special file and cannot be copied") def _copy_from_file(self, source, preserve_metadata=False): ensure_different_files(source, self) diff --git a/Lib/test/test_pathlib/test_copy.py b/Lib/test/test_pathlib/test_copy.py index 5f4cf82a0314c4..2a6bc824f3ed7e 100644 --- a/Lib/test/test_pathlib/test_copy.py +++ b/Lib/test/test_pathlib/test_copy.py @@ -169,6 +169,35 @@ class LocalToLocalPathCopyTest(CopyTestBase, unittest.TestCase): source_ground = LocalPathGround(Path) target_ground = LocalPathGround(Path) + def test_copy_fifo(self): + import io + import os + if not hasattr(os, 'mkfifo'): + self.skipTest('os.mkfifo() required') + + source = self.source_root / 'test.fifo' + try: + os.mkfifo(source) + except OSError: + self.skipTest("cannot create fifo") + + target = self.target_root / 'copy_fifo' + with self.assertRaises(io.UnsupportedOperation): + source.copy(target) + + def test_copy_char_device(self): + import io + # /dev/null is a character device on POSIX + source = Path('/dev/null') + if not source.exists() or not source.is_char_device(): + self.skipTest('/dev/null required') + + target = self.target_root / 'copy_null' + # This should fail immediately with UnsupportedOperation + # If it were buggy, it might loop infinitely or copy empty file depending on implementation + with self.assertRaises(io.UnsupportedOperation): + source.copy(target) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-01-17-15-49-04.gh-issue-143968.5R_yPR.rst b/Misc/NEWS.d/next/Library/2026-01-17-15-49-04.gh-issue-143968.5R_yPR.rst new file mode 100644 index 00000000000000..eba8d2cd0dc18c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-17-15-49-04.gh-issue-143968.5R_yPR.rst @@ -0,0 +1 @@ +Prevent :meth:`pathlib.Path.copy` from attempting to copy special files like FIFOs or character devices, avoiding hangs or infinite loops.