Eryk Sun added the comment:

> To extend support for this to Windows, we can add a 
> feature to mkstmp to not use O_TEMPORARY

O_TEMPORARY is only used for NamedTemporaryFile, not mkstemp. 

Regarding NamedTemporaryFile, that can be worked around to keep Windows from 
deleting the file. Just open a second handle with DELETE (0x00010000) access 
before closing the first one. Then close the first handle. Finally, use the 
second handle to call SetFileInformationByHandle [1] to remove the delete 
disposition. 

Since using O_TEMPORARY opens the file with DELETE access, you have to open the 
new handle with delete sharing. Unfortunately the CRT only provides O_TEMPORARY 
for opening a file with delete access and delete sharing, so just call 
CreateFile [2] directly instead. For example:

    >>> import os, tempfile, msvcrt, ctypes
    >>> kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
    >>> f1 = tempfile.NamedTemporaryFile()
    >>> f1.write(b'spam')
    4
    >>> h = kernel32.CreateFileW(f1.name, 0xC0010000, 7,
    ...                          None, 3, 0x80, None)
    >>> f1.close()
    >>> os.path.exists(f1.name) # really, it does exist
    False
    >>> info = (ctypes.c_int * 1)(0)
    >>> kernel32.SetFileInformationByHandle(h, 4, info, 4)
    1
    >>> os.path.exists(f1.name)
    True
    >>> f2 = os.fdopen(msvcrt.open_osfhandle(h, os.O_RDWR), 'r+')
    >>> f2.read()
    'spam'

Notice that right after f1 is closed, os.path.exists(f1.name) lies, saying the 
file no longer exists. The problem is you can't stat the file at this point 
because you can't open a *new* handle to a file that's marked for deletion. But 
you can use the existing handle to remove the delete disposition, after which 
the file is resurrected.

Also note that the FILE_DISPOSITION_INFO [3] docs say "t]his member has no 
effect if the handle was opened with FILE_FLAG_DELETE_ON_CLOSE". That's 
referring literally to the handle passed to SetFileInformationByHandle. 

Microsoft publishes the source for the FAT filesystem, so I could provide links 
for how this is implemented. Basically every kernel file object has a context 
control block (CCB) that points at an underlying kernel filesystem structure 
such as a file control block (FCB) or NTFS link/stream control block (LCB / 
SCB). When the file object is closed, the delete-on-close flag in the CCB gets 
transferred over to the underlying control structure and the delete disposition 
is set. You can't remove the CCB flag from the kernel file object (as the 
documentation correctly notes), but as long as you have an open handle to a 
file object whose CCB does not have this flag, you can use this other file 
handle to remove the delete disposition and make the file permanent. Just make 
sure to first close all file objects that do have the CCB delete-on-close flag 
because otherwise they'll just set the delete disposition again when closed.

[1]: https://msdn.microsoft.com/en-us/library/aa365539
[2]: https://msdn.microsoft.com/en-us/library/aa363858
[3]: https://msdn.microsoft.com/en-us/library/aa364221

----------
nosy: +eryksun

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue21579>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to