~bzr-pqm/bzr/bzr.dev

4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
577 by Martin Pool
- merge portable lock module from John
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
577 by Martin Pool
- merge portable lock module from John
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
577 by Martin Pool
- merge portable lock module from John
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
577 by Martin Pool
- merge portable lock module from John
16
17
1553.5.39 by Martin Pool
More lock docs
18
"""Locking using OS file locks or file existence.
577 by Martin Pool
- merge portable lock module from John
19
1553.5.46 by Martin Pool
doc
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.
577 by Martin Pool
- merge portable lock module from John
23
24
This module causes two methods, lock() and unlock() to be defined in
25
any way that works on the current platform.
26
27
It is not specified whether these locks are reentrant (i.e. can be
28
taken repeatedly by a single process) or whether they exclude
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
29
different threads in a single process.  That reentrancy is provided by
1553.5.39 by Martin Pool
More lock docs
30
LockableFiles.
615 by Martin Pool
Major rework of locking code:
31
32
This defines two classes: ReadLock and WriteLock, which can be
33
implemented in different ways on different platforms.  Both have an
34
unlock() method.
614 by Martin Pool
- unify two defintions of LockError
35
"""
577 by Martin Pool
- merge portable lock module from John
36
1185.65.29 by Robert Collins
Implement final review suggestions.
37
import errno
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
38
import os
2353.3.12 by John Arbash Meinel
Don't create the alternative lock types unless we are on windows.
39
import sys
577 by Martin Pool
- merge portable lock module from John
40
2353.3.11 by John Arbash Meinel
Code cleanup
41
from bzrlib import (
42
    errors,
43
    osutils,
44
    trace,
45
    )
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
46
from bzrlib.hooks import HookPoint, Hooks
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
47
48
3724.1.1 by Martin Pool
Move Lock hooks onto a base Lock class and make them more consistent with other lock classes
49
class LockHooks(Hooks):
50
51
    def __init__(self):
52
        Hooks.__init__(self)
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
53
        self.create_hook(HookPoint('lock_acquired',
54
            "Called with a bzrlib.lock.LockResult when a physical lock is "
55
            "acquired.", (1, 8), None))
56
        self.create_hook(HookPoint('lock_released',
57
            "Called with a bzrlib.lock.LockResult when a physical lock is "
58
            "released.", (1, 8), None))
4327.1.2 by Vincent Ladeuil
Introduce a new lock_broken hook.
59
        self.create_hook(HookPoint('lock_broken',
60
            "Called with a bzrlib.lock.LockResult when a physical lock is "
61
            "broken.", (1, 15), None))
3724.1.1 by Martin Pool
Move Lock hooks onto a base Lock class and make them more consistent with other lock classes
62
63
64
class Lock(object):
65
    """Base class for locks.
66
67
    :cvar hooks: Hook dictionary for operations on locks.
68
    """
69
70
    hooks = LockHooks()
71
72
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
73
class LockResult(object):
3331.3.5 by Martin Pool
Move physical lock hooks onto new PhysicalLock class variable
74
    """Result of an operation on a lock; passed to a hook"""
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
75
3331.3.2 by Robert Collins
Polish on lock hooks to be easier to use.
76
    def __init__(self, lock_url, details=None):
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
77
        """Create a lock result for lock with optional details about the lock."""
3331.3.2 by Robert Collins
Polish on lock hooks to be easier to use.
78
        self.lock_url = lock_url
3331.3.1 by Robert Collins
* ``LockDir`` lock acquisition and release now trigger hooks allowing
79
        self.details = details
80
81
    def __eq__(self, other):
3331.3.2 by Robert Collins
Polish on lock hooks to be easier to use.
82
        return self.lock_url == other.lock_url and self.details == other.details
1711.8.1 by John Arbash Meinel
Branch.lock_read/lock_write/unlock should handle failures
83
4327.1.1 by Vincent Ladeuil
Start addressing test failing when run with -Dlock.
84
    def __repr__(self):
85
        return '%s(%s%s)' % (self.__class__.__name__,
86
                             self.lock_url, self.details)
87
577 by Martin Pool
- merge portable lock module from John
88
3224.5.32 by Andrew Bennetts
Tidy conditional imports in bzrlib/lock.py as suggested by John's review.
89
try:
90
    import fcntl
91
    have_fcntl = True
92
except ImportError:
93
    have_fcntl = False
94
95
have_pywin32 = False
96
have_ctypes_win32 = False
97
if sys.platform == 'win32':
98
    import msvcrt
99
    try:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
100
        import win32file, pywintypes, winerror
3224.5.32 by Andrew Bennetts
Tidy conditional imports in bzrlib/lock.py as suggested by John's review.
101
        have_pywin32 = True
102
    except ImportError:
103
        pass
104
105
    try:
106
        import ctypes
107
        have_ctypes_win32 = True
108
    except ImportError:
109
        pass
110
111
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
112
class _OSLock(object):
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
113
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
114
    def __init__(self):
115
        self.f = None
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
116
        self.filename = None
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
117
615 by Martin Pool
Major rework of locking code:
118
    def _open(self, filename, filemode):
2353.3.11 by John Arbash Meinel
Code cleanup
119
        self.filename = osutils.realpath(filename)
656 by Martin Pool
- create branch lock files if they don't exist
120
        try:
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
121
            self.f = open(self.filename, filemode)
656 by Martin Pool
- create branch lock files if they don't exist
122
            return self.f
123
        except IOError, e:
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
124
            if e.errno in (errno.EACCES, errno.EPERM):
2872.5.1 by Martin Pool
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).
125
                raise errors.LockFailed(self.filename, str(e))
656 by Martin Pool
- create branch lock files if they don't exist
126
            if e.errno != errno.ENOENT:
127
                raise
128
129
            # maybe this is an old branch (before may 2005)
2353.3.11 by John Arbash Meinel
Code cleanup
130
            trace.mutter("trying to create missing lock %r", self.filename)
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
131
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
132
            self.f = open(self.filename, 'wb+')
656 by Martin Pool
- create branch lock files if they don't exist
133
            return self.f
134
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
135
    def _clear_f(self):
136
        """Clear the self.f attribute cleanly."""
137
        if self.f:
138
            self.f.close()
139
            self.f = None
140
615 by Martin Pool
Major rework of locking code:
141
    def __del__(self):
142
        if self.f:
143
            from warnings import warn
144
            warn("lock on %r not released" % self.f)
145
            self.unlock()
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
146
615 by Martin Pool
Major rework of locking code:
147
    def unlock(self):
148
        raise NotImplementedError()
149
150
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
151
_lock_classes = []
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
152
153
154
if have_fcntl:
615 by Martin Pool
Major rework of locking code:
155
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
156
    class _fcntl_FileLock(_OSLock):
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
157
158
        def _unlock(self):
1185.9.2 by Harald Meland
Use fcntl.lockf() rather than fcntl.flock() to support NFS file systems.
159
            fcntl.lockf(self.f, fcntl.LOCK_UN)
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
160
            self._clear_f()
161
162
615 by Martin Pool
Major rework of locking code:
163
    class _fcntl_WriteLock(_fcntl_FileLock):
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
164
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
165
        _open_locks = set()
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
166
615 by Martin Pool
Major rework of locking code:
167
        def __init__(self, filename):
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
168
            super(_fcntl_WriteLock, self).__init__()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
169
            # Check we can grab a lock before we actually open the file.
170
            self.filename = osutils.realpath(filename)
2363.3.3 by John Arbash Meinel
make Write locks not block on Read locks, so that revert tests don't fail
171
            if self.filename in _fcntl_WriteLock._open_locks:
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
172
                self._clear_f()
173
                raise errors.LockContention(self.filename)
174
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
175
            self._open(self.filename, 'rb+')
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
176
            # reserve a slot for this lock - even if the lockf call fails,
177
            # at thisi point unlock() will be called, because self.f is set.
178
            # TODO: make this fully threadsafe, if we decide we care.
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
179
            _fcntl_WriteLock._open_locks.add(self.filename)
615 by Martin Pool
Major rework of locking code:
180
            try:
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
181
                # LOCK_NB will cause IOError to be raised if we can't grab a
182
                # lock right away.
183
                fcntl.lockf(self.f, fcntl.LOCK_EX | fcntl.LOCK_NB)
1185.65.29 by Robert Collins
Implement final review suggestions.
184
            except IOError, e:
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
185
                if e.errno in (errno.EAGAIN, errno.EACCES):
186
                    # We couldn't grab the lock
187
                    self.unlock()
1185.65.29 by Robert Collins
Implement final review suggestions.
188
                # we should be more precise about whats a locking
189
                # error and whats a random-other error
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
190
                raise errors.LockContention(self.filename, e)
615 by Martin Pool
Major rework of locking code:
191
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
192
        def unlock(self):
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
193
            _fcntl_WriteLock._open_locks.remove(self.filename)
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
194
            self._unlock()
195
196
615 by Martin Pool
Major rework of locking code:
197
    class _fcntl_ReadLock(_fcntl_FileLock):
1185.65.29 by Robert Collins
Implement final review suggestions.
198
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
199
        _open_locks = {}
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
200
2353.4.11 by John Arbash Meinel
Remove the unused _ignore_write_lock parameter.
201
        def __init__(self, filename):
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
202
            super(_fcntl_ReadLock, self).__init__()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
203
            self.filename = osutils.realpath(filename)
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
204
            _fcntl_ReadLock._open_locks.setdefault(self.filename, 0)
205
            _fcntl_ReadLock._open_locks[self.filename] += 1
1185.65.29 by Robert Collins
Implement final review suggestions.
206
            self._open(filename, 'rb')
615 by Martin Pool
Major rework of locking code:
207
            try:
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
208
                # LOCK_NB will cause IOError to be raised if we can't grab a
209
                # lock right away.
210
                fcntl.lockf(self.f, fcntl.LOCK_SH | fcntl.LOCK_NB)
1185.65.29 by Robert Collins
Implement final review suggestions.
211
            except IOError, e:
212
                # we should be more precise about whats a locking
213
                # error and whats a random-other error
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
214
                raise errors.LockContention(self.filename, e)
615 by Martin Pool
Major rework of locking code:
215
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
216
        def unlock(self):
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
217
            count = _fcntl_ReadLock._open_locks[self.filename]
218
            if count == 1:
219
                del _fcntl_ReadLock._open_locks[self.filename]
220
            else:
221
                _fcntl_ReadLock._open_locks[self.filename] = count - 1
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
222
            self._unlock()
223
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
224
        def temporary_write_lock(self):
225
            """Try to grab a write lock on the file.
226
227
            On platforms that support it, this will upgrade to a write lock
228
            without unlocking the file.
229
            Otherwise, this will release the read lock, and try to acquire a
230
            write lock.
231
232
            :return: A token which can be used to switch back to a read lock.
233
            """
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
234
            if self.filename in _fcntl_WriteLock._open_locks:
235
                raise AssertionError('file already locked: %r'
236
                    % (self.filename,))
2353.4.7 by John Arbash Meinel
Change the temporary_write_lock api, so that it always returns a lock object,
237
            try:
238
                wlock = _fcntl_TemporaryWriteLock(self)
239
            except errors.LockError:
240
                # We didn't unlock, so we can just return 'self'
241
                return False, self
242
            return True, wlock
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
243
244
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
245
    class _fcntl_TemporaryWriteLock(_OSLock):
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
246
        """A token used when grabbing a temporary_write_lock.
247
248
        Call restore_read_lock() when you are done with the write lock.
249
        """
250
251
        def __init__(self, read_lock):
252
            super(_fcntl_TemporaryWriteLock, self).__init__()
253
            self._read_lock = read_lock
254
            self.filename = read_lock.filename
255
256
            count = _fcntl_ReadLock._open_locks[self.filename]
257
            if count > 1:
258
                # Something else also has a read-lock, so we cannot grab a
259
                # write lock.
260
                raise errors.LockContention(self.filename)
261
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
262
            if self.filename in _fcntl_WriteLock._open_locks:
263
                raise AssertionError('file already locked: %r'
264
                    % (self.filename,))
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
265
266
            # See if we can open the file for writing. Another process might
267
            # have a read lock. We don't use self._open() because we don't want
268
            # to create the file if it exists. That would have already been
269
            # done by _fcntl_ReadLock
270
            try:
271
                new_f = open(self.filename, 'rb+')
272
            except IOError, e:
273
                if e.errno in (errno.EACCES, errno.EPERM):
2872.5.1 by Martin Pool
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).
274
                    raise errors.LockFailed(self.filename, str(e))
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
275
                raise
276
            try:
277
                # LOCK_NB will cause IOError to be raised if we can't grab a
278
                # lock right away.
2379.3.1 by John Arbash Meinel
Cherry-pick the 2 locking fixes from the 0.15 branch.
279
                fcntl.lockf(new_f, fcntl.LOCK_EX | fcntl.LOCK_NB)
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
280
            except IOError, e:
281
                # TODO: Raise a more specific error based on the type of error
4100.1.4 by Martin Pool
LockContention on OS locks now includes the filename
282
                raise errors.LockContention(self.filename, e)
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
283
            _fcntl_WriteLock._open_locks.add(self.filename)
284
285
            self.f = new_f
286
287
        def restore_read_lock(self):
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
288
            """Restore the original ReadLock."""
289
            # For fcntl, since we never released the read lock, just release the
290
            # write lock, and return the original lock.
2353.4.3 by John Arbash Meinel
Implement a 'ReadLock.temporary_write_lock()' to upgrade to a write-lock in-process.
291
            fcntl.lockf(self.f, fcntl.LOCK_UN)
292
            self._clear_f()
293
            _fcntl_WriteLock._open_locks.remove(self.filename)
294
            # Avoid reference cycles
295
            read_lock = self._read_lock
296
            self._read_lock = None
297
            return read_lock
298
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
299
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
300
    _lock_classes.append(('fcntl', _fcntl_WriteLock, _fcntl_ReadLock))
577 by Martin Pool
- merge portable lock module from John
301
2353.3.11 by John Arbash Meinel
Code cleanup
302
2353.3.12 by John Arbash Meinel
Don't create the alternative lock types unless we are on windows.
303
if have_pywin32 and sys.platform == 'win32':
4513.1.1 by Alexander Belchenko
improved unicode support for OS locks @ win32.
304
    if os.path.supports_unicode_filenames:
305
        # for Windows NT/2K/XP/etc
306
        win32file_CreateFile = win32file.CreateFileW
307
    else:
308
        # for Windows 98
309
        win32file_CreateFile = win32file.CreateFile
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
310
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
311
    class _w32c_FileLock(_OSLock):
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
312
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
313
        def _open(self, filename, access, share, cflags, pymode):
314
            self.filename = osutils.realpath(filename)
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
315
            try:
4513.1.1 by Alexander Belchenko
improved unicode support for OS locks @ win32.
316
                self._handle = win32file_CreateFile(filename, access, share,
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
317
                    None, win32file.OPEN_ALWAYS,
318
                    win32file.FILE_ATTRIBUTE_NORMAL, None)
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
319
            except pywintypes.error, e:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
320
                if e.args[0] == winerror.ERROR_ACCESS_DENIED:
321
                    raise errors.LockFailed(filename, e)
322
                if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
323
                    raise errors.LockContention(filename, e)
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
324
                raise
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
325
            fd = win32file._open_osfhandle(self._handle, cflags)
326
            self.f = os.fdopen(fd, pymode)
327
            return self.f
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
328
329
        def unlock(self):
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
330
            self._clear_f()
331
            self._handle = None
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
332
333
334
    class _w32c_ReadLock(_w32c_FileLock):
335
        def __init__(self, filename):
336
            super(_w32c_ReadLock, self).__init__()
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
337
            self._open(filename, win32file.GENERIC_READ,
338
                win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
339
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
340
        def temporary_write_lock(self):
341
            """Try to grab a write lock on the file.
342
343
            On platforms that support it, this will upgrade to a write lock
344
            without unlocking the file.
345
            Otherwise, this will release the read lock, and try to acquire a
346
            write lock.
347
348
            :return: A token which can be used to switch back to a read lock.
349
            """
350
            # I can't find a way to upgrade a read lock to a write lock without
351
            # unlocking first. So here, we do just that.
352
            self.unlock()
2353.4.7 by John Arbash Meinel
Change the temporary_write_lock api, so that it always returns a lock object,
353
            try:
354
                wlock = _w32c_WriteLock(self.filename)
355
            except errors.LockError:
356
                return False, _w32c_ReadLock(self.filename)
357
            return True, wlock
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
358
2353.3.11 by John Arbash Meinel
Code cleanup
359
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
360
    class _w32c_WriteLock(_w32c_FileLock):
361
        def __init__(self, filename):
362
            super(_w32c_WriteLock, self).__init__()
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
363
            self._open(filename,
364
                win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0,
365
                os.O_RDWR, "rb+")
2353.3.4 by John Arbash Meinel
Clean up the lock.py code to use less indenting, and conform to better coding practise.
366
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
367
        def restore_read_lock(self):
368
            """Restore the original ReadLock."""
369
            # For win32 we had to completely let go of the original lock, so we
370
            # just unlock and create a new read lock.
371
            self.unlock()
372
            return _w32c_ReadLock(self.filename)
373
2353.3.11 by John Arbash Meinel
Code cleanup
374
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
375
    _lock_classes.append(('pywin32', _w32c_WriteLock, _w32c_ReadLock))
376
2353.3.11 by John Arbash Meinel
Code cleanup
377
3224.5.1 by Andrew Bennetts
Lots of assorted hackery to reduce the number of imports for common operations. Improves 'rocks', 'st' and 'help' times by ~50ms on my laptop.
378
if have_ctypes_win32:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
379
    from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
380
    LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
381
    HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
382
    if os.path.supports_unicode_filenames:
383
        _function_name = "CreateFileW"
384
        LPTSTR = LPCWSTR
385
    else:
386
        _function_name = "CreateFileA"
387
        class LPTSTR(LPCSTR):
388
            def __new__(cls, obj):
389
                return LPCSTR.__new__(cls, obj.encode("mbcs"))
390
391
    # CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
392
    _CreateFile = ctypes.WINFUNCTYPE(
393
            HANDLE,                # return value
394
            LPTSTR,                # lpFileName
395
            DWORD,                 # dwDesiredAccess
396
            DWORD,                 # dwShareMode
397
            LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
398
            DWORD,                 # dwCreationDisposition
399
            DWORD,                 # dwFlagsAndAttributes
400
            HANDLE                 # hTemplateFile
401
        )((_function_name, ctypes.windll.kernel32))
402
    
403
    INVALID_HANDLE_VALUE = -1
404
    
405
    GENERIC_READ = 0x80000000
406
    GENERIC_WRITE = 0x40000000
407
    FILE_SHARE_READ = 1
408
    OPEN_ALWAYS = 4
409
    FILE_ATTRIBUTE_NORMAL = 128
410
    
411
    ERROR_ACCESS_DENIED = 5
412
    ERROR_SHARING_VIOLATION = 32
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
413
2555.3.2 by Martin Pool
rename _base_Lock to _OSLock
414
    class _ctypes_FileLock(_OSLock):
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
415
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
416
        def _open(self, filename, access, share, cflags, pymode):
417
            self.filename = osutils.realpath(filename)
418
            handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
419
                FILE_ATTRIBUTE_NORMAL, 0)
420
            if handle in (INVALID_HANDLE_VALUE, 0):
421
                e = ctypes.WinError()
4459.3.2 by Martin
Fix issue with change of semantics of WindowsError.errno in Python 2.5
422
                if e.args[0] == ERROR_ACCESS_DENIED:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
423
                    raise errors.LockFailed(filename, e)
4459.3.2 by Martin
Fix issue with change of semantics of WindowsError.errno in Python 2.5
424
                if e.args[0] == ERROR_SHARING_VIOLATION:
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
425
                    raise errors.LockContention(filename, e)
426
                raise e
427
            fd = msvcrt.open_osfhandle(handle, cflags)
428
            self.f = os.fdopen(fd, pymode)
429
            return self.f
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
430
431
        def unlock(self):
4404.1.1 by Martin
Correct use of GetLastError in ctypes windows locking code
432
            self._clear_f()
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
433
434
435
    class _ctypes_ReadLock(_ctypes_FileLock):
436
        def __init__(self, filename):
437
            super(_ctypes_ReadLock, self).__init__()
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
438
            self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
439
                "rb")
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
440
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
441
        def temporary_write_lock(self):
442
            """Try to grab a write lock on the file.
443
444
            On platforms that support it, this will upgrade to a write lock
445
            without unlocking the file.
446
            Otherwise, this will release the read lock, and try to acquire a
447
            write lock.
448
449
            :return: A token which can be used to switch back to a read lock.
450
            """
451
            # I can't find a way to upgrade a read lock to a write lock without
452
            # unlocking first. So here, we do just that.
453
            self.unlock()
2353.4.7 by John Arbash Meinel
Change the temporary_write_lock api, so that it always returns a lock object,
454
            try:
455
                wlock = _ctypes_WriteLock(self.filename)
456
            except errors.LockError:
457
                return False, _ctypes_ReadLock(self.filename)
458
            return True, wlock
2353.3.11 by John Arbash Meinel
Code cleanup
459
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
460
    class _ctypes_WriteLock(_ctypes_FileLock):
461
        def __init__(self, filename):
462
            super(_ctypes_WriteLock, self).__init__()
4459.3.1 by Martin
Implement bzrlib.lock with CreateFile rather than LockFileEx on win32
463
            self._open(filename, GENERIC_READ | GENERIC_WRITE, 0, os.O_RDWR,
464
                "rb+")
2353.3.5 by John Arbash Meinel
Fall back on ctypes to get LockFileEx, because msvcrt.locking()
465
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
466
        def restore_read_lock(self):
467
            """Restore the original ReadLock."""
468
            # For win32 we had to completely let go of the original lock, so we
469
            # just unlock and create a new read lock.
470
            self.unlock()
2353.4.6 by John Arbash Meinel
ctypes locks should return ctypes locks.
471
            return _ctypes_ReadLock(self.filename)
2353.4.4 by John Arbash Meinel
Implement temporary_write_lock, and restore_read_lock for win32 locks.
472
2353.3.11 by John Arbash Meinel
Code cleanup
473
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
474
    _lock_classes.append(('ctypes', _ctypes_WriteLock, _ctypes_ReadLock))
475
476
477
if len(_lock_classes) == 0:
2353.3.11 by John Arbash Meinel
Code cleanup
478
    raise NotImplementedError(
479
        "We must have one of fcntl, pywin32, or ctypes available"
480
        " to support OS locking."
481
        )
482
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
483
484
# We default to using the first available lock class.
485
_lock_type, WriteLock, ReadLock = _lock_classes[0]
486