gh-142155: Fix infinite recursion in shutil.copytree on Windows junctions by ChuheLin · Pull Request #142156 · python/cpython · GitHub
Skip to content
Open
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
20 changes: 15 additions & 5 deletions Lib/shutil.py
36 changes: 36 additions & 0 deletions Lib/test/test_shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,42 @@ def test_copytree_subdirectory(self):
rv = shutil.copytree(src_dir, dst_dir)
self.assertEqual(['pol'], os.listdir(rv))

@unittest.skipUnless(sys.platform == "win32", "Windows-specific test")
def test_copytree_recursive_junction(self):
# Test that copytree raises Error for recursive junctions (Windows)
base_dir = self.mkdtemp()
self.addCleanup(shutil.rmtree, base_dir, ignore_errors=True)

# Create source directory structure
src_dir = os.path.join(base_dir, "source")
junction_dir = os.path.join(src_dir, "junction")
os.makedirs(junction_dir)

# Create a junction pointing to its parent, creating a cycle
junction_target = os.path.dirname(junction_dir) # Points to Source

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
junction_target = os.path.dirname(junction_dir) # Points to Source
junction_target = os.path.dirname(junction_dir)

try:
result = subprocess.run(
["mklink", "/J", junction_dir, junction_target],
shell=True, check=False, capture_output=True, text=True
)
if result.returncode != 0:
# Skip if we don't have permission to create junctions
self.skipTest(f"Failed to create junction: {result.stderr.strip()}")
except Exception as e:
# Skip if mklink is not available or fails for any reason
self.skipTest(f"Failed to create junction: {e}")
Comment on lines +1123 to +1125

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a good idea. Can't we create a junction from Python directly? (cc @barneygale).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still not addressed.


# Create destination directory
dst_dir = os.path.join(base_dir, "Dest")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dest -> dest


# Test that copytree raises Error with infinite recursion message
with self.assertRaises(shutil.Error) as cm:
shutil.copytree(src_dir, dst_dir)

# Verify the error message contains "Infinite recursion detected"
self.assertIn("Infinite recursion detected", str(cm.exception))

Comment thread
ChuheLin marked this conversation as resolved.

class TestCopy(BaseTest, unittest.TestCase):

### shutil.copymode
Expand Down
Loading