changeset 44702:0b0e72b5d551

manifest: start removing 40-byte hash restrictions from C code Differential Revision: https://phab.mercurial-scm.org/D8368
author Augie Fackler <augie@google.com>
date Tue, 07 Jan 2020 13:47:29 -0500
parents ecbba7b2e444
children 0e99b876966a
files mercurial/cext/manifest.c
diffstat 1 files changed, 28 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/cext/manifest.c	Tue Jan 07 11:25:13 2020 -0500
+++ b/mercurial/cext/manifest.c	Tue Jan 07 13:47:29 2020 -0500
@@ -53,21 +53,35 @@
 {
 	char *s = l->start;
 	Py_ssize_t llen = pathlen(l);
+	Py_ssize_t hlen = l->len - llen - 2;
+	Py_ssize_t hlen_raw = 20;
 	PyObject *hash;
 	if (llen + 1 + 40 + 1 > l->len) { /* path '\0' hash '\n' */
 		PyErr_SetString(PyExc_ValueError, "manifest line too short");
 		return NULL;
 	}
-	hash = unhexlify(s + llen + 1, 40);
+	switch (hlen) {
+	case 40: /* sha1 */
+	case 41: /* sha1 with cruft for a merge */
+		break;
+	case 64: /* new hash */
+	case 65: /* new hash with cruft for a merge */
+		hlen_raw = 32;
+		break;
+	default:
+		PyErr_SetString(PyExc_ValueError, "invalid node length in manifest");
+		return NULL;
+	}
+	hash = unhexlify(s + llen + 1, hlen_raw * 2);
 	if (!hash) {
 		return NULL;
 	}
 	if (l->hash_suffix != '\0') {
-		char newhash[21];
-		memcpy(newhash, PyBytes_AsString(hash), 20);
+		char newhash[33];
+		memcpy(newhash, PyBytes_AsString(hash), hlen_raw);
 		Py_DECREF(hash);
-		newhash[20] = l->hash_suffix;
-		hash = PyBytes_FromStringAndSize(newhash, 21);
+		newhash[hlen_raw] = l->hash_suffix;
+		hash = PyBytes_FromStringAndSize(newhash, hlen_raw+1);
 	}
 	return hash;
 }
@@ -78,15 +92,20 @@
 	char *s = l->start;
 	Py_ssize_t plen = pathlen(l);
 	PyObject *hash = nodeof(l);
-
-	/* 40 for hash, 1 for null byte, 1 for newline */
-	Py_ssize_t hplen = plen + 42;
-	Py_ssize_t flen = l->len - hplen;
+	ssize_t hlen;
+	Py_ssize_t hplen, flen;
 	PyObject *flags;
 	PyObject *tup;
 
 	if (!hash)
 		return NULL;
+	/* hash is either 20 or 21 bytes for an old hash, so we use a
+	   ternary here to get the "real" hexlified sha length. */
+	hlen = PyBytes_GET_SIZE(hash) < 22 ? 40 : 64;
+	/* 1 for null byte, 1 for newline */
+	hplen = plen + hlen + 2;
+	flen = l->len - hplen;
+
 	flags = PyBytes_FromStringAndSize(s + hplen - 1, flen);
 	if (!flags) {
 		Py_DECREF(hash);