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