*** added file 'bzrlib/lock.py'
--- /dev/null 
+++ bzrlib/lock.py 
@@ -0,0 +1,152 @@
+# Copyright (C) 2005 Canonical Ltd
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+import sys, os
+
+import bzrlib
+from trace import mutter, note, warning
+
+class error(Exception):
+    """All exceptions from the lock/unlock functions should be from this exception class.
+    They will be translated as necessary. The original exception is available as e.original_error
+    """
+    def __init__(self, e=None):
+        self.original_error = e
+        if e:
+            Exception.__init__(self, e)
+        else:
+            Exception.__init__(self)
+
+try:
+    import fcntl
+    LOCK_SH = fcntl.LOCK_SH
+    LOCK_EX = fcntl.LOCK_EX
+    LOCK_NB = fcntl.LOCK_NB
+    def lock(f, flags):
+        try:
+            fcntl.flock(f, flags)
+        except Exception, e:
+            raise error(e)
+
+    def unlock(f):
+        try:
+            fcntl.flock(f, fcntl.LOCK_UN)
+        except Exception, e:
+            raise error(e)
+
+except ImportError:
+    try:
+        import win32con, win32file, pywintypes
+        LOCK_SH = 0 # the default
+        LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
+        LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
+
+        def lock(f, flags):
+            try:
+                if type(f) == file:
+                    hfile = win32file._get_osfhandle(f.fileno())
+                else:
+                    hfile = win32file._get_osfhandle(f)
+                overlapped = pywintypes.OVERLAPPED()
+                win32file.LockFileEx(hfile, flags, 0, 0x7fff0000, overlapped)
+            except Exception, e:
+                raise error(e)
+
+        def unlock(f):
+            try:
+                if type(f) == file:
+                    hfile = win32file._get_osfhandle(f.fileno())
+                else:
+                    hfile = win32file._get_osfhandle(f)
+                overlapped = pywintypes.OVERLAPPED()
+                win32file.UnlockFileEx(hfile, 0, 0x7fff0000, overlapped)
+            except Exception, e:
+                raise error(e)
+    except ImportError:
+        try:
+            import msvcrt
+            # Unfortunately, msvcrt.locking() doesn't distinguish between
+            # read locks and write locks. Also, the way the combinations
+            # work to get non-blocking is not the same, so we
+            # have to write extra special functions here.
+
+            LOCK_SH = 1
+            LOCK_EX = 2
+            LOCK_NB = 4
+
+            def lock(f, flags):
+                try:
+                    # Unfortunately, msvcrt.LK_RLCK is equivalent to msvcrt.LK_LOCK
+                    # according to the comments, LK_RLCK is open the lock for writing.
+
+                    # Unfortunately, msvcrt.locking() also has the side effect that it
+                    # will only block for 10 seconds at most, and then it will throw an
+                    # exception, this isn't terrible, though.
+                    if type(f) == file:
+                        fpos = f.tell()
+                        fn = f.fileno()
+                        f.seek(0)
+                    else:
+                        fn = f
+                        fpos = os.lseek(fn, 0,0)
+                        os.lseek(fn, 0,0)
+                    
+                    if flags & LOCK_SH:
+                        if flags & LOCK_NB:
+                            lock_mode = msvcrt.LK_NBLCK
+                        else:
+                            lock_mode = msvcrt.LK_LOCK
+                    elif flags & LOCK_EX:
+                        if flags & LOCK_NB:
+                            lock_mode = msvcrt.LK_NBRLCK
+                        else:
+                            lock_mode = msvcrt.LK_RLCK
+                    else:
+                        raise ValueError('Invalid lock mode: %r' % flags)
+                    try:
+                        msvcrt.locking(fn, lock_mode, -1)
+                    finally:
+                        os.lseek(fn, fpos, 0)
+                except Exception, e:
+                    raise error(e)
+
+            def unlock(f):
+                try:
+                    if type(f) == file:
+                        fpos = f.tell()
+                        fn = f.fileno()
+                        f.seek(0)
+                    else:
+                        fn = f
+                        fpos = os.lseek(fn, 0,0)
+                        os.lseek(fn, 0,0)
+
+                    try:
+                        msvcrt.locking(fn, msvcrt.LK_UNLCK, -1)
+                    finally:
+                        os.lseek(fn, fpos, 0)
+                except Exception, e:
+                    raise error(e)
+        except ImportError:
+            warning("please write a locking method for platform %r" % sys.platform)
+
+            # Creating no-op lock/unlock for now
+            def lock(f, flags):
+                pass
+            def unlock(f):
+                pass
+

*** modified file 'bzrlib/branch.py'
--- bzrlib/branch.py 
+++ bzrlib/branch.py 
@@ -21,7 +21,7 @@
 
 import bzrlib
 from inventory import Inventory
-from trace import mutter, note
+from trace import mutter, note, warning
 from tree import Tree, EmptyTree, RevisionTree
 from inventory import InventoryEntry, Inventory
 from osutils import isdir, quotefn, isfile, uuid, sha_file, username, \
@@ -31,6 +31,8 @@
 from revision import Revision
 from errors import bailout, BzrError
 from textui import show_status
+
+import lock
 
 BZR_BRANCH_FORMAT = "Bazaar-NG branch, format 0.0.4\n"
 ## TODO: Maybe include checks for common corruption of newlines, etc?
@@ -115,6 +117,7 @@
                         ['use "bzr init" to initialize a new working tree',
                          'current bzr can only operate from top-of-tree'])
         self._check_format()
+        self._lockfile = None
         self.lock(lock_mode)
 
         self.text_store = ImmutableStore(self.controlfilename('text-store'))
@@ -128,46 +131,47 @@
 
     __repr__ = __str__
 
+    def __del__(self):
+        self.unlock()
 
 
     def lock(self, mode='w'):
         """Lock the on-disk branch, excluding other processes."""
+        import errno
+        if self._lockfile: 
+            if self._lockmode == mode:
+                return
+            # On some platforms (*cough* win32 *cough*), upgrading a lock requires unlocking it first
+            if sys.platform in ('win32', 'cygwin'):
+                self.unlock()
+        if mode == 'w':
+            lm = lock.LOCK_EX
+            om = os.O_WRONLY | os.O_CREAT
+        elif mode == 'r':
+            lm = lock.LOCK_SH
+            om = os.O_RDONLY
+        else:
+            raise BzrError("invalid locking mode %r" % mode)
+
         try:
-            import fcntl, errno
-
-            if mode == 'w':
-                lm = fcntl.LOCK_EX
-                om = os.O_WRONLY | os.O_CREAT
-            elif mode == 'r':
-                lm = fcntl.LOCK_SH
-                om = os.O_RDONLY
+            self._lockfile = os.open(self.controlfilename('branch-lock'), om)
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                # might not exist on branches from <0.0.4
+                self.controlfile('branch-lock', 'w').close()
+                self._lockfile = os.open(self.controlfilename('branch-lock'), om)
             else:
-                raise BzrError("invalid locking mode %r" % mode)
-
-            try:
-                lockfile = os.open(self.controlfilename('branch-lock'), om)
-            except OSError, e:
-                if e.errno == errno.ENOENT:
-                    # might not exist on branches from <0.0.4
-                    self.controlfile('branch-lock', 'w').close()
-                    lockfile = os.open(self.controlfilename('branch-lock'), om)
-                else:
-                    raise e
+                raise e
             
-            fcntl.lockf(lockfile, lm)
-            def unlock():
-                fcntl.lockf(lockfile, fcntl.LOCK_UN)
-                os.close(lockfile)
-                self._lockmode = None
-            self.unlock = unlock
-            self._lockmode = mode
-        except ImportError:
-            warning("please write a locking method for platform %r" % sys.platform)
-            def unlock():
-                self._lockmode = None
-            self.unlock = unlock
-            self._lockmode = mode
-
+        lock.lock(self._lockfile, lm)
+        self._lockmode = mode
+
+    def unlock(self):
+        if self._lockfile:
+            lock.unlock(self._lockfile)
+            os.close(self._lockfile)
+            self._lockfile = None
+            self._lockmode = None
 
     def _need_readlock(self):
         if self._lockmode not in ['r', 'w']:
