/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-08 14:37:25 UTC
  • mfrom: (4516 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4517.
  • Revision ID: john@arbash-meinel.com-20090708143725-sc9sjy3mz4cxwxzz
Merge bzr.dev 4516

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
 
    _GetLastError = ctypes.windll.kernel32.GetLastError
395
 
 
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;
401
 
    #   union {
402
 
    #     struct {
403
 
    #       DWORD Offset;
404
 
    #       DWORD OffsetHigh;
405
 
    #     };
406
 
    #     PVOID Pointer;
407
 
    #   };
408
 
    #   HANDLE hEvent;
409
 
    # } OVERLAPPED,
410
 
 
411
 
    class _inner_struct(ctypes.Structure):
412
 
        _fields_ = [('Offset', ctypes.c_uint), # DWORD
413
 
                    ('OffsetHigh', ctypes.c_uint), # DWORD
414
 
                   ]
415
 
 
416
 
    class _inner_union(ctypes.Union):
417
 
        _fields_  = [('anon_struct', _inner_struct), # struct
418
 
                     ('Pointer', ctypes.c_void_p), # PVOID
419
 
                    ]
420
 
 
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
426
 
                   ]
 
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
427
413
 
428
414
    class _ctypes_FileLock(_OSLock):
429
415
 
430
 
        def _lock(self, filename, openmode, lockmode):
431
 
            self._open(filename, openmode)
432
 
 
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
441
 
                                )
442
 
            if result == 0:
443
 
                self._clear_f()
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,))
 
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
449
430
 
450
431
        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
457
 
                                  )
458
432
            self._clear_f()
459
 
            if result == 0:
460
 
                self._clear_f()
461
 
                last_err = _GetLastError()
462
 
                raise errors.LockContention(self.filename,
463
 
                    'Unknown unlocking error: %s' % (last_err,))
464
433
 
465
434
 
466
435
    class _ctypes_ReadLock(_ctypes_FileLock):
467
436
        def __init__(self, filename):
468
437
            super(_ctypes_ReadLock, self).__init__()
469
 
            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
 
438
            self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
 
439
                "rb")
470
440
 
471
441
        def temporary_write_lock(self):
472
442
            """Try to grab a write lock on the file.
490
460
    class _ctypes_WriteLock(_ctypes_FileLock):
491
461
        def __init__(self, filename):
492
462
            super(_ctypes_WriteLock, self).__init__()
493
 
            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
 
463
            self._open(filename, GENERIC_READ | GENERIC_WRITE, 0, os.O_RDWR,
 
464
                "rb+")
494
465
 
495
466
        def restore_read_lock(self):
496
467
            """Restore the original ReadLock."""