Last active
December 22, 2015 08:19
-
-
Save embray/6444262 to your computer and use it in GitHub Desktop.
A function written with ctypes called is_append_mode_win32 which, given a file object, can determine, on Windows, if it was opened in append mode (regardless of what its mode string says). In UNIX this would be equivalent to fcntl(fd, F_GETFL) & O_APPEND. These are the hoops we have to go through to get the same functionality on Windows.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from ctypes import (cdll, c_size_t, c_void_p, c_int, c_char, Structure, | |
POINTER, cast) | |
from ctypes.util import find_msvcrt | |
msvcrt = cdll.LoadLibrary(find_msvcrt()) | |
# Constants | |
IOINFO_L2E = 5 | |
IOINFO_ARRAY_ELTS = 1 << IOINFO_L2E | |
IOINFO_ARRAYS = 64 | |
FAPPEND = 0x20 | |
_NO_CONSOLE_FILENO = -2 | |
# Types | |
intptr_t = POINTER(c_int) | |
class my_ioinfo(Structure): | |
_fields_ = [('osfhnd', intptr_t), | |
('osfile', c_char)] | |
# Functions | |
_msize = msvcrt._msize | |
_msize.argtypes = (c_void_p,) | |
_msize.restype = c_size_t | |
# Variables | |
# Since we don't know how large the ioinfo struct is just treat the __pioinfo | |
# array as an array of byte pointers | |
__pioinfo = cast(msvcrt.__pioinfo, POINTER(POINTER(c_char))) | |
_sizeof_ioinfo = None | |
def is_append_mode_win32(fileobj): | |
global _sizeof_ioinfo | |
if _sizeof_ioinfo is None: | |
if __pioinfo[0] is not None: | |
_sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS | |
#else: | |
# this shouldn't happen but... | |
fd = fileobj.fileno() | |
if fd != _NO_CONSOLE_FILENO: | |
idx1 = fd >> IOINFO_L2E # The index into the __pioinfo array | |
# The n-th ioinfo pointer in __pioinfo[idx1] | |
idx2 = fd & ((1 << IOINFO_L2E) - 1) | |
if 0 <= idx1 < IOINFO_ARRAYS and __pioinfo[idx1] is not None: | |
# Doing pointer arithmetic in ctypes is irritating | |
pio = c_void_p(cast(__pioinfo[idx1], c_void_p).value + | |
idx2 * _sizeof_ioinfo) | |
ioinfo = cast(pio, POINTER(my_ioinfo)).contents | |
return bool(ord(ioinfo.osfile) & FAPPEND) | |
return False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment