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