Skip to content

Commit

Permalink
Fix 'force' remove file without write permissions
Browse files Browse the repository at this point in the history
Preserve existing mode flags, handle case where we even lack
permission to change the mode.
  • Loading branch information
ales-erjavec committed Aug 22, 2022
1 parent 800e1a9 commit f16d8a9
Showing 1 changed file with 19 additions and 9 deletions.
28 changes: 19 additions & 9 deletions src/pip/_internal/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,24 +152,34 @@ def rmtree_errorhandler(
*,
onerror: Callable[..., Any] = _onerror_reraise,
) -> None:
"""On Windows, the files in .svn are read-only, so when rmtree() tries to
remove them, an exception is thrown. We catch that here, remove the
read-only attribute, and hopefully continue without problems."""
"""
`rmtree` error handler to 'force' a file remove (i.e. like `rm -f`).
* If a file is readonly then it's write flag is set and operation is
retried.
* `onerror` is the original callback from `rmtree(... onerror=onerror)`
that is chained at the end if the "rm -f" still fails.
"""
try:
has_attr_readonly = not (os.stat(path).st_mode & stat.S_IWRITE)
st_mode = os.stat(path).st_mode
except OSError:
# it's equivalent to os.path.exists
return

if has_attr_readonly:
if not st_mode & stat.S_IWRITE:
# convert to read/write
os.chmod(path, stat.S_IWRITE)
# use the original function to repeat the operation
try:
func(path)
return
os.chmod(path, st_mode | stat.S_IWRITE)
except OSError:
pass
else:
# use the original function to repeat the operation
try:
func(path)
return
except OSError:
pass

onerror(func, path, exc_info)

Expand Down

0 comments on commit f16d8a9

Please sign in to comment.