This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Win32: shutil.move does not inherit permissions
Type: Stage: resolved
Components: Library (Lib) Versions: Python 2.7
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: Anders.Østhus, brian.curtin, pitrou, tarek
Priority: normal Keywords:

Created on 2011-02-12 18:54 by Anders.Østhus, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (10)
msg128452 - (view) Author: Anders Østhus (Anders.Østhus) Date: 2011-02-12 18:54
Hi

I'm running Python 2.7.1 (r271:86832, Nov 27 2010, 17:19:03) [MSC v.1500 64 bit (AMD64)] on win32 (Server 2008 R2).

I've discovered that when moving files with shutil.move, the file won't inherit the security settings as it should.

When using shutil.copy, it does get the right permissions.
msg128454 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-02-12 18:58
Intuitively, this seems rather normal to me. If I move a file under Unix, I don't expect its access rights or ownership to change. "Move" really means what it means: you have to update its permission explicitly if that's what you need (shutil.copystat() can help you with that, I think).
msg128455 - (view) Author: Brian Curtin (brian.curtin) * (Python committer) Date: 2011-02-12 18:59
shutil.move is implemented using copy2, which as the documentation states at the top, "On Windows, file owners, ACLs and alternate data streams are not copied."

See http://docs.python.org/library/shutil
msg128461 - (view) Author: Anders Østhus (Anders.Østhus) Date: 2011-02-12 19:54
Ok, but the whole page you linked to (http://docs.python.org/library/shutil) confuses me then.

It states at the top:
"Warning

Even the higher-level file copying functions (copy(), copy2()) can’t copy all file metadata.

On POSIX platforms, this means that file owner and group are lost as well as ACLs. On Mac OS, the resource fork and other metadata are not used. This means that resources will be lost and file type and creator codes will not be correct. On Windows, file owners, ACLs and alternate data streams are not copied."

Then, under shutil.copy: "Permission bits are copied". I'm assuming this is UGO permissions on POSIX systems, and thus correct according to the top text.

shutil.copy2 says: Similar to shutil.copy, but with metadata.

Files copied with both shutil.copy and shutil.copy2 both inherits the permissions from their destination, but shutil.move does not.

According to the shutil doc page, neither copy or copy2 should do this. And since they do, and you say shutil.move is implemented using shutil.copy2, shouldn't files moved with shutil.move also then inherit the permissions?
msg128462 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-02-12 20:11
> According to the shutil doc page, neither copy or copy2 should do
> this. And since they do, and you say shutil.move is implemented using
> shutil.copy2, shouldn't files moved with shutil.move also then inherit
> the permissions?

There's a misunderstanding I think. shutil.move()'s main path uses
os.rename(). Only does it fall back on copy2() when rename() fails.
msg128463 - (view) Author: Anders Østhus (Anders.Østhus) Date: 2011-02-12 20:14
Ok.

But that makes the whole method inconsistent.

Basically, if it's on the same filesystem, rename the file, and thus not inheriting ACL. If it's on another use copy2, and inherit ACL.

That makes no sense, atleast not to me :)
msg128467 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-02-12 20:24
> Ok.
> 
> But that makes the whole method inconsistent.
> 
> Basically, if it's on the same filesystem, rename the file, and thus
> not inheriting ACL. If it's on another use copy2, and inherit ACL.

I think you're misunderstanding copy2. It will copy the ACL from the
source file, not from the target directory or filesystem.
Actually, if you look at copy2's implementation, it's just copyfile()
followed by copystat().
msg128468 - (view) Author: Anders Østhus (Anders.Østhus) Date: 2011-02-12 20:33
On my system (Win Server 2008 R2 64-Bit, Python 2.7.1), when I use copy, copy2 or move(to another filesystem), the file _will_ get the ACL of the DST folder, and remove any ACL in SRC file that the DST folder does not have.

Thus, it doesn't copy it from the source file, but inherits from the DST folder.
msg128469 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-02-12 20:45
> On my system (Win Server 2008 R2 64-Bit, Python 2.7.1), when I use
> copy, copy2 or move(to another filesystem), the file _will_ get the
> ACL of the DST folder, and remove any ACL in SRC file that the DST
> folder does not have.
> 
> Thus, it doesn't copy it from the source file, but inherits from the
> DST folder.

Again, this follows from the warning at the top of the shutil doc page:

“On Windows, file owners, ACLs and alternate data streams are not
copied.”

If they are not copied, then obviously they simply get the default value
for a new file, which is simply the value of the containing folder.
msg128470 - (view) Author: Anders Østhus (Anders.Østhus) Date: 2011-02-12 21:12
Thank you for taking the time to explain it to me, but it still seems inconsistent to me.

I did a test with the functions copy, copy2, move, os.rename, copyfile, both on the same filesystem and another filesystem, and the result is:

Same filesystem:
	shutil.copy:		Inherit
	shutil.copy2:		Inherit
	shutil.move:		Original
	os.rename:		Original
	shutil.copyfile:	Inherit

Different filesystem:
	shutil.copy:		Inherit
	shutil.copy2:		Inherit
	shutil.move:		Inherit
	os.rename:		Inherit
	shutil.copyfile:	Inherit

On the same system, the result will differ if you move the file to a different location on the same filesystem, or if you move it to another filesystem.

But still, I'm happy. I'll just use copy/copy2 and then delete the original file afterwards :)
History
Date User Action Args
2022-04-11 14:57:12adminsetgithub: 55411
2011-02-12 21:19:25pitrousetstatus: open -> closed
nosy: pitrou, tarek, brian.curtin, Anders.Østhus
2011-02-12 21:12:57Anders.Østhussetnosy: pitrou, tarek, brian.curtin, Anders.Østhus
messages: + msg128470
2011-02-12 20:45:50pitrousetnosy: pitrou, tarek, brian.curtin, Anders.Østhus
messages: + msg128469
2011-02-12 20:33:43Anders.Østhussetnosy: pitrou, tarek, brian.curtin, Anders.Østhus
messages: + msg128468
2011-02-12 20:24:34pitrousetnosy: pitrou, tarek, brian.curtin, Anders.Østhus
messages: + msg128467
2011-02-12 20:14:20Anders.Østhussetnosy: pitrou, tarek, brian.curtin, Anders.Østhus
messages: + msg128463
2011-02-12 20:11:04pitrousetnosy: pitrou, tarek, brian.curtin, Anders.Østhus
messages: + msg128462
2011-02-12 19:54:06Anders.Østhussetstatus: closed -> open
nosy: pitrou, tarek, brian.curtin, Anders.Østhus
messages: + msg128461
2011-02-12 19:11:17brian.curtinsetstatus: open -> closed
nosy: pitrou, tarek, brian.curtin, Anders.Østhus
2011-02-12 18:59:56brian.curtinsetnosy: + brian.curtin
messages: + msg128455

resolution: rejected
stage: resolved
2011-02-12 18:58:42pitrousetnosy: + pitrou
messages: + msg128454
2011-02-12 18:56:00pitrousetnosy: + tarek
components: + Library (Lib), - IO
2011-02-12 18:54:56Anders.Østhuscreate