You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
shutil.move fails to move symlink (Invalid cross-device link) #70978
I'm not really sure if this is a new issue but digging through the bug reports from the past I couldn't find an answer.
There's http://bugs.python.org/issue1438480 but this seems to be a different issue.
I also found http://bugs.python.org/issue9993 that addressed problems with symlinks but didn't correct the behavior reported here.
The problem can be visualized with the following code.
Code fails on python 2.7 as well as python 3.4+. Not tested in python <2.7 and <3.4.
% python3 test.py
Traceback (most recent call last):
File "test.py", line 14, in<module>
shutil.move(TESTLINK, TMPDIR)
File "/usr/lib64/python3.4/shutil.py", line 516, in move
os.rename(src, dst)
OSError: [Errno 18] Invalid cross-device link: 'test_dir'->'/tmp/tmpdir'
This happens because /tmp is:
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noatime,nodiratime)
In the past the recommendation to handle this problem was to stop using os.rename and use shutil.move instead.
This was even discussed in a bug report - http://bugs.python.org/issue14848
If one searches for this exception there's plenty of advice [1][2][3][4] in the same direction.
However, given that shutil.move uses os.rename internally, the problem returns.
On the other end doing the equivalent action in the shell with 'mv' works fine.
This seems to be only triggered when moving a symlink into its destination. Assumption in the code is that when _samefile returns True, it must be due to case-insensitive filesystem, rather than this edge case.
It also happens when moving a file in linux from an xfs filesystem to a NFS mounted filesystem.
websurfer5 commented on Aug 6, 2020
websurfer5mannequin
Mannequin
More actions
SilentGhost's analysis is correct. The provided example code causes the error because it is trying to move the symlink into its target when the target is a directory. Any cross-device moving issues are unrelated to this example code. Here is the relevant code in the master branch:
ifos.path.isdir(dst):
if_samefile(src, dst):
# We might be on a case insensitive filesystem,# perform the rename anyway.os.rename(src, dst)
return
shutil._samefile() considers the example link and its target to be the same. When _samefile() returns False, this code gets executed:
A simple fix is to check whether src is a symlink when _samefile() returns True. The "Destination path...already exists" error isn't a problem for our symlink case because the shell mv command also returns an error.
$ ls -l /tmp/tmpdir/
total 0
lrwxr-xr-x 1 jeff staff 11 Aug 5 23:36 test_dir -> /tmp/tmpdir
$ mv test_dir /tmp/tmpdir
mv: test_dir and /tmp/tmpdir/test_dir are identical
Activity
Unode commentedon Apr 17, 2016
Hi everyone,
I'm not really sure if this is a new issue but digging through the bug reports from the past I couldn't find an answer.
There's http://bugs.python.org/issue1438480 but this seems to be a different issue.
I also found http://bugs.python.org/issue9993 that addressed problems with symlinks but didn't correct the behavior reported here.
The problem can be visualized with the following code.
Code fails on python 2.7 as well as python 3.4+. Not tested in python <2.7 and <3.4.
When executed it gives me:
This happens because /tmp is:
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noatime,nodiratime)
In the past the recommendation to handle this problem was to stop using os.rename and use shutil.move instead.
This was even discussed in a bug report - http://bugs.python.org/issue14848
If one searches for this exception there's plenty of advice [1][2][3][4] in the same direction.
However, given that shutil.move uses os.rename internally, the problem returns.
On the other end doing the equivalent action in the shell with 'mv' works fine.
[1] - http://stackoverflow.com/a/15300474
[2] - https://mail.python.org/pipermail/python-list/2005-February/342892.html
[3] - http://www.thecodingforums.com/threads/errno-18-invalid-cross-device-link-using-os-rename.341597/
[4] - pypa/pip#103
Unode commentedon Apr 17, 2016
Also related to http://bugs.python.org/issue212317
SilentGhost commentedon Apr 18, 2016
This seems to be only triggered when moving a symlink into its destination. Assumption in the code is that when _samefile returns True, it must be due to case-insensitive filesystem, rather than this edge case.
MurrayWilson commentedon Jul 31, 2020
It also happens when moving a file in linux from an xfs filesystem to a NFS mounted filesystem.
websurfer5 commentedon Aug 6, 2020
SilentGhost's analysis is correct. The provided example code causes the error because it is trying to move the symlink into its target when the target is a directory. Any cross-device moving issues are unrelated to this example code. Here is the relevant code in the master branch:
shutil._samefile() considers the example link and its target to be the same. When _samefile() returns False, this code gets executed:
A simple fix is to check whether src is a symlink when _samefile() returns True. The "Destination path...already exists" error isn't a problem for our symlink case because the shell mv command also returns an error.
$ ls -l /tmp/tmpdir/ total 0 lrwxr-xr-x 1 jeff staff 11 Aug 5 23:36 test_dir -> /tmp/tmpdir $ mv test_dir /tmp/tmpdir mv: test_dir and /tmp/tmpdir/test_dir are identicalI will generate a pull request.
iritkatriel commentedon Nov 30, 2021
Removing old versions.