Mercurial > p > roundup > code
comparison roundup/backends/portalocker.py @ 4686:4e740f02e165
Remove pywin32 installation dependency by porting portalocker.py to ctypes.
portalocker.py lock/unlock functions now return result of operation, support
for Windows 95/98/ME is removed.
| author | anatoly techtonik <techtonik@gmail.com> |
|---|---|
| date | Wed, 28 Nov 2012 04:51:56 +0300 |
| parents | 6c74a8bff423 |
| children | d27de8f08c31 |
comparison
equal
deleted
inserted
replaced
| 4685:61e922a93112 | 4686:4e740f02e165 |
|---|---|
| 1 #!/usr/bin/env python | |
| 2 # | |
| 1 # portalocker.py - Cross-platform (posix/nt) API for flock-style file locking. | 3 # portalocker.py - Cross-platform (posix/nt) API for flock-style file locking. |
| 2 # Requires python 1.5.2 or better. | 4 # |
| 3 | 5 # http://code.activestate.com/recipes/65203-portalocker-cross-platform-posixnt-api-for-flock-s/ |
| 4 """Cross-platform (posix/nt) API for flock-style file locking. | 6 # |
| 7 """ | |
| 8 Cross-platform (posix/nt) API for flock-style file locking. | |
| 5 | 9 |
| 6 Synopsis:: | 10 Synopsis:: |
| 7 | 11 |
| 8 import portalocker | 12 import portalocker |
| 9 file = open("somefile", "r+") | 13 file = open("somefile", "r+") |
| 32 I learned the win32 technique for locking files from sample code | 36 I learned the win32 technique for locking files from sample code |
| 33 provided by John Nielsen <nielsenjf@my-deja.com> in the documentation | 37 provided by John Nielsen <nielsenjf@my-deja.com> in the documentation |
| 34 that accompanies the win32 modules. | 38 that accompanies the win32 modules. |
| 35 | 39 |
| 36 :Author: Jonathan Feinberg <jdf@pobox.com> | 40 :Author: Jonathan Feinberg <jdf@pobox.com> |
| 37 :Version: Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp | 41 |
| 38 **un-cvsified by richard so the version doesn't change** | 42 Roundup Changes |
| 43 --------------- | |
| 44 2012-11-28 (anatoly techtonik) | |
| 45 - Ported to ctypes | |
| 46 - Dropped support for Win95, Win98 and WinME | |
| 47 - Added return result | |
| 39 """ | 48 """ |
| 49 | |
| 40 __docformat__ = 'restructuredtext' | 50 __docformat__ = 'restructuredtext' |
| 41 | 51 |
| 42 import os | 52 import os |
| 43 | 53 |
| 44 if os.name == 'nt': | 54 if os.name == 'nt': |
| 45 import win32file | |
| 46 import pywintypes | |
| 47 import msvcrt | 55 import msvcrt |
| 56 from ctypes import * | |
| 57 from ctypes.wintypes import BOOL, DWORD, HANDLE | |
| 58 | |
| 48 LOCK_SH = 0 # the default | 59 LOCK_SH = 0 # the default |
| 49 LOCK_NB = 0x1 # LOCKFILE_FAIL_IMMEDIATELY | 60 LOCK_NB = 0x1 # LOCKFILE_FAIL_IMMEDIATELY |
| 50 LOCK_EX = 0x2 # LOCKFILE_EXCLUSIVE_LOCK | 61 LOCK_EX = 0x2 # LOCKFILE_EXCLUSIVE_LOCK |
| 51 # is there any reason not to reuse the following structure? | 62 |
| 52 __overlapped = pywintypes.OVERLAPPED() | 63 # --- the code is taken from pyserial project --- |
| 64 # | |
| 65 # detect size of ULONG_PTR | |
| 66 def is_64bit(): | |
| 67 return sizeof(c_ulong) != sizeof(c_void_p) | |
| 68 if is_64bit(): | |
| 69 ULONG_PTR = c_int64 | |
| 70 else: | |
| 71 ULONG_PTR = c_ulong | |
| 72 PVOID = c_void_p | |
| 73 | |
| 74 # --- Union inside Structure by stackoverflow:3480240 --- | |
| 75 class _OFFSET(Structure): | |
| 76 _fields_ = [ | |
| 77 ('Offset', DWORD), | |
| 78 ('OffsetHigh', DWORD)] | |
| 79 | |
| 80 class _OFFSET_UNION(Union): | |
| 81 _anonymous_ = ['_offset'] | |
| 82 _fields_ = [ | |
| 83 ('_offset', _OFFSET), | |
| 84 ('Pointer', PVOID)] | |
| 85 | |
| 86 class OVERLAPPED(Structure): | |
| 87 _anonymous_ = ['_offset_union'] | |
| 88 _fields_ = [ | |
| 89 ('Internal', ULONG_PTR), | |
| 90 ('InternalHigh', ULONG_PTR), | |
| 91 ('_offset_union', _OFFSET_UNION), | |
| 92 ('hEvent', HANDLE)] | |
| 93 | |
| 94 LPOVERLAPPED = POINTER(OVERLAPPED) | |
| 95 | |
| 96 # --- Define function prototypes for extra safety --- | |
| 97 LockFileEx = windll.kernel32.LockFileEx | |
| 98 LockFileEx.restype = BOOL | |
| 99 LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED] | |
| 100 UnlockFileEx = windll.kernel32.UnlockFileEx | |
| 101 UnlockFileEx.restype = BOOL | |
| 102 UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED] | |
| 103 | |
| 53 elif os.name == 'posix': | 104 elif os.name == 'posix': |
| 54 import fcntl | 105 import fcntl |
| 55 LOCK_SH = fcntl.LOCK_SH # shared lock | 106 LOCK_SH = fcntl.LOCK_SH # shared lock |
| 56 LOCK_NB = fcntl.LOCK_NB # non-blocking | 107 LOCK_NB = fcntl.LOCK_NB # non-blocking |
| 57 LOCK_EX = fcntl.LOCK_EX | 108 LOCK_EX = fcntl.LOCK_EX |
| 58 else: | 109 else: |
| 59 raise RuntimeError("PortaLocker only defined for nt and posix platforms") | 110 raise RuntimeError("PortaLocker only defined for nt and posix platforms") |
| 60 | 111 |
| 61 if os.name == 'nt': | 112 if os.name == 'nt': |
| 62 def lock(file, flags): | 113 def lock(file, flags): |
| 114 """ Return True on success, False otherwise """ | |
| 63 hfile = msvcrt.get_osfhandle(file.fileno()) | 115 hfile = msvcrt.get_osfhandle(file.fileno()) |
| 64 # LockFileEx is not supported on all Win32 platforms (Win95, Win98, | 116 overlapped = OVERLAPPED() |
| 65 # WinME). | 117 if LockFileEx(hfile, flags, 0, 0, 0xFFFF0000, byref(overlapped)): |
| 66 # If it's not supported, win32file will raise an exception. | 118 return True |
| 67 # Try LockFileEx first, as it has more functionality and handles | 119 else: |
| 68 # blocking locks more efficiently. | 120 return False |
| 69 try: | 121 |
| 70 win32file.LockFileEx(hfile, flags, 0, 0xFFFF0000, __overlapped) | |
| 71 except win32file.error, e: | |
| 72 import winerror | |
| 73 # Propagate upwards all exceptions other than not-implemented. | |
| 74 if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED: | |
| 75 raise e | |
| 76 | |
| 77 # LockFileEx is not supported. Use LockFile. | |
| 78 # LockFile does not support shared locking -- always exclusive. | |
| 79 # Care: the low/high length params are reversed compared to | |
| 80 # LockFileEx. | |
| 81 if not flags & LOCK_EX: | |
| 82 import warnings | |
| 83 warnings.warn("PortaLocker does not support shared " | |
| 84 "locking on Win9x", RuntimeWarning) | |
| 85 # LockFile only supports immediate-fail locking. | |
| 86 if flags & LOCK_NB: | |
| 87 win32file.LockFile(hfile, 0, 0, 0xFFFF0000, 0) | |
| 88 else: | |
| 89 # Emulate a blocking lock with a polling loop. | |
| 90 import time | |
| 91 while 1: | |
| 92 # Attempt a lock. | |
| 93 try: | |
| 94 win32file.LockFile(hfile, 0, 0, 0xFFFF0000, 0) | |
| 95 break | |
| 96 except win32file.error, e: | |
| 97 # Propagate upwards all exceptions other than lock | |
| 98 # violation. | |
| 99 if e[0] != winerror.ERROR_LOCK_VIOLATION: | |
| 100 raise e | |
| 101 # Sleep and poll again. | |
| 102 time.sleep(0.1) | |
| 103 # TODO: should this return the result of the lock? | |
| 104 | |
| 105 def unlock(file): | 122 def unlock(file): |
| 106 hfile = msvcrt.get_osfhandle(file.fileno()) | 123 hfile = msvcrt.get_osfhandle(file.fileno()) |
| 107 # UnlockFileEx is not supported on all Win32 platforms (Win95, Win98, | 124 overlapped = OVERLAPPED() |
| 108 # WinME). | 125 if UnlockFileEx(hfile, 0, 0, 0xFFFF0000, byref(overlapped)): |
| 109 # If it's not supported, win32file will raise an api_error exception. | 126 return True |
| 110 try: | 127 else: |
| 111 win32file.UnlockFileEx(hfile, 0, 0xFFFF0000, __overlapped) | 128 return False |
| 112 except win32file.error, e: | |
| 113 import winerror | |
| 114 # Propagate upwards all exceptions other than not-implemented. | |
| 115 if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED: | |
| 116 raise e | |
| 117 | |
| 118 # UnlockFileEx is not supported. Use UnlockFile. | |
| 119 # Care: the low/high length params are reversed compared to | |
| 120 # UnLockFileEx. | |
| 121 win32file.UnlockFile(hfile, 0, 0, 0xFFFF0000, 0) | |
| 122 | 129 |
| 123 elif os.name =='posix': | 130 elif os.name =='posix': |
| 124 def lock(file, flags): | 131 def lock(file, flags): |
| 125 fcntl.flock(file.fileno(), flags) | 132 if fcntl.flock(file.fileno(), flags) == 0: |
| 126 # TODO: should this return the result of the lock? | 133 return True |
| 134 else: | |
| 135 return False | |
| 127 | 136 |
| 128 def unlock(file): | 137 def unlock(file): |
| 129 fcntl.flock(file.fileno(), fcntl.LOCK_UN) | 138 if fcntl.flock(file.fileno(), fcntl.LOCK_UN) == 0: |
| 139 return True | |
| 140 else: | |
| 141 return False | |
| 130 | 142 |
| 131 if __name__ == '__main__': | 143 if __name__ == '__main__': |
| 132 from time import time, strftime, localtime | 144 from time import time, strftime, localtime |
| 133 import sys | 145 import sys |
| 134 | 146 |
