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