Skip to content

Commit a70e12d

Browse files
author
Richard Jones
committed
latest version of portalocker fixed for win98 and winnt, thanks James Kew
1 parent 43222e7 commit a70e12d

File tree

1 file changed

+83
-35
lines changed

1 file changed

+83
-35
lines changed

roundup/backends/portalocker.py

Lines changed: 83 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Requires python 1.5.2 or better.
33

44
# ID line added by richard for Roundup file tracking
5-
# $Id: portalocker.py,v 1.2 2002-10-03 06:56:29 richard Exp $
5+
# $Id: portalocker.py,v 1.3 2003-01-19 23:14:42 richard Exp $
66

77
""" Cross-platform (posix/nt) API for flock-style file locking.
88
@@ -43,51 +43,99 @@
4343
import os
4444

4545
if os.name == 'nt':
46-
import win32con
47-
import win32file
48-
import pywintypes
49-
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
50-
LOCK_SH = 0 # the default
51-
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
52-
# is there any reason not to reuse the following structure?
53-
__overlapped = pywintypes.OVERLAPPED()
46+
import win32con
47+
import win32file
48+
import pywintypes
49+
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
50+
LOCK_SH = 0 # the default
51+
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
52+
# is there any reason not to reuse the following structure?
53+
__overlapped = pywintypes.OVERLAPPED()
5454
elif os.name == 'posix':
55-
import fcntl
56-
LOCK_EX = fcntl.LOCK_EX
57-
LOCK_SH = fcntl.LOCK_SH
58-
LOCK_NB = fcntl.LOCK_NB
55+
import fcntl
56+
LOCK_EX = fcntl.LOCK_EX
57+
LOCK_SH = fcntl.LOCK_SH
58+
LOCK_NB = fcntl.LOCK_NB
5959
else:
60-
raise RuntimeError("PortaLocker only defined for nt and posix platforms")
60+
raise RuntimeError("PortaLocker only defined for nt and posix platforms")
6161

6262
if os.name == 'nt':
63-
def lock(file, flags):
64-
hfile = win32file._get_osfhandle(file.fileno())
65-
win32file.LockFileEx(hfile, flags, 0, 0xffff0000, __overlapped)
66-
67-
def unlock(file):
68-
hfile = win32file._get_osfhandle(file.fileno())
69-
win32file.UnlockFileEx(hfile, 0, 0xffff0000, __overlapped)
63+
def lock(file, flags):
64+
hfile = win32file._get_osfhandle(file.fileno())
65+
# LockFileEx is not supported on all Win32 platforms (Win95, Win98, WinME).
66+
# If it's not supported, win32file will raise an exception.
67+
# Try LockFileEx first, as it has more functionality and handles
68+
# blocking locks more efficiently.
69+
try:
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 LockFileEx.
80+
if not flags & LOCK_EX:
81+
import warnings
82+
warnings.warn("PortaLocker does not support shared locking on Win9x", RuntimeWarning)
83+
# LockFile only supports immediate-fail locking.
84+
if flags & LOCK_NB:
85+
win32file.LockFile(hfile, 0, 0, 0xffff0000, 0)
86+
else:
87+
# Emulate a blocking lock with a polling loop.
88+
import time
89+
while 1:
90+
# Attempt a lock.
91+
try:
92+
win32file.LockFile(hfile, 0, 0, 0xffff0000, 0)
93+
break
94+
except win32file.error, e:
95+
# Propagate upwards all exceptions other than lock violation.
96+
if e[0] != winerror.ERROR_LOCK_VIOLATION:
97+
raise e
98+
# Sleep and poll again.
99+
time.sleep(0.1)
100+
# TODO: should this return the result of the lock?
101+
102+
def unlock(file):
103+
hfile = win32file._get_osfhandle(file.fileno())
104+
# UnlockFileEx is not supported on all Win32 platforms (Win95, Win98, WinME).
105+
# If it's not supported, win32file will raise an api_error exception.
106+
try:
107+
win32file.UnlockFileEx(hfile, 0, 0xffff0000, __overlapped)
108+
except win32file.error, e:
109+
import winerror
110+
# Propagate upwards all exceptions other than not-implemented.
111+
if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
112+
raise e
113+
114+
# UnlockFileEx is not supported. Use UnlockFile.
115+
# Care: the low/high length params are reversed compared to UnLockFileEx.
116+
win32file.UnlockFile(hfile, 0, 0, 0xffff0000, 0)
70117

71118
elif os.name =='posix':
72-
def lock(file, flags):
73-
fcntl.flock(file.fileno(), flags)
119+
def lock(file, flags):
120+
fcntl.flock(file.fileno(), flags)
121+
# TODO: should this return the result of the lock?
74122

75-
def unlock(file):
76-
fcntl.flock(file.fileno(), fcntl.LOCK_UN)
123+
def unlock(file):
124+
fcntl.flock(file.fileno(), fcntl.LOCK_UN)
77125

78126
if __name__ == '__main__':
79-
from time import time, strftime, localtime
80-
import sys
81-
import portalocker
127+
from time import time, strftime, localtime
128+
import sys
129+
import portalocker
82130

83-
log = open('log.txt', "a+")
84-
portalocker.lock(log, portalocker.LOCK_EX)
131+
log = open('log.txt', "a+")
132+
portalocker.lock(log, portalocker.LOCK_EX)
85133

86-
timestamp = strftime("%m/%d/%Y %H:%M:%S\n", localtime(time()))
87-
log.write( timestamp )
134+
timestamp = strftime("%m/%d/%Y %H:%M:%S\n", localtime(time()))
135+
log.write( timestamp )
88136

89-
print "Wrote lines. Hit enter to release lock."
90-
dummy = sys.stdin.readline()
137+
print "Wrote lines. Hit enter to release lock."
138+
dummy = sys.stdin.readline()
91139

92-
log.close()
140+
log.close()
93141

0 commit comments

Comments
 (0)