When will os.remove fail?

eryk sun eryksun at gmail.com
Tue Mar 14 21:21:12 EDT 2017

On Tue, Mar 14, 2017 at 10:05 PM, Dennis Lee Bieber
<wlfraed at ix.netcom.com> wrote:
> On Wed, 15 Mar 2017 00:07:32 +1100, Chris Angelico <rosuav at gmail.com>
>>Yes, but you can't always control the process that opens them. For
>>example, it's annoyingly difficult to update a running executable.
> I wouldn't be surprised if Windows mmap()'s running executables into
> swap space, rather than actually swapping in-core image to the normal swap
> file.

Executables are memory mapped, and this also applies to memory-mapped
data files (i.e. CreateFileMapping / MapViewOfFile) like with Python's
mmap module. Notice how the fastfat driver's function that sets the
delete disposition, FatSetDispositionInfo [1], has to check for this
by calling the kernel memory-manager function MmFlushImageSection [2]
(note that a flush type of MmFlushForDelete also checks the number of
views of the data section). If the mapped view prevents deleting the
file it returns STATUS_CANNOT_DELETE. This status code gets translated
to the Windows error code ERROR_ACCESS_DENIED, for which Python raises
a PermissionError. This is misleading because you were probably
granted delete access. The file just can't be deleted.

Typically you can still open such files with delete access to allow
renaming (relinking) them to another directory on the volume. You're
just not allowed to unlink them.

[1]: https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/fileinfo.c#L2417
[2]: https://msdn.microsoft.com/en-us/library/ff549808

It's also interesting that the sharing mode is special cased. Normally
if write access isn't shared you're denied the right to open the file
with either write or append access. But with executables mapped by the
loader, you can still open them for append access.

The C runtime's POSIX (low) I/O layer has its own implementation of
append mode that requires opening the file with both write and append
access (O_WRONLY | O_APPEND), which is what Python's "a" mode uses. So
you have to call CreateFile directly to get append-only access. For
example, using a virtual environment copy of python.exe:

    append = 4
    h = _winapi.CreateFile(sys.executable, append, 7, 0, 3, 0, 0)
    _winapi.WriteFile(h, b'spam')

    f = open(sys.executable, 'rb')
    f.seek(-4, os.SEEK_END)

    >>> f.read()

More information about the Python-list mailing list