[PATCH 1 of 2] pure/mpatch: use StringIO in case of mmap error (issue1493)

Martin Geisler mg at daimi.au.dk
Wed Feb 11 17:37:04 CST 2009


# HG changeset patch
# User Martin Geisler <mg at daimi.au.dk>
# Date 1234395384 -3600
# Node ID 9125eb8632498449a5fcb4ce165ac175861b04d5
# Parent  998fc8f62539ee26601d526803d6da2476129411
pure/mpatch: use StringIO in case of mmap error (issue1493)

This fixes a problem on Windows which obviously does not have
/dev/zero, and on Mac OS X which does not like mmap on /dev/zero.

diff --git a/mercurial/pure/mpatch.py b/mercurial/pure/mpatch.py
--- a/mercurial/pure/mpatch.py
+++ b/mercurial/pure/mpatch.py
@@ -7,8 +7,6 @@
 
 import struct, mmap
 
-devzero = file("/dev/zero")
-
 # This attempts to apply a series of patches in time proportional to
 # the total size of the patches, rather than patches * len(text). This
 # means rather than shuffling strings around, we shuffle around
@@ -30,7 +28,35 @@
 
     if not tl: return a
 
-    m = mmap.mmap(devzero.fileno(), tl, mmap.MAP_PRIVATE)
+    try:
+        # try to map a piece of anonymous memory first
+        m = mmap.mmap(-1, tl, mmap.MAP_PRIVATE)
+        move = m.move
+    except EnvironmentError:
+        # Python 2.4 and older do not understand fileno = -1, try
+        # mapping /dev/zero instead
+        try:
+            devzero = file("/dev/zero")
+            m = mmap.mmap(devzero.fileno(), tl, mmap.MAP_PRIVATE)
+            move = m.move
+        except (mmap.error, IOError):
+            # fallback to StringIO if /dev/zero is not present or
+            # cannot be mapped
+            try:
+                import cStringIO as StringIO
+            except ImportError:
+                import StringIO
+
+            m = StringIO.StringIO()
+            def move(dest, src, count):
+                """move count bytes from src to dest
+
+                The file pointer is left at the end of dest.
+                """
+                m.seek(src)
+                buf = self.read(count)
+                m.seek(dest)
+                m.write(buf)
 
     # load our original text
     m.write(a)
@@ -54,7 +80,7 @@
     def collect(buf, list):
         start = buf
         for l, p in list:
-            m.move(buf, p, l)
+            move(buf, p, l)
             buf += l
         return (buf - start, start)
 
@@ -68,7 +94,8 @@
         end = pos + plen
         last = 0
         while pos < end:
-            p1, p2, l = struct.unpack(">lll", m[pos:pos + 12])
+            m.seek(pos)
+            p1, p2, l = struct.unpack(">lll", m.read(12))
             pull(new, frags, p1 - last) # what didn't change
             pull([], frags, p2 - p1)    # what got deleted
             new.append((l, pos + 12))        # what got added
@@ -78,7 +105,8 @@
 
     t = collect(b2, frags)
 
-    return m[t[1]:t[1] + t[0]]
+    m.seek(t[1])
+    return m.read(t[0])
 
 def patchedsize(orig, delta):
     outlen, last, bin = 0, 0, 0


More information about the Mercurial-devel mailing list