15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
"""Locking using OS file locks or file existence.
20
Note: This method of locking is generally deprecated in favour of LockDir, but
21
is used to lock local WorkingTrees, and by some old formats. It's accessed
22
through Transport.lock_read(), etc.
20
This only does local locking using OS locks for now.
24
22
This module causes two methods, lock() and unlock() to be defined in
25
23
any way that works on the current platform.
27
25
It is not specified whether these locks are reentrant (i.e. can be
28
26
taken repeatedly by a single process) or whether they exclude
29
different threads in a single process. That reentrancy is provided by
32
This defines two classes: ReadLock and WriteLock, which can be
33
implemented in different ways on different platforms. Both have an
41
from bzrlib.trace import mutter, note, warning
42
from bzrlib.errors import LockError
44
class _base_Lock(object):
45
def _open(self, filename, filemode):
47
self.f = open(filename, filemode)
50
if e.errno != errno.ENOENT:
53
# maybe this is an old branch (before may 2005)
54
mutter("trying to create missing branch lock %r", filename)
56
self.f = open(filename, 'wb+')
61
from warnings import warn
62
warn("lock on %r not released" % self.f)
66
raise NotImplementedError()
73
############################################################
27
different threads in a single process.
29
Eventually we may need to use some kind of lock representation that
30
will work on a dumb filesystem without actual locking primitives."""
36
from trace import mutter, note, warning
38
class LockError(Exception):
39
"""All exceptions from the lock/unlock functions should be from this exception class.
40
They will be translated as necessary. The original exception is available as e.original_error
42
def __init__(self, e=None):
43
self.original_error = e
45
Exception.__init__(self, e)
47
Exception.__init__(self)
80
class _fcntl_FileLock(_base_Lock):
84
fcntl.lockf(self.f, fcntl.LOCK_UN)
88
class _fcntl_WriteLock(_fcntl_FileLock):
89
def __init__(self, filename):
90
# standard IO errors get exposed directly.
91
self._open(filename, 'wb')
93
fcntl.lockf(self.f, fcntl.LOCK_EX)
95
# we should be more precise about whats a locking
96
# error and whats a random-other error
99
class _fcntl_ReadLock(_fcntl_FileLock):
101
def __init__(self, filename):
102
# standard IO errors get exposed directly.
103
self._open(filename, 'rb')
105
fcntl.lockf(self.f, fcntl.LOCK_SH)
107
# we should be more precise about whats a locking
108
# error and whats a random-other error
111
WriteLock = _fcntl_WriteLock
112
ReadLock = _fcntl_ReadLock
51
LOCK_SH = fcntl.LOCK_SH
52
LOCK_EX = fcntl.LOCK_EX
53
LOCK_NB = fcntl.LOCK_NB
62
fcntl.flock(f, fcntl.LOCK_UN)
115
66
except ImportError:
117
68
import win32con, win32file, pywintypes
120
69
LOCK_SH = 0 # the default
121
70
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
122
71
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
124
class _w32c_FileLock(_base_Lock):
125
def _lock(self, filename, openmode, lockmode):
127
self._open(filename, openmode)
128
self.hfile = win32file._get_osfhandle(self.f.fileno())
129
overlapped = pywintypes.OVERLAPPED()
130
win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000, overlapped)
136
overlapped = pywintypes.OVERLAPPED()
137
win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
145
class _w32c_ReadLock(_w32c_FileLock):
146
def __init__(self, filename):
147
_w32c_FileLock._lock(self, filename, 'rb',
150
class _w32c_WriteLock(_w32c_FileLock):
151
def __init__(self, filename):
152
_w32c_FileLock._lock(self, filename, 'wb',
157
WriteLock = _w32c_WriteLock
158
ReadLock = _w32c_ReadLock
76
hfile = win32file._get_osfhandle(f.fileno())
78
hfile = win32file._get_osfhandle(f)
79
overlapped = pywintypes.OVERLAPPED()
80
win32file.LockFileEx(hfile, flags, 0, 0x7fff0000, overlapped)
87
hfile = win32file._get_osfhandle(f.fileno())
89
hfile = win32file._get_osfhandle(f)
90
overlapped = pywintypes.OVERLAPPED()
91
win32file.UnlockFileEx(hfile, 0, 0x7fff0000, overlapped)
160
94
except ImportError:
165
97
# Unfortunately, msvcrt.locking() doesn't distinguish between
166
98
# read locks and write locks. Also, the way the combinations
167
99
# work to get non-blocking is not the same, so we
168
100
# have to write extra special functions here.
171
class _msvc_FileLock(_base_Lock):
181
class _msvc_ReadLock(_msvc_FileLock):
182
def __init__(self, filename):
183
_msvc_lock(self._open(filename, 'rb'), self.LOCK_SH)
186
class _msvc_WriteLock(_msvc_FileLock):
187
def __init__(self, filename):
188
_msvc_lock(self._open(filename, 'wb'), self.LOCK_EX)
192
def _msvc_lock(f, flags):
194
108
# Unfortunately, msvcrt.LK_RLCK is equivalent to msvcrt.LK_LOCK
195
109
# according to the comments, LK_RLCK is open the lock for writing.