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]; |