/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: Martin Pool
  • Date: 2009-07-17 10:38:41 UTC
  • mfrom: (4536 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4558.
  • Revision ID: mbp@sourcefrog.net-20090717103841-z35onk04bkiw7zb6
Merge trunk

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
39
40
 
40
41
from bzrlib import (
96
97
if sys.platform == 'win32':
97
98
    import msvcrt
98
99
    try:
99
 
        import win32con, win32file, pywintypes, winerror
 
100
        import win32file, pywintypes, winerror
100
101
        have_pywin32 = True
101
102
    except ImportError:
102
103
        pass
151
152
 
152
153
 
153
154
if have_fcntl:
154
 
    LOCK_SH = fcntl.LOCK_SH
155
 
    LOCK_NB = fcntl.LOCK_NB
156
 
    lock_EX = fcntl.LOCK_EX
157
 
 
158
155
 
159
156
    class _fcntl_FileLock(_OSLock):
160
157
 
304
301
 
305
302
 
306
303
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
 
 
 
304
    if os.path.supports_unicode_filenames:
 
305
        # for Windows NT/2K/XP/etc
 
306
        win32file_CreateFile = win32file.CreateFileW
 
307
    else:
 
308
        # for Windows 98
 
309
        win32file_CreateFile = win32file.CreateFile
311
310
 
312
311
    class _w32c_FileLock(_OSLock):
313
312
 
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()
 
313
        def _open(self, filename, access, share, cflags, pymode):
 
314
            self.filename = osutils.realpath(filename)
319
315
            try:
320
 
                win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000,
321
 
                                     overlapped)
 
316
                self._handle = win32file_CreateFile(filename, access, share,
 
317
                    None, win32file.OPEN_ALWAYS,
 
318
                    win32file.FILE_ATTRIBUTE_NORMAL, None)
322
319
            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()
 
320
                if e.args[0] == winerror.ERROR_ACCESS_DENIED:
 
321
                    raise errors.LockFailed(filename, e)
 
322
                if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
 
323
                    raise errors.LockContention(filename, e)
327
324
                raise
328
 
            except Exception, e:
329
 
                self._clear_f()
330
 
                raise errors.LockContention(filename, e)
 
325
            fd = win32file._open_osfhandle(self._handle, cflags)
 
326
            self.f = os.fdopen(fd, pymode)
 
327
            return self.f
331
328
 
332
329
        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)
 
330
            self._clear_f()
 
331
            self._handle = None
339
332
 
340
333
 
341
334
    class _w32c_ReadLock(_w32c_FileLock):
342
335
        def __init__(self, filename):
343
336
            super(_w32c_ReadLock, self).__init__()
344
 
            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
 
337
            self._open(filename, win32file.GENERIC_READ,
 
338
                win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
345
339
 
346
340
        def temporary_write_lock(self):
347
341
            """Try to grab a write lock on the file.
366
360
    class _w32c_WriteLock(_w32c_FileLock):
367
361
        def __init__(self, filename):
368
362
            super(_w32c_WriteLock, self).__init__()
369
 
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
 
363
            self._open(filename,
 
364
                win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0,
 
365
                os.O_RDWR, "rb+")
370
366
 
371
367
        def restore_read_lock(self):
372
368
            """Restore the original ReadLock."""
380
376
 
381
377
 
382
378
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
 
                   ]
 
379
    from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
 
380
    LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
 
381
    HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
 
382
    if os.path.supports_unicode_filenames:
 
383
        _function_name = "CreateFileW"
 
384
        LPTSTR = LPCWSTR
 
385
    else:
 
386
        _function_name = "CreateFileA"
 
387
        class LPTSTR(LPCSTR):
 
388
            def __new__(cls, obj):
 
389
                return LPCSTR.__new__(cls, obj.encode("mbcs"))
 
390
 
 
391
    # CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
 
392
    _CreateFile = ctypes.WINFUNCTYPE(
 
393
            HANDLE,                # return value
 
394
            LPTSTR,                # lpFileName
 
395
            DWORD,                 # dwDesiredAccess
 
396
            DWORD,                 # dwShareMode
 
397
            LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
 
398
            DWORD,                 # dwCreationDisposition
 
399
            DWORD,                 # dwFlagsAndAttributes
 
400
            HANDLE                 # hTemplateFile
 
401
        )((_function_name, ctypes.windll.kernel32))
 
402
    
 
403
    INVALID_HANDLE_VALUE = -1
 
404
    
 
405
    GENERIC_READ = 0x80000000
 
406
    GENERIC_WRITE = 0x40000000
 
407
    FILE_SHARE_READ = 1
 
408
    OPEN_ALWAYS = 4
 
409
    FILE_ATTRIBUTE_NORMAL = 128
 
410
    
 
411
    ERROR_ACCESS_DENIED = 5
 
412
    ERROR_SHARING_VIOLATION = 32
426
413
 
427
414
    class _ctypes_FileLock(_OSLock):
428
415
 
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,))
 
416
        def _open(self, filename, access, share, cflags, pymode):
 
417
            self.filename = osutils.realpath(filename)
 
418
            handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
 
419
                FILE_ATTRIBUTE_NORMAL, 0)
 
420
            if handle in (INVALID_HANDLE_VALUE, 0):
 
421
                e = ctypes.WinError()
 
422
                if e.args[0] == ERROR_ACCESS_DENIED:
 
423
                    raise errors.LockFailed(filename, e)
 
424
                if e.args[0] == ERROR_SHARING_VIOLATION:
 
425
                    raise errors.LockContention(filename, e)
 
426
                raise e
 
427
            fd = msvcrt.open_osfhandle(handle, cflags)
 
428
            self.f = os.fdopen(fd, pymode)
 
429
            return self.f
448
430
 
449
431
        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
432
            self._clear_f()
463
433
 
464
434
 
465
435
    class _ctypes_ReadLock(_ctypes_FileLock):
466
436
        def __init__(self, filename):
467
437
            super(_ctypes_ReadLock, self).__init__()
468
 
            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
 
438
            self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
 
439
                "rb")
469
440
 
470
441
        def temporary_write_lock(self):
471
442
            """Try to grab a write lock on the file.
489
460
    class _ctypes_WriteLock(_ctypes_FileLock):
490
461
        def __init__(self, filename):
491
462
            super(_ctypes_WriteLock, self).__init__()
492
 
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
 
463
            self._open(filename, GENERIC_READ | GENERIC_WRITE, 0, os.O_RDWR,
 
464
                "rb+")
493
465
 
494
466
        def restore_read_lock(self):
495
467
            """Restore the original ReadLock."""