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