Python shutil.copy fails on FAT file systems (Ubuntu)
Asked Answered
D

2

6

Problem: Using shutil.copy() to copy a file to a FAT16 mounted filesystem in Linux fails (Python 2.7.x). The failure is shutil internal error and failing actually on shutil.chmod, which shutil.copy seems to execute.

Shell chmod fails, too, as permissions are not supported in FAT.

Questions: Is there any neat way around this? I know I have several options, for example:

  1. Use copyfile - not ideal as it requires full path, not just target directory, but doable
  2. Execute shell cp to copy files
  3. Write own copy function that doesn't try to change file modes

Is there a way around this in Python OR in FAT mount options? I now mount the filesystem inside my program by executing mount -t vfat -o umask=000 /dev/loop0 /mnt/foo

Catching the exception doesn't help, as the exception happens inside shutil.copy and shutil.copy() seems to delete the target file when it catches IOException from shutil.chmod(), before passing IOException to the calling function.

Any ideas, or should I just choose one from 1-3?

Hannu

Dimpledimwit answered 16/11, 2013 at 15:30 Comment(0)
T
5

Well I cheat in this case.

If I know that the target is a file system where chmod fails, I simply delete the chmod method from the os package using del os.chmod, and this allows the copy to succeed.

>>> import os
>>> print hasattr(os, 'chmod')
True
>>> foo = os.chmod
>>> del os.chmod
>>> print hasattr(os, 'chmod')
False

This now allows you to perform the copy without failing on the chmod. Then we re-enable it by assigning the attribute back.

>>> setattr(os, 'chmod', foo)
>>> print hasattr(os, 'chmod')
True
Tintinnabulum answered 16/11, 2013 at 19:22 Comment(2)
OS X is much neater in that it simply ignores the chmod on the FAT/VFAT file system, so you don't need to work around this issue.Tintinnabulum
Works well. Good man. I actually came across this when moving my code from OSX to Linux. It worked fine on a Mac but crashed on Ubuntu. In this case I don't have much choice but this seems to do the trick.Dimpledimwit
O
0

Use shutil.copyfile, it does not require full path.

Deleting os.chmod globally is not a good idea.

$ mkdir folder
$ touch folder/a
$ python2.7 -c 'import shutil; shutil.copyfile("folder/a","folder/b")'
$ ls -rthla folder/
total 0
drwxr-xr-x+ Apr 17 12:49 ../
-rw-r--r--  Apr 17 12:49 a
-rw-r--r--  Apr 17 12:50 b
drwxr-xr-x+ Apr 17 12:50 ./

As you can see in the python source code of shutil (/usr/lib/python2.7/shutil.py), there is no path consideration (relative/absolute) in the copy source code, the src variable is directly passed as an argument of copyfile.

def copy(src, dst):
    """Copy data and mode bits ("cp src dst").

    The destination may be a directory.

    """
    if os.path.isdir(dst):
        dst = os.path.join(dst, os.path.basename(src))
    copyfile(src, dst)
    copymode(src, dst)
Outhaul answered 17/4, 2015 at 10:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.