Skip to content

Instantly share code, notes, and snippets.

@embray
Last active December 22, 2015 08:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save embray/6444262 to your computer and use it in GitHub Desktop.
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.
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