84
81
return self.lock_url == other.lock_url and self.details == other.details
86
83
def __repr__(self):
87
return '%s(%s, %s)' % (self.__class__.__name__,
84
return '%s(%s%s)' % (self.__class__.__name__,
88
85
self.lock_url, self.details)
91
class LogicalLockResult(object):
92
"""The result of a lock_read/lock_write/lock_tree_write call on lockables.
94
:ivar unlock: A callable which will unlock the lock.
97
def __init__(self, unlock):
101
return "LogicalLockResult(%s)" % (self.unlock)
105
def cant_unlock_not_held(locked_object):
106
"""An attempt to unlock failed because the object was not locked.
108
This provides a policy point from which we can generate either a warning
111
# This is typically masking some other error and called from a finally
112
# block, so it's useful to have the option not to generate a new error
113
# here. You can use -Werror to make it fatal. It should possibly also
115
if 'unlock' in debug.debug_flags:
116
warnings.warn("%r is already unlocked" % (locked_object,),
119
raise errors.LockNotHeld(locked_object)
351
306
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
307
LOCK_SH = 0 # the default
308
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
309
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
359
312
class _w32c_FileLock(_OSLock):
361
def _open(self, filename, access, share, cflags, pymode):
362
self.filename = osutils.realpath(filename)
314
def _lock(self, filename, openmode, lockmode):
315
self._open(filename, openmode)
317
self.hfile = msvcrt.get_osfhandle(self.f.fileno())
318
overlapped = pywintypes.OVERLAPPED()
364
self._handle = win32file_CreateFile(filename, access, share,
365
None, win32file.OPEN_ALWAYS,
366
win32file.FILE_ATTRIBUTE_NORMAL, None)
320
win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000,
367
322
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)
324
if e.args[0] in (winerror.ERROR_LOCK_VIOLATION,):
325
raise errors.LockContention(filename)
326
## import pdb; pdb.set_trace()
373
fd = win32file._open_osfhandle(self._handle, cflags)
374
self.f = os.fdopen(fd, pymode)
330
raise errors.LockContention(filename, e)
377
332
def unlock(self):
333
overlapped = pywintypes.OVERLAPPED()
335
win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
338
raise errors.LockContention(self.filename, e)
382
341
class _w32c_ReadLock(_w32c_FileLock):
383
342
def __init__(self, filename):
384
343
super(_w32c_ReadLock, self).__init__()
385
self._open(filename, win32file.GENERIC_READ,
386
win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
344
self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
388
346
def temporary_write_lock(self):
389
347
"""Try to grab a write lock on the file.
426
382
if have_ctypes_win32:
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"))
439
# CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
440
_CreateFile = ctypes.WINFUNCTYPE(
441
HANDLE, # return value
443
DWORD, # dwDesiredAccess
445
LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
446
DWORD, # dwCreationDisposition
447
DWORD, # dwFlagsAndAttributes
448
HANDLE # hTemplateFile
449
)((_function_name, ctypes.windll.kernel32))
451
INVALID_HANDLE_VALUE = -1
453
GENERIC_READ = 0x80000000
454
GENERIC_WRITE = 0x40000000
457
FILE_ATTRIBUTE_NORMAL = 128
459
ERROR_ACCESS_DENIED = 5
460
ERROR_SHARING_VIOLATION = 32
383
# These constants were copied from the win32con.py module.
384
LOCKFILE_FAIL_IMMEDIATELY = 1
385
LOCKFILE_EXCLUSIVE_LOCK = 2
386
# Constant taken from winerror.py module
387
ERROR_LOCK_VIOLATION = 33
390
LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK
391
LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
392
_LockFileEx = ctypes.windll.kernel32.LockFileEx
393
_UnlockFileEx = ctypes.windll.kernel32.UnlockFileEx
394
_GetLastError = ctypes.windll.kernel32.GetLastError
396
### Define the OVERLAPPED structure.
397
# http://msdn2.microsoft.com/en-us/library/ms684342.aspx
398
# typedef struct _OVERLAPPED {
399
# ULONG_PTR Internal;
400
# ULONG_PTR InternalHigh;
411
class _inner_struct(ctypes.Structure):
412
_fields_ = [('Offset', ctypes.c_uint), # DWORD
413
('OffsetHigh', ctypes.c_uint), # DWORD
416
class _inner_union(ctypes.Union):
417
_fields_ = [('anon_struct', _inner_struct), # struct
418
('Pointer', ctypes.c_void_p), # PVOID
421
class OVERLAPPED(ctypes.Structure):
422
_fields_ = [('Internal', ctypes.c_void_p), # ULONG_PTR
423
('InternalHigh', ctypes.c_void_p), # ULONG_PTR
424
('_inner_union', _inner_union),
425
('hEvent', ctypes.c_void_p), # HANDLE
462
428
class _ctypes_FileLock(_OSLock):
464
def _open(self, filename, access, share, cflags, pymode):
465
self.filename = osutils.realpath(filename)
466
handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
467
FILE_ATTRIBUTE_NORMAL, 0)
468
if handle in (INVALID_HANDLE_VALUE, 0):
469
e = ctypes.WinError()
470
if e.args[0] == ERROR_ACCESS_DENIED:
471
raise errors.LockFailed(filename, e)
472
if e.args[0] == ERROR_SHARING_VIOLATION:
473
raise errors.LockContention(filename, e)
475
fd = msvcrt.open_osfhandle(handle, cflags)
476
self.f = os.fdopen(fd, pymode)
430
def _lock(self, filename, openmode, lockmode):
431
self._open(filename, openmode)
433
self.hfile = msvcrt.get_osfhandle(self.f.fileno())
434
overlapped = OVERLAPPED()
435
result = _LockFileEx(self.hfile, # HANDLE hFile
436
lockmode, # DWORD dwFlags
437
0, # DWORD dwReserved
438
0x7fffffff, # DWORD nNumberOfBytesToLockLow
439
0x00000000, # DWORD nNumberOfBytesToLockHigh
440
ctypes.byref(overlapped), # lpOverlapped
444
last_err = _GetLastError()
445
if last_err in (ERROR_LOCK_VIOLATION,):
446
raise errors.LockContention(filename)
447
raise errors.LockContention(filename,
448
'Unknown locking error: %s' % (last_err,))
479
450
def unlock(self):
451
overlapped = OVERLAPPED()
452
result = _UnlockFileEx(self.hfile, # HANDLE hFile
453
0, # DWORD dwReserved
454
0x7fffffff, # DWORD nNumberOfBytesToLockLow
455
0x00000000, # DWORD nNumberOfBytesToLockHigh
456
ctypes.byref(overlapped), # lpOverlapped
461
last_err = _GetLastError()
462
raise errors.LockContention(self.filename,
463
'Unknown unlocking error: %s' % (last_err,))
483
466
class _ctypes_ReadLock(_ctypes_FileLock):
484
467
def __init__(self, filename):
485
468
super(_ctypes_ReadLock, self).__init__()
486
self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
469
self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
489
471
def temporary_write_lock(self):
490
472
"""Try to grab a write lock on the file.