# HG changeset patch # User Augie Fackler # Date 1578422849 18000 # Node ID 0b0e72b5d551fc58338366ba4006efd019ece23d # Parent ecbba7b2e44483c99b5600a4a178f956ccb76fca manifest: start removing 40-byte hash restrictions from C code Differential Revision: https://phab.mercurial-scm.org/D8368 diff -r ecbba7b2e444 -r 0b0e72b5d551 mercurial/cext/manifest.c --- 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);