Add shutil.chown(..., recursive=False)

...as in (not tested): def _rchown(dir, user, group): for root, dirs, files in os.walk(dir, topdown=False): for name in files: chown(os.path.join(root, name), user, group) def chown(path, user=None, group=None, recursive=False): if recursive and os.path.isdir(path): _rchown(dir, user, group) ... It appears like a common enough use case to me ("chown -R path"). Thoughts? -- Giampaolo - http://grodola.blogspot.com

On Mon, May 28, 2018 at 11:13 PM, Barry <barry@barrys-emacs.org> wrote:
You're right, I didn't think about that. I remember myself doing "chown -R dir" every once in a while but didn't recall I prepended "sudo". =) -- Giampaolo - http://grodola.blogspot.com

path.py Path.choen supports names in addition to the uid/gid numbers which os.chown supports: https://pathpy.readthedocs.io/en/stable/api.html#path.Path.chown https://github.com/jaraco/path.py/blob/master/path.py#L1176 https://pathpy.readthedocs.io/en/stable/api.html#path.Path.walk On Monday, May 28, 2018, Giampaolo Rodola' <g.rodola@gmail.com> wrote:

On Mon, May 28, 2018 at 10:13:47PM +0100, Barry wrote:
On 28 May 2018, at 21:23, Giampaolo Rodola' <g.rodola@gmail.com> wrote:
[...]
Certainly not. You only have to be root to change permissions on files that you otherwise wouldn't be able to change permissions on. chmod -R works fine for regular users changing their own files. Why wouldn't it? [steve@ando ~]$ ls -lR test test: total 12 -rw-rw-r-- 1 steve steve 5 Feb 4 2017 eggs.py drwxrwxr-x 2 steve steve 4096 May 29 09:41 package -rw-rw-r-- 1 steve steve 40 Feb 4 2017 spam.py test/package: total 0 -rw-rw-r-- 1 steve steve 0 May 29 09:41 __init__.py -rw-rw-r-- 1 steve steve 0 May 29 09:41 spam.py [steve@ando ~]$ chmod -R a-w test [steve@ando ~]$ ls -lR test test: total 12 -r--r--r-- 1 steve steve 5 Feb 4 2017 eggs.py dr-xr-xr-x 2 steve steve 4096 May 29 09:41 package -r--r--r-- 1 steve steve 40 Feb 4 2017 spam.py test/package: total 0 -r--r--r-- 1 steve steve 0 May 29 09:41 __init__.py -r--r--r-- 1 steve steve 0 May 29 09:41 spam.py -- Steve

On Tue, May 29, 2018 at 10:11:22AM +1000, Chris Angelico wrote:
On Tue, May 29, 2018 at 9:47 AM, Steven D'Aprano <steve@pearwood.info> wrote:
/face-palm Indeed he did. But it doesn't matter: regular users can call chown -R: [steve@ando ~]$ chown -R steve.users test [steve@ando ~]$ ls -lR test test: total 12 -rw-rw-rw- 1 steve users 5 Feb 4 2017 eggs.py drwxrwxrwx 2 steve users 4096 May 29 09:41 package -rw-rw-rw- 1 steve users 40 Feb 4 2017 spam.py test/package: total 0 -rw-rw-rw- 1 steve users 0 May 29 09:41 __init__.py -rw-rw-rw- 1 steve users 0 May 29 09:41 spam.py The limitations on calling chown apply equally to the recursive and non-recursive case. -- Steve

Steven D'Aprano wrote:
But it doesn't matter: regular users can call chown -R:
Only if you're not actually telling it to change anything. % ls -l foo.txt -rw-r--r-- 1 greg users 1 29 May 18:19 foo.txt % chown greg foo.txt % chown fred foo.txt chown: foo.txt: Operation not permitted So you have to be root in order to do anything *useful* with it. -- Greg

On Tue, May 29, 2018 at 06:29:50PM +1200, Greg Ewing wrote:
That's not correct. Look closely at my example: the file ownership recursively changed from steve.steve to steve.users.
And yet Python provides a chown function despite this alleged uselessness. Maybe it's not quite so useless as you think? Here's a thought... maybe sometimes people actually do run Python scripts as root? And as the comments to this Stackoverflow post explain: https://unix.stackexchange.com/questions/119229/can-not-chown-a-file-from-my... the ability for unprivileged users to change ownership to another user is configurable under POSIX.
So you have to be root in order to do anything *useful* with it.
Fortunately that is not correct, but even if it were, that's no reason to not allow chown to apply recursively. -- Steve

Steven D'Aprano wrote:
Look closely at my example: the file ownership recursively changed from steve.steve to steve.users.
You're quite right. I hadn't realised that chown can be used to change the group as well as the user. It's permitted to change the group to one that the user is a member of. -- Greg

BTW, I wouldn't argue that Python shouldn't provide things that are only useful to root. While writing setuid utilities in Python is a bad idea for lots of reasons, I don't think there's anything wrong with becoming root by another means and then running a Python program that you know well enough to trust. -- Greg

On Wed, May 30, 2018 at 9:11 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
I'd go further. Once a shell script gets longer than about a page or two of code, it often needs to be rewritten in a different language, and Python is well situated to be that language. That doesn't change when the script is to be run as root. I've written many Python scripts to do sysadminning jobs for me - usually one-shot scripts, but also some that stick around. Since I wrote the scripts myself, the trust issue doesn't come up; I trust the Python interpreter the same way that I trust /bin/bash. ChrisA

Configuration management tools with far more code than this are regularly run with root privileges. OTOH, Salt and Ansible, for example, both support recursive chown and chmod; and report what actually changed. Yum/dnf probably do, too. Supporting recursive chmod/chown OOB may be useful. That it might be run as root is not the criteria, AFAIU. On Tuesday, May 29, 2018, Chris Angelico <rosuav@gmail.com> wrote:

On 29 May 2018 at 06:23, Giampaolo Rodola' <g.rodola@gmail.com> wrote:
https://bugs.python.org/issue13033 is a long-open RFE for this, proposing to add it as "shutil.chowntree" (naming inspired by "shutil.rmtree" and "shutil.copytree"). The "walkdir" project I mention on that PR has been on hiatus for a few years now (aside from a bit of activity to get a new release out in 2016 with several contributed fixes), but the main point of the comment where I mentioned it still stands: the hard part of designing recursive state modification APIs is deciding what to do when an operation fails after you've already made changes to the state of the disk. shutil.rmtree fortunately provides some good precedent there, but it does mean this feature would need to be implemented as its own API, rather than as an option on shutil.chown. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

Honestly, despite the occasional use case(1), I'm not sure that this is a battery we need in the stdlib. Nobody seems too excited about writing the code, and when the operation is needed, shelling out to the system chown is not too onerous. (Ditto for chmod.) (1) Not even sure that a use case was shown -- it was just shown that the operation is not necessarily useless. On Tue, May 29, 2018 at 5:57 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
-- --Guido van Rossum (python.org/~guido)

On 30 May 2018 at 02:38, Guido van Rossum <guido@python.org> wrote:
My main use cases have been in installers and test suites, but those cases have also been for Linux-specific code where shelling out to "chown -R" and "chmod -R" was an entirely acceptable alternative. I think one of the other key points here is that "chown" and "chmod" inherently don't map at all well to the Windows filesystem access control model [1], so there's no new portability challenges arising from expecting the chown and chmod commands to be available. Cheers, Nick. [1] os.chown and shutil.chown don't exist at all there, and os.chmod only supports setting a file to read-only - there isn't any access to user or group permissions. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Wednesday, May 30, 2018, Nick Coghlan <ncoghlan@gmail.com> wrote:
Notably, Ansible and Salt don't haven't even tried to abstract Linux/BSD and Windows filesystem ACLs into a common API: https://github.com/ansible/ansible/blob/devel/lib/ansible/ modules/files/acl.py https://github.com/ansible/ansible/blob/devel/lib/ansible/ modules/windows/win_acl.py https://github.com/ansible/ansible/blob/devel/lib/ ansible/modules/windows/win_acl.ps1 https://github.com/saltstack/salt/blob/develop/salt/states/file.py https://github.com/saltstack/salt/blob/develop/salt/states/win_dacl.py https://github.com/saltstack/salt/blob/develop/salt/modules/win_dacl.py https://github.com/saltstack/salt/blob/develop/salt/utils/win_dacl.py https://github.com/saltstack/salt/blob/develop/salt/states/linux_acl.py https://github.com/saltstack/salt/blob/develop/salt/modules/linux_acl.py ... Looked these up and thought I'd share.

On Mon, May 28, 2018 at 11:13 PM, Barry <barry@barrys-emacs.org> wrote:
You're right, I didn't think about that. I remember myself doing "chown -R dir" every once in a while but didn't recall I prepended "sudo". =) -- Giampaolo - http://grodola.blogspot.com

path.py Path.choen supports names in addition to the uid/gid numbers which os.chown supports: https://pathpy.readthedocs.io/en/stable/api.html#path.Path.chown https://github.com/jaraco/path.py/blob/master/path.py#L1176 https://pathpy.readthedocs.io/en/stable/api.html#path.Path.walk On Monday, May 28, 2018, Giampaolo Rodola' <g.rodola@gmail.com> wrote:

On Mon, May 28, 2018 at 10:13:47PM +0100, Barry wrote:
On 28 May 2018, at 21:23, Giampaolo Rodola' <g.rodola@gmail.com> wrote:
[...]
Certainly not. You only have to be root to change permissions on files that you otherwise wouldn't be able to change permissions on. chmod -R works fine for regular users changing their own files. Why wouldn't it? [steve@ando ~]$ ls -lR test test: total 12 -rw-rw-r-- 1 steve steve 5 Feb 4 2017 eggs.py drwxrwxr-x 2 steve steve 4096 May 29 09:41 package -rw-rw-r-- 1 steve steve 40 Feb 4 2017 spam.py test/package: total 0 -rw-rw-r-- 1 steve steve 0 May 29 09:41 __init__.py -rw-rw-r-- 1 steve steve 0 May 29 09:41 spam.py [steve@ando ~]$ chmod -R a-w test [steve@ando ~]$ ls -lR test test: total 12 -r--r--r-- 1 steve steve 5 Feb 4 2017 eggs.py dr-xr-xr-x 2 steve steve 4096 May 29 09:41 package -r--r--r-- 1 steve steve 40 Feb 4 2017 spam.py test/package: total 0 -r--r--r-- 1 steve steve 0 May 29 09:41 __init__.py -r--r--r-- 1 steve steve 0 May 29 09:41 spam.py -- Steve

On Tue, May 29, 2018 at 10:11:22AM +1000, Chris Angelico wrote:
On Tue, May 29, 2018 at 9:47 AM, Steven D'Aprano <steve@pearwood.info> wrote:
/face-palm Indeed he did. But it doesn't matter: regular users can call chown -R: [steve@ando ~]$ chown -R steve.users test [steve@ando ~]$ ls -lR test test: total 12 -rw-rw-rw- 1 steve users 5 Feb 4 2017 eggs.py drwxrwxrwx 2 steve users 4096 May 29 09:41 package -rw-rw-rw- 1 steve users 40 Feb 4 2017 spam.py test/package: total 0 -rw-rw-rw- 1 steve users 0 May 29 09:41 __init__.py -rw-rw-rw- 1 steve users 0 May 29 09:41 spam.py The limitations on calling chown apply equally to the recursive and non-recursive case. -- Steve

Steven D'Aprano wrote:
But it doesn't matter: regular users can call chown -R:
Only if you're not actually telling it to change anything. % ls -l foo.txt -rw-r--r-- 1 greg users 1 29 May 18:19 foo.txt % chown greg foo.txt % chown fred foo.txt chown: foo.txt: Operation not permitted So you have to be root in order to do anything *useful* with it. -- Greg

On Tue, May 29, 2018 at 06:29:50PM +1200, Greg Ewing wrote:
That's not correct. Look closely at my example: the file ownership recursively changed from steve.steve to steve.users.
And yet Python provides a chown function despite this alleged uselessness. Maybe it's not quite so useless as you think? Here's a thought... maybe sometimes people actually do run Python scripts as root? And as the comments to this Stackoverflow post explain: https://unix.stackexchange.com/questions/119229/can-not-chown-a-file-from-my... the ability for unprivileged users to change ownership to another user is configurable under POSIX.
So you have to be root in order to do anything *useful* with it.
Fortunately that is not correct, but even if it were, that's no reason to not allow chown to apply recursively. -- Steve

Steven D'Aprano wrote:
Look closely at my example: the file ownership recursively changed from steve.steve to steve.users.
You're quite right. I hadn't realised that chown can be used to change the group as well as the user. It's permitted to change the group to one that the user is a member of. -- Greg

BTW, I wouldn't argue that Python shouldn't provide things that are only useful to root. While writing setuid utilities in Python is a bad idea for lots of reasons, I don't think there's anything wrong with becoming root by another means and then running a Python program that you know well enough to trust. -- Greg

On Wed, May 30, 2018 at 9:11 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
I'd go further. Once a shell script gets longer than about a page or two of code, it often needs to be rewritten in a different language, and Python is well situated to be that language. That doesn't change when the script is to be run as root. I've written many Python scripts to do sysadminning jobs for me - usually one-shot scripts, but also some that stick around. Since I wrote the scripts myself, the trust issue doesn't come up; I trust the Python interpreter the same way that I trust /bin/bash. ChrisA

Configuration management tools with far more code than this are regularly run with root privileges. OTOH, Salt and Ansible, for example, both support recursive chown and chmod; and report what actually changed. Yum/dnf probably do, too. Supporting recursive chmod/chown OOB may be useful. That it might be run as root is not the criteria, AFAIU. On Tuesday, May 29, 2018, Chris Angelico <rosuav@gmail.com> wrote:

On 29 May 2018 at 06:23, Giampaolo Rodola' <g.rodola@gmail.com> wrote:
https://bugs.python.org/issue13033 is a long-open RFE for this, proposing to add it as "shutil.chowntree" (naming inspired by "shutil.rmtree" and "shutil.copytree"). The "walkdir" project I mention on that PR has been on hiatus for a few years now (aside from a bit of activity to get a new release out in 2016 with several contributed fixes), but the main point of the comment where I mentioned it still stands: the hard part of designing recursive state modification APIs is deciding what to do when an operation fails after you've already made changes to the state of the disk. shutil.rmtree fortunately provides some good precedent there, but it does mean this feature would need to be implemented as its own API, rather than as an option on shutil.chown. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

Honestly, despite the occasional use case(1), I'm not sure that this is a battery we need in the stdlib. Nobody seems too excited about writing the code, and when the operation is needed, shelling out to the system chown is not too onerous. (Ditto for chmod.) (1) Not even sure that a use case was shown -- it was just shown that the operation is not necessarily useless. On Tue, May 29, 2018 at 5:57 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
-- --Guido van Rossum (python.org/~guido)

On 30 May 2018 at 02:38, Guido van Rossum <guido@python.org> wrote:
My main use cases have been in installers and test suites, but those cases have also been for Linux-specific code where shelling out to "chown -R" and "chmod -R" was an entirely acceptable alternative. I think one of the other key points here is that "chown" and "chmod" inherently don't map at all well to the Windows filesystem access control model [1], so there's no new portability challenges arising from expecting the chown and chmod commands to be available. Cheers, Nick. [1] os.chown and shutil.chown don't exist at all there, and os.chmod only supports setting a file to read-only - there isn't any access to user or group permissions. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Wednesday, May 30, 2018, Nick Coghlan <ncoghlan@gmail.com> wrote:
Notably, Ansible and Salt don't haven't even tried to abstract Linux/BSD and Windows filesystem ACLs into a common API: https://github.com/ansible/ansible/blob/devel/lib/ansible/ modules/files/acl.py https://github.com/ansible/ansible/blob/devel/lib/ansible/ modules/windows/win_acl.py https://github.com/ansible/ansible/blob/devel/lib/ ansible/modules/windows/win_acl.ps1 https://github.com/saltstack/salt/blob/develop/salt/states/file.py https://github.com/saltstack/salt/blob/develop/salt/states/win_dacl.py https://github.com/saltstack/salt/blob/develop/salt/modules/win_dacl.py https://github.com/saltstack/salt/blob/develop/salt/utils/win_dacl.py https://github.com/saltstack/salt/blob/develop/salt/states/linux_acl.py https://github.com/saltstack/salt/blob/develop/salt/modules/linux_acl.py ... Looked these up and thought I'd share.
participants (8)
-
Barry
-
Chris Angelico
-
Giampaolo Rodola'
-
Greg Ewing
-
Guido van Rossum
-
Nick Coghlan
-
Steven D'Aprano
-
Wes Turner