win32: when removing file, open it as O_TEMPORARY as a last effort

Summary:
When a file is mmap'ed, removing it will always fail, even with all the rename
magic. The only option that works is to ask the OS to remove the file when
there is no other file handles to it. In Python, we can use the O_TEMPORARY for
that.

Reviewed By: quark-zju

Differential Revision: D22224572

fbshipit-source-id: bee564a3006c8389f506633da5622aa7a27421ac
This commit is contained in:
Xavier Deguillard 2020-06-24 20:33:23 -07:00 committed by Facebook GitHub Bot
parent a935fc38b4
commit d6ca62a1d7
2 changed files with 30 additions and 5 deletions

View File

@ -745,12 +745,17 @@ def unlink(f):
try:
os.unlink(temp)
except OSError:
# The unlink might have failed because the READONLY attribute may heave
# The unlink might have failed because the READONLY attribute may have
# been set on the original file. Rename works fine with READONLY set,
# but not os.unlink. Reset all attributes and try again.
_kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
try:
os.unlink(temp)
except OSError:
try:
# Last effort, open it as a temporary file which will remove it
# when it's unmapped.
os.open(temp, os.O_TEMPORARY)
except OSError:
# The unlink might have failed due to some very rude AV-Scanners.
# Leaking a tempfile is the lesser evil than aborting here and

View File

@ -0,0 +1,20 @@
#chg-compatible
$ cat <<EOF > mmap-unlink.py
> import mmap
> import os
> import shutil
>
> from edenscm.mercurial import util
>
> with util.posixfile("file", "w") as f:
> f.write("CONTENT")
>
> with util.posixfile("file", "r+b") as f:
> m = mmap.mmap(f.fileno(), 0)
> util.unlink("file")
> EOF
$ hg debugpython -- ./mmap-unlink.py
$ ls
mmap-unlink.py