This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients Eduardo.Seabra, berker.peksag, eryksun, georg.brandl, ncoghlan, pitrou, r.david.murray, serhiy.storchaka, socketpair, vstinner
Date 2015-12-21.23:54:18
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1450742058.81.0.904423573908.issue21579@psf.upfronthosting.co.za>
In-reply-to
Content
> 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
History
Date User Action Args
2015-12-21 23:54:18eryksunsetrecipients: + eryksun, georg.brandl, ncoghlan, pitrou, vstinner, r.david.murray, socketpair, berker.peksag, serhiy.storchaka, Eduardo.Seabra
2015-12-21 23:54:18eryksunsetmessageid: <1450742058.81.0.904423573908.issue21579@psf.upfronthosting.co.za>
2015-12-21 23:54:18eryksunlinkissue21579 messages
2015-12-21 23:54:18eryksuncreate