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