/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/lock.py

  • Committer: John Arbash Meinel
  • Date: 2009-07-29 21:35:05 UTC
  • mfrom: (4576 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4577.
  • Revision ID: john@arbash-meinel.com-20090729213505-tkqsvy1zfpocu75w
Merge bzr.dev 4576 in prep for NEWS

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
"""
36
36
 
37
37
import errno
 
38
import os
38
39
import sys
 
40
import warnings
39
41
 
40
42
from bzrlib import (
 
43
    debug,
41
44
    errors,
42
45
    osutils,
43
46
    trace,
85
88
                             self.lock_url, self.details)
86
89
 
87
90
 
 
91
def cant_unlock_not_held(locked_object):
 
92
    """An attempt to unlock failed because the object was not locked.
 
93
 
 
94
    This provides a policy point from which we can generate either a warning 
 
95
    or an exception.
 
96
    """
 
97
    # This is typically masking some other error and called from a finally
 
98
    # block, so it's useful to have the option not to generate a new error
 
99
    # here.  You can use -Werror to make it fatal.  It should possibly also
 
100
    # raise LockNotHeld.
 
101
    if 'unlock' in debug.debug_flags:
 
102
        warnings.warn("%r is already unlocked" % (locked_object,),
 
103
            stacklevel=3)
 
104
    else:
 
105
        raise errors.LockNotHeld(locked_object)
 
106
 
 
107
 
88
108
try:
89
109
    import fcntl
90
110
    have_fcntl = True
96
116
if sys.platform == 'win32':
97
117
    import msvcrt
98
118
    try:
99
 
        import win32con, win32file, pywintypes, winerror
 
119
        import win32file, pywintypes, winerror
100
120
        have_pywin32 = True
101
121
    except ImportError:
102
122
        pass
151
171
 
152
172
 
153
173
if have_fcntl:
154
 
    LOCK_SH = fcntl.LOCK_SH
155
 
    LOCK_NB = fcntl.LOCK_NB
156
 
    lock_EX = fcntl.LOCK_EX
157
 
 
158
174
 
159
175
    class _fcntl_FileLock(_OSLock):
160
176
 
304
320
 
305
321
 
306
322
if have_pywin32 and sys.platform == 'win32':
307
 
    LOCK_SH = 0 # the default
308
 
    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
309
 
    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
310
 
 
 
323
    if os.path.supports_unicode_filenames:
 
324
        # for Windows NT/2K/XP/etc
 
325
        win32file_CreateFile = win32file.CreateFileW
 
326
    else:
 
327
        # for Windows 98
 
328
        win32file_CreateFile = win32file.CreateFile
311
329
 
312
330
    class _w32c_FileLock(_OSLock):
313
331
 
314
 
        def _lock(self, filename, openmode, lockmode):
315
 
            self._open(filename, openmode)
316
 
 
317
 
            self.hfile = msvcrt.get_osfhandle(self.f.fileno())
318
 
            overlapped = pywintypes.OVERLAPPED()
 
332
        def _open(self, filename, access, share, cflags, pymode):
 
333
            self.filename = osutils.realpath(filename)
319
334
            try:
320
 
                win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000,
321
 
                                     overlapped)
 
335
                self._handle = win32file_CreateFile(filename, access, share,
 
336
                    None, win32file.OPEN_ALWAYS,
 
337
                    win32file.FILE_ATTRIBUTE_NORMAL, None)
322
338
            except pywintypes.error, e:
323
 
                self._clear_f()
324
 
                if e.args[0] in (winerror.ERROR_LOCK_VIOLATION,):
325
 
                    raise errors.LockContention(filename)
326
 
                ## import pdb; pdb.set_trace()
 
339
                if e.args[0] == winerror.ERROR_ACCESS_DENIED:
 
340
                    raise errors.LockFailed(filename, e)
 
341
                if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
 
342
                    raise errors.LockContention(filename, e)
327
343
                raise
328
 
            except Exception, e:
329
 
                self._clear_f()
330
 
                raise errors.LockContention(filename, e)
 
344
            fd = win32file._open_osfhandle(self._handle, cflags)
 
345
            self.f = os.fdopen(fd, pymode)
 
346
            return self.f
331
347
 
332
348
        def unlock(self):
333
 
            overlapped = pywintypes.OVERLAPPED()
334
 
            try:
335
 
                win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
336
 
                self._clear_f()
337
 
            except Exception, e:
338
 
                raise errors.LockContention(self.filename, e)
 
349
            self._clear_f()
 
350
            self._handle = None
339
351
 
340
352
 
341
353
    class _w32c_ReadLock(_w32c_FileLock):
342
354
        def __init__(self, filename):
343
355
            super(_w32c_ReadLock, self).__init__()
344
 
            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
 
356
            self._open(filename, win32file.GENERIC_READ,
 
357
                win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
345
358
 
346
359
        def temporary_write_lock(self):
347
360
            """Try to grab a write lock on the file.
366
379
    class _w32c_WriteLock(_w32c_FileLock):
367
380
        def __init__(self, filename):
368
381
            super(_w32c_WriteLock, self).__init__()
369
 
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
 
382
            self._open(filename,
 
383
                win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0,
 
384
                os.O_RDWR, "rb+")
370
385
 
371
386
        def restore_read_lock(self):
372
387
            """Restore the original ReadLock."""
380
395
 
381
396
 
382
397
if have_ctypes_win32:
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
388
 
 
389
 
    LOCK_SH = 0
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
 
 
395
 
    ### Define the OVERLAPPED structure.
396
 
    #   http://msdn2.microsoft.com/en-us/library/ms684342.aspx
397
 
    # typedef struct _OVERLAPPED {
398
 
    #   ULONG_PTR Internal;
399
 
    #   ULONG_PTR InternalHigh;
400
 
    #   union {
401
 
    #     struct {
402
 
    #       DWORD Offset;
403
 
    #       DWORD OffsetHigh;
404
 
    #     };
405
 
    #     PVOID Pointer;
406
 
    #   };
407
 
    #   HANDLE hEvent;
408
 
    # } OVERLAPPED,
409
 
 
410
 
    class _inner_struct(ctypes.Structure):
411
 
        _fields_ = [('Offset', ctypes.c_uint), # DWORD
412
 
                    ('OffsetHigh', ctypes.c_uint), # DWORD
413
 
                   ]
414
 
 
415
 
    class _inner_union(ctypes.Union):
416
 
        _fields_  = [('anon_struct', _inner_struct), # struct
417
 
                     ('Pointer', ctypes.c_void_p), # PVOID
418
 
                    ]
419
 
 
420
 
    class OVERLAPPED(ctypes.Structure):
421
 
        _fields_ = [('Internal', ctypes.c_void_p), # ULONG_PTR
422
 
                    ('InternalHigh', ctypes.c_void_p), # ULONG_PTR
423
 
                    ('_inner_union', _inner_union),
424
 
                    ('hEvent', ctypes.c_void_p), # HANDLE
425
 
                   ]
 
398
    from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
 
399
    LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
 
400
    HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
 
401
    if os.path.supports_unicode_filenames:
 
402
        _function_name = "CreateFileW"
 
403
        LPTSTR = LPCWSTR
 
404
    else:
 
405
        _function_name = "CreateFileA"
 
406
        class LPTSTR(LPCSTR):
 
407
            def __new__(cls, obj):
 
408
                return LPCSTR.__new__(cls, obj.encode("mbcs"))
 
409
 
 
410
    # CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
 
411
    _CreateFile = ctypes.WINFUNCTYPE(
 
412
            HANDLE,                # return value
 
413
            LPTSTR,                # lpFileName
 
414
            DWORD,                 # dwDesiredAccess
 
415
            DWORD,                 # dwShareMode
 
416
            LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
 
417
            DWORD,                 # dwCreationDisposition
 
418
            DWORD,                 # dwFlagsAndAttributes
 
419
            HANDLE                 # hTemplateFile
 
420
        )((_function_name, ctypes.windll.kernel32))
 
421
    
 
422
    INVALID_HANDLE_VALUE = -1
 
423
    
 
424
    GENERIC_READ = 0x80000000
 
425
    GENERIC_WRITE = 0x40000000
 
426
    FILE_SHARE_READ = 1
 
427
    OPEN_ALWAYS = 4
 
428
    FILE_ATTRIBUTE_NORMAL = 128
 
429
    
 
430
    ERROR_ACCESS_DENIED = 5
 
431
    ERROR_SHARING_VIOLATION = 32
426
432
 
427
433
    class _ctypes_FileLock(_OSLock):
428
434
 
429
 
        def _lock(self, filename, openmode, lockmode):
430
 
            self._open(filename, openmode)
431
 
 
432
 
            self.hfile = msvcrt.get_osfhandle(self.f.fileno())
433
 
            overlapped = OVERLAPPED()
434
 
            result = _LockFileEx(self.hfile, # HANDLE hFile
435
 
                                 lockmode,   # DWORD dwFlags
436
 
                                 0,          # DWORD dwReserved
437
 
                                 0x7fffffff, # DWORD nNumberOfBytesToLockLow
438
 
                                 0x00000000, # DWORD nNumberOfBytesToLockHigh
439
 
                                 ctypes.byref(overlapped), # lpOverlapped
440
 
                                )
441
 
            if result == 0:
442
 
                last_err = ctypes.GetLastError()
443
 
                self._clear_f()
444
 
                if last_err in (ERROR_LOCK_VIOLATION,):
445
 
                    raise errors.LockContention(filename)
446
 
                raise errors.LockContention(filename,
447
 
                    'Unknown locking error: %s' % (last_err,))
 
435
        def _open(self, filename, access, share, cflags, pymode):
 
436
            self.filename = osutils.realpath(filename)
 
437
            handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
 
438
                FILE_ATTRIBUTE_NORMAL, 0)
 
439
            if handle in (INVALID_HANDLE_VALUE, 0):
 
440
                e = ctypes.WinError()
 
441
                if e.args[0] == ERROR_ACCESS_DENIED:
 
442
                    raise errors.LockFailed(filename, e)
 
443
                if e.args[0] == ERROR_SHARING_VIOLATION:
 
444
                    raise errors.LockContention(filename, e)
 
445
                raise e
 
446
            fd = msvcrt.open_osfhandle(handle, cflags)
 
447
            self.f = os.fdopen(fd, pymode)
 
448
            return self.f
448
449
 
449
450
        def unlock(self):
450
 
            overlapped = OVERLAPPED()
451
 
            result = _UnlockFileEx(self.hfile, # HANDLE hFile
452
 
                                   0,          # DWORD dwReserved
453
 
                                   0x7fffffff, # DWORD nNumberOfBytesToLockLow
454
 
                                   0x00000000, # DWORD nNumberOfBytesToLockHigh
455
 
                                   ctypes.byref(overlapped), # lpOverlapped
456
 
                                  )
457
 
            if result == 0:
458
 
                last_err = ctypes.GetLastError()
459
 
                self._clear_f()
460
 
                raise errors.LockContention(self.filename,
461
 
                    'Unknown unlocking error: %s' % (last_err,))
462
451
            self._clear_f()
463
452
 
464
453
 
465
454
    class _ctypes_ReadLock(_ctypes_FileLock):
466
455
        def __init__(self, filename):
467
456
            super(_ctypes_ReadLock, self).__init__()
468
 
            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
 
457
            self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
 
458
                "rb")
469
459
 
470
460
        def temporary_write_lock(self):
471
461
            """Try to grab a write lock on the file.
489
479
    class _ctypes_WriteLock(_ctypes_FileLock):
490
480
        def __init__(self, filename):
491
481
            super(_ctypes_WriteLock, self).__init__()
492
 
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
 
482
            self._open(filename, GENERIC_READ | GENERIC_WRITE, 0, os.O_RDWR,
 
483
                "rb+")
493
484
 
494
485
        def restore_read_lock(self):
495
486
            """Restore the original ReadLock."""