python / cpython

The Python programming language
https://www.python.org
Other
63.1k stars 30.22k forks source link

Linux shutil.move between mountpoints as root does not retain ownership #71874

Open 8ca6f4de-1a5f-4e3f-8fb4-88e4f2f60513 opened 8 years ago

8ca6f4de-1a5f-4e3f-8fb4-88e4f2f60513 commented 8 years ago
BPO 27687
Nosy @giampaolo, @bitdancer, @ztane

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields: ```python assignee = None closed_at = None created_at = labels = ['type-feature', 'library'] title = 'Linux shutil.move between mountpoints as root does not retain ownership' updated_at = user = 'https://bugs.python.org/jortbloem' ``` bugs.python.org fields: ```python activity = actor = 'giampaolo.rodola' assignee = 'none' closed = False closed_date = None closer = None components = ['Library (Lib)'] creation = creator = 'jort.bloem' dependencies = [] files = [] hgrepos = [] issue_num = 27687 keywords = [] message_count = 3.0 messages = ['272001', '272166', '272306'] nosy_count = 4.0 nosy_names = ['giampaolo.rodola', 'r.david.murray', 'ztane', 'jort.bloem'] pr_nums = [] priority = 'normal' resolution = None stage = None status = 'open' superseder = None type = 'enhancement' url = 'https://bugs.python.org/issue27687' versions = ['Python 3.6'] ```

8ca6f4de-1a5f-4e3f-8fb4-88e4f2f60513 commented 8 years ago

When using shutil.move() between mounts (i.e. when it does a copy/delete), running as root, ownership should be maintained.

To test: log in as root, create a file owned by a regular user. In python, use shutil.move() to move it to another mountpoint. Check that the ownership of the moved file is the same as the ownership of the original file.

bitdancer commented 8 years ago

This is as documented (see copystat). To do anything with user and group would be an enhancement.

ff59cd45-ebe3-4b3e-9696-65dc59a38b8c commented 8 years ago

And as it is documented, it would be a change against documentation. However as a stop-gap it is rather trivial to make your own copy function to fix this. copy2 returns the actual destination, so you could do

     def copy_with_ownership(src, dest, *, follow_symlinks=True):
         actual_dest = copy2(src, dest, follow_symlinks=follow_symlinks)
         fix_ownership(src, actual_dest)
         return actual_dest

implement fix_ownership to do what it needs to do, and pass copy_with_ownership as the copy_function argument to move.