##// END OF EJS Templates
parsers: better bounds checking in fm1readmarkers...
Augie Fackler -
r41052:5c68b617 default
parent child Browse files
Show More
@@ -1,717 +1,728 b''
1 1 /*
2 2 parsers.c - efficient content parsing
3 3
4 4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5 5
6 6 This software may be used and distributed according to the terms of
7 7 the GNU General Public License, incorporated herein by reference.
8 8 */
9 9
10 10 #include <Python.h>
11 11 #include <ctype.h>
12 12 #include <stddef.h>
13 13 #include <string.h>
14 14
15 15 #include "bitmanipulation.h"
16 16 #include "charencode.h"
17 17 #include "util.h"
18 18
19 19 #ifdef IS_PY3K
20 20 /* The mapping of Python types is meant to be temporary to get Python
21 21 * 3 to compile. We should remove this once Python 3 support is fully
22 22 * supported and proper types are used in the extensions themselves. */
23 23 #define PyInt_Check PyLong_Check
24 24 #define PyInt_FromLong PyLong_FromLong
25 25 #define PyInt_FromSsize_t PyLong_FromSsize_t
26 26 #define PyInt_AsLong PyLong_AsLong
27 27 #endif
28 28
29 29 static const char *const versionerrortext = "Python minor version mismatch";
30 30
31 31 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
32 32 {
33 33 Py_ssize_t expected_size;
34 34
35 35 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size))
36 36 return NULL;
37 37
38 38 return _dict_new_presized(expected_size);
39 39 }
40 40
41 41 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
42 42 int size, int mtime)
43 43 {
44 44 dirstateTupleObject *t =
45 45 PyObject_New(dirstateTupleObject, &dirstateTupleType);
46 46 if (!t)
47 47 return NULL;
48 48 t->state = state;
49 49 t->mode = mode;
50 50 t->size = size;
51 51 t->mtime = mtime;
52 52 return t;
53 53 }
54 54
55 55 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
56 56 PyObject *kwds)
57 57 {
58 58 /* We do all the initialization here and not a tp_init function because
59 59 * dirstate_tuple is immutable. */
60 60 dirstateTupleObject *t;
61 61 char state;
62 62 int size, mode, mtime;
63 63 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
64 64 return NULL;
65 65
66 66 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
67 67 if (!t)
68 68 return NULL;
69 69 t->state = state;
70 70 t->mode = mode;
71 71 t->size = size;
72 72 t->mtime = mtime;
73 73
74 74 return (PyObject *)t;
75 75 }
76 76
77 77 static void dirstate_tuple_dealloc(PyObject *o)
78 78 {
79 79 PyObject_Del(o);
80 80 }
81 81
82 82 static Py_ssize_t dirstate_tuple_length(PyObject *o)
83 83 {
84 84 return 4;
85 85 }
86 86
87 87 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
88 88 {
89 89 dirstateTupleObject *t = (dirstateTupleObject *)o;
90 90 switch (i) {
91 91 case 0:
92 92 return PyBytes_FromStringAndSize(&t->state, 1);
93 93 case 1:
94 94 return PyInt_FromLong(t->mode);
95 95 case 2:
96 96 return PyInt_FromLong(t->size);
97 97 case 3:
98 98 return PyInt_FromLong(t->mtime);
99 99 default:
100 100 PyErr_SetString(PyExc_IndexError, "index out of range");
101 101 return NULL;
102 102 }
103 103 }
104 104
105 105 static PySequenceMethods dirstate_tuple_sq = {
106 106 dirstate_tuple_length, /* sq_length */
107 107 0, /* sq_concat */
108 108 0, /* sq_repeat */
109 109 dirstate_tuple_item, /* sq_item */
110 110 0, /* sq_ass_item */
111 111 0, /* sq_contains */
112 112 0, /* sq_inplace_concat */
113 113 0 /* sq_inplace_repeat */
114 114 };
115 115
116 116 PyTypeObject dirstateTupleType = {
117 117 PyVarObject_HEAD_INIT(NULL, 0) /* header */
118 118 "dirstate_tuple", /* tp_name */
119 119 sizeof(dirstateTupleObject), /* tp_basicsize */
120 120 0, /* tp_itemsize */
121 121 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
122 122 0, /* tp_print */
123 123 0, /* tp_getattr */
124 124 0, /* tp_setattr */
125 125 0, /* tp_compare */
126 126 0, /* tp_repr */
127 127 0, /* tp_as_number */
128 128 &dirstate_tuple_sq, /* tp_as_sequence */
129 129 0, /* tp_as_mapping */
130 130 0, /* tp_hash */
131 131 0, /* tp_call */
132 132 0, /* tp_str */
133 133 0, /* tp_getattro */
134 134 0, /* tp_setattro */
135 135 0, /* tp_as_buffer */
136 136 Py_TPFLAGS_DEFAULT, /* tp_flags */
137 137 "dirstate tuple", /* tp_doc */
138 138 0, /* tp_traverse */
139 139 0, /* tp_clear */
140 140 0, /* tp_richcompare */
141 141 0, /* tp_weaklistoffset */
142 142 0, /* tp_iter */
143 143 0, /* tp_iternext */
144 144 0, /* tp_methods */
145 145 0, /* tp_members */
146 146 0, /* tp_getset */
147 147 0, /* tp_base */
148 148 0, /* tp_dict */
149 149 0, /* tp_descr_get */
150 150 0, /* tp_descr_set */
151 151 0, /* tp_dictoffset */
152 152 0, /* tp_init */
153 153 0, /* tp_alloc */
154 154 dirstate_tuple_new, /* tp_new */
155 155 };
156 156
157 157 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
158 158 {
159 159 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
160 160 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
161 161 char state, *cur, *str, *cpos;
162 162 int mode, size, mtime;
163 163 unsigned int flen, len, pos = 40;
164 164 int readlen;
165 165
166 166 if (!PyArg_ParseTuple(
167 167 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
168 168 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen))
169 169 goto quit;
170 170
171 171 len = readlen;
172 172
173 173 /* read parents */
174 174 if (len < 40) {
175 175 PyErr_SetString(PyExc_ValueError,
176 176 "too little data for parents");
177 177 goto quit;
178 178 }
179 179
180 180 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, 20, str + 20, 20);
181 181 if (!parents)
182 182 goto quit;
183 183
184 184 /* read filenames */
185 185 while (pos >= 40 && pos < len) {
186 186 if (pos + 17 > len) {
187 187 PyErr_SetString(PyExc_ValueError,
188 188 "overflow in dirstate");
189 189 goto quit;
190 190 }
191 191 cur = str + pos;
192 192 /* unpack header */
193 193 state = *cur;
194 194 mode = getbe32(cur + 1);
195 195 size = getbe32(cur + 5);
196 196 mtime = getbe32(cur + 9);
197 197 flen = getbe32(cur + 13);
198 198 pos += 17;
199 199 cur += 17;
200 200 if (flen > len - pos) {
201 201 PyErr_SetString(PyExc_ValueError,
202 202 "overflow in dirstate");
203 203 goto quit;
204 204 }
205 205
206 206 entry =
207 207 (PyObject *)make_dirstate_tuple(state, mode, size, mtime);
208 208 cpos = memchr(cur, 0, flen);
209 209 if (cpos) {
210 210 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
211 211 cname = PyBytes_FromStringAndSize(
212 212 cpos + 1, flen - (cpos - cur) - 1);
213 213 if (!fname || !cname ||
214 214 PyDict_SetItem(cmap, fname, cname) == -1 ||
215 215 PyDict_SetItem(dmap, fname, entry) == -1)
216 216 goto quit;
217 217 Py_DECREF(cname);
218 218 } else {
219 219 fname = PyBytes_FromStringAndSize(cur, flen);
220 220 if (!fname || PyDict_SetItem(dmap, fname, entry) == -1)
221 221 goto quit;
222 222 }
223 223 Py_DECREF(fname);
224 224 Py_DECREF(entry);
225 225 fname = cname = entry = NULL;
226 226 pos += flen;
227 227 }
228 228
229 229 ret = parents;
230 230 Py_INCREF(ret);
231 231 quit:
232 232 Py_XDECREF(fname);
233 233 Py_XDECREF(cname);
234 234 Py_XDECREF(entry);
235 235 Py_XDECREF(parents);
236 236 return ret;
237 237 }
238 238
239 239 /*
240 240 * Build a set of non-normal and other parent entries from the dirstate dmap
241 241 */
242 242 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
243 243 {
244 244 PyObject *dmap, *fname, *v;
245 245 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
246 246 Py_ssize_t pos;
247 247
248 248 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type, &dmap))
249 249 goto bail;
250 250
251 251 nonnset = PySet_New(NULL);
252 252 if (nonnset == NULL)
253 253 goto bail;
254 254
255 255 otherpset = PySet_New(NULL);
256 256 if (otherpset == NULL)
257 257 goto bail;
258 258
259 259 pos = 0;
260 260 while (PyDict_Next(dmap, &pos, &fname, &v)) {
261 261 dirstateTupleObject *t;
262 262 if (!dirstate_tuple_check(v)) {
263 263 PyErr_SetString(PyExc_TypeError,
264 264 "expected a dirstate tuple");
265 265 goto bail;
266 266 }
267 267 t = (dirstateTupleObject *)v;
268 268
269 269 if (t->state == 'n' && t->size == -2) {
270 270 if (PySet_Add(otherpset, fname) == -1) {
271 271 goto bail;
272 272 }
273 273 }
274 274
275 275 if (t->state == 'n' && t->mtime != -1)
276 276 continue;
277 277 if (PySet_Add(nonnset, fname) == -1)
278 278 goto bail;
279 279 }
280 280
281 281 result = Py_BuildValue("(OO)", nonnset, otherpset);
282 282 if (result == NULL)
283 283 goto bail;
284 284 Py_DECREF(nonnset);
285 285 Py_DECREF(otherpset);
286 286 return result;
287 287 bail:
288 288 Py_XDECREF(nonnset);
289 289 Py_XDECREF(otherpset);
290 290 Py_XDECREF(result);
291 291 return NULL;
292 292 }
293 293
294 294 /*
295 295 * Efficiently pack a dirstate object into its on-disk format.
296 296 */
297 297 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
298 298 {
299 299 PyObject *packobj = NULL;
300 300 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
301 301 Py_ssize_t nbytes, pos, l;
302 302 PyObject *k, *v = NULL, *pn;
303 303 char *p, *s;
304 304 int now;
305 305
306 306 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
307 307 &PyDict_Type, &copymap, &PyTuple_Type, &pl, &now))
308 308 return NULL;
309 309
310 310 if (PyTuple_Size(pl) != 2) {
311 311 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
312 312 return NULL;
313 313 }
314 314
315 315 /* Figure out how much we need to allocate. */
316 316 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
317 317 PyObject *c;
318 318 if (!PyBytes_Check(k)) {
319 319 PyErr_SetString(PyExc_TypeError, "expected string key");
320 320 goto bail;
321 321 }
322 322 nbytes += PyBytes_GET_SIZE(k) + 17;
323 323 c = PyDict_GetItem(copymap, k);
324 324 if (c) {
325 325 if (!PyBytes_Check(c)) {
326 326 PyErr_SetString(PyExc_TypeError,
327 327 "expected string key");
328 328 goto bail;
329 329 }
330 330 nbytes += PyBytes_GET_SIZE(c) + 1;
331 331 }
332 332 }
333 333
334 334 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
335 335 if (packobj == NULL)
336 336 goto bail;
337 337
338 338 p = PyBytes_AS_STRING(packobj);
339 339
340 340 pn = PyTuple_GET_ITEM(pl, 0);
341 341 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
342 342 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
343 343 goto bail;
344 344 }
345 345 memcpy(p, s, l);
346 346 p += 20;
347 347 pn = PyTuple_GET_ITEM(pl, 1);
348 348 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
349 349 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
350 350 goto bail;
351 351 }
352 352 memcpy(p, s, l);
353 353 p += 20;
354 354
355 355 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
356 356 dirstateTupleObject *tuple;
357 357 char state;
358 358 int mode, size, mtime;
359 359 Py_ssize_t len, l;
360 360 PyObject *o;
361 361 char *t;
362 362
363 363 if (!dirstate_tuple_check(v)) {
364 364 PyErr_SetString(PyExc_TypeError,
365 365 "expected a dirstate tuple");
366 366 goto bail;
367 367 }
368 368 tuple = (dirstateTupleObject *)v;
369 369
370 370 state = tuple->state;
371 371 mode = tuple->mode;
372 372 size = tuple->size;
373 373 mtime = tuple->mtime;
374 374 if (state == 'n' && mtime == now) {
375 375 /* See pure/parsers.py:pack_dirstate for why we do
376 376 * this. */
377 377 mtime = -1;
378 378 mtime_unset = (PyObject *)make_dirstate_tuple(
379 379 state, mode, size, mtime);
380 380 if (!mtime_unset)
381 381 goto bail;
382 382 if (PyDict_SetItem(map, k, mtime_unset) == -1)
383 383 goto bail;
384 384 Py_DECREF(mtime_unset);
385 385 mtime_unset = NULL;
386 386 }
387 387 *p++ = state;
388 388 putbe32((uint32_t)mode, p);
389 389 putbe32((uint32_t)size, p + 4);
390 390 putbe32((uint32_t)mtime, p + 8);
391 391 t = p + 12;
392 392 p += 16;
393 393 len = PyBytes_GET_SIZE(k);
394 394 memcpy(p, PyBytes_AS_STRING(k), len);
395 395 p += len;
396 396 o = PyDict_GetItem(copymap, k);
397 397 if (o) {
398 398 *p++ = '\0';
399 399 l = PyBytes_GET_SIZE(o);
400 400 memcpy(p, PyBytes_AS_STRING(o), l);
401 401 p += l;
402 402 len += l + 1;
403 403 }
404 404 putbe32((uint32_t)len, t);
405 405 }
406 406
407 407 pos = p - PyBytes_AS_STRING(packobj);
408 408 if (pos != nbytes) {
409 409 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
410 410 (long)pos, (long)nbytes);
411 411 goto bail;
412 412 }
413 413
414 414 return packobj;
415 415 bail:
416 416 Py_XDECREF(mtime_unset);
417 417 Py_XDECREF(packobj);
418 418 Py_XDECREF(v);
419 419 return NULL;
420 420 }
421 421
422 422 #define BUMPED_FIX 1
423 423 #define USING_SHA_256 2
424 424 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
425 425
426 426 static PyObject *readshas(const char *source, unsigned char num,
427 427 Py_ssize_t hashwidth)
428 428 {
429 429 int i;
430 430 PyObject *list = PyTuple_New(num);
431 431 if (list == NULL) {
432 432 return NULL;
433 433 }
434 434 for (i = 0; i < num; i++) {
435 435 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
436 436 if (hash == NULL) {
437 437 Py_DECREF(list);
438 438 return NULL;
439 439 }
440 440 PyTuple_SET_ITEM(list, i, hash);
441 441 source += hashwidth;
442 442 }
443 443 return list;
444 444 }
445 445
446 446 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
447 447 uint32_t *msize)
448 448 {
449 449 const char *data = databegin;
450 450 const char *meta;
451 451
452 452 double mtime;
453 453 int16_t tz;
454 454 uint16_t flags;
455 455 unsigned char nsuccs, nparents, nmetadata;
456 456 Py_ssize_t hashwidth = 20;
457 457
458 458 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
459 459 PyObject *metadata = NULL, *ret = NULL;
460 460 int i;
461 461
462 462 if (data + FM1_HEADER_SIZE > dataend) {
463 463 goto overflow;
464 464 }
465 465
466 466 *msize = getbe32(data);
467 467 data += 4;
468 468 mtime = getbefloat64(data);
469 469 data += 8;
470 470 tz = getbeint16(data);
471 471 data += 2;
472 472 flags = getbeuint16(data);
473 473 data += 2;
474 474
475 475 if (flags & USING_SHA_256) {
476 476 hashwidth = 32;
477 477 }
478 478
479 479 nsuccs = (unsigned char)(*data++);
480 480 nparents = (unsigned char)(*data++);
481 481 nmetadata = (unsigned char)(*data++);
482 482
483 483 if (databegin + *msize > dataend) {
484 484 goto overflow;
485 485 }
486 486 dataend = databegin + *msize; /* narrow down to marker size */
487 487
488 488 if (data + hashwidth > dataend) {
489 489 goto overflow;
490 490 }
491 491 prec = PyBytes_FromStringAndSize(data, hashwidth);
492 492 data += hashwidth;
493 493 if (prec == NULL) {
494 494 goto bail;
495 495 }
496 496
497 497 if (data + nsuccs * hashwidth > dataend) {
498 498 goto overflow;
499 499 }
500 500 succs = readshas(data, nsuccs, hashwidth);
501 501 if (succs == NULL) {
502 502 goto bail;
503 503 }
504 504 data += nsuccs * hashwidth;
505 505
506 506 if (nparents == 1 || nparents == 2) {
507 507 if (data + nparents * hashwidth > dataend) {
508 508 goto overflow;
509 509 }
510 510 parents = readshas(data, nparents, hashwidth);
511 511 if (parents == NULL) {
512 512 goto bail;
513 513 }
514 514 data += nparents * hashwidth;
515 515 } else {
516 516 parents = Py_None;
517 517 Py_INCREF(parents);
518 518 }
519 519
520 520 if (data + 2 * nmetadata > dataend) {
521 521 goto overflow;
522 522 }
523 523 meta = data + (2 * nmetadata);
524 524 metadata = PyTuple_New(nmetadata);
525 525 if (metadata == NULL) {
526 526 goto bail;
527 527 }
528 528 for (i = 0; i < nmetadata; i++) {
529 529 PyObject *tmp, *left = NULL, *right = NULL;
530 530 Py_ssize_t leftsize = (unsigned char)(*data++);
531 531 Py_ssize_t rightsize = (unsigned char)(*data++);
532 532 if (meta + leftsize + rightsize > dataend) {
533 533 goto overflow;
534 534 }
535 535 left = PyBytes_FromStringAndSize(meta, leftsize);
536 536 meta += leftsize;
537 537 right = PyBytes_FromStringAndSize(meta, rightsize);
538 538 meta += rightsize;
539 539 tmp = PyTuple_New(2);
540 540 if (!left || !right || !tmp) {
541 541 Py_XDECREF(left);
542 542 Py_XDECREF(right);
543 543 Py_XDECREF(tmp);
544 544 goto bail;
545 545 }
546 546 PyTuple_SET_ITEM(tmp, 0, left);
547 547 PyTuple_SET_ITEM(tmp, 1, right);
548 548 PyTuple_SET_ITEM(metadata, i, tmp);
549 549 }
550 550 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
551 551 (int)tz * 60, parents);
552 552 goto bail; /* return successfully */
553 553
554 554 overflow:
555 555 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
556 556 bail:
557 557 Py_XDECREF(prec);
558 558 Py_XDECREF(succs);
559 559 Py_XDECREF(metadata);
560 560 Py_XDECREF(parents);
561 561 return ret;
562 562 }
563 563
564 564 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
565 565 {
566 566 const char *data, *dataend;
567 567 int datalen;
568 568 Py_ssize_t offset, stop;
569 569 PyObject *markers = NULL;
570 570
571 571 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
572 572 &offset, &stop)) {
573 573 return NULL;
574 574 }
575 if (offset < 0) {
576 PyErr_SetString(PyExc_ValueError,
577 "invalid negative offset in fm1readmarkers");
578 return NULL;
579 }
580 if (stop > datalen) {
581 PyErr_SetString(
582 PyExc_ValueError,
583 "stop longer than data length in fm1readmarkers");
584 return NULL;
585 }
575 586 dataend = data + datalen;
576 587 data += offset;
577 588 markers = PyList_New(0);
578 589 if (!markers) {
579 590 return NULL;
580 591 }
581 592 while (offset < stop) {
582 593 uint32_t msize;
583 594 int error;
584 595 PyObject *record = fm1readmarker(data, dataend, &msize);
585 596 if (!record) {
586 597 goto bail;
587 598 }
588 599 error = PyList_Append(markers, record);
589 600 Py_DECREF(record);
590 601 if (error) {
591 602 goto bail;
592 603 }
593 604 data += msize;
594 605 offset += msize;
595 606 }
596 607 return markers;
597 608 bail:
598 609 Py_DECREF(markers);
599 610 return NULL;
600 611 }
601 612
602 613 static char parsers_doc[] = "Efficient content parsing.";
603 614
604 615 PyObject *encodedir(PyObject *self, PyObject *args);
605 616 PyObject *pathencode(PyObject *self, PyObject *args);
606 617 PyObject *lowerencode(PyObject *self, PyObject *args);
607 618 PyObject *parse_index2(PyObject *self, PyObject *args);
608 619
609 620 static PyMethodDef methods[] = {
610 621 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
611 622 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
612 623 "create a set containing non-normal and other parent entries of given "
613 624 "dirstate\n"},
614 625 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
615 626 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
616 627 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
617 628 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
618 629 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
619 630 {"dict_new_presized", dict_new_presized, METH_VARARGS,
620 631 "construct a dict with an expected size\n"},
621 632 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
622 633 "make file foldmap\n"},
623 634 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
624 635 "escape a UTF-8 byte string to JSON (fast path)\n"},
625 636 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
626 637 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
627 638 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
628 639 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
629 640 "parse v1 obsolete markers\n"},
630 641 {NULL, NULL}};
631 642
632 643 void dirs_module_init(PyObject *mod);
633 644 void manifest_module_init(PyObject *mod);
634 645 void revlog_module_init(PyObject *mod);
635 646
636 647 static const int version = 12;
637 648
638 649 static void module_init(PyObject *mod)
639 650 {
640 651 PyModule_AddIntConstant(mod, "version", version);
641 652
642 653 /* This module constant has two purposes. First, it lets us unit test
643 654 * the ImportError raised without hard-coding any error text. This
644 655 * means we can change the text in the future without breaking tests,
645 656 * even across changesets without a recompile. Second, its presence
646 657 * can be used to determine whether the version-checking logic is
647 658 * present, which also helps in testing across changesets without a
648 659 * recompile. Note that this means the pure-Python version of parsers
649 660 * should not have this module constant. */
650 661 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
651 662
652 663 dirs_module_init(mod);
653 664 manifest_module_init(mod);
654 665 revlog_module_init(mod);
655 666
656 667 if (PyType_Ready(&dirstateTupleType) < 0)
657 668 return;
658 669 Py_INCREF(&dirstateTupleType);
659 670 PyModule_AddObject(mod, "dirstatetuple",
660 671 (PyObject *)&dirstateTupleType);
661 672 }
662 673
663 674 static int check_python_version(void)
664 675 {
665 676 PyObject *sys = PyImport_ImportModule("sys"), *ver;
666 677 long hexversion;
667 678 if (!sys)
668 679 return -1;
669 680 ver = PyObject_GetAttrString(sys, "hexversion");
670 681 Py_DECREF(sys);
671 682 if (!ver)
672 683 return -1;
673 684 hexversion = PyInt_AsLong(ver);
674 685 Py_DECREF(ver);
675 686 /* sys.hexversion is a 32-bit number by default, so the -1 case
676 687 * should only occur in unusual circumstances (e.g. if sys.hexversion
677 688 * is manually set to an invalid value). */
678 689 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
679 690 PyErr_Format(PyExc_ImportError,
680 691 "%s: The Mercurial extension "
681 692 "modules were compiled with Python " PY_VERSION
682 693 ", but "
683 694 "Mercurial is currently using Python with "
684 695 "sys.hexversion=%ld: "
685 696 "Python %s\n at: %s",
686 697 versionerrortext, hexversion, Py_GetVersion(),
687 698 Py_GetProgramFullPath());
688 699 return -1;
689 700 }
690 701 return 0;
691 702 }
692 703
693 704 #ifdef IS_PY3K
694 705 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
695 706 parsers_doc, -1, methods};
696 707
697 708 PyMODINIT_FUNC PyInit_parsers(void)
698 709 {
699 710 PyObject *mod;
700 711
701 712 if (check_python_version() == -1)
702 713 return NULL;
703 714 mod = PyModule_Create(&parsers_module);
704 715 module_init(mod);
705 716 return mod;
706 717 }
707 718 #else
708 719 PyMODINIT_FUNC initparsers(void)
709 720 {
710 721 PyObject *mod;
711 722
712 723 if (check_python_version() == -1)
713 724 return;
714 725 mod = Py_InitModule3("parsers", methods, parsers_doc);
715 726 module_init(mod);
716 727 }
717 728 #endif
General Comments 0
You need to be logged in to leave comments. Login now