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