mercurial/cext/manifest.c
changeset 45118 d0ef8c1dddd4
parent 44702 0b0e72b5d551
child 45141 9719e118e4af
equal deleted inserted replaced
45117:b1e51ef4e536 45118:d0ef8c1dddd4
    47 	const char *end = memchr(l->start, '\0', l->len);
    47 	const char *end = memchr(l->start, '\0', l->len);
    48 	return (end) ? (Py_ssize_t)(end - l->start) : l->len;
    48 	return (end) ? (Py_ssize_t)(end - l->start) : l->len;
    49 }
    49 }
    50 
    50 
    51 /* get the node value of a single line */
    51 /* get the node value of a single line */
    52 static PyObject *nodeof(line *l)
    52 static PyObject *nodeof(line *l, char *flag)
    53 {
    53 {
    54 	char *s = l->start;
    54 	char *s = l->start;
    55 	Py_ssize_t llen = pathlen(l);
    55 	Py_ssize_t llen = pathlen(l);
    56 	Py_ssize_t hlen = l->len - llen - 2;
    56 	Py_ssize_t hlen = l->len - llen - 2;
    57 	Py_ssize_t hlen_raw = 20;
    57 	Py_ssize_t hlen_raw;
    58 	PyObject *hash;
    58 	PyObject *hash;
    59 	if (llen + 1 + 40 + 1 > l->len) { /* path '\0' hash '\n' */
    59 	if (llen + 1 + 40 + 1 > l->len) { /* path '\0' hash '\n' */
    60 		PyErr_SetString(PyExc_ValueError, "manifest line too short");
    60 		PyErr_SetString(PyExc_ValueError, "manifest line too short");
    61 		return NULL;
    61 		return NULL;
    62 	}
    62 	}
       
    63 	/* Detect flags after the hash first. */
       
    64 	switch (s[llen + hlen]) {
       
    65 	case 'l':
       
    66 	case 't':
       
    67 	case 'x':
       
    68 		*flag = s[llen + hlen];
       
    69 		--hlen;
       
    70 		break;
       
    71 	default:
       
    72 		*flag = '\0';
       
    73 		break;
       
    74 	}
       
    75 
    63 	switch (hlen) {
    76 	switch (hlen) {
    64 	case 40: /* sha1 */
    77 	case 40: /* sha1 */
    65 	case 41: /* sha1 with cruft for a merge */
    78 		hlen_raw = 20;
    66 		break;
    79 		break;
    67 	case 64: /* new hash */
    80 	case 64: /* new hash */
    68 	case 65: /* new hash with cruft for a merge */
       
    69 		hlen_raw = 32;
    81 		hlen_raw = 32;
    70 		break;
    82 		break;
    71 	default:
    83 	default:
    72 		PyErr_SetString(PyExc_ValueError, "invalid node length in manifest");
    84 		PyErr_SetString(PyExc_ValueError, "invalid node length in manifest");
    73 		return NULL;
    85 		return NULL;
    87 }
    99 }
    88 
   100 
    89 /* get the node hash and flags of a line as a tuple */
   101 /* get the node hash and flags of a line as a tuple */
    90 static PyObject *hashflags(line *l)
   102 static PyObject *hashflags(line *l)
    91 {
   103 {
    92 	char *s = l->start;
   104 	char flag;
    93 	Py_ssize_t plen = pathlen(l);
   105 	PyObject *hash = nodeof(l, &flag);
    94 	PyObject *hash = nodeof(l);
       
    95 	ssize_t hlen;
   106 	ssize_t hlen;
    96 	Py_ssize_t hplen, flen;
   107 	Py_ssize_t hplen, flen;
    97 	PyObject *flags;
   108 	PyObject *flags;
    98 	PyObject *tup;
   109 	PyObject *tup;
    99 
   110 
   100 	if (!hash)
   111 	if (!hash)
   101 		return NULL;
   112 		return NULL;
   102 	/* hash is either 20 or 21 bytes for an old hash, so we use a
   113 	flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
   103 	   ternary here to get the "real" hexlified sha length. */
       
   104 	hlen = PyBytes_GET_SIZE(hash) < 22 ? 40 : 64;
       
   105 	/* 1 for null byte, 1 for newline */
       
   106 	hplen = plen + hlen + 2;
       
   107 	flen = l->len - hplen;
       
   108 
       
   109 	flags = PyBytes_FromStringAndSize(s + hplen - 1, flen);
       
   110 	if (!flags) {
   114 	if (!flags) {
   111 		Py_DECREF(hash);
   115 		Py_DECREF(hash);
   112 		return NULL;
   116 		return NULL;
   113 	}
   117 	}
   114 	tup = PyTuple_Pack(2, hash, flags);
   118 	tup = PyTuple_Pack(2, hash, flags);
   289 
   293 
   290 static PyObject *lmiter_iterentriesnext(PyObject *o)
   294 static PyObject *lmiter_iterentriesnext(PyObject *o)
   291 {
   295 {
   292 	Py_ssize_t pl;
   296 	Py_ssize_t pl;
   293 	line *l;
   297 	line *l;
       
   298 	char flag;
   294 	Py_ssize_t consumed;
   299 	Py_ssize_t consumed;
   295 	PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
   300 	PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
   296 	l = lmiter_nextline((lmIter *)o);
   301 	l = lmiter_nextline((lmIter *)o);
   297 	if (!l) {
   302 	if (!l) {
   298 		goto done;
   303 		goto done;
   299 	}
   304 	}
   300 	pl = pathlen(l);
   305 	pl = pathlen(l);
   301 	path = PyBytes_FromStringAndSize(l->start, pl);
   306 	path = PyBytes_FromStringAndSize(l->start, pl);
   302 	hash = nodeof(l);
   307 	hash = nodeof(l, &flag);
   303 	if (!path || !hash) {
   308 	if (!path || !hash) {
   304 		goto done;
   309 		goto done;
   305 	}
   310 	}
   306 	consumed = pl + 41;
   311 	flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
   307 	flags = PyBytes_FromStringAndSize(l->start + consumed,
       
   308 					   l->len - consumed - 1);
       
   309 	if (!flags) {
   312 	if (!flags) {
   310 		goto done;
   313 		goto done;
   311 	}
   314 	}
   312 	ret = PyTuple_Pack(3, path, hash, flags);
   315 	ret = PyTuple_Pack(3, path, hash, flags);
   313 done:
   316 done:
   566 	}
   569 	}
   567 
   570 
   568 	pyhash = PyTuple_GetItem(value, 0);
   571 	pyhash = PyTuple_GetItem(value, 0);
   569 	if (!PyBytes_Check(pyhash)) {
   572 	if (!PyBytes_Check(pyhash)) {
   570 		PyErr_Format(PyExc_TypeError,
   573 		PyErr_Format(PyExc_TypeError,
   571 			     "node must be a 20-byte string");
   574 			     "node must be a 20 or 32 bytes string");
   572 		return -1;
   575 		return -1;
   573 	}
   576 	}
   574 	hlen = PyBytes_Size(pyhash);
   577 	hlen = PyBytes_Size(pyhash);
   575 	/* Some parts of the codebase try and set 21 or 22
   578 	if (hlen != 20 && hlen != 32) {
   576 	 * byte "hash" values in order to perturb things for
       
   577 	 * status. We have to preserve at least the 21st
       
   578 	 * byte. Sigh. If there's a 22nd byte, we drop it on
       
   579 	 * the floor, which works fine.
       
   580 	 */
       
   581 	if (hlen != 20 && hlen != 21 && hlen != 22) {
       
   582 		PyErr_Format(PyExc_TypeError,
   579 		PyErr_Format(PyExc_TypeError,
   583 			     "node must be a 20-byte string");
   580 			     "node must be a 20 or 32 bytes string");
   584 		return -1;
   581 		return -1;
   585 	}
   582 	}
   586 	hash = PyBytes_AsString(pyhash);
   583 	hash = PyBytes_AsString(pyhash);
   587 
   584 
   588 	pyflags = PyTuple_GetItem(value, 1);
   585 	pyflags = PyTuple_GetItem(value, 1);
   589 	if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
   586 	if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
   590 		PyErr_Format(PyExc_TypeError,
   587 		PyErr_Format(PyExc_TypeError,
   591 			     "flags must a 0 or 1 byte string");
   588 			     "flags must a 0 or 1 bytes string");
   592 		return -1;
   589 		return -1;
   593 	}
   590 	}
   594 	if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
   591 	if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
   595 		return -1;
   592 		return -1;
   596 	}
   593 	}
       
   594 	if (flen == 1) {
       
   595 		switch (*flags) {
       
   596 		case 'l':
       
   597 		case 't':
       
   598 		case 'x':
       
   599 			break;
       
   600 		default:
       
   601 			PyErr_Format(PyExc_TypeError, "invalid manifest flag");
       
   602 			return -1;
       
   603 		}
       
   604 	}
   597 	/* one null byte and one newline */
   605 	/* one null byte and one newline */
   598 	dlen = plen + 41 + flen + 1;
   606 	dlen = plen + hlen * 2 + 1 + flen + 1;
   599 	dest = malloc(dlen);
   607 	dest = malloc(dlen);
   600 	if (!dest) {
   608 	if (!dest) {
   601 		PyErr_NoMemory();
   609 		PyErr_NoMemory();
   602 		return -1;
   610 		return -1;
   603 	}
   611 	}
   604 	memcpy(dest, path, plen + 1);
   612 	memcpy(dest, path, plen + 1);
   605 	for (i = 0; i < 20; i++) {
   613 	for (i = 0; i < hlen; i++) {
   606 		/* Cast to unsigned, so it will not get sign-extended when promoted
   614 		/* Cast to unsigned, so it will not get sign-extended when promoted
   607 		 * to int (as is done when passing to a variadic function)
   615 		 * to int (as is done when passing to a variadic function)
   608 		 */
   616 		 */
   609 		sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
   617 		sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
   610 	}
   618 	}
   611 	memcpy(dest + plen + 41, flags, flen);
   619 	memcpy(dest + plen + 2 * hlen + 1, flags, flen);
   612 	dest[plen + 41 + flen] = '\n';
   620 	dest[plen + 2 * hlen + 1 + flen] = '\n';
   613 	new.start = dest;
   621 	new.start = dest;
   614 	new.len = dlen;
   622 	new.len = dlen;
   615 	new.hash_suffix = '\0';
   623 	new.hash_suffix = '\0';
   616 	if (hlen > 20) {
   624 	if (hlen > 20) {
   617 		new.hash_suffix = hash[20];
   625 		new.hash_suffix = hash[20];