AdaCore / e3-core

Core framework for developing portable automated build systems
26 stars 36 forks source link

sync_tree turns Windows directory symlinks into file symlinks #738

Open sebastianpoeplau opened 1 month ago

sebastianpoeplau commented 1 month ago

When sync_tree is used to copy a directory containing Windows directory symlinks, the resulting copy unexpectedly contains file symlinks instead.

To reproduce the problem, set up a test directory in a Windows shell:

> mkdir test
> mkdir test/real
> cd test
> mklink /D link real
> dir
[...]
 Directory of C:\Users\itmgr\test

07/02/2024  04:07 PM    <DIR>          .
07/03/2024  08:42 AM    <DIR>          ..
07/02/2024  04:06 PM    <SYMLINKD>     link [real]
07/02/2024  04:06 PM    <DIR>          real
[...]

Note that the type of the link is SYMLINKD, indicating a directory link. (This corresponds to the flag SYMBOLIC_LINK_FLAG_DIRECTORY in the Windows API function CreateSymbolicLink.)

Now use sync_tree to copy the directory test somewhere else; the link type changes to SYMLINK:

[...]
 Directory of C:\Users\itmgr\synced

07/02/2024  04:07 PM    <DIR>          .
07/03/2024  08:42 AM    <DIR>          ..
07/02/2024  04:13 PM    <SYMLINK>      link [real]
07/02/2024  04:06 PM    <DIR>          real
[...]

The changed symlink causes the Windows function GetFinalPathNameByHandle to raise API error 123: "The filename, directory name, or volume label syntax is incorrect." The consequence is that the symlink breaks tools using Rust's fs::canonicalize or Python's os.path.realpath(..., strict=True). (The non-strict version of the Python function catches OS error 123 and uses a workaround to still read the link.)

leocardao commented 1 month ago

An MR is under review. I'll come back to you once it's merged. Thank you :)