New submission from Darko Poljak:

shutil.copytree() always calls copystat() for symlinks. Copying symlink to 
another volume fails if some attributes cannot be set. And there is no 
alternative to bypass this as it can be done for files and directories using 
copy_function.
By default copy_function equals copy2() which calls copystat(). There is also 
copy() available which calls copymode().

>From the copytree() source code one can see that for symlink copystat()
is called in any case:

            if os.path.islink(srcname):
                linkto = os.readlink(srcname)
                if symlinks:
                    # We can't just leave it to `copy_function` because legacy
                    # code with a custom `copy_function` may rely on copytree
                    # doing the right thing.
                    os.symlink(linkto, dstname)
                    copystat(srcname, dstname, follow_symlinks=not symlinks)

An example is running inside a docker container with a zfs based volume
mounted at /root/.cdist. Root filesytem with /tmp is also on zfs based
container root-volume.

And copying files with shutil.move which in this case uses copytree results in 
the following error:

Traceback (most recent call last):
  File "/appenv/lib/python3.5/shutil.py", line 538, in move
    os.rename(src, real_dst)
OSError: [Errno 18] Cross-device link: 
'/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data' -> 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/appenv/bin/cdist", line 94, in <module>
    commandline()
  File "/appenv/bin/cdist", line 66, in commandline
    args.func(args)
  File "/appenv/lib/python3.5/site-packages/cdist/config.py", line 157, in 
commandline
    args, parallel=False)
  File "/appenv/lib/python3.5/site-packages/cdist/config.py", line 227, in 
onehost
    c.run()
  File "/appenv/lib/python3.5/site-packages/cdist/config.py", line 255, in run
    self.local.save_cache()
  File "/appenv/lib/python3.5/site-packages/cdist/exec/local.py", line 265, in 
save_cache
    shutil.move(self.base_path, destination)
  File "/appenv/lib/python3.5/shutil.py", line 549, in move
    symlinks=True)
  File "/appenv/lib/python3.5/shutil.py", line 353, in copytree
    raise Error(errors)
shutil.Error: 
[('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/network',
 '/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/network', 
"[Errno 95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/network'"), 
('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/os', 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/os', "[Errno 
95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/os'"), 
('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/machine',
 '/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/machine', 
"[Errno 95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/machine'"), 
('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/init-system',
 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/init-system',
 "[Errno 95] Not supported: '/root/.cdist
 /cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/init-system'"), 
('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/interfaces',
 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/interfaces', 
"[Errno 95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/interfaces'"),
 
('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/os_version',
 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/os_version', 
"[Errno 95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/os_version'"),
 
('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/cpu_cores',
 '/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/cpu_cores', 
"[Errno 95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/cpu_cores'"),
 
('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/lsb_description',
 '/root/.cdist/cache/93
 6a8745479046ce91a00ee3013fc9b8/conf/explorer/lsb_description', "[Errno 95] Not 
supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/lsb_description'"),
 
('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/machine_type',
 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/machine_type',
 "[Errno 95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/machine_type'"),
 ('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/efi', 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/efi', 
"[Errno 95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/efi'"), 
('/tmp/tmpuxb_jr3y/936a8745479046ce91a00ee3013fc9b8/data/conf/explorer/lsb_id', 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/lsb_id', 
"[Errno 95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/explorer/lsb_id'"), 
...

Using copy_function=copy instead of default copy2 does not solve the problem 
since for symlinks copytree() always uses copystat().

Concrete example which mimics copytree() code for symlink:

(appenv) ~ # rm 
/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/type/__hpc_syslog
(appenv) ~ # python
Python 3.5.2 (default, Dec 20 2016, 17:58:45)
[GCC 5.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> src='/tmp/tmpoiwfrgvk/936a8745479046ce91a00ee3013fc9b8/data/conf/type/__hpc_syslog'
>>> dst='/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/type/__hpc_syslog'
>>> linkto = os.readlink(src)
>>> os.symlink(linkto, dst)
>>> os.stat(dst)
os.stat_result(st_mode=16877, st_ino=955, st_dev=71, st_nlink=4, st_uid=65534, 
st_gid=65534, st_size=8, st_atime=1486540058, st_mtime=1485953153, 
st_ctime=1485953153)

>>> import shutil
>>> shutil.copystat(src, dst, follow_symlinks=False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/appenv/lib/python3.5/shutil.py", line 197, in copystat
    lookup("chmod")(dst, mode, follow_symlinks=follow)
OSError: [Errno 95] Not supported: 
'/root/.cdist/cache/936a8745479046ce91a00ee3013fc9b8/conf/type/__hpc_syslog'
>>>

----------
components: Library (Lib)
messages: 287455
nosy: poljakowski
priority: normal
severity: normal
status: open
title: shutil.copytree(symlinks=True) fails when copying symlinks cross-device 
and there is no alternative
type: crash
versions: Python 3.3, Python 3.4, Python 3.5, Python 3.6, Python 3.7

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

Reply via email to