Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python getting WindowsError 5 when deleting a file even though I have full permissions

quick question about Python on windows. I have a script that compiles a program (using an install rule), and then moves the build products to a remote destination over the network.

However, I keep getting WindowsError 5 Access Denied. All files are created from the script context, I have ownership and full control on all of them. The copy to the remote destination succeeds, but the failure is during the deletion process. If I try to delete or rename the file manually within windows, I get no errors. Just the shutil.move fails.

I'm thinking maybe the API is trying to delete the file when the network operation is not yet complete?

Any input is very appreciated.

try:
    shutil.move(directory, destination)
except OSError:
    print "Failed to move %s to %s." %(directory, destination)
    raise

...

Traceback (most recent call last):
  File "C:\WIP\BuildMachine\build_machine.py", line 176, in <module>
    main()
  File "C:\WIP\BuildMachine.hg\BuilderInstance.py", line 496, in deployVersion
    shutil.move(directory, destination)
  File "C:\Python27\lib\shutil.py", line 300, in move
    rmtree(src)
  File "C:\Python27\lib\shutil.py", line 252, in rmtree
    onerror(os.remove, fullname, sys.exc_info())
  File "C:\Python27\lib\shutil.py", line 250, in rmtree
    os.remove(fullname)
WindowsError: [Error 5] Access is denied: '3_54_7__B_1\\Application_Release_Note.doc'
like image 314
shayst Avatar asked Jun 28 '18 20:06

shayst


1 Answers

the problem with shutil.move on windows is that it doesn't handle the case where:

  • the source & destination aren't on the same drive AND
  • some files in the source directory are write-protected.

If both conditions are met, shutil.move cannot perform a os.rename, it has to:

  • copy the files (which isn't an issue)
  • delete the source files (which is an issue because of a limitation of shutil)

To fix that, I made myself a copy of the shutil module (under a different name) and added that line (for you it'll be right before line 250):

   os.chmod(fullname,0o777)  # <-- add that line
   os.remove(fullname)  # some versions have "unlink" instead

The rmtree function has the same issue on Windows.

On Linux this doesn't happen because file delete permissions aren't handled at the file level but at the directory level. On windows, it doesn't work that way. Adding os.chmod does the trick (even if it's a hack), and os.remove succeeds (unless the file is open in Word or whatever)

Note that shutil authors encourage you to copy & improve the functions. Also a note from the documentation of shutil.move:

A lot more could be done here... A look at a mv.c shows a lot of the issues this implementation glosses over.

If you don't want to modify shutil, you can run a recursive chmod on the source files to make sure that shutil.move will work, for instance like this:

for root, dirs, files in os.walk(path):  
  for f in dirs+files:  
    os.chmod(os.path.join(root, f), 0o777)

You could also use shutil.copytree then a modified version of shutil.rmtree (since you know that source & dest aren't on the same filesystem)

like image 54
Jean-François Fabre Avatar answered Nov 09 '22 12:11

Jean-François Fabre