79
85
def __eq__(self, other):
80
86
return self.lock_url == other.lock_url and self.details == other.details
89
return '%s(%s, %s)' % (self.__class__.__name__,
90
self.lock_url, self.details)
93
class LogicalLockResult(object):
94
"""The result of a lock_read/lock_write/lock_tree_write call on lockables.
96
:ivar unlock: A callable which will unlock the lock.
99
def __init__(self, unlock):
103
return "LogicalLockResult(%s)" % (self.unlock)
107
def cant_unlock_not_held(locked_object):
108
"""An attempt to unlock failed because the object was not locked.
110
This provides a policy point from which we can generate either a warning
113
# This is typically masking some other error and called from a finally
114
# block, so it's useful to have the option not to generate a new error
115
# here. You can use -Werror to make it fatal. It should possibly also
117
if 'unlock' in debug.debug_flags:
118
warnings.warn("%r is already unlocked" % (locked_object,),
121
raise errors.LockNotHeld(locked_object)
301
347
if have_pywin32 and sys.platform == 'win32':
302
LOCK_SH = 0 # the default
303
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
304
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
348
if os.path.supports_unicode_filenames:
349
# for Windows NT/2K/XP/etc
350
win32file_CreateFile = win32file.CreateFileW
353
win32file_CreateFile = win32file.CreateFile
307
355
class _w32c_FileLock(_OSLock):
309
def _lock(self, filename, openmode, lockmode):
310
self._open(filename, openmode)
312
self.hfile = msvcrt.get_osfhandle(self.f.fileno())
313
overlapped = pywintypes.OVERLAPPED()
357
def _open(self, filename, access, share, cflags, pymode):
358
self.filename = osutils.realpath(filename)
315
win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000,
360
self._handle = win32file_CreateFile(filename, access, share,
361
None, win32file.OPEN_ALWAYS,
362
win32file.FILE_ATTRIBUTE_NORMAL, None)
317
363
except pywintypes.error, e:
319
if e.args[0] in (winerror.ERROR_LOCK_VIOLATION,):
320
raise errors.LockContention(filename)
321
## import pdb; pdb.set_trace()
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)
325
raise errors.LockContention(e)
369
fd = win32file._open_osfhandle(self._handle, cflags)
370
self.f = os.fdopen(fd, pymode)
327
373
def unlock(self):
328
overlapped = pywintypes.OVERLAPPED()
330
win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
333
raise errors.LockContention(e)
336
378
class _w32c_ReadLock(_w32c_FileLock):
337
379
def __init__(self, filename):
338
380
super(_w32c_ReadLock, self).__init__()
339
self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
381
self._open(filename, win32file.GENERIC_READ,
382
win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
341
384
def temporary_write_lock(self):
342
385
"""Try to grab a write lock on the file.
377
422
if have_ctypes_win32:
378
# These constants were copied from the win32con.py module.
379
LOCKFILE_FAIL_IMMEDIATELY = 1
380
LOCKFILE_EXCLUSIVE_LOCK = 2
381
# Constant taken from winerror.py module
382
ERROR_LOCK_VIOLATION = 33
385
LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK
386
LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
387
_LockFileEx = ctypes.windll.kernel32.LockFileEx
388
_UnlockFileEx = ctypes.windll.kernel32.UnlockFileEx
389
_GetLastError = ctypes.windll.kernel32.GetLastError
391
### Define the OVERLAPPED structure.
392
# http://msdn2.microsoft.com/en-us/library/ms684342.aspx
393
# typedef struct _OVERLAPPED {
394
# ULONG_PTR Internal;
395
# ULONG_PTR InternalHigh;
406
class _inner_struct(ctypes.Structure):
407
_fields_ = [('Offset', ctypes.c_uint), # DWORD
408
('OffsetHigh', ctypes.c_uint), # DWORD
411
class _inner_union(ctypes.Union):
412
_fields_ = [('anon_struct', _inner_struct), # struct
413
('Pointer', ctypes.c_void_p), # PVOID
416
class OVERLAPPED(ctypes.Structure):
417
_fields_ = [('Internal', ctypes.c_void_p), # ULONG_PTR
418
('InternalHigh', ctypes.c_void_p), # ULONG_PTR
419
('_inner_union', _inner_union),
420
('hEvent', ctypes.c_void_p), # HANDLE
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"))
435
# CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
436
_CreateFile = ctypes.WINFUNCTYPE(
437
HANDLE, # return value
439
DWORD, # dwDesiredAccess
441
LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
442
DWORD, # dwCreationDisposition
443
DWORD, # dwFlagsAndAttributes
444
HANDLE # hTemplateFile
445
)((_function_name, ctypes.windll.kernel32))
447
INVALID_HANDLE_VALUE = -1
449
GENERIC_READ = 0x80000000
450
GENERIC_WRITE = 0x40000000
453
FILE_ATTRIBUTE_NORMAL = 128
455
ERROR_ACCESS_DENIED = 5
456
ERROR_SHARING_VIOLATION = 32
423
458
class _ctypes_FileLock(_OSLock):
425
def _lock(self, filename, openmode, lockmode):
426
self._open(filename, openmode)
428
self.hfile = msvcrt.get_osfhandle(self.f.fileno())
429
overlapped = OVERLAPPED()
430
result = _LockFileEx(self.hfile, # HANDLE hFile
431
lockmode, # DWORD dwFlags
432
0, # DWORD dwReserved
433
0x7fffffff, # DWORD nNumberOfBytesToLockLow
434
0x00000000, # DWORD nNumberOfBytesToLockHigh
435
ctypes.byref(overlapped), # lpOverlapped
439
last_err = _GetLastError()
440
if last_err in (ERROR_LOCK_VIOLATION,):
441
raise errors.LockContention(filename)
442
raise errors.LockContention('Unknown locking error: %s'
460
def _open(self, filename, access, share, cflags, pymode):
461
self.filename = osutils.realpath(filename)
462
handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
463
FILE_ATTRIBUTE_NORMAL, 0)
464
if handle in (INVALID_HANDLE_VALUE, 0):
465
e = ctypes.WinError()
466
if e.args[0] == ERROR_ACCESS_DENIED:
467
raise errors.LockFailed(filename, e)
468
if e.args[0] == ERROR_SHARING_VIOLATION:
469
raise errors.LockContention(filename, e)
471
fd = msvcrt.open_osfhandle(handle, cflags)
472
self.f = os.fdopen(fd, pymode)
445
475
def unlock(self):
446
overlapped = OVERLAPPED()
447
result = _UnlockFileEx(self.hfile, # HANDLE hFile
448
0, # DWORD dwReserved
449
0x7fffffff, # DWORD nNumberOfBytesToLockLow
450
0x00000000, # DWORD nNumberOfBytesToLockHigh
451
ctypes.byref(overlapped), # lpOverlapped
456
last_err = _GetLastError()
457
raise errors.LockContention('Unknown unlocking error: %s'
461
479
class _ctypes_ReadLock(_ctypes_FileLock):
462
480
def __init__(self, filename):
463
481
super(_ctypes_ReadLock, self).__init__()
464
self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
482
self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
466
485
def temporary_write_lock(self):
467
486
"""Try to grab a write lock on the file.