Rev 4478: (Martin <gzlist>) Use CreateFile rather than LockFileEx for OS locks. in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Thu Jun 25 18:36:34 BST 2009


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 4478 [merge]
revision-id: pqm at pqm.ubuntu.com-20090625173629-yw2y6x938qnr0hr4
parent: pqm at pqm.ubuntu.com-20090625163519-mkzk2ohzadj749h3
parent: john at arbash-meinel.com-20090625154112-tgg8jq0ldhaizseg
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2009-06-25 18:36:29 +0100
message:
  (Martin <gzlist>) Use CreateFile rather than LockFileEx for OS locks.
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/lock.py                 lock.py-20050527050856-ec090bb51bc03349
=== modified file 'NEWS'
--- a/NEWS	2009-06-25 14:58:00 +0000
+++ b/NEWS	2009-06-25 17:36:29 +0000
@@ -94,6 +94,11 @@
   parameter to permit cross-format fetching to incrementally pack the
   converted data. (Robert Collins)
 
+* OS file locks are now taken out using ``CreateFile`` rather than
+  ``LockFileEx`` on Windows. The locking remains exclusive with
+  ``LockFileEx`` but now it also works on older versions of Windows (such
+  as Win98). (Martin <gzlist>)
+
 * pack <=> pack fetching is now done via a ``PackStreamSource`` rather
   than the ``Packer`` code. The user visible change is that we now
   properly fetch the minimum number of texts for non-smart fetching.

=== modified file 'bzrlib/lock.py'
--- a/bzrlib/lock.py	2009-06-10 03:56:49 +0000
+++ b/bzrlib/lock.py	2009-06-19 10:04:02 +0000
@@ -35,6 +35,7 @@
 """
 
 import errno
+import os
 import sys
 
 from bzrlib import (
@@ -96,7 +97,7 @@
 if sys.platform == 'win32':
     import msvcrt
     try:
-        import win32con, win32file, pywintypes, winerror
+        import win32file, pywintypes, winerror
         have_pywin32 = True
     except ImportError:
         pass
@@ -151,10 +152,6 @@
 
 
 if have_fcntl:
-    LOCK_SH = fcntl.LOCK_SH
-    LOCK_NB = fcntl.LOCK_NB
-    lock_EX = fcntl.LOCK_EX
-
 
     class _fcntl_FileLock(_OSLock):
 
@@ -304,44 +301,35 @@
 
 
 if have_pywin32 and sys.platform == 'win32':
-    LOCK_SH = 0 # the default
-    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
-    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
-
 
     class _w32c_FileLock(_OSLock):
 
-        def _lock(self, filename, openmode, lockmode):
-            self._open(filename, openmode)
-
-            self.hfile = msvcrt.get_osfhandle(self.f.fileno())
-            overlapped = pywintypes.OVERLAPPED()
+        def _open(self, filename, access, share, cflags, pymode):
+            self.filename = osutils.realpath(filename)
             try:
-                win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000,
-                                     overlapped)
+                self._handle = win32file.CreateFile(filename, access, share,
+                    None, win32file.OPEN_ALWAYS,
+                    win32file.FILE_ATTRIBUTE_NORMAL, None)
             except pywintypes.error, e:
-                self._clear_f()
-                if e.args[0] in (winerror.ERROR_LOCK_VIOLATION,):
-                    raise errors.LockContention(filename)
-                ## import pdb; pdb.set_trace()
+                if e.args[0] == winerror.ERROR_ACCESS_DENIED:
+                    raise errors.LockFailed(filename, e)
+                if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
+                    raise errors.LockContention(filename, e)
                 raise
-            except Exception, e:
-                self._clear_f()
-                raise errors.LockContention(filename, e)
+            fd = win32file._open_osfhandle(self._handle, cflags)
+            self.f = os.fdopen(fd, pymode)
+            return self.f
 
         def unlock(self):
-            overlapped = pywintypes.OVERLAPPED()
-            try:
-                win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
-                self._clear_f()
-            except Exception, e:
-                raise errors.LockContention(self.filename, e)
+            self._clear_f()
+            self._handle = None
 
 
     class _w32c_ReadLock(_w32c_FileLock):
         def __init__(self, filename):
             super(_w32c_ReadLock, self).__init__()
-            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
+            self._open(filename, win32file.GENERIC_READ,
+                win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
 
         def temporary_write_lock(self):
             """Try to grab a write lock on the file.
@@ -366,7 +354,9 @@
     class _w32c_WriteLock(_w32c_FileLock):
         def __init__(self, filename):
             super(_w32c_WriteLock, self).__init__()
-            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
+            self._open(filename,
+                win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0,
+                os.O_RDWR, "rb+")
 
         def restore_read_lock(self):
             """Restore the original ReadLock."""
@@ -380,92 +370,67 @@
 
 
 if have_ctypes_win32:
-    # These constants were copied from the win32con.py module.
-    LOCKFILE_FAIL_IMMEDIATELY = 1
-    LOCKFILE_EXCLUSIVE_LOCK = 2
-    # Constant taken from winerror.py module
-    ERROR_LOCK_VIOLATION = 33
-
-    LOCK_SH = 0
-    LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK
-    LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
-    _LockFileEx = ctypes.windll.kernel32.LockFileEx
-    _UnlockFileEx = ctypes.windll.kernel32.UnlockFileEx
-
-    ### Define the OVERLAPPED structure.
-    #   http://msdn2.microsoft.com/en-us/library/ms684342.aspx
-    # typedef struct _OVERLAPPED {
-    #   ULONG_PTR Internal;
-    #   ULONG_PTR InternalHigh;
-    #   union {
-    #     struct {
-    #       DWORD Offset;
-    #       DWORD OffsetHigh;
-    #     };
-    #     PVOID Pointer;
-    #   };
-    #   HANDLE hEvent;
-    # } OVERLAPPED,
-
-    class _inner_struct(ctypes.Structure):
-        _fields_ = [('Offset', ctypes.c_uint), # DWORD
-                    ('OffsetHigh', ctypes.c_uint), # DWORD
-                   ]
-
-    class _inner_union(ctypes.Union):
-        _fields_  = [('anon_struct', _inner_struct), # struct
-                     ('Pointer', ctypes.c_void_p), # PVOID
-                    ]
-
-    class OVERLAPPED(ctypes.Structure):
-        _fields_ = [('Internal', ctypes.c_void_p), # ULONG_PTR
-                    ('InternalHigh', ctypes.c_void_p), # ULONG_PTR
-                    ('_inner_union', _inner_union),
-                    ('hEvent', ctypes.c_void_p), # HANDLE
-                   ]
+    from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
+    LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
+    HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
+    if os.path.supports_unicode_filenames:
+        _function_name = "CreateFileW"
+        LPTSTR = LPCWSTR
+    else:
+        _function_name = "CreateFileA"
+        class LPTSTR(LPCSTR):
+            def __new__(cls, obj):
+                return LPCSTR.__new__(cls, obj.encode("mbcs"))
+
+    # CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
+    _CreateFile = ctypes.WINFUNCTYPE(
+            HANDLE,                # return value
+            LPTSTR,                # lpFileName
+            DWORD,                 # dwDesiredAccess
+            DWORD,                 # dwShareMode
+            LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
+            DWORD,                 # dwCreationDisposition
+            DWORD,                 # dwFlagsAndAttributes
+            HANDLE                 # hTemplateFile
+        )((_function_name, ctypes.windll.kernel32))
+    
+    INVALID_HANDLE_VALUE = -1
+    
+    GENERIC_READ = 0x80000000
+    GENERIC_WRITE = 0x40000000
+    FILE_SHARE_READ = 1
+    OPEN_ALWAYS = 4
+    FILE_ATTRIBUTE_NORMAL = 128
+    
+    ERROR_ACCESS_DENIED = 5
+    ERROR_SHARING_VIOLATION = 32
 
     class _ctypes_FileLock(_OSLock):
 
-        def _lock(self, filename, openmode, lockmode):
-            self._open(filename, openmode)
-
-            self.hfile = msvcrt.get_osfhandle(self.f.fileno())
-            overlapped = OVERLAPPED()
-            result = _LockFileEx(self.hfile, # HANDLE hFile
-                                 lockmode,   # DWORD dwFlags
-                                 0,          # DWORD dwReserved
-                                 0x7fffffff, # DWORD nNumberOfBytesToLockLow
-                                 0x00000000, # DWORD nNumberOfBytesToLockHigh
-                                 ctypes.byref(overlapped), # lpOverlapped
-                                )
-            if result == 0:
-                last_err = ctypes.GetLastError()
-                self._clear_f()
-                if last_err in (ERROR_LOCK_VIOLATION,):
-                    raise errors.LockContention(filename)
-                raise errors.LockContention(filename,
-                    'Unknown locking error: %s' % (last_err,))
+        def _open(self, filename, access, share, cflags, pymode):
+            self.filename = osutils.realpath(filename)
+            handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
+                FILE_ATTRIBUTE_NORMAL, 0)
+            if handle in (INVALID_HANDLE_VALUE, 0):
+                e = ctypes.WinError()
+                if e.args[0] == ERROR_ACCESS_DENIED:
+                    raise errors.LockFailed(filename, e)
+                if e.args[0] == ERROR_SHARING_VIOLATION:
+                    raise errors.LockContention(filename, e)
+                raise e
+            fd = msvcrt.open_osfhandle(handle, cflags)
+            self.f = os.fdopen(fd, pymode)
+            return self.f
 
         def unlock(self):
-            overlapped = OVERLAPPED()
-            result = _UnlockFileEx(self.hfile, # HANDLE hFile
-                                   0,          # DWORD dwReserved
-                                   0x7fffffff, # DWORD nNumberOfBytesToLockLow
-                                   0x00000000, # DWORD nNumberOfBytesToLockHigh
-                                   ctypes.byref(overlapped), # lpOverlapped
-                                  )
-            if result == 0:
-                last_err = ctypes.GetLastError()
-                self._clear_f()
-                raise errors.LockContention(self.filename,
-                    'Unknown unlocking error: %s' % (last_err,))
             self._clear_f()
 
 
     class _ctypes_ReadLock(_ctypes_FileLock):
         def __init__(self, filename):
             super(_ctypes_ReadLock, self).__init__()
-            self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
+            self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
+                "rb")
 
         def temporary_write_lock(self):
             """Try to grab a write lock on the file.
@@ -489,7 +454,8 @@
     class _ctypes_WriteLock(_ctypes_FileLock):
         def __init__(self, filename):
             super(_ctypes_WriteLock, self).__init__()
-            self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
+            self._open(filename, GENERIC_READ | GENERIC_WRITE, 0, os.O_RDWR,
+                "rb+")
 
         def restore_read_lock(self):
             """Restore the original ReadLock."""




More information about the bazaar-commits mailing list