portable file locking utilities based partially on an example by jonathan feignberg in the python cookbook 1 licensed under the python software license and a ctypes port by anatoly techtonik for roundup 2 license 3 1 https code activestate comrecipes65203 2 https sourceforge netproundupcodecidefaulttreeroundupbackendsportalocker py noqa 3 https sourceforge netproundupcodecidefaulttreecopying txt example usage from django core files import locks with open file wb as f locks lockf locks lockex f write django get a filedescriptor from something which could be a file or an fd return f fileno if hasattrf fileno else f if os name nt import msvcrt from ctypes import pointer structure union windll byref cint64 culong cvoidp sizeof from ctypes wintypes import bool dword handle locksh 0 the default locknb 0x1 lockfilefailimmediately lockex 0x2 lockfileexclusivelock adapted from the pyserial project detect size of ulongptr if sizeofculong sizeofcvoidp ulongptr cint64 else ulongptr culong pvoid cvoidp union inside structure by stackoverflow 3480240 class offsetstructure fields offset dword offsethigh dword class offsetunionunion anonymous offset fields offset offset pointer pvoid class overlappedstructure anonymous offsetunion fields internal ulongptr internalhigh ulongptr offsetunion offsetunion hevent handle lpoverlapped pointeroverlapped define function prototypes for extra safety kernel32 windllkernel32 lockfileex kernel32 lockfileex lockfileex restype bool lockfileex argtypes handle dword dword dword dword lpoverlapped unlockfileex kernel32 unlockfileex unlockfileex restype bool unlockfileex argtypes handle dword dword dword lpoverlapped def lockf flags hfile msvcrt getosfhandlefdf overlapped overlapped ret lockfileexhfile flags 0 0 0xffff0000 byrefoverlapped return boolret def unlockf hfile msvcrt getosfhandlefdf overlapped overlapped ret unlockfileexhfile 0 0 0xffff0000 byrefoverlapped return boolret else try import fcntl locksh fcntl locksh shared lock locknb fcntl locknb nonblocking lockex fcntl lockex except importerror attributeerror file locking is not supported lockex locksh locknb 0 dummy functions that don t do anything def lockf flags file is not locked return false def unlockf file is unlocked return true else def lockf flags try fcntl flockfdf flags return true except blockingioerror return false def unlockf fcntl flockfdf fcntl lockun return true get a filedescriptor from something which could be a file or an fd the default lockfile_fail_immediately lockfile_exclusive_lock adapted from the pyserial project detect size of ulong_ptr union inside structure by stackoverflow 3480240 define function prototypes for extra safety shared lock non blocking file locking is not supported dummy functions that don t do anything file is not locked file is unlocked
import os

__all__ = ("LOCK_EX", "LOCK_SH", "LOCK_NB", "lock", "unlock")


def _fd(f):
    
    return f.fileno() if hasattr(f, "fileno") else f


if os.name == "nt":
    import msvcrt
    from ctypes import (
        POINTER,
        Structure,
        Union,
        WinDLL,
        byref,
        c_int64,
        c_ulong,
        c_void_p,
        sizeof,
    )
    from ctypes.wintypes import BOOL, DWORD, HANDLE

    LOCK_SH = 0  
    LOCK_NB = 0x1  
    LOCK_EX = 0x2  

    
    
    if sizeof(c_ulong) != sizeof(c_void_p):
        ULONG_PTR = c_int64
    else:
        ULONG_PTR = c_ulong
    PVOID = c_void_p

    
    class _OFFSET(Structure):
        _fields_ = [("Offset", DWORD), ("OffsetHigh", DWORD)]

    class _OFFSET_UNION(Union):
        _anonymous_ = ["_offset"]
        _fields_ = [("_offset", _OFFSET), ("Pointer", PVOID)]

    class OVERLAPPED(Structure):
        _anonymous_ = ["_offset_union"]
        _fields_ = [
            ("Internal", ULONG_PTR),
            ("InternalHigh", ULONG_PTR),
            ("_offset_union", _OFFSET_UNION),
            ("hEvent", HANDLE),
        ]

    LPOVERLAPPED = POINTER(OVERLAPPED)

    
    kernel32 = WinDLL("kernel32")
    LockFileEx = kernel32.LockFileEx
    LockFileEx.restype = BOOL
    LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED]
    UnlockFileEx = kernel32.UnlockFileEx
    UnlockFileEx.restype = BOOL
    UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED]

    def lock(f, flags):
        hfile = msvcrt.get_osfhandle(_fd(f))
        overlapped = OVERLAPPED()
        ret = LockFileEx(hfile, flags, 0, 0, 0xFFFF0000, byref(overlapped))
        return bool(ret)

    def unlock(f):
        hfile = msvcrt.get_osfhandle(_fd(f))
        overlapped = OVERLAPPED()
        ret = UnlockFileEx(hfile, 0, 0, 0xFFFF0000, byref(overlapped))
        return bool(ret)

else:
    try:
        import fcntl

        LOCK_SH = fcntl.LOCK_SH  
        LOCK_NB = fcntl.LOCK_NB  
        LOCK_EX = fcntl.LOCK_EX
    except (ImportError, AttributeError):
        
        LOCK_EX = LOCK_SH = LOCK_NB = 0

        
        def lock(f, flags):
            
            return False

        def unlock(f):
            
            return True

    else:

        def lock(f, flags):
            try:
                fcntl.flock(_fd(f), flags)
                return True
            except BlockingIOError:
                return False

        def unlock(f):
            fcntl.flock(_fd(f), fcntl.LOCK_UN)
            return True