equal
deleted
inserted
replaced
26 } line; |
26 } line; |
27 |
27 |
28 typedef struct { |
28 typedef struct { |
29 PyObject_HEAD |
29 PyObject_HEAD |
30 PyObject *pydata; |
30 PyObject *pydata; |
|
31 Py_ssize_t nodelen; |
31 line *lines; |
32 line *lines; |
32 int numlines; /* number of line entries */ |
33 int numlines; /* number of line entries */ |
33 int livelines; /* number of non-deleted lines */ |
34 int livelines; /* number of non-deleted lines */ |
34 int maxlines; /* allocated number of lines */ |
35 int maxlines; /* allocated number of lines */ |
35 bool dirty; |
36 bool dirty; |
47 const char *end = memchr(l->start, '\0', l->len); |
48 const char *end = memchr(l->start, '\0', l->len); |
48 return (end) ? (Py_ssize_t)(end - l->start) : l->len; |
49 return (end) ? (Py_ssize_t)(end - l->start) : l->len; |
49 } |
50 } |
50 |
51 |
51 /* get the node value of a single line */ |
52 /* get the node value of a single line */ |
52 static PyObject *nodeof(line *l, char *flag) |
53 static PyObject *nodeof(Py_ssize_t nodelen, line *l, char *flag) |
53 { |
54 { |
54 char *s = l->start; |
55 char *s = l->start; |
55 Py_ssize_t llen = pathlen(l); |
56 Py_ssize_t llen = pathlen(l); |
56 Py_ssize_t hlen = l->len - llen - 2; |
57 Py_ssize_t hlen = l->len - llen - 2; |
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 } |
71 default: |
71 default: |
72 *flag = '\0'; |
72 *flag = '\0'; |
73 break; |
73 break; |
74 } |
74 } |
75 |
75 |
76 switch (hlen) { |
76 if (hlen != 2 * nodelen) { |
77 case 40: /* sha1 */ |
|
78 hlen_raw = 20; |
|
79 break; |
|
80 case 64: /* new hash */ |
|
81 hlen_raw = 32; |
|
82 break; |
|
83 default: |
|
84 PyErr_SetString(PyExc_ValueError, "invalid node length in manifest"); |
77 PyErr_SetString(PyExc_ValueError, "invalid node length in manifest"); |
85 return NULL; |
78 return NULL; |
86 } |
79 } |
87 hash = unhexlify(s + llen + 1, hlen_raw * 2); |
80 hash = unhexlify(s + llen + 1, nodelen * 2); |
88 if (!hash) { |
81 if (!hash) { |
89 return NULL; |
82 return NULL; |
90 } |
83 } |
91 if (l->hash_suffix != '\0') { |
84 if (l->hash_suffix != '\0') { |
92 char newhash[33]; |
85 char newhash[33]; |
93 memcpy(newhash, PyBytes_AsString(hash), hlen_raw); |
86 memcpy(newhash, PyBytes_AsString(hash), nodelen); |
94 Py_DECREF(hash); |
87 Py_DECREF(hash); |
95 newhash[hlen_raw] = l->hash_suffix; |
88 newhash[nodelen] = l->hash_suffix; |
96 hash = PyBytes_FromStringAndSize(newhash, hlen_raw+1); |
89 hash = PyBytes_FromStringAndSize(newhash, nodelen + 1); |
97 } |
90 } |
98 return hash; |
91 return hash; |
99 } |
92 } |
100 |
93 |
101 /* get the node hash and flags of a line as a tuple */ |
94 /* get the node hash and flags of a line as a tuple */ |
102 static PyObject *hashflags(line *l) |
95 static PyObject *hashflags(Py_ssize_t nodelen, line *l) |
103 { |
96 { |
104 char flag; |
97 char flag; |
105 PyObject *hash = nodeof(l, &flag); |
98 PyObject *hash = nodeof(nodelen, l, &flag); |
106 PyObject *flags; |
99 PyObject *flags; |
107 PyObject *tup; |
100 PyObject *tup; |
108 |
101 |
109 if (!hash) |
102 if (!hash) |
110 return NULL; |
103 return NULL; |
188 } |
181 } |
189 |
182 |
190 static int lazymanifest_init(lazymanifest *self, PyObject *args) |
183 static int lazymanifest_init(lazymanifest *self, PyObject *args) |
191 { |
184 { |
192 char *data; |
185 char *data; |
193 Py_ssize_t len; |
186 Py_ssize_t nodelen, len; |
194 int err, ret; |
187 int err, ret; |
195 PyObject *pydata; |
188 PyObject *pydata; |
196 |
189 |
197 lazymanifest_init_early(self); |
190 lazymanifest_init_early(self); |
198 if (!PyArg_ParseTuple(args, "S", &pydata)) { |
191 if (!PyArg_ParseTuple(args, "nS", &nodelen, &pydata)) { |
199 return -1; |
192 return -1; |
200 } |
193 } |
|
194 if (nodelen != 20 && nodelen != 32) { |
|
195 /* See fixed buffer in nodeof */ |
|
196 PyErr_Format(PyExc_ValueError, "Unsupported node length"); |
|
197 return -1; |
|
198 } |
|
199 self->nodelen = nodelen; |
|
200 self->dirty = false; |
|
201 |
201 err = PyBytes_AsStringAndSize(pydata, &data, &len); |
202 err = PyBytes_AsStringAndSize(pydata, &data, &len); |
202 |
|
203 self->dirty = false; |
|
204 if (err == -1) |
203 if (err == -1) |
205 return -1; |
204 return -1; |
206 self->pydata = pydata; |
205 self->pydata = pydata; |
207 Py_INCREF(self->pydata); |
206 Py_INCREF(self->pydata); |
208 Py_BEGIN_ALLOW_THREADS |
207 Py_BEGIN_ALLOW_THREADS |
289 return self->m->lines + self->pos; |
288 return self->m->lines + self->pos; |
290 } |
289 } |
291 |
290 |
292 static PyObject *lmiter_iterentriesnext(PyObject *o) |
291 static PyObject *lmiter_iterentriesnext(PyObject *o) |
293 { |
292 { |
|
293 lmIter *self = (lmIter *)o; |
294 Py_ssize_t pl; |
294 Py_ssize_t pl; |
295 line *l; |
295 line *l; |
296 char flag; |
296 char flag; |
297 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL; |
297 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL; |
298 l = lmiter_nextline((lmIter *)o); |
298 l = lmiter_nextline(self); |
299 if (!l) { |
299 if (!l) { |
300 goto done; |
300 goto done; |
301 } |
301 } |
302 pl = pathlen(l); |
302 pl = pathlen(l); |
303 path = PyBytes_FromStringAndSize(l->start, pl); |
303 path = PyBytes_FromStringAndSize(l->start, pl); |
304 hash = nodeof(l, &flag); |
304 hash = nodeof(self->m->nodelen, l, &flag); |
305 if (!path || !hash) { |
305 if (!path || !hash) { |
306 goto done; |
306 goto done; |
307 } |
307 } |
308 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0); |
308 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0); |
309 if (!flags) { |
309 if (!flags) { |
469 &linecmp); |
469 &linecmp); |
470 if (!hit || hit->deleted) { |
470 if (!hit || hit->deleted) { |
471 PyErr_Format(PyExc_KeyError, "No such manifest entry."); |
471 PyErr_Format(PyExc_KeyError, "No such manifest entry."); |
472 return NULL; |
472 return NULL; |
473 } |
473 } |
474 return hashflags(hit); |
474 return hashflags(self->nodelen, hit); |
475 } |
475 } |
476 |
476 |
477 static int lazymanifest_delitem(lazymanifest *self, PyObject *key) |
477 static int lazymanifest_delitem(lazymanifest *self, PyObject *key) |
478 { |
478 { |
479 line needle; |
479 line needle; |
566 } |
566 } |
567 |
567 |
568 pyhash = PyTuple_GetItem(value, 0); |
568 pyhash = PyTuple_GetItem(value, 0); |
569 if (!PyBytes_Check(pyhash)) { |
569 if (!PyBytes_Check(pyhash)) { |
570 PyErr_Format(PyExc_TypeError, |
570 PyErr_Format(PyExc_TypeError, |
571 "node must be a 20 or 32 bytes string"); |
571 "node must be a %zi bytes string", self->nodelen); |
572 return -1; |
572 return -1; |
573 } |
573 } |
574 hlen = PyBytes_Size(pyhash); |
574 hlen = PyBytes_Size(pyhash); |
575 if (hlen != 20 && hlen != 32) { |
575 if (hlen != self->nodelen) { |
576 PyErr_Format(PyExc_TypeError, |
576 PyErr_Format(PyExc_TypeError, |
577 "node must be a 20 or 32 bytes string"); |
577 "node must be a %zi bytes string", self->nodelen); |
578 return -1; |
578 return -1; |
579 } |
579 } |
580 hash = PyBytes_AsString(pyhash); |
580 hash = PyBytes_AsString(pyhash); |
581 |
581 |
582 pyflags = PyTuple_GetItem(value, 1); |
582 pyflags = PyTuple_GetItem(value, 1); |
737 copy = PyObject_New(lazymanifest, &lazymanifestType); |
737 copy = PyObject_New(lazymanifest, &lazymanifestType); |
738 if (!copy) { |
738 if (!copy) { |
739 goto nomem; |
739 goto nomem; |
740 } |
740 } |
741 lazymanifest_init_early(copy); |
741 lazymanifest_init_early(copy); |
|
742 copy->nodelen = self->nodelen; |
742 copy->numlines = self->numlines; |
743 copy->numlines = self->numlines; |
743 copy->livelines = self->livelines; |
744 copy->livelines = self->livelines; |
744 copy->dirty = false; |
745 copy->dirty = false; |
745 copy->lines = malloc(self->maxlines *sizeof(line)); |
746 copy->lines = malloc(self->maxlines *sizeof(line)); |
746 if (!copy->lines) { |
747 if (!copy->lines) { |
775 copy = PyObject_New(lazymanifest, &lazymanifestType); |
776 copy = PyObject_New(lazymanifest, &lazymanifestType); |
776 if (!copy) { |
777 if (!copy) { |
777 goto nomem; |
778 goto nomem; |
778 } |
779 } |
779 lazymanifest_init_early(copy); |
780 lazymanifest_init_early(copy); |
|
781 copy->nodelen = self->nodelen; |
780 copy->dirty = true; |
782 copy->dirty = true; |
781 copy->lines = malloc(self->maxlines * sizeof(line)); |
783 copy->lines = malloc(self->maxlines * sizeof(line)); |
782 if (!copy->lines) { |
784 if (!copy->lines) { |
783 goto nomem; |
785 goto nomem; |
784 } |
786 } |
870 PyBytes_FromString(left->start) : |
872 PyBytes_FromString(left->start) : |
871 PyBytes_FromString(right->start); |
873 PyBytes_FromString(right->start); |
872 if (!key) |
874 if (!key) |
873 goto nomem; |
875 goto nomem; |
874 if (result < 0) { |
876 if (result < 0) { |
875 PyObject *l = hashflags(left); |
877 PyObject *l = hashflags(self->nodelen, left); |
876 if (!l) { |
878 if (!l) { |
877 goto nomem; |
879 goto nomem; |
878 } |
880 } |
879 outer = PyTuple_Pack(2, l, emptyTup); |
881 outer = PyTuple_Pack(2, l, emptyTup); |
880 Py_DECREF(l); |
882 Py_DECREF(l); |
883 } |
885 } |
884 PyDict_SetItem(ret, key, outer); |
886 PyDict_SetItem(ret, key, outer); |
885 Py_DECREF(outer); |
887 Py_DECREF(outer); |
886 sneedle++; |
888 sneedle++; |
887 } else if (result > 0) { |
889 } else if (result > 0) { |
888 PyObject *r = hashflags(right); |
890 PyObject *r = hashflags(self->nodelen, right); |
889 if (!r) { |
891 if (!r) { |
890 goto nomem; |
892 goto nomem; |
891 } |
893 } |
892 outer = PyTuple_Pack(2, emptyTup, r); |
894 outer = PyTuple_Pack(2, emptyTup, r); |
893 Py_DECREF(r); |
895 Py_DECREF(r); |
900 } else { |
902 } else { |
901 /* file exists in both manifests */ |
903 /* file exists in both manifests */ |
902 if (left->len != right->len |
904 if (left->len != right->len |
903 || memcmp(left->start, right->start, left->len) |
905 || memcmp(left->start, right->start, left->len) |
904 || left->hash_suffix != right->hash_suffix) { |
906 || left->hash_suffix != right->hash_suffix) { |
905 PyObject *l = hashflags(left); |
907 PyObject *l = hashflags(self->nodelen, left); |
906 PyObject *r; |
908 PyObject *r; |
907 if (!l) { |
909 if (!l) { |
908 goto nomem; |
910 goto nomem; |
909 } |
911 } |
910 r = hashflags(right); |
912 r = hashflags(self->nodelen, right); |
911 if (!r) { |
913 if (!r) { |
912 Py_DECREF(l); |
914 Py_DECREF(l); |
913 goto nomem; |
915 goto nomem; |
914 } |
916 } |
915 outer = PyTuple_Pack(2, l, r); |
917 outer = PyTuple_Pack(2, l, r); |