##// END OF EJS Templates
lazymanifest: avoid reading uninitialized memory...
Jun Wu -
r35828:113a30b8 stable
parent child Browse files
Show More
@@ -1,941 +1,941
1 /*
1 /*
2 * manifest.c - manifest type that does on-demand parsing.
2 * manifest.c - manifest type that does on-demand parsing.
3 *
3 *
4 * Copyright 2015, Google Inc.
4 * Copyright 2015, Google Inc.
5 *
5 *
6 * This software may be used and distributed according to the terms of
6 * This software may be used and distributed according to the terms of
7 * the GNU General Public License, incorporated herein by reference.
7 * the GNU General Public License, incorporated herein by reference.
8 */
8 */
9 #include <Python.h>
9 #include <Python.h>
10
10
11 #include <assert.h>
11 #include <assert.h>
12 #include <stdlib.h>
12 #include <stdlib.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "charencode.h"
15 #include "charencode.h"
16 #include "util.h"
16 #include "util.h"
17
17
18 #define DEFAULT_LINES 100000
18 #define DEFAULT_LINES 100000
19
19
20 typedef struct {
20 typedef struct {
21 char *start;
21 char *start;
22 Py_ssize_t len; /* length of line including terminal newline */
22 Py_ssize_t len; /* length of line including terminal newline */
23 char hash_suffix;
23 char hash_suffix;
24 bool from_malloc;
24 bool from_malloc;
25 bool deleted;
25 bool deleted;
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 line *lines;
31 line *lines;
32 int numlines; /* number of line entries */
32 int numlines; /* number of line entries */
33 int livelines; /* number of non-deleted lines */
33 int livelines; /* number of non-deleted lines */
34 int maxlines; /* allocated number of lines */
34 int maxlines; /* allocated number of lines */
35 bool dirty;
35 bool dirty;
36 } lazymanifest;
36 } lazymanifest;
37
37
38 #define MANIFEST_OOM -1
38 #define MANIFEST_OOM -1
39 #define MANIFEST_NOT_SORTED -2
39 #define MANIFEST_NOT_SORTED -2
40 #define MANIFEST_MALFORMED -3
40 #define MANIFEST_MALFORMED -3
41
41
42 /* get the length of the path for a line */
42 /* get the length of the path for a line */
43 static size_t pathlen(line *l)
43 static size_t pathlen(line *l)
44 {
44 {
45 return strlen(l->start);
45 return strlen(l->start);
46 }
46 }
47
47
48 /* get the node value of a single line */
48 /* get the node value of a single line */
49 static PyObject *nodeof(line *l)
49 static PyObject *nodeof(line *l)
50 {
50 {
51 char *s = l->start;
51 char *s = l->start;
52 ssize_t llen = pathlen(l);
52 ssize_t llen = pathlen(l);
53 PyObject *hash = unhexlify(s + llen + 1, 40);
53 PyObject *hash = unhexlify(s + llen + 1, 40);
54 if (!hash) {
54 if (!hash) {
55 return NULL;
55 return NULL;
56 }
56 }
57 if (l->hash_suffix != '\0') {
57 if (l->hash_suffix != '\0') {
58 char newhash[21];
58 char newhash[21];
59 memcpy(newhash, PyBytes_AsString(hash), 20);
59 memcpy(newhash, PyBytes_AsString(hash), 20);
60 Py_DECREF(hash);
60 Py_DECREF(hash);
61 newhash[20] = l->hash_suffix;
61 newhash[20] = l->hash_suffix;
62 hash = PyBytes_FromStringAndSize(newhash, 21);
62 hash = PyBytes_FromStringAndSize(newhash, 21);
63 }
63 }
64 return hash;
64 return hash;
65 }
65 }
66
66
67 /* get the node hash and flags of a line as a tuple */
67 /* get the node hash and flags of a line as a tuple */
68 static PyObject *hashflags(line *l)
68 static PyObject *hashflags(line *l)
69 {
69 {
70 char *s = l->start;
70 char *s = l->start;
71 size_t plen = pathlen(l);
71 size_t plen = pathlen(l);
72 PyObject *hash = nodeof(l);
72 PyObject *hash = nodeof(l);
73
73
74 /* 40 for hash, 1 for null byte, 1 for newline */
74 /* 40 for hash, 1 for null byte, 1 for newline */
75 size_t hplen = plen + 42;
75 size_t hplen = plen + 42;
76 Py_ssize_t flen = l->len - hplen;
76 Py_ssize_t flen = l->len - hplen;
77 PyObject *flags;
77 PyObject *flags;
78 PyObject *tup;
78 PyObject *tup;
79
79
80 if (!hash)
80 if (!hash)
81 return NULL;
81 return NULL;
82 flags = PyBytes_FromStringAndSize(s + hplen - 1, flen);
82 flags = PyBytes_FromStringAndSize(s + hplen - 1, flen);
83 if (!flags) {
83 if (!flags) {
84 Py_DECREF(hash);
84 Py_DECREF(hash);
85 return NULL;
85 return NULL;
86 }
86 }
87 tup = PyTuple_Pack(2, hash, flags);
87 tup = PyTuple_Pack(2, hash, flags);
88 Py_DECREF(flags);
88 Py_DECREF(flags);
89 Py_DECREF(hash);
89 Py_DECREF(hash);
90 return tup;
90 return tup;
91 }
91 }
92
92
93 /* if we're about to run out of space in the line index, add more */
93 /* if we're about to run out of space in the line index, add more */
94 static bool realloc_if_full(lazymanifest *self)
94 static bool realloc_if_full(lazymanifest *self)
95 {
95 {
96 if (self->numlines == self->maxlines) {
96 if (self->numlines == self->maxlines) {
97 self->maxlines *= 2;
97 self->maxlines *= 2;
98 self->lines = realloc(self->lines, self->maxlines * sizeof(line));
98 self->lines = realloc(self->lines, self->maxlines * sizeof(line));
99 }
99 }
100 return !!self->lines;
100 return !!self->lines;
101 }
101 }
102
102
103 /*
103 /*
104 * Find the line boundaries in the manifest that 'data' points to and store
104 * Find the line boundaries in the manifest that 'data' points to and store
105 * information about each line in 'self'.
105 * information about each line in 'self'.
106 */
106 */
107 static int find_lines(lazymanifest *self, char *data, Py_ssize_t len)
107 static int find_lines(lazymanifest *self, char *data, Py_ssize_t len)
108 {
108 {
109 char *prev = NULL;
109 char *prev = NULL;
110 while (len > 0) {
110 while (len > 0) {
111 line *l;
111 line *l;
112 char *next = memchr(data, '\n', len);
112 char *next = memchr(data, '\n', len);
113 if (!next) {
113 if (!next) {
114 return MANIFEST_MALFORMED;
114 return MANIFEST_MALFORMED;
115 }
115 }
116 next++; /* advance past newline */
116 next++; /* advance past newline */
117 if (!realloc_if_full(self)) {
117 if (!realloc_if_full(self)) {
118 return MANIFEST_OOM; /* no memory */
118 return MANIFEST_OOM; /* no memory */
119 }
119 }
120 if (prev && strcmp(prev, data) > -1) {
120 if (prev && strcmp(prev, data) > -1) {
121 /* This data isn't sorted, so we have to abort. */
121 /* This data isn't sorted, so we have to abort. */
122 return MANIFEST_NOT_SORTED;
122 return MANIFEST_NOT_SORTED;
123 }
123 }
124 l = self->lines + ((self->numlines)++);
124 l = self->lines + ((self->numlines)++);
125 l->start = data;
125 l->start = data;
126 l->len = next - data;
126 l->len = next - data;
127 l->hash_suffix = '\0';
127 l->hash_suffix = '\0';
128 l->from_malloc = false;
128 l->from_malloc = false;
129 l->deleted = false;
129 l->deleted = false;
130 len = len - l->len;
130 len = len - l->len;
131 prev = data;
131 prev = data;
132 data = next;
132 data = next;
133 }
133 }
134 self->livelines = self->numlines;
134 self->livelines = self->numlines;
135 return 0;
135 return 0;
136 }
136 }
137
137
138 static int lazymanifest_init(lazymanifest *self, PyObject *args)
138 static int lazymanifest_init(lazymanifest *self, PyObject *args)
139 {
139 {
140 char *data;
140 char *data;
141 Py_ssize_t len;
141 Py_ssize_t len;
142 int err, ret;
142 int err, ret;
143 PyObject *pydata;
143 PyObject *pydata;
144 if (!PyArg_ParseTuple(args, "S", &pydata)) {
144 if (!PyArg_ParseTuple(args, "S", &pydata)) {
145 return -1;
145 return -1;
146 }
146 }
147 err = PyBytes_AsStringAndSize(pydata, &data, &len);
147 err = PyBytes_AsStringAndSize(pydata, &data, &len);
148
148
149 self->dirty = false;
149 self->dirty = false;
150 if (err == -1)
150 if (err == -1)
151 return -1;
151 return -1;
152 self->pydata = pydata;
152 self->pydata = pydata;
153 Py_INCREF(self->pydata);
153 Py_INCREF(self->pydata);
154 Py_BEGIN_ALLOW_THREADS
154 Py_BEGIN_ALLOW_THREADS
155 self->lines = malloc(DEFAULT_LINES * sizeof(line));
155 self->lines = malloc(DEFAULT_LINES * sizeof(line));
156 self->maxlines = DEFAULT_LINES;
156 self->maxlines = DEFAULT_LINES;
157 self->numlines = 0;
157 self->numlines = 0;
158 if (!self->lines)
158 if (!self->lines)
159 ret = MANIFEST_OOM;
159 ret = MANIFEST_OOM;
160 else
160 else
161 ret = find_lines(self, data, len);
161 ret = find_lines(self, data, len);
162 Py_END_ALLOW_THREADS
162 Py_END_ALLOW_THREADS
163 switch (ret) {
163 switch (ret) {
164 case 0:
164 case 0:
165 break;
165 break;
166 case MANIFEST_OOM:
166 case MANIFEST_OOM:
167 PyErr_NoMemory();
167 PyErr_NoMemory();
168 break;
168 break;
169 case MANIFEST_NOT_SORTED:
169 case MANIFEST_NOT_SORTED:
170 PyErr_Format(PyExc_ValueError,
170 PyErr_Format(PyExc_ValueError,
171 "Manifest lines not in sorted order.");
171 "Manifest lines not in sorted order.");
172 break;
172 break;
173 case MANIFEST_MALFORMED:
173 case MANIFEST_MALFORMED:
174 PyErr_Format(PyExc_ValueError,
174 PyErr_Format(PyExc_ValueError,
175 "Manifest did not end in a newline.");
175 "Manifest did not end in a newline.");
176 break;
176 break;
177 default:
177 default:
178 PyErr_Format(PyExc_ValueError,
178 PyErr_Format(PyExc_ValueError,
179 "Unknown problem parsing manifest.");
179 "Unknown problem parsing manifest.");
180 }
180 }
181 return ret == 0 ? 0 : -1;
181 return ret == 0 ? 0 : -1;
182 }
182 }
183
183
184 static void lazymanifest_dealloc(lazymanifest *self)
184 static void lazymanifest_dealloc(lazymanifest *self)
185 {
185 {
186 /* free any extra lines we had to allocate */
186 /* free any extra lines we had to allocate */
187 int i;
187 int i;
188 for (i = 0; i < self->numlines; i++) {
188 for (i = 0; i < self->numlines; i++) {
189 if (self->lines[i].from_malloc) {
189 if (self->lines[i].from_malloc) {
190 free(self->lines[i].start);
190 free(self->lines[i].start);
191 }
191 }
192 }
192 }
193 if (self->lines) {
193 if (self->lines) {
194 free(self->lines);
194 free(self->lines);
195 self->lines = NULL;
195 self->lines = NULL;
196 }
196 }
197 if (self->pydata) {
197 if (self->pydata) {
198 Py_DECREF(self->pydata);
198 Py_DECREF(self->pydata);
199 self->pydata = NULL;
199 self->pydata = NULL;
200 }
200 }
201 PyObject_Del(self);
201 PyObject_Del(self);
202 }
202 }
203
203
204 /* iteration support */
204 /* iteration support */
205
205
206 typedef struct {
206 typedef struct {
207 PyObject_HEAD lazymanifest *m;
207 PyObject_HEAD lazymanifest *m;
208 Py_ssize_t pos;
208 Py_ssize_t pos;
209 } lmIter;
209 } lmIter;
210
210
211 static void lmiter_dealloc(PyObject *o)
211 static void lmiter_dealloc(PyObject *o)
212 {
212 {
213 lmIter *self = (lmIter *)o;
213 lmIter *self = (lmIter *)o;
214 Py_DECREF(self->m);
214 Py_DECREF(self->m);
215 PyObject_Del(self);
215 PyObject_Del(self);
216 }
216 }
217
217
218 static line *lmiter_nextline(lmIter *self)
218 static line *lmiter_nextline(lmIter *self)
219 {
219 {
220 do {
220 do {
221 self->pos++;
221 self->pos++;
222 if (self->pos >= self->m->numlines) {
222 if (self->pos >= self->m->numlines) {
223 return NULL;
223 return NULL;
224 }
224 }
225 /* skip over deleted manifest entries */
225 /* skip over deleted manifest entries */
226 } while (self->m->lines[self->pos].deleted);
226 } while (self->m->lines[self->pos].deleted);
227 return self->m->lines + self->pos;
227 return self->m->lines + self->pos;
228 }
228 }
229
229
230 static PyObject *lmiter_iterentriesnext(PyObject *o)
230 static PyObject *lmiter_iterentriesnext(PyObject *o)
231 {
231 {
232 size_t pl;
232 size_t pl;
233 line *l;
233 line *l;
234 Py_ssize_t consumed;
234 Py_ssize_t consumed;
235 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
235 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
236 l = lmiter_nextline((lmIter *)o);
236 l = lmiter_nextline((lmIter *)o);
237 if (!l) {
237 if (!l) {
238 goto done;
238 goto done;
239 }
239 }
240 pl = pathlen(l);
240 pl = pathlen(l);
241 path = PyBytes_FromStringAndSize(l->start, pl);
241 path = PyBytes_FromStringAndSize(l->start, pl);
242 hash = nodeof(l);
242 hash = nodeof(l);
243 consumed = pl + 41;
243 consumed = pl + 41;
244 flags = PyBytes_FromStringAndSize(l->start + consumed,
244 flags = PyBytes_FromStringAndSize(l->start + consumed,
245 l->len - consumed - 1);
245 l->len - consumed - 1);
246 if (!path || !hash || !flags) {
246 if (!path || !hash || !flags) {
247 goto done;
247 goto done;
248 }
248 }
249 ret = PyTuple_Pack(3, path, hash, flags);
249 ret = PyTuple_Pack(3, path, hash, flags);
250 done:
250 done:
251 Py_XDECREF(path);
251 Py_XDECREF(path);
252 Py_XDECREF(hash);
252 Py_XDECREF(hash);
253 Py_XDECREF(flags);
253 Py_XDECREF(flags);
254 return ret;
254 return ret;
255 }
255 }
256
256
257 #ifdef IS_PY3K
257 #ifdef IS_PY3K
258 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
258 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
259 #else
259 #else
260 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
260 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
261 | Py_TPFLAGS_HAVE_ITER
261 | Py_TPFLAGS_HAVE_ITER
262 #endif
262 #endif
263
263
264 static PyTypeObject lazymanifestEntriesIterator = {
264 static PyTypeObject lazymanifestEntriesIterator = {
265 PyVarObject_HEAD_INIT(NULL, 0) /* header */
265 PyVarObject_HEAD_INIT(NULL, 0) /* header */
266 "parsers.lazymanifest.entriesiterator", /*tp_name */
266 "parsers.lazymanifest.entriesiterator", /*tp_name */
267 sizeof(lmIter), /*tp_basicsize */
267 sizeof(lmIter), /*tp_basicsize */
268 0, /*tp_itemsize */
268 0, /*tp_itemsize */
269 lmiter_dealloc, /*tp_dealloc */
269 lmiter_dealloc, /*tp_dealloc */
270 0, /*tp_print */
270 0, /*tp_print */
271 0, /*tp_getattr */
271 0, /*tp_getattr */
272 0, /*tp_setattr */
272 0, /*tp_setattr */
273 0, /*tp_compare */
273 0, /*tp_compare */
274 0, /*tp_repr */
274 0, /*tp_repr */
275 0, /*tp_as_number */
275 0, /*tp_as_number */
276 0, /*tp_as_sequence */
276 0, /*tp_as_sequence */
277 0, /*tp_as_mapping */
277 0, /*tp_as_mapping */
278 0, /*tp_hash */
278 0, /*tp_hash */
279 0, /*tp_call */
279 0, /*tp_call */
280 0, /*tp_str */
280 0, /*tp_str */
281 0, /*tp_getattro */
281 0, /*tp_getattro */
282 0, /*tp_setattro */
282 0, /*tp_setattro */
283 0, /*tp_as_buffer */
283 0, /*tp_as_buffer */
284 LAZYMANIFESTENTRIESITERATOR_TPFLAGS, /* tp_flags */
284 LAZYMANIFESTENTRIESITERATOR_TPFLAGS, /* tp_flags */
285 "Iterator for 3-tuples in a lazymanifest.", /* tp_doc */
285 "Iterator for 3-tuples in a lazymanifest.", /* tp_doc */
286 0, /* tp_traverse */
286 0, /* tp_traverse */
287 0, /* tp_clear */
287 0, /* tp_clear */
288 0, /* tp_richcompare */
288 0, /* tp_richcompare */
289 0, /* tp_weaklistoffset */
289 0, /* tp_weaklistoffset */
290 PyObject_SelfIter, /* tp_iter: __iter__() method */
290 PyObject_SelfIter, /* tp_iter: __iter__() method */
291 lmiter_iterentriesnext, /* tp_iternext: next() method */
291 lmiter_iterentriesnext, /* tp_iternext: next() method */
292 };
292 };
293
293
294 static PyObject *lmiter_iterkeysnext(PyObject *o)
294 static PyObject *lmiter_iterkeysnext(PyObject *o)
295 {
295 {
296 size_t pl;
296 size_t pl;
297 line *l = lmiter_nextline((lmIter *)o);
297 line *l = lmiter_nextline((lmIter *)o);
298 if (!l) {
298 if (!l) {
299 return NULL;
299 return NULL;
300 }
300 }
301 pl = pathlen(l);
301 pl = pathlen(l);
302 return PyBytes_FromStringAndSize(l->start, pl);
302 return PyBytes_FromStringAndSize(l->start, pl);
303 }
303 }
304
304
305 #ifdef IS_PY3K
305 #ifdef IS_PY3K
306 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
306 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
307 #else
307 #else
308 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
308 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
309 | Py_TPFLAGS_HAVE_ITER
309 | Py_TPFLAGS_HAVE_ITER
310 #endif
310 #endif
311
311
312 static PyTypeObject lazymanifestKeysIterator = {
312 static PyTypeObject lazymanifestKeysIterator = {
313 PyVarObject_HEAD_INIT(NULL, 0) /* header */
313 PyVarObject_HEAD_INIT(NULL, 0) /* header */
314 "parsers.lazymanifest.keysiterator", /*tp_name */
314 "parsers.lazymanifest.keysiterator", /*tp_name */
315 sizeof(lmIter), /*tp_basicsize */
315 sizeof(lmIter), /*tp_basicsize */
316 0, /*tp_itemsize */
316 0, /*tp_itemsize */
317 lmiter_dealloc, /*tp_dealloc */
317 lmiter_dealloc, /*tp_dealloc */
318 0, /*tp_print */
318 0, /*tp_print */
319 0, /*tp_getattr */
319 0, /*tp_getattr */
320 0, /*tp_setattr */
320 0, /*tp_setattr */
321 0, /*tp_compare */
321 0, /*tp_compare */
322 0, /*tp_repr */
322 0, /*tp_repr */
323 0, /*tp_as_number */
323 0, /*tp_as_number */
324 0, /*tp_as_sequence */
324 0, /*tp_as_sequence */
325 0, /*tp_as_mapping */
325 0, /*tp_as_mapping */
326 0, /*tp_hash */
326 0, /*tp_hash */
327 0, /*tp_call */
327 0, /*tp_call */
328 0, /*tp_str */
328 0, /*tp_str */
329 0, /*tp_getattro */
329 0, /*tp_getattro */
330 0, /*tp_setattro */
330 0, /*tp_setattro */
331 0, /*tp_as_buffer */
331 0, /*tp_as_buffer */
332 LAZYMANIFESTKEYSITERATOR_TPFLAGS, /* tp_flags */
332 LAZYMANIFESTKEYSITERATOR_TPFLAGS, /* tp_flags */
333 "Keys iterator for a lazymanifest.", /* tp_doc */
333 "Keys iterator for a lazymanifest.", /* tp_doc */
334 0, /* tp_traverse */
334 0, /* tp_traverse */
335 0, /* tp_clear */
335 0, /* tp_clear */
336 0, /* tp_richcompare */
336 0, /* tp_richcompare */
337 0, /* tp_weaklistoffset */
337 0, /* tp_weaklistoffset */
338 PyObject_SelfIter, /* tp_iter: __iter__() method */
338 PyObject_SelfIter, /* tp_iter: __iter__() method */
339 lmiter_iterkeysnext, /* tp_iternext: next() method */
339 lmiter_iterkeysnext, /* tp_iternext: next() method */
340 };
340 };
341
341
342 static lazymanifest *lazymanifest_copy(lazymanifest *self);
342 static lazymanifest *lazymanifest_copy(lazymanifest *self);
343
343
344 static PyObject *lazymanifest_getentriesiter(lazymanifest *self)
344 static PyObject *lazymanifest_getentriesiter(lazymanifest *self)
345 {
345 {
346 lmIter *i = NULL;
346 lmIter *i = NULL;
347 lazymanifest *t = lazymanifest_copy(self);
347 lazymanifest *t = lazymanifest_copy(self);
348 if (!t) {
348 if (!t) {
349 PyErr_NoMemory();
349 PyErr_NoMemory();
350 return NULL;
350 return NULL;
351 }
351 }
352 i = PyObject_New(lmIter, &lazymanifestEntriesIterator);
352 i = PyObject_New(lmIter, &lazymanifestEntriesIterator);
353 if (i) {
353 if (i) {
354 i->m = t;
354 i->m = t;
355 i->pos = -1;
355 i->pos = -1;
356 } else {
356 } else {
357 Py_DECREF(t);
357 Py_DECREF(t);
358 PyErr_NoMemory();
358 PyErr_NoMemory();
359 }
359 }
360 return (PyObject *)i;
360 return (PyObject *)i;
361 }
361 }
362
362
363 static PyObject *lazymanifest_getkeysiter(lazymanifest *self)
363 static PyObject *lazymanifest_getkeysiter(lazymanifest *self)
364 {
364 {
365 lmIter *i = NULL;
365 lmIter *i = NULL;
366 lazymanifest *t = lazymanifest_copy(self);
366 lazymanifest *t = lazymanifest_copy(self);
367 if (!t) {
367 if (!t) {
368 PyErr_NoMemory();
368 PyErr_NoMemory();
369 return NULL;
369 return NULL;
370 }
370 }
371 i = PyObject_New(lmIter, &lazymanifestKeysIterator);
371 i = PyObject_New(lmIter, &lazymanifestKeysIterator);
372 if (i) {
372 if (i) {
373 i->m = t;
373 i->m = t;
374 i->pos = -1;
374 i->pos = -1;
375 } else {
375 } else {
376 Py_DECREF(t);
376 Py_DECREF(t);
377 PyErr_NoMemory();
377 PyErr_NoMemory();
378 }
378 }
379 return (PyObject *)i;
379 return (PyObject *)i;
380 }
380 }
381
381
382 /* __getitem__ and __setitem__ support */
382 /* __getitem__ and __setitem__ support */
383
383
384 static Py_ssize_t lazymanifest_size(lazymanifest *self)
384 static Py_ssize_t lazymanifest_size(lazymanifest *self)
385 {
385 {
386 return self->livelines;
386 return self->livelines;
387 }
387 }
388
388
389 static int linecmp(const void *left, const void *right)
389 static int linecmp(const void *left, const void *right)
390 {
390 {
391 return strcmp(((const line *)left)->start,
391 return strcmp(((const line *)left)->start,
392 ((const line *)right)->start);
392 ((const line *)right)->start);
393 }
393 }
394
394
395 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
395 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
396 {
396 {
397 line needle;
397 line needle;
398 line *hit;
398 line *hit;
399 if (!PyBytes_Check(key)) {
399 if (!PyBytes_Check(key)) {
400 PyErr_Format(PyExc_TypeError,
400 PyErr_Format(PyExc_TypeError,
401 "getitem: manifest keys must be a string.");
401 "getitem: manifest keys must be a string.");
402 return NULL;
402 return NULL;
403 }
403 }
404 needle.start = PyBytes_AsString(key);
404 needle.start = PyBytes_AsString(key);
405 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
405 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
406 &linecmp);
406 &linecmp);
407 if (!hit || hit->deleted) {
407 if (!hit || hit->deleted) {
408 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
408 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
409 return NULL;
409 return NULL;
410 }
410 }
411 return hashflags(hit);
411 return hashflags(hit);
412 }
412 }
413
413
414 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
414 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
415 {
415 {
416 line needle;
416 line needle;
417 line *hit;
417 line *hit;
418 if (!PyBytes_Check(key)) {
418 if (!PyBytes_Check(key)) {
419 PyErr_Format(PyExc_TypeError,
419 PyErr_Format(PyExc_TypeError,
420 "delitem: manifest keys must be a string.");
420 "delitem: manifest keys must be a string.");
421 return -1;
421 return -1;
422 }
422 }
423 needle.start = PyBytes_AsString(key);
423 needle.start = PyBytes_AsString(key);
424 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
424 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
425 &linecmp);
425 &linecmp);
426 if (!hit || hit->deleted) {
426 if (!hit || hit->deleted) {
427 PyErr_Format(PyExc_KeyError,
427 PyErr_Format(PyExc_KeyError,
428 "Tried to delete nonexistent manifest entry.");
428 "Tried to delete nonexistent manifest entry.");
429 return -1;
429 return -1;
430 }
430 }
431 self->dirty = true;
431 self->dirty = true;
432 hit->deleted = true;
432 hit->deleted = true;
433 self->livelines--;
433 self->livelines--;
434 return 0;
434 return 0;
435 }
435 }
436
436
437 /* Do a binary search for the insertion point for new, creating the
437 /* Do a binary search for the insertion point for new, creating the
438 * new entry if needed. */
438 * new entry if needed. */
439 static int internalsetitem(lazymanifest *self, line *new)
439 static int internalsetitem(lazymanifest *self, line *new)
440 {
440 {
441 int start = 0, end = self->numlines;
441 int start = 0, end = self->numlines;
442 while (start < end) {
442 while (start < end) {
443 int pos = start + (end - start) / 2;
443 int pos = start + (end - start) / 2;
444 int c = linecmp(new, self->lines + pos);
444 int c = linecmp(new, self->lines + pos);
445 if (c < 0)
445 if (c < 0)
446 end = pos;
446 end = pos;
447 else if (c > 0)
447 else if (c > 0)
448 start = pos + 1;
448 start = pos + 1;
449 else {
449 else {
450 if (self->lines[pos].deleted)
450 if (self->lines[pos].deleted)
451 self->livelines++;
451 self->livelines++;
452 if (self->lines[pos].from_malloc)
452 if (self->lines[pos].from_malloc)
453 free(self->lines[pos].start);
453 free(self->lines[pos].start);
454 start = pos;
454 start = pos;
455 goto finish;
455 goto finish;
456 }
456 }
457 }
457 }
458 /* being here means we need to do an insert */
458 /* being here means we need to do an insert */
459 if (!realloc_if_full(self)) {
459 if (!realloc_if_full(self)) {
460 PyErr_NoMemory();
460 PyErr_NoMemory();
461 return -1;
461 return -1;
462 }
462 }
463 memmove(self->lines + start + 1, self->lines + start,
463 memmove(self->lines + start + 1, self->lines + start,
464 (self->numlines - start) * sizeof(line));
464 (self->numlines - start) * sizeof(line));
465 self->numlines++;
465 self->numlines++;
466 self->livelines++;
466 self->livelines++;
467 finish:
467 finish:
468 self->lines[start] = *new;
468 self->lines[start] = *new;
469 self->dirty = true;
469 self->dirty = true;
470 return 0;
470 return 0;
471 }
471 }
472
472
473 static int lazymanifest_setitem(
473 static int lazymanifest_setitem(
474 lazymanifest *self, PyObject *key, PyObject *value)
474 lazymanifest *self, PyObject *key, PyObject *value)
475 {
475 {
476 char *path;
476 char *path;
477 Py_ssize_t plen;
477 Py_ssize_t plen;
478 PyObject *pyhash;
478 PyObject *pyhash;
479 Py_ssize_t hlen;
479 Py_ssize_t hlen;
480 char *hash;
480 char *hash;
481 PyObject *pyflags;
481 PyObject *pyflags;
482 char *flags;
482 char *flags;
483 Py_ssize_t flen;
483 Py_ssize_t flen;
484 size_t dlen;
484 size_t dlen;
485 char *dest;
485 char *dest;
486 int i;
486 int i;
487 line new;
487 line new;
488 if (!PyBytes_Check(key)) {
488 if (!PyBytes_Check(key)) {
489 PyErr_Format(PyExc_TypeError,
489 PyErr_Format(PyExc_TypeError,
490 "setitem: manifest keys must be a string.");
490 "setitem: manifest keys must be a string.");
491 return -1;
491 return -1;
492 }
492 }
493 if (!value) {
493 if (!value) {
494 return lazymanifest_delitem(self, key);
494 return lazymanifest_delitem(self, key);
495 }
495 }
496 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
496 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
497 PyErr_Format(PyExc_TypeError,
497 PyErr_Format(PyExc_TypeError,
498 "Manifest values must be a tuple of (node, flags).");
498 "Manifest values must be a tuple of (node, flags).");
499 return -1;
499 return -1;
500 }
500 }
501 if (PyBytes_AsStringAndSize(key, &path, &plen) == -1) {
501 if (PyBytes_AsStringAndSize(key, &path, &plen) == -1) {
502 return -1;
502 return -1;
503 }
503 }
504
504
505 pyhash = PyTuple_GetItem(value, 0);
505 pyhash = PyTuple_GetItem(value, 0);
506 if (!PyBytes_Check(pyhash)) {
506 if (!PyBytes_Check(pyhash)) {
507 PyErr_Format(PyExc_TypeError,
507 PyErr_Format(PyExc_TypeError,
508 "node must be a 20-byte string");
508 "node must be a 20-byte string");
509 return -1;
509 return -1;
510 }
510 }
511 hlen = PyBytes_Size(pyhash);
511 hlen = PyBytes_Size(pyhash);
512 /* Some parts of the codebase try and set 21 or 22
512 /* Some parts of the codebase try and set 21 or 22
513 * byte "hash" values in order to perturb things for
513 * byte "hash" values in order to perturb things for
514 * status. We have to preserve at least the 21st
514 * status. We have to preserve at least the 21st
515 * byte. Sigh. If there's a 22nd byte, we drop it on
515 * byte. Sigh. If there's a 22nd byte, we drop it on
516 * the floor, which works fine.
516 * the floor, which works fine.
517 */
517 */
518 if (hlen != 20 && hlen != 21 && hlen != 22) {
518 if (hlen != 20 && hlen != 21 && hlen != 22) {
519 PyErr_Format(PyExc_TypeError,
519 PyErr_Format(PyExc_TypeError,
520 "node must be a 20-byte string");
520 "node must be a 20-byte string");
521 return -1;
521 return -1;
522 }
522 }
523 hash = PyBytes_AsString(pyhash);
523 hash = PyBytes_AsString(pyhash);
524
524
525 pyflags = PyTuple_GetItem(value, 1);
525 pyflags = PyTuple_GetItem(value, 1);
526 if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
526 if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
527 PyErr_Format(PyExc_TypeError,
527 PyErr_Format(PyExc_TypeError,
528 "flags must a 0 or 1 byte string");
528 "flags must a 0 or 1 byte string");
529 return -1;
529 return -1;
530 }
530 }
531 if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
531 if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
532 return -1;
532 return -1;
533 }
533 }
534 /* one null byte and one newline */
534 /* one null byte and one newline */
535 dlen = plen + 41 + flen + 1;
535 dlen = plen + 41 + flen + 1;
536 dest = malloc(dlen);
536 dest = malloc(dlen);
537 if (!dest) {
537 if (!dest) {
538 PyErr_NoMemory();
538 PyErr_NoMemory();
539 return -1;
539 return -1;
540 }
540 }
541 memcpy(dest, path, plen + 1);
541 memcpy(dest, path, plen + 1);
542 for (i = 0; i < 20; i++) {
542 for (i = 0; i < 20; i++) {
543 /* Cast to unsigned, so it will not get sign-extended when promoted
543 /* Cast to unsigned, so it will not get sign-extended when promoted
544 * to int (as is done when passing to a variadic function)
544 * to int (as is done when passing to a variadic function)
545 */
545 */
546 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
546 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
547 }
547 }
548 memcpy(dest + plen + 41, flags, flen);
548 memcpy(dest + plen + 41, flags, flen);
549 dest[plen + 41 + flen] = '\n';
549 dest[plen + 41 + flen] = '\n';
550 new.start = dest;
550 new.start = dest;
551 new.len = dlen;
551 new.len = dlen;
552 new.hash_suffix = '\0';
552 new.hash_suffix = '\0';
553 if (hlen > 20) {
553 if (hlen > 20) {
554 new.hash_suffix = hash[20];
554 new.hash_suffix = hash[20];
555 }
555 }
556 new.from_malloc = true; /* is `start` a pointer we allocated? */
556 new.from_malloc = true; /* is `start` a pointer we allocated? */
557 new.deleted = false; /* is this entry deleted? */
557 new.deleted = false; /* is this entry deleted? */
558 if (internalsetitem(self, &new)) {
558 if (internalsetitem(self, &new)) {
559 return -1;
559 return -1;
560 }
560 }
561 return 0;
561 return 0;
562 }
562 }
563
563
564 static PyMappingMethods lazymanifest_mapping_methods = {
564 static PyMappingMethods lazymanifest_mapping_methods = {
565 (lenfunc)lazymanifest_size, /* mp_length */
565 (lenfunc)lazymanifest_size, /* mp_length */
566 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
566 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
567 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
567 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
568 };
568 };
569
569
570 /* sequence methods (important or __contains__ builds an iterator) */
570 /* sequence methods (important or __contains__ builds an iterator) */
571
571
572 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
572 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
573 {
573 {
574 line needle;
574 line needle;
575 line *hit;
575 line *hit;
576 if (!PyBytes_Check(key)) {
576 if (!PyBytes_Check(key)) {
577 /* Our keys are always strings, so if the contains
577 /* Our keys are always strings, so if the contains
578 * check is for a non-string, just return false. */
578 * check is for a non-string, just return false. */
579 return 0;
579 return 0;
580 }
580 }
581 needle.start = PyBytes_AsString(key);
581 needle.start = PyBytes_AsString(key);
582 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
582 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
583 &linecmp);
583 &linecmp);
584 if (!hit || hit->deleted) {
584 if (!hit || hit->deleted) {
585 return 0;
585 return 0;
586 }
586 }
587 return 1;
587 return 1;
588 }
588 }
589
589
590 static PySequenceMethods lazymanifest_seq_meths = {
590 static PySequenceMethods lazymanifest_seq_meths = {
591 (lenfunc)lazymanifest_size, /* sq_length */
591 (lenfunc)lazymanifest_size, /* sq_length */
592 0, /* sq_concat */
592 0, /* sq_concat */
593 0, /* sq_repeat */
593 0, /* sq_repeat */
594 0, /* sq_item */
594 0, /* sq_item */
595 0, /* sq_slice */
595 0, /* sq_slice */
596 0, /* sq_ass_item */
596 0, /* sq_ass_item */
597 0, /* sq_ass_slice */
597 0, /* sq_ass_slice */
598 (objobjproc)lazymanifest_contains, /* sq_contains */
598 (objobjproc)lazymanifest_contains, /* sq_contains */
599 0, /* sq_inplace_concat */
599 0, /* sq_inplace_concat */
600 0, /* sq_inplace_repeat */
600 0, /* sq_inplace_repeat */
601 };
601 };
602
602
603
603
604 /* Other methods (copy, diff, etc) */
604 /* Other methods (copy, diff, etc) */
605 static PyTypeObject lazymanifestType;
605 static PyTypeObject lazymanifestType;
606
606
607 /* If the manifest has changes, build the new manifest text and reindex it. */
607 /* If the manifest has changes, build the new manifest text and reindex it. */
608 static int compact(lazymanifest *self)
608 static int compact(lazymanifest *self)
609 {
609 {
610 int i;
610 int i;
611 ssize_t need = 0;
611 ssize_t need = 0;
612 char *data;
612 char *data;
613 line *src, *dst;
613 line *src, *dst;
614 PyObject *pydata;
614 PyObject *pydata;
615 if (!self->dirty)
615 if (!self->dirty)
616 return 0;
616 return 0;
617 for (i = 0; i < self->numlines; i++) {
617 for (i = 0; i < self->numlines; i++) {
618 if (!self->lines[i].deleted) {
618 if (!self->lines[i].deleted) {
619 need += self->lines[i].len;
619 need += self->lines[i].len;
620 }
620 }
621 }
621 }
622 pydata = PyBytes_FromStringAndSize(NULL, need);
622 pydata = PyBytes_FromStringAndSize(NULL, need);
623 if (!pydata)
623 if (!pydata)
624 return -1;
624 return -1;
625 data = PyBytes_AsString(pydata);
625 data = PyBytes_AsString(pydata);
626 if (!data) {
626 if (!data) {
627 return -1;
627 return -1;
628 }
628 }
629 src = self->lines;
629 src = self->lines;
630 dst = self->lines;
630 dst = self->lines;
631 for (i = 0; i < self->numlines; i++, src++) {
631 for (i = 0; i < self->numlines; i++, src++) {
632 char *tofree = NULL;
632 char *tofree = NULL;
633 if (src->from_malloc) {
633 if (src->from_malloc) {
634 tofree = src->start;
634 tofree = src->start;
635 }
635 }
636 if (!src->deleted) {
636 if (!src->deleted) {
637 memcpy(data, src->start, src->len);
637 memcpy(data, src->start, src->len);
638 *dst = *src;
638 *dst = *src;
639 dst->start = data;
639 dst->start = data;
640 dst->from_malloc = false;
640 dst->from_malloc = false;
641 data += dst->len;
641 data += dst->len;
642 dst++;
642 dst++;
643 }
643 }
644 free(tofree);
644 free(tofree);
645 }
645 }
646 Py_DECREF(self->pydata);
646 Py_DECREF(self->pydata);
647 self->pydata = pydata;
647 self->pydata = pydata;
648 self->numlines = self->livelines;
648 self->numlines = self->livelines;
649 self->dirty = false;
649 self->dirty = false;
650 return 0;
650 return 0;
651 }
651 }
652
652
653 static PyObject *lazymanifest_text(lazymanifest *self)
653 static PyObject *lazymanifest_text(lazymanifest *self)
654 {
654 {
655 if (compact(self) != 0) {
655 if (compact(self) != 0) {
656 PyErr_NoMemory();
656 PyErr_NoMemory();
657 return NULL;
657 return NULL;
658 }
658 }
659 Py_INCREF(self->pydata);
659 Py_INCREF(self->pydata);
660 return self->pydata;
660 return self->pydata;
661 }
661 }
662
662
663 static lazymanifest *lazymanifest_copy(lazymanifest *self)
663 static lazymanifest *lazymanifest_copy(lazymanifest *self)
664 {
664 {
665 lazymanifest *copy = NULL;
665 lazymanifest *copy = NULL;
666 if (compact(self) != 0) {
666 if (compact(self) != 0) {
667 goto nomem;
667 goto nomem;
668 }
668 }
669 copy = PyObject_New(lazymanifest, &lazymanifestType);
669 copy = PyObject_New(lazymanifest, &lazymanifestType);
670 if (!copy) {
670 if (!copy) {
671 goto nomem;
671 goto nomem;
672 }
672 }
673 copy->numlines = self->numlines;
673 copy->numlines = self->numlines;
674 copy->livelines = self->livelines;
674 copy->livelines = self->livelines;
675 copy->dirty = false;
675 copy->dirty = false;
676 copy->lines = malloc(self->maxlines *sizeof(line));
676 copy->lines = malloc(self->maxlines *sizeof(line));
677 if (!copy->lines) {
677 if (!copy->lines) {
678 goto nomem;
678 goto nomem;
679 }
679 }
680 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
680 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
681 copy->maxlines = self->maxlines;
681 copy->maxlines = self->maxlines;
682 copy->pydata = self->pydata;
682 copy->pydata = self->pydata;
683 Py_INCREF(copy->pydata);
683 Py_INCREF(copy->pydata);
684 return copy;
684 return copy;
685 nomem:
685 nomem:
686 PyErr_NoMemory();
686 PyErr_NoMemory();
687 Py_XDECREF(copy);
687 Py_XDECREF(copy);
688 return NULL;
688 return NULL;
689 }
689 }
690
690
691 static lazymanifest *lazymanifest_filtercopy(
691 static lazymanifest *lazymanifest_filtercopy(
692 lazymanifest *self, PyObject *matchfn)
692 lazymanifest *self, PyObject *matchfn)
693 {
693 {
694 lazymanifest *copy = NULL;
694 lazymanifest *copy = NULL;
695 int i;
695 int i;
696 if (!PyCallable_Check(matchfn)) {
696 if (!PyCallable_Check(matchfn)) {
697 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
697 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
698 return NULL;
698 return NULL;
699 }
699 }
700 /* compact ourselves first to avoid double-frees later when we
700 /* compact ourselves first to avoid double-frees later when we
701 * compact tmp so that it doesn't have random pointers to our
701 * compact tmp so that it doesn't have random pointers to our
702 * underlying from_malloc-data (self->pydata is safe) */
702 * underlying from_malloc-data (self->pydata is safe) */
703 if (compact(self) != 0) {
703 if (compact(self) != 0) {
704 goto nomem;
704 goto nomem;
705 }
705 }
706 copy = PyObject_New(lazymanifest, &lazymanifestType);
706 copy = PyObject_New(lazymanifest, &lazymanifestType);
707 if (!copy) {
707 if (!copy) {
708 goto nomem;
708 goto nomem;
709 }
709 }
710 copy->dirty = true;
710 copy->dirty = true;
711 copy->lines = malloc(self->maxlines * sizeof(line));
711 copy->lines = malloc(self->maxlines * sizeof(line));
712 if (!copy->lines) {
712 if (!copy->lines) {
713 goto nomem;
713 goto nomem;
714 }
714 }
715 copy->maxlines = self->maxlines;
715 copy->maxlines = self->maxlines;
716 copy->numlines = 0;
716 copy->numlines = 0;
717 copy->pydata = self->pydata;
717 copy->pydata = self->pydata;
718 Py_INCREF(self->pydata);
718 Py_INCREF(self->pydata);
719 for (i = 0; i < self->numlines; i++) {
719 for (i = 0; i < self->numlines; i++) {
720 PyObject *arglist = NULL, *result = NULL;
720 PyObject *arglist = NULL, *result = NULL;
721 arglist = Py_BuildValue("(s)", self->lines[i].start);
721 arglist = Py_BuildValue("(s)", self->lines[i].start);
722 if (!arglist) {
722 if (!arglist) {
723 return NULL;
723 return NULL;
724 }
724 }
725 result = PyObject_CallObject(matchfn, arglist);
725 result = PyObject_CallObject(matchfn, arglist);
726 Py_DECREF(arglist);
726 Py_DECREF(arglist);
727 /* if the callback raised an exception, just let it
727 /* if the callback raised an exception, just let it
728 * through and give up */
728 * through and give up */
729 if (!result) {
729 if (!result) {
730 free(copy->lines);
730 free(copy->lines);
731 Py_DECREF(self->pydata);
731 Py_DECREF(self->pydata);
732 return NULL;
732 return NULL;
733 }
733 }
734 if (PyObject_IsTrue(result)) {
734 if (PyObject_IsTrue(result)) {
735 assert(!(self->lines[i].from_malloc));
735 assert(!(self->lines[i].from_malloc));
736 copy->lines[copy->numlines++] = self->lines[i];
736 copy->lines[copy->numlines++] = self->lines[i];
737 }
737 }
738 Py_DECREF(result);
738 Py_DECREF(result);
739 }
739 }
740 copy->livelines = copy->numlines;
740 copy->livelines = copy->numlines;
741 return copy;
741 return copy;
742 nomem:
742 nomem:
743 PyErr_NoMemory();
743 PyErr_NoMemory();
744 Py_XDECREF(copy);
744 Py_XDECREF(copy);
745 return NULL;
745 return NULL;
746 }
746 }
747
747
748 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
748 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
749 {
749 {
750 lazymanifest *other;
750 lazymanifest *other;
751 PyObject *pyclean = NULL;
751 PyObject *pyclean = NULL;
752 bool listclean;
752 bool listclean;
753 PyObject *emptyTup = NULL, *ret = NULL;
753 PyObject *emptyTup = NULL, *ret = NULL;
754 PyObject *es;
754 PyObject *es;
755 int sneedle = 0, oneedle = 0;
755 int sneedle = 0, oneedle = 0;
756 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
756 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
757 return NULL;
757 return NULL;
758 }
758 }
759 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
759 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
760 es = PyBytes_FromString("");
760 es = PyBytes_FromString("");
761 if (!es) {
761 if (!es) {
762 goto nomem;
762 goto nomem;
763 }
763 }
764 emptyTup = PyTuple_Pack(2, Py_None, es);
764 emptyTup = PyTuple_Pack(2, Py_None, es);
765 Py_DECREF(es);
765 Py_DECREF(es);
766 if (!emptyTup) {
766 if (!emptyTup) {
767 goto nomem;
767 goto nomem;
768 }
768 }
769 ret = PyDict_New();
769 ret = PyDict_New();
770 if (!ret) {
770 if (!ret) {
771 goto nomem;
771 goto nomem;
772 }
772 }
773 while (sneedle != self->numlines || oneedle != other->numlines) {
773 while (sneedle != self->numlines || oneedle != other->numlines) {
774 line *left = self->lines + sneedle;
774 line *left = self->lines + sneedle;
775 line *right = other->lines + oneedle;
775 line *right = other->lines + oneedle;
776 int result;
776 int result;
777 PyObject *key;
777 PyObject *key;
778 PyObject *outer;
778 PyObject *outer;
779 /* If we're looking at a deleted entry and it's not
779 /* If we're looking at a deleted entry and it's not
780 * the end of the manifest, just skip it. */
780 * the end of the manifest, just skip it. */
781 if (left->deleted && sneedle < self->numlines) {
781 if (sneedle < self->numlines && left->deleted) {
782 sneedle++;
782 sneedle++;
783 continue;
783 continue;
784 }
784 }
785 if (right->deleted && oneedle < other->numlines) {
785 if (oneedle < other->numlines && right->deleted) {
786 oneedle++;
786 oneedle++;
787 continue;
787 continue;
788 }
788 }
789 /* if we're at the end of either manifest, then we
789 /* if we're at the end of either manifest, then we
790 * know the remaining items are adds so we can skip
790 * know the remaining items are adds so we can skip
791 * the strcmp. */
791 * the strcmp. */
792 if (sneedle == self->numlines) {
792 if (sneedle == self->numlines) {
793 result = 1;
793 result = 1;
794 } else if (oneedle == other->numlines) {
794 } else if (oneedle == other->numlines) {
795 result = -1;
795 result = -1;
796 } else {
796 } else {
797 result = linecmp(left, right);
797 result = linecmp(left, right);
798 }
798 }
799 key = result <= 0 ?
799 key = result <= 0 ?
800 PyBytes_FromString(left->start) :
800 PyBytes_FromString(left->start) :
801 PyBytes_FromString(right->start);
801 PyBytes_FromString(right->start);
802 if (!key)
802 if (!key)
803 goto nomem;
803 goto nomem;
804 if (result < 0) {
804 if (result < 0) {
805 PyObject *l = hashflags(left);
805 PyObject *l = hashflags(left);
806 if (!l) {
806 if (!l) {
807 goto nomem;
807 goto nomem;
808 }
808 }
809 outer = PyTuple_Pack(2, l, emptyTup);
809 outer = PyTuple_Pack(2, l, emptyTup);
810 Py_DECREF(l);
810 Py_DECREF(l);
811 if (!outer) {
811 if (!outer) {
812 goto nomem;
812 goto nomem;
813 }
813 }
814 PyDict_SetItem(ret, key, outer);
814 PyDict_SetItem(ret, key, outer);
815 Py_DECREF(outer);
815 Py_DECREF(outer);
816 sneedle++;
816 sneedle++;
817 } else if (result > 0) {
817 } else if (result > 0) {
818 PyObject *r = hashflags(right);
818 PyObject *r = hashflags(right);
819 if (!r) {
819 if (!r) {
820 goto nomem;
820 goto nomem;
821 }
821 }
822 outer = PyTuple_Pack(2, emptyTup, r);
822 outer = PyTuple_Pack(2, emptyTup, r);
823 Py_DECREF(r);
823 Py_DECREF(r);
824 if (!outer) {
824 if (!outer) {
825 goto nomem;
825 goto nomem;
826 }
826 }
827 PyDict_SetItem(ret, key, outer);
827 PyDict_SetItem(ret, key, outer);
828 Py_DECREF(outer);
828 Py_DECREF(outer);
829 oneedle++;
829 oneedle++;
830 } else {
830 } else {
831 /* file exists in both manifests */
831 /* file exists in both manifests */
832 if (left->len != right->len
832 if (left->len != right->len
833 || memcmp(left->start, right->start, left->len)
833 || memcmp(left->start, right->start, left->len)
834 || left->hash_suffix != right->hash_suffix) {
834 || left->hash_suffix != right->hash_suffix) {
835 PyObject *l = hashflags(left);
835 PyObject *l = hashflags(left);
836 PyObject *r;
836 PyObject *r;
837 if (!l) {
837 if (!l) {
838 goto nomem;
838 goto nomem;
839 }
839 }
840 r = hashflags(right);
840 r = hashflags(right);
841 if (!r) {
841 if (!r) {
842 Py_DECREF(l);
842 Py_DECREF(l);
843 goto nomem;
843 goto nomem;
844 }
844 }
845 outer = PyTuple_Pack(2, l, r);
845 outer = PyTuple_Pack(2, l, r);
846 Py_DECREF(l);
846 Py_DECREF(l);
847 Py_DECREF(r);
847 Py_DECREF(r);
848 if (!outer) {
848 if (!outer) {
849 goto nomem;
849 goto nomem;
850 }
850 }
851 PyDict_SetItem(ret, key, outer);
851 PyDict_SetItem(ret, key, outer);
852 Py_DECREF(outer);
852 Py_DECREF(outer);
853 } else if (listclean) {
853 } else if (listclean) {
854 PyDict_SetItem(ret, key, Py_None);
854 PyDict_SetItem(ret, key, Py_None);
855 }
855 }
856 sneedle++;
856 sneedle++;
857 oneedle++;
857 oneedle++;
858 }
858 }
859 Py_DECREF(key);
859 Py_DECREF(key);
860 }
860 }
861 Py_DECREF(emptyTup);
861 Py_DECREF(emptyTup);
862 return ret;
862 return ret;
863 nomem:
863 nomem:
864 PyErr_NoMemory();
864 PyErr_NoMemory();
865 Py_XDECREF(ret);
865 Py_XDECREF(ret);
866 Py_XDECREF(emptyTup);
866 Py_XDECREF(emptyTup);
867 return NULL;
867 return NULL;
868 }
868 }
869
869
870 static PyMethodDef lazymanifest_methods[] = {
870 static PyMethodDef lazymanifest_methods[] = {
871 {"iterkeys", (PyCFunction)lazymanifest_getkeysiter, METH_NOARGS,
871 {"iterkeys", (PyCFunction)lazymanifest_getkeysiter, METH_NOARGS,
872 "Iterate over file names in this lazymanifest."},
872 "Iterate over file names in this lazymanifest."},
873 {"iterentries", (PyCFunction)lazymanifest_getentriesiter, METH_NOARGS,
873 {"iterentries", (PyCFunction)lazymanifest_getentriesiter, METH_NOARGS,
874 "Iterate over (path, nodeid, flags) tuples in this lazymanifest."},
874 "Iterate over (path, nodeid, flags) tuples in this lazymanifest."},
875 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
875 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
876 "Make a copy of this lazymanifest."},
876 "Make a copy of this lazymanifest."},
877 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
877 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
878 "Make a copy of this manifest filtered by matchfn."},
878 "Make a copy of this manifest filtered by matchfn."},
879 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
879 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
880 "Compare this lazymanifest to another one."},
880 "Compare this lazymanifest to another one."},
881 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
881 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
882 "Encode this manifest to text."},
882 "Encode this manifest to text."},
883 {NULL},
883 {NULL},
884 };
884 };
885
885
886 #ifdef IS_PY3K
886 #ifdef IS_PY3K
887 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT
887 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT
888 #else
888 #else
889 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_SEQUENCE_IN
889 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_SEQUENCE_IN
890 #endif
890 #endif
891
891
892 static PyTypeObject lazymanifestType = {
892 static PyTypeObject lazymanifestType = {
893 PyVarObject_HEAD_INIT(NULL, 0) /* header */
893 PyVarObject_HEAD_INIT(NULL, 0) /* header */
894 "parsers.lazymanifest", /* tp_name */
894 "parsers.lazymanifest", /* tp_name */
895 sizeof(lazymanifest), /* tp_basicsize */
895 sizeof(lazymanifest), /* tp_basicsize */
896 0, /* tp_itemsize */
896 0, /* tp_itemsize */
897 (destructor)lazymanifest_dealloc, /* tp_dealloc */
897 (destructor)lazymanifest_dealloc, /* tp_dealloc */
898 0, /* tp_print */
898 0, /* tp_print */
899 0, /* tp_getattr */
899 0, /* tp_getattr */
900 0, /* tp_setattr */
900 0, /* tp_setattr */
901 0, /* tp_compare */
901 0, /* tp_compare */
902 0, /* tp_repr */
902 0, /* tp_repr */
903 0, /* tp_as_number */
903 0, /* tp_as_number */
904 &lazymanifest_seq_meths, /* tp_as_sequence */
904 &lazymanifest_seq_meths, /* tp_as_sequence */
905 &lazymanifest_mapping_methods, /* tp_as_mapping */
905 &lazymanifest_mapping_methods, /* tp_as_mapping */
906 0, /* tp_hash */
906 0, /* tp_hash */
907 0, /* tp_call */
907 0, /* tp_call */
908 0, /* tp_str */
908 0, /* tp_str */
909 0, /* tp_getattro */
909 0, /* tp_getattro */
910 0, /* tp_setattro */
910 0, /* tp_setattro */
911 0, /* tp_as_buffer */
911 0, /* tp_as_buffer */
912 LAZYMANIFEST_TPFLAGS, /* tp_flags */
912 LAZYMANIFEST_TPFLAGS, /* tp_flags */
913 "TODO(augie)", /* tp_doc */
913 "TODO(augie)", /* tp_doc */
914 0, /* tp_traverse */
914 0, /* tp_traverse */
915 0, /* tp_clear */
915 0, /* tp_clear */
916 0, /* tp_richcompare */
916 0, /* tp_richcompare */
917 0, /* tp_weaklistoffset */
917 0, /* tp_weaklistoffset */
918 (getiterfunc)lazymanifest_getkeysiter, /* tp_iter */
918 (getiterfunc)lazymanifest_getkeysiter, /* tp_iter */
919 0, /* tp_iternext */
919 0, /* tp_iternext */
920 lazymanifest_methods, /* tp_methods */
920 lazymanifest_methods, /* tp_methods */
921 0, /* tp_members */
921 0, /* tp_members */
922 0, /* tp_getset */
922 0, /* tp_getset */
923 0, /* tp_base */
923 0, /* tp_base */
924 0, /* tp_dict */
924 0, /* tp_dict */
925 0, /* tp_descr_get */
925 0, /* tp_descr_get */
926 0, /* tp_descr_set */
926 0, /* tp_descr_set */
927 0, /* tp_dictoffset */
927 0, /* tp_dictoffset */
928 (initproc)lazymanifest_init, /* tp_init */
928 (initproc)lazymanifest_init, /* tp_init */
929 0, /* tp_alloc */
929 0, /* tp_alloc */
930 };
930 };
931
931
932 void manifest_module_init(PyObject * mod)
932 void manifest_module_init(PyObject * mod)
933 {
933 {
934 lazymanifestType.tp_new = PyType_GenericNew;
934 lazymanifestType.tp_new = PyType_GenericNew;
935 if (PyType_Ready(&lazymanifestType) < 0)
935 if (PyType_Ready(&lazymanifestType) < 0)
936 return;
936 return;
937 Py_INCREF(&lazymanifestType);
937 Py_INCREF(&lazymanifestType);
938
938
939 PyModule_AddObject(mod, "lazymanifest",
939 PyModule_AddObject(mod, "lazymanifest",
940 (PyObject *)&lazymanifestType);
940 (PyObject *)&lazymanifestType);
941 }
941 }
General Comments 0
You need to be logged in to leave comments. Login now