1 # portalocker.py - Cross-platform (posix/nt) API for flock-style file locking.
2 # Requires python 1.5.2 or better.
4 # ID line added by richard for Roundup file tracking
5 # $Id: portalocker.py,v 1.9 2006-09-09 05:42:45 richard Exp $
7 """Cross-platform (posix/nt) API for flock-style file locking.
9 Synopsis::
11 import portalocker
12 file = open("somefile", "r+")
13 portalocker.lock(file, portalocker.LOCK_EX)
14 file.seek(12)
15 file.write("foo")
16 file.close()
18 If you know what you're doing, you may choose to::
20 portalocker.unlock(file)
22 before closing the file, but why?
24 Methods::
26 lock( file, flags )
27 unlock( file )
29 Constants::
31 LOCK_EX
32 LOCK_SH
33 LOCK_NB
35 I learned the win32 technique for locking files from sample code
36 provided by John Nielsen <nielsenjf@my-deja.com> in the documentation
37 that accompanies the win32 modules.
39 :Author: Jonathan Feinberg <jdf@pobox.com>
40 :Version: Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp
41 **un-cvsified by richard so the version doesn't change**
42 """
43 __docformat__ = 'restructuredtext'
45 import os
47 if os.name == 'nt':
48 import win32con
49 import win32file
50 import pywintypes
51 LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
52 LOCK_SH = 0 # the default
53 LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
54 # is there any reason not to reuse the following structure?
55 __overlapped = pywintypes.OVERLAPPED()
56 elif os.name == 'posix':
57 import fcntl
58 LOCK_EX = fcntl.LOCK_EX
59 LOCK_SH = fcntl.LOCK_SH
60 LOCK_NB = fcntl.LOCK_NB
61 else:
62 raise RuntimeError("PortaLocker only defined for nt and posix platforms")
64 if os.name == 'nt':
65 # eugh, we want 0xffff0000 here, but python 2.3 won't let us :(
66 FFFF0000 = -65536
67 def lock(file, flags):
68 hfile = win32file._get_osfhandle(file.fileno())
69 # LockFileEx is not supported on all Win32 platforms (Win95, Win98,
70 # WinME).
71 # If it's not supported, win32file will raise an exception.
72 # Try LockFileEx first, as it has more functionality and handles
73 # blocking locks more efficiently.
74 try:
75 win32file.LockFileEx(hfile, flags, 0, FFFF0000, __overlapped)
76 except win32file.error, e:
77 import winerror
78 # Propagate upwards all exceptions other than not-implemented.
79 if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
80 raise e
82 # LockFileEx is not supported. Use LockFile.
83 # LockFile does not support shared locking -- always exclusive.
84 # Care: the low/high length params are reversed compared to
85 # LockFileEx.
86 if not flags & LOCK_EX:
87 import warnings
88 warnings.warn("PortaLocker does not support shared "
89 "locking on Win9x", RuntimeWarning)
90 # LockFile only supports immediate-fail locking.
91 if flags & LOCK_NB:
92 win32file.LockFile(hfile, 0, 0, FFFF0000, 0)
93 else:
94 # Emulate a blocking lock with a polling loop.
95 import time
96 while 1:
97 # Attempt a lock.
98 try:
99 win32file.LockFile(hfile, 0, 0, FFFF0000, 0)
100 break
101 except win32file.error, e:
102 # Propagate upwards all exceptions other than lock
103 # violation.
104 if e[0] != winerror.ERROR_LOCK_VIOLATION:
105 raise e
106 # Sleep and poll again.
107 time.sleep(0.1)
108 # TODO: should this return the result of the lock?
110 def unlock(file):
111 hfile = win32file._get_osfhandle(file.fileno())
112 # UnlockFileEx is not supported on all Win32 platforms (Win95, Win98,
113 # WinME).
114 # If it's not supported, win32file will raise an api_error exception.
115 try:
116 win32file.UnlockFileEx(hfile, 0, FFFF0000, __overlapped)
117 except win32file.error, e:
118 import winerror
119 # Propagate upwards all exceptions other than not-implemented.
120 if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
121 raise e
123 # UnlockFileEx is not supported. Use UnlockFile.
124 # Care: the low/high length params are reversed compared to
125 # UnLockFileEx.
126 win32file.UnlockFile(hfile, 0, 0, FFFF0000, 0)
128 elif os.name =='posix':
129 def lock(file, flags):
130 fcntl.flock(file.fileno(), flags)
131 # TODO: should this return the result of the lock?
133 def unlock(file):
134 fcntl.flock(file.fileno(), fcntl.LOCK_UN)
136 if __name__ == '__main__':
137 from time import time, strftime, localtime
138 import sys
139 import portalocker
141 log = open('log.txt', "a+")
142 portalocker.lock(log, portalocker.LOCK_EX)
144 timestamp = strftime("%m/%d/%Y %H:%M:%S\n", localtime(time()))
145 log.write( timestamp )
147 print "Wrote lines. Hit enter to release lock."
148 dummy = sys.stdin.readline()
150 log.close()