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