24

The docs of shutil tells me:

Even the higher-level file copying functions (shutil.copy(), shutil.copy2()) can’t copy all file metadata. On POSIX platforms, this means that file owner and group are lost as well as ACLs

How can I keep the file owner and group if I need to copy a file in python?

The process runs on linux as root.

Update: We don't use ACLs. We only need to keep the stuff which is preserved with tools like tar and rsync.

guettli
  • 25,042
  • 81
  • 346
  • 663

6 Answers6

23

You perhaps could use os.stat to get the guid and uid like in this answer and then reset the uid and guid after coping using os.chown.

Community
  • 1
  • 1
Thom Wiggers
  • 6,938
  • 1
  • 39
  • 65
  • 1
    You should read the shutil documentation. `copy2` get everything but owner/group. – lunixbochs Nov 12 '13 at 16:44
  • 1
    You can get `uid` and `guid` using `os.stat` though. – Thom Wiggers Nov 12 '13 at 16:45
  • 2
    @lunixbochs: what is wrong with reading uid, gid of the source file using `os.stat` then setting them on the destination file using `os.chown(path, uid, gid)`? – jfs Nov 12 '13 at 16:46
  • 3
    Works for me. I just saw chmod, not chown (was that in your edit?). You should note the potential requirement for root privileges to arbitrarily set user/group to someone other than yourself. – lunixbochs Nov 12 '13 at 16:47
  • 1
    @lunixbochs: the question clear says: "The process runs on linux as *root*." – jfs Nov 12 '13 at 16:53
20

I did it this way:

import os
import stat
import shutil

def copyComplete(source, target):
    # copy content, stat-info (mode too), timestamps...
    shutil.copy2(source, target)
    # copy owner and group
    st = os.stat(source)
    os.chown(target, st.st_uid, st.st_gid)
Mayra Delgado
  • 531
  • 4
  • 17
9

You can use the subprocess module:

from subprocess import Popen

p = Popen(['cp','-p','--preserve',src,dest])
p.wait()
user545424
  • 15,713
  • 11
  • 56
  • 70
2

See Keeping fileowner and permissions after copying file in C on how cp itself does this, then just replicate its logic. Python has all the system calls mentioned in its os module.

Community
  • 1
  • 1
ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
1

I suggest you use the OS and subprocess modules. This will only work in Unix, but it should work well. Use the os.fchown to change file ownership, and subprocess.Popen() to pipe ls -l into a variable to read ownership. For one file, the permissions reader would look like this:

import os
import subprocess

def readfile(filepath):
    process = subprocess.Popen(["ls","-l"],stdout=subprocess.PIPE)
    output = process.communicate()[0]
    output = output.split()
    return (output[0],output[1])  #insert into this tuple the indexing for the words you want from ls -l

and for the uid setter (just a wrapper for os function):

def setuid(filepath,uid,gid):
    os.chown(filepath,uid,gid)
guettli
  • 25,042
  • 81
  • 346
  • 663
trevorKirkby
  • 1,886
  • 20
  • 47
  • True enough. Especially since os has a function to list the contents of a directory programmatically. Probably better to use that. – trevorKirkby Jun 18 '16 at 06:22
1

as @Thom Wiggers 's answer

  • os.stat get uid,gid
  • os.chmod set uid,gid

demo code:

import os
st = os.stat(src_path)
os.chown(dst_path, st.st_uid, st.st_gid)

check except:

import os
def copy_owner_group(src, dst):
    try:
        st = os.stat(src)
    except Exception as e:
        print 'stat except:', e
    else:
        try:
            os.chown(dst, st.st_uid, st.st_gid)
        except Exception as e:
            print 'chmod except:', e
yurenchen
  • 1,897
  • 19
  • 17
  • 4
    I just ask myself "Why do I need to do coding for this? Why is there no lib which handles this?" – guettli Sep 05 '18 at 09:34