changeset 4381:28054fc34923

Merge with crew
author Brendan Cully <brendan@kublai.com>
date Sat, 28 Apr 2007 09:03:47 -0700
parents 8c2a18cc3096 (current diff) e89f9afc462b (diff)
children caaba589d9c7
files mercurial/commands.py
diffstat 4 files changed, 92 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -200,6 +200,50 @@ def addremove(repo, pats=[], opts={}, wl
             if not dry_run:
                 repo.copy(old, new, wlock=wlock)
 
+def service(opts, parentfn=None, initfn=None, runfn=None):
+    '''Run a command as a service.'''
+
+    if opts['daemon'] and not opts['daemon_pipefds']:
+        rfd, wfd = os.pipe()
+        args = sys.argv[:]
+        args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
+        pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
+                         args[0], args)
+        os.close(wfd)
+        os.read(rfd, 1)
+        if parentfn:
+            return parentfn(pid)
+        else:
+            os._exit(0)
+
+    if initfn:
+        initfn()
+
+    if opts['pid_file']:
+        fp = open(opts['pid_file'], 'w')
+        fp.write(str(os.getpid()) + '\n')
+        fp.close()
+
+    if opts['daemon_pipefds']:
+        rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
+        os.close(rfd)
+        try:
+            os.setsid()
+        except AttributeError:
+            pass
+        os.write(wfd, 'y')
+        os.close(wfd)
+        sys.stdout.flush()
+        sys.stderr.flush()
+        fd = os.open(util.nulldev, os.O_RDWR)
+        if fd != 0: os.dup2(fd, 0)
+        if fd != 1: os.dup2(fd, 1)
+        if fd != 2: os.dup2(fd, 2)
+        if fd not in (0, 1, 2): os.close(fd)
+
+    if runfn:
+        return runfn()
+
 class changeset_printer(object):
     '''show changeset information when templating not requested.'''
 
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2375,44 +2375,27 @@ def serve(ui, repo, **opts):
         raise hg.RepoError(_("There is no Mercurial repository here"
                              " (.hg not found)"))
 
-    if opts['daemon'] and not opts['daemon_pipefds']:
-        rfd, wfd = os.pipe()
-        args = sys.argv[:]
-        args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
-        pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
-                         args[0], args)
-        os.close(wfd)
-        os.read(rfd, 1)
-        os._exit(0)
-
-    httpd = hgweb.server.create_server(parentui, repo)
-
-    if ui.verbose:
-        if httpd.port != 80:
-            ui.status(_('listening at http://%s:%d/\n') %
-                      (httpd.addr, httpd.port))
-        else:
-            ui.status(_('listening at http://%s/\n') % httpd.addr)
-
-    if opts['pid_file']:
-        fp = open(opts['pid_file'], 'w')
-        fp.write(str(os.getpid()) + '\n')
-        fp.close()
-
-    if opts['daemon_pipefds']:
-        rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
-        os.close(rfd)
-        os.write(wfd, 'y')
-        os.close(wfd)
-        sys.stdout.flush()
-        sys.stderr.flush()
-        fd = os.open(util.nulldev, os.O_RDWR)
-        if fd != 0: os.dup2(fd, 0)
-        if fd != 1: os.dup2(fd, 1)
-        if fd != 2: os.dup2(fd, 2)
-        if fd not in (0, 1, 2): os.close(fd)
-
-    httpd.serve_forever()
+    class service:
+        def init(self):
+            try:
+                self.httpd = hgweb.server.create_server(parentui, repo)
+            except socket.error, inst:
+                raise util.Abort(_('cannot start server: ') + inst.args[1])
+
+            if not ui.verbose: return
+
+            if httpd.port != 80:
+                ui.status(_('listening at http://%s:%d/\n') %
+                          (httpd.addr, httpd.port))
+            else:
+                ui.status(_('listening at http://%s/\n') % httpd.addr)
+
+        def run(self):
+            self.httpd.serve_forever()
+
+    service = service()
+
+    cmdutil.service(opts, initfn=service.init, runfn=service.run)
 
 def status(ui, repo, *pats, **opts):
     """show changed files in the working directory
--- a/mercurial/mpatch.c
+++ b/mercurial/mpatch.c
@@ -225,7 +225,7 @@ static struct flist *decode(char *bin, i
 {
 	struct flist *l;
 	struct frag *lt;
-	char *end = bin + len;
+	char *data = bin + 12, *end = bin + len;
 	char decode[12]; /* for dealing with alignment issues */
 
 	/* assume worst case size, we won't have many of these lists */
@@ -235,13 +235,18 @@ static struct flist *decode(char *bin, i
 
 	lt = l->tail;
 
-	while (bin < end) {
+	while (data <= end) {
 		memcpy(decode, bin, 12);
 		lt->start = ntohl(*(uint32_t *)decode);
 		lt->end = ntohl(*(uint32_t *)(decode + 4));
 		lt->len = ntohl(*(uint32_t *)(decode + 8));
-		lt->data = bin + 12;
-		bin += 12 + lt->len;
+		if (lt->start > lt->end)
+			break; /* sanity check */
+		bin = data + lt->len;
+		if (bin < data)
+			break; /* big data + big (bogus) len can wrap around */
+		lt->data = data;
+		data = bin + 12;
 		lt++;
 	}
 
@@ -371,20 +376,26 @@ patchedsize(PyObject *self, PyObject *ar
 {
 	long orig, start, end, len, outlen = 0, last = 0;
 	int patchlen;
-	char *bin, *binend;
+	char *bin, *binend, *data;
 	char decode[12]; /* for dealing with alignment issues */
 
 	if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen))
 		return NULL;
 
 	binend = bin + patchlen;
+	data = bin + 12;
 
-	while (bin < binend) {
+	while (data <= binend) {
 		memcpy(decode, bin, 12);
 		start = ntohl(*(uint32_t *)decode);
 		end = ntohl(*(uint32_t *)(decode + 4));
 		len = ntohl(*(uint32_t *)(decode + 8));
-		bin += 12 + len;
+		if (start > end)
+			break; /* sanity check */
+		bin = data + len;
+		if (bin < data)
+			break; /* big data + big (bogus) len can wrap around */
+		data = bin + 12;
 		outlen += start - last;
 		last = end;
 		outlen += len;
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -1161,11 +1161,19 @@ def opener(base, audit=True):
     class atomicfile(atomictempfile):
         """the file will only be copied on close"""
         def __init__(self, name, mode):
+            self._err = False
             atomictempfile.__init__(self, name, mode)
+        def write(self, s):
+            try:
+                atomictempfile.write(self, s)
+            except:
+                self._err = True
+                raise
         def close(self):
             self.rename()
         def __del__(self):
-            self.rename()
+            if not self._err:
+                self.rename()
 
     def o(path, mode="r", text=False, atomic=False, atomictemp=False):
         if audit_p: