Eryk Sun <eryk...@gmail.com> added the comment:

Windows implements filesystem symlinks and mountpoints as name-surrogate 
reparse points. Python 3.8 introduced behavior changes to how reparse points 
are supported, but the stat st_mode value still sets S_IFLNK only for actual 
symlinks, not for mountpoints. This ensures that if os.path.islink() is true, 
it's safe to read its target and copy it via os.readlink() and os.symlink().

A mountpoint is not equivalent to a symlink in a few cases, so it shouldn't 
always be handled the same or copied as a symlink. The major difference is that 
mountpoints in a remote path are evaluated by the server, whereas symlinks in a 
remote path are evaluated by the client. Also, during path parsing, the target 
of a symlink replaces the opened path, but mountpoints are retained in the 
opened path (except if the target path contains a symlink, but that's broken in 
remote paths and should be avoided). This means that relative ".." components 
and rooted paths in a relative symlink target will traverse a mountpoint as if 
it's just a directory in the opened path. That's an important distinction, but 
in practice I'd steer someone away from relying on it, especially if a 
filesystem is mounted in multiple locations (e.g. on both a DOS drive and a 
directory), else resolution of the symlink will depend on which mountpoint is 
used.

It's best to handle mountpoints as if they're symlinks when deleting a tree 
because the way they're implemented as reparse points doesn't prevent loops. 
However, when walking a tree, you may or may not want to traverse a mountpoint. 
If it's traversed, a seen set() can be used to remember previously traversed 
directories, in order to prevent loops. As Steve mentioned, look to the 
implementation of shutil.rmtree() as an example. 

However, don't look to shutil.copytree() since it's wrong. The is_symlink() 
method of a scandir() entry is only true for an actual symlink, not a 
mountpoint, so the extra check that copytree() does is redundant. I think it 
was left in by mistake when the plan was to handle mountpoints as symlinks. It 
would be nice if we could copy a mountpoint instead of traversing it in 
copytree(), but the private implementation of _winapi.CreateJunction() isn't 
well-behaved and tested enough to be promoted into the standard library as 
something like os.mount().

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue23407>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to