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