36
from __future__ import absolute_import
48
from .hooks import Hooks
49
from .i18n import gettext
50
from bzrlib.hooks import Hooks
51
from bzrlib.i18n import gettext
52
53
class LockHooks(Hooks):
54
55
def __init__(self):
55
Hooks.__init__(self, "breezy.lock", "Lock.hooks")
58
"Called with a breezy.lock.LockResult when a physical lock is "
56
Hooks.__init__(self, "bzrlib.lock", "Lock.hooks")
57
self.add_hook('lock_acquired',
58
"Called with a bzrlib.lock.LockResult when a physical lock is "
59
59
"acquired.", (1, 8))
62
"Called with a breezy.lock.LockResult when a physical lock is "
60
self.add_hook('lock_released',
61
"Called with a bzrlib.lock.LockResult when a physical lock is "
63
62
"released.", (1, 8))
66
"Called with a breezy.lock.LockResult when a physical lock is "
63
self.add_hook('lock_broken',
64
"Called with a bzrlib.lock.LockResult when a physical lock is "
67
65
"broken.", (1, 15))
98
96
:ivar unlock: A callable which will unlock the lock.
101
def __init__(self, unlock, token=None):
99
def __init__(self, unlock):
102
100
self.unlock = unlock
105
102
def __repr__(self):
106
103
return "LogicalLockResult(%s)" % (self.unlock)
111
def __exit__(self, exc_type, exc_val, exc_tb):
112
# If there was an error raised, prefer the original one
115
except BaseException:
121
107
def cant_unlock_not_held(locked_object):
122
108
"""An attempt to unlock failed because the object was not locked.
124
This provides a policy point from which we can generate either a warning or
110
This provides a policy point from which we can generate either a warning
127
113
# This is typically masking some other error and called from a finally
128
114
# block, so it's useful to have the option not to generate a new error
344
340
self._read_lock = None
347
344
_lock_classes.append(('fcntl', _fcntl_WriteLock, _fcntl_ReadLock))
347
if have_pywin32 and sys.platform == 'win32':
348
if os.path.supports_unicode_filenames:
349
# for Windows NT/2K/XP/etc
350
win32file_CreateFile = win32file.CreateFileW
353
win32file_CreateFile = win32file.CreateFile
355
class _w32c_FileLock(_OSLock):
357
def _open(self, filename, access, share, cflags, pymode):
358
self.filename = osutils.realpath(filename)
360
self._handle = win32file_CreateFile(filename, access, share,
361
None, win32file.OPEN_ALWAYS,
362
win32file.FILE_ATTRIBUTE_NORMAL, None)
363
except pywintypes.error, e:
364
if e.args[0] == winerror.ERROR_ACCESS_DENIED:
365
raise errors.LockFailed(filename, e)
366
if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
367
raise errors.LockContention(filename, e)
369
fd = win32file._open_osfhandle(self._handle, cflags)
370
self.f = os.fdopen(fd, pymode)
378
class _w32c_ReadLock(_w32c_FileLock):
379
def __init__(self, filename):
380
super(_w32c_ReadLock, self).__init__()
381
self._open(filename, win32file.GENERIC_READ,
382
win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
384
def temporary_write_lock(self):
385
"""Try to grab a write lock on the file.
387
On platforms that support it, this will upgrade to a write lock
388
without unlocking the file.
389
Otherwise, this will release the read lock, and try to acquire a
392
:return: A token which can be used to switch back to a read lock.
394
# I can't find a way to upgrade a read lock to a write lock without
395
# unlocking first. So here, we do just that.
398
wlock = _w32c_WriteLock(self.filename)
399
except errors.LockError:
400
return False, _w32c_ReadLock(self.filename)
404
class _w32c_WriteLock(_w32c_FileLock):
405
def __init__(self, filename):
406
super(_w32c_WriteLock, self).__init__()
408
win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0,
411
def restore_read_lock(self):
412
"""Restore the original ReadLock."""
413
# For win32 we had to completely let go of the original lock, so we
414
# just unlock and create a new read lock.
416
return _w32c_ReadLock(self.filename)
419
_lock_classes.append(('pywin32', _w32c_WriteLock, _w32c_ReadLock))
350
422
if have_ctypes_win32:
351
from ctypes.wintypes import DWORD, LPWSTR
352
LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
353
HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
354
_function_name = "CreateFileW"
423
from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
424
LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
425
HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
426
if os.path.supports_unicode_filenames:
427
_function_name = "CreateFileW"
430
_function_name = "CreateFileA"
431
class LPTSTR(LPCSTR):
432
def __new__(cls, obj):
433
return LPCSTR.__new__(cls, obj.encode("mbcs"))
356
435
# CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
357
436
_CreateFile = ctypes.WINFUNCTYPE(
358
HANDLE, # return value
360
DWORD, # dwDesiredAccess
362
LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
363
DWORD, # dwCreationDisposition
364
DWORD, # dwFlagsAndAttributes
365
HANDLE # hTemplateFile
437
HANDLE, # return value
439
DWORD, # dwDesiredAccess
441
LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
442
DWORD, # dwCreationDisposition
443
DWORD, # dwFlagsAndAttributes
444
HANDLE # hTemplateFile
366
445
)((_function_name, ctypes.windll.kernel32))
368
447
INVALID_HANDLE_VALUE = -1