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