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 <[email protected]>
<http://bugs.python.org/issue21579>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com