##// END OF EJS Templates
dirstate-item: fix the declaration of the Cext `from_v1_meth`...
marmoute -
r48703:32aa80a8 default
parent child Browse files
Show More
@@ -1,1004 +1,1004 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
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
9
10 #define PY_SSIZE_T_CLEAN
10 #define PY_SSIZE_T_CLEAN
11 #include <Python.h>
11 #include <Python.h>
12 #include <ctype.h>
12 #include <ctype.h>
13 #include <stddef.h>
13 #include <stddef.h>
14 #include <string.h>
14 #include <string.h>
15
15
16 #include "bitmanipulation.h"
16 #include "bitmanipulation.h"
17 #include "charencode.h"
17 #include "charencode.h"
18 #include "util.h"
18 #include "util.h"
19
19
20 #ifdef IS_PY3K
20 #ifdef IS_PY3K
21 /* The mapping of Python types is meant to be temporary to get Python
21 /* The mapping of Python types is meant to be temporary to get Python
22 * 3 to compile. We should remove this once Python 3 support is fully
22 * 3 to compile. We should remove this once Python 3 support is fully
23 * supported and proper types are used in the extensions themselves. */
23 * supported and proper types are used in the extensions themselves. */
24 #define PyInt_Check PyLong_Check
24 #define PyInt_Check PyLong_Check
25 #define PyInt_FromLong PyLong_FromLong
25 #define PyInt_FromLong PyLong_FromLong
26 #define PyInt_FromSsize_t PyLong_FromSsize_t
26 #define PyInt_FromSsize_t PyLong_FromSsize_t
27 #define PyInt_AsLong PyLong_AsLong
27 #define PyInt_AsLong PyLong_AsLong
28 #endif
28 #endif
29
29
30 static const char *const versionerrortext = "Python minor version mismatch";
30 static const char *const versionerrortext = "Python minor version mismatch";
31
31
32 static const int dirstate_v1_from_p2 = -2;
32 static const int dirstate_v1_from_p2 = -2;
33 static const int dirstate_v1_nonnormal = -1;
33 static const int dirstate_v1_nonnormal = -1;
34 static const int ambiguous_time = -1;
34 static const int ambiguous_time = -1;
35
35
36 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
36 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
37 {
37 {
38 Py_ssize_t expected_size;
38 Py_ssize_t expected_size;
39
39
40 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
40 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
41 return NULL;
41 return NULL;
42 }
42 }
43
43
44 return _dict_new_presized(expected_size);
44 return _dict_new_presized(expected_size);
45 }
45 }
46
46
47 static inline dirstateItemObject *make_dirstate_item(char state, int mode,
47 static inline dirstateItemObject *make_dirstate_item(char state, int mode,
48 int size, int mtime)
48 int size, int mtime)
49 {
49 {
50 dirstateItemObject *t =
50 dirstateItemObject *t =
51 PyObject_New(dirstateItemObject, &dirstateItemType);
51 PyObject_New(dirstateItemObject, &dirstateItemType);
52 if (!t) {
52 if (!t) {
53 return NULL;
53 return NULL;
54 }
54 }
55 t->state = state;
55 t->state = state;
56 t->mode = mode;
56 t->mode = mode;
57 t->size = size;
57 t->size = size;
58 t->mtime = mtime;
58 t->mtime = mtime;
59 return t;
59 return t;
60 }
60 }
61
61
62 static PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
62 static PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
63 PyObject *kwds)
63 PyObject *kwds)
64 {
64 {
65 /* We do all the initialization here and not a tp_init function because
65 /* We do all the initialization here and not a tp_init function because
66 * dirstate_item is immutable. */
66 * dirstate_item is immutable. */
67 dirstateItemObject *t;
67 dirstateItemObject *t;
68 char state;
68 char state;
69 int size, mode, mtime;
69 int size, mode, mtime;
70 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
70 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
71 return NULL;
71 return NULL;
72 }
72 }
73
73
74 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
74 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
75 if (!t) {
75 if (!t) {
76 return NULL;
76 return NULL;
77 }
77 }
78 t->state = state;
78 t->state = state;
79 t->mode = mode;
79 t->mode = mode;
80 t->size = size;
80 t->size = size;
81 t->mtime = mtime;
81 t->mtime = mtime;
82
82
83 return (PyObject *)t;
83 return (PyObject *)t;
84 }
84 }
85
85
86 static void dirstate_item_dealloc(PyObject *o)
86 static void dirstate_item_dealloc(PyObject *o)
87 {
87 {
88 PyObject_Del(o);
88 PyObject_Del(o);
89 }
89 }
90
90
91 static Py_ssize_t dirstate_item_length(PyObject *o)
91 static Py_ssize_t dirstate_item_length(PyObject *o)
92 {
92 {
93 return 4;
93 return 4;
94 }
94 }
95
95
96 static PyObject *dirstate_item_item(PyObject *o, Py_ssize_t i)
96 static PyObject *dirstate_item_item(PyObject *o, Py_ssize_t i)
97 {
97 {
98 dirstateItemObject *t = (dirstateItemObject *)o;
98 dirstateItemObject *t = (dirstateItemObject *)o;
99 switch (i) {
99 switch (i) {
100 case 0:
100 case 0:
101 return PyBytes_FromStringAndSize(&t->state, 1);
101 return PyBytes_FromStringAndSize(&t->state, 1);
102 case 1:
102 case 1:
103 return PyInt_FromLong(t->mode);
103 return PyInt_FromLong(t->mode);
104 case 2:
104 case 2:
105 return PyInt_FromLong(t->size);
105 return PyInt_FromLong(t->size);
106 case 3:
106 case 3:
107 return PyInt_FromLong(t->mtime);
107 return PyInt_FromLong(t->mtime);
108 default:
108 default:
109 PyErr_SetString(PyExc_IndexError, "index out of range");
109 PyErr_SetString(PyExc_IndexError, "index out of range");
110 return NULL;
110 return NULL;
111 }
111 }
112 }
112 }
113
113
114 static PySequenceMethods dirstate_item_sq = {
114 static PySequenceMethods dirstate_item_sq = {
115 dirstate_item_length, /* sq_length */
115 dirstate_item_length, /* sq_length */
116 0, /* sq_concat */
116 0, /* sq_concat */
117 0, /* sq_repeat */
117 0, /* sq_repeat */
118 dirstate_item_item, /* sq_item */
118 dirstate_item_item, /* sq_item */
119 0, /* sq_ass_item */
119 0, /* sq_ass_item */
120 0, /* sq_contains */
120 0, /* sq_contains */
121 0, /* sq_inplace_concat */
121 0, /* sq_inplace_concat */
122 0 /* sq_inplace_repeat */
122 0 /* sq_inplace_repeat */
123 };
123 };
124
124
125 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
125 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
126 {
126 {
127 return PyBytes_FromStringAndSize(&self->state, 1);
127 return PyBytes_FromStringAndSize(&self->state, 1);
128 };
128 };
129
129
130 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
130 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
131 {
131 {
132 return PyInt_FromLong(self->mode);
132 return PyInt_FromLong(self->mode);
133 };
133 };
134
134
135 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
135 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
136 {
136 {
137 return PyInt_FromLong(self->size);
137 return PyInt_FromLong(self->size);
138 };
138 };
139
139
140 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
140 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
141 {
141 {
142 return PyInt_FromLong(self->mtime);
142 return PyInt_FromLong(self->mtime);
143 };
143 };
144
144
145 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
145 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
146 PyObject *value)
146 PyObject *value)
147 {
147 {
148 long now;
148 long now;
149 if (!pylong_to_long(value, &now)) {
149 if (!pylong_to_long(value, &now)) {
150 return NULL;
150 return NULL;
151 }
151 }
152 if (self->state == 'n' && self->mtime == now) {
152 if (self->state == 'n' && self->mtime == now) {
153 Py_RETURN_TRUE;
153 Py_RETURN_TRUE;
154 } else {
154 } else {
155 Py_RETURN_FALSE;
155 Py_RETURN_FALSE;
156 }
156 }
157 };
157 };
158
158
159 /* This will never change since it's bound to V1, unlike `make_dirstate_item`
159 /* This will never change since it's bound to V1, unlike `make_dirstate_item`
160 */
160 */
161 static inline dirstateItemObject *
161 static inline dirstateItemObject *
162 dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
162 dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
163 {
163 {
164 dirstateItemObject *t =
164 dirstateItemObject *t =
165 PyObject_New(dirstateItemObject, &dirstateItemType);
165 PyObject_New(dirstateItemObject, &dirstateItemType);
166 if (!t) {
166 if (!t) {
167 return NULL;
167 return NULL;
168 }
168 }
169 t->state = state;
169 t->state = state;
170 t->mode = mode;
170 t->mode = mode;
171 t->size = size;
171 t->size = size;
172 t->mtime = mtime;
172 t->mtime = mtime;
173 return t;
173 return t;
174 }
174 }
175
175
176 /* This will never change since it's bound to V1, unlike `dirstate_item_new` */
176 /* This will never change since it's bound to V1, unlike `dirstate_item_new` */
177 static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
177 static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
178 PyObject *args)
178 PyObject *args)
179 {
179 {
180 /* We do all the initialization here and not a tp_init function because
180 /* We do all the initialization here and not a tp_init function because
181 * dirstate_item is immutable. */
181 * dirstate_item is immutable. */
182 dirstateItemObject *t;
182 dirstateItemObject *t;
183 char state;
183 char state;
184 int size, mode, mtime;
184 int size, mode, mtime;
185 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
185 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
186 return NULL;
186 return NULL;
187 }
187 }
188
188
189 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
189 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
190 if (!t) {
190 if (!t) {
191 return NULL;
191 return NULL;
192 }
192 }
193 t->state = state;
193 t->state = state;
194 t->mode = mode;
194 t->mode = mode;
195 t->size = size;
195 t->size = size;
196 t->mtime = mtime;
196 t->mtime = mtime;
197
197
198 return (PyObject *)t;
198 return (PyObject *)t;
199 };
199 };
200
200
201 /* This means the next status call will have to actually check its content
201 /* This means the next status call will have to actually check its content
202 to make sure it is correct. */
202 to make sure it is correct. */
203 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
203 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
204 {
204 {
205 self->mtime = ambiguous_time;
205 self->mtime = ambiguous_time;
206 Py_RETURN_NONE;
206 Py_RETURN_NONE;
207 }
207 }
208
208
209 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
209 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
210 {
210 {
211 if (self->state == 'm') {
211 if (self->state == 'm') {
212 self->size = dirstate_v1_nonnormal;
212 self->size = dirstate_v1_nonnormal;
213 } else if (self->state == 'n' && self->size == dirstate_v1_from_p2) {
213 } else if (self->state == 'n' && self->size == dirstate_v1_from_p2) {
214 self->size = dirstate_v1_from_p2;
214 self->size = dirstate_v1_from_p2;
215 } else {
215 } else {
216 self->size = 0;
216 self->size = 0;
217 }
217 }
218 self->state = 'r';
218 self->state = 'r';
219 self->mode = 0;
219 self->mode = 0;
220 self->mtime = 0;
220 self->mtime = 0;
221 Py_RETURN_NONE;
221 Py_RETURN_NONE;
222 }
222 }
223
223
224 static PyMethodDef dirstate_item_methods[] = {
224 static PyMethodDef dirstate_item_methods[] = {
225 {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
225 {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
226 "return a \"state\" suitable for v1 serialization"},
226 "return a \"state\" suitable for v1 serialization"},
227 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
227 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
228 "return a \"mode\" suitable for v1 serialization"},
228 "return a \"mode\" suitable for v1 serialization"},
229 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
229 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
230 "return a \"size\" suitable for v1 serialization"},
230 "return a \"size\" suitable for v1 serialization"},
231 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
231 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
232 "return a \"mtime\" suitable for v1 serialization"},
232 "return a \"mtime\" suitable for v1 serialization"},
233 {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O,
233 {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O,
234 "True if the stored mtime would be ambiguous with the current time"},
234 "True if the stored mtime would be ambiguous with the current time"},
235 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth, METH_O,
235 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
236 "build a new DirstateItem object from V1 data"},
236 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V1 data"},
237 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
237 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
238 METH_NOARGS, "mark a file as \"possibly dirty\""},
238 METH_NOARGS, "mark a file as \"possibly dirty\""},
239 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
239 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
240 "mark a file as \"untracked\""},
240 "mark a file as \"untracked\""},
241 {NULL} /* Sentinel */
241 {NULL} /* Sentinel */
242 };
242 };
243
243
244 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
244 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
245 {
245 {
246 return PyInt_FromLong(self->mode);
246 return PyInt_FromLong(self->mode);
247 };
247 };
248
248
249 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
249 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
250 {
250 {
251 return PyInt_FromLong(self->size);
251 return PyInt_FromLong(self->size);
252 };
252 };
253
253
254 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
254 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
255 {
255 {
256 return PyInt_FromLong(self->mtime);
256 return PyInt_FromLong(self->mtime);
257 };
257 };
258
258
259 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
259 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
260 {
260 {
261 return PyBytes_FromStringAndSize(&self->state, 1);
261 return PyBytes_FromStringAndSize(&self->state, 1);
262 };
262 };
263
263
264 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
264 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
265 {
265 {
266 if (self->state == 'a' || self->state == 'm' || self->state == 'n') {
266 if (self->state == 'a' || self->state == 'm' || self->state == 'n') {
267 Py_RETURN_TRUE;
267 Py_RETURN_TRUE;
268 } else {
268 } else {
269 Py_RETURN_FALSE;
269 Py_RETURN_FALSE;
270 }
270 }
271 };
271 };
272
272
273 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
273 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
274 {
274 {
275 if (self->state == 'a') {
275 if (self->state == 'a') {
276 Py_RETURN_TRUE;
276 Py_RETURN_TRUE;
277 } else {
277 } else {
278 Py_RETURN_FALSE;
278 Py_RETURN_FALSE;
279 }
279 }
280 };
280 };
281
281
282 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
282 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
283 {
283 {
284 if (self->state == 'm') {
284 if (self->state == 'm') {
285 Py_RETURN_TRUE;
285 Py_RETURN_TRUE;
286 } else {
286 } else {
287 Py_RETURN_FALSE;
287 Py_RETURN_FALSE;
288 }
288 }
289 };
289 };
290
290
291 static PyObject *dirstate_item_get_merged_removed(dirstateItemObject *self)
291 static PyObject *dirstate_item_get_merged_removed(dirstateItemObject *self)
292 {
292 {
293 if (self->state == 'r' && self->size == dirstate_v1_nonnormal) {
293 if (self->state == 'r' && self->size == dirstate_v1_nonnormal) {
294 Py_RETURN_TRUE;
294 Py_RETURN_TRUE;
295 } else {
295 } else {
296 Py_RETURN_FALSE;
296 Py_RETURN_FALSE;
297 }
297 }
298 };
298 };
299
299
300 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
300 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
301 {
301 {
302 if (self->state == 'n' && self->size == dirstate_v1_from_p2) {
302 if (self->state == 'n' && self->size == dirstate_v1_from_p2) {
303 Py_RETURN_TRUE;
303 Py_RETURN_TRUE;
304 } else {
304 } else {
305 Py_RETURN_FALSE;
305 Py_RETURN_FALSE;
306 }
306 }
307 };
307 };
308
308
309 static PyObject *dirstate_item_get_from_p2_removed(dirstateItemObject *self)
309 static PyObject *dirstate_item_get_from_p2_removed(dirstateItemObject *self)
310 {
310 {
311 if (self->state == 'r' && self->size == dirstate_v1_from_p2) {
311 if (self->state == 'r' && self->size == dirstate_v1_from_p2) {
312 Py_RETURN_TRUE;
312 Py_RETURN_TRUE;
313 } else {
313 } else {
314 Py_RETURN_FALSE;
314 Py_RETURN_FALSE;
315 }
315 }
316 };
316 };
317
317
318 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
318 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
319 {
319 {
320 if (self->state == 'r') {
320 if (self->state == 'r') {
321 Py_RETURN_TRUE;
321 Py_RETURN_TRUE;
322 } else {
322 } else {
323 Py_RETURN_FALSE;
323 Py_RETURN_FALSE;
324 }
324 }
325 };
325 };
326
326
327 static PyObject *dm_nonnormal(dirstateItemObject *self)
327 static PyObject *dm_nonnormal(dirstateItemObject *self)
328 {
328 {
329 if (self->state != 'n' || self->mtime == ambiguous_time) {
329 if (self->state != 'n' || self->mtime == ambiguous_time) {
330 Py_RETURN_TRUE;
330 Py_RETURN_TRUE;
331 } else {
331 } else {
332 Py_RETURN_FALSE;
332 Py_RETURN_FALSE;
333 }
333 }
334 };
334 };
335 static PyObject *dm_otherparent(dirstateItemObject *self)
335 static PyObject *dm_otherparent(dirstateItemObject *self)
336 {
336 {
337 if (self->size == dirstate_v1_from_p2) {
337 if (self->size == dirstate_v1_from_p2) {
338 Py_RETURN_TRUE;
338 Py_RETURN_TRUE;
339 } else {
339 } else {
340 Py_RETURN_FALSE;
340 Py_RETURN_FALSE;
341 }
341 }
342 };
342 };
343
343
344 static PyGetSetDef dirstate_item_getset[] = {
344 static PyGetSetDef dirstate_item_getset[] = {
345 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
345 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
346 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
346 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
347 {"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
347 {"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
348 {"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
348 {"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
349 {"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
349 {"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
350 {"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
350 {"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
351 {"merged_removed", (getter)dirstate_item_get_merged_removed, NULL,
351 {"merged_removed", (getter)dirstate_item_get_merged_removed, NULL,
352 "merged_removed", NULL},
352 "merged_removed", NULL},
353 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
353 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
354 {"from_p2_removed", (getter)dirstate_item_get_from_p2_removed, NULL,
354 {"from_p2_removed", (getter)dirstate_item_get_from_p2_removed, NULL,
355 "from_p2_removed", NULL},
355 "from_p2_removed", NULL},
356 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
356 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
357 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
357 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
358 {"dm_nonnormal", (getter)dm_nonnormal, NULL, "dm_nonnormal", NULL},
358 {"dm_nonnormal", (getter)dm_nonnormal, NULL, "dm_nonnormal", NULL},
359 {"dm_otherparent", (getter)dm_otherparent, NULL, "dm_otherparent", NULL},
359 {"dm_otherparent", (getter)dm_otherparent, NULL, "dm_otherparent", NULL},
360 {NULL} /* Sentinel */
360 {NULL} /* Sentinel */
361 };
361 };
362
362
363 PyTypeObject dirstateItemType = {
363 PyTypeObject dirstateItemType = {
364 PyVarObject_HEAD_INIT(NULL, 0) /* header */
364 PyVarObject_HEAD_INIT(NULL, 0) /* header */
365 "dirstate_tuple", /* tp_name */
365 "dirstate_tuple", /* tp_name */
366 sizeof(dirstateItemObject), /* tp_basicsize */
366 sizeof(dirstateItemObject), /* tp_basicsize */
367 0, /* tp_itemsize */
367 0, /* tp_itemsize */
368 (destructor)dirstate_item_dealloc, /* tp_dealloc */
368 (destructor)dirstate_item_dealloc, /* tp_dealloc */
369 0, /* tp_print */
369 0, /* tp_print */
370 0, /* tp_getattr */
370 0, /* tp_getattr */
371 0, /* tp_setattr */
371 0, /* tp_setattr */
372 0, /* tp_compare */
372 0, /* tp_compare */
373 0, /* tp_repr */
373 0, /* tp_repr */
374 0, /* tp_as_number */
374 0, /* tp_as_number */
375 &dirstate_item_sq, /* tp_as_sequence */
375 &dirstate_item_sq, /* tp_as_sequence */
376 0, /* tp_as_mapping */
376 0, /* tp_as_mapping */
377 0, /* tp_hash */
377 0, /* tp_hash */
378 0, /* tp_call */
378 0, /* tp_call */
379 0, /* tp_str */
379 0, /* tp_str */
380 0, /* tp_getattro */
380 0, /* tp_getattro */
381 0, /* tp_setattro */
381 0, /* tp_setattro */
382 0, /* tp_as_buffer */
382 0, /* tp_as_buffer */
383 Py_TPFLAGS_DEFAULT, /* tp_flags */
383 Py_TPFLAGS_DEFAULT, /* tp_flags */
384 "dirstate tuple", /* tp_doc */
384 "dirstate tuple", /* tp_doc */
385 0, /* tp_traverse */
385 0, /* tp_traverse */
386 0, /* tp_clear */
386 0, /* tp_clear */
387 0, /* tp_richcompare */
387 0, /* tp_richcompare */
388 0, /* tp_weaklistoffset */
388 0, /* tp_weaklistoffset */
389 0, /* tp_iter */
389 0, /* tp_iter */
390 0, /* tp_iternext */
390 0, /* tp_iternext */
391 dirstate_item_methods, /* tp_methods */
391 dirstate_item_methods, /* tp_methods */
392 0, /* tp_members */
392 0, /* tp_members */
393 dirstate_item_getset, /* tp_getset */
393 dirstate_item_getset, /* tp_getset */
394 0, /* tp_base */
394 0, /* tp_base */
395 0, /* tp_dict */
395 0, /* tp_dict */
396 0, /* tp_descr_get */
396 0, /* tp_descr_get */
397 0, /* tp_descr_set */
397 0, /* tp_descr_set */
398 0, /* tp_dictoffset */
398 0, /* tp_dictoffset */
399 0, /* tp_init */
399 0, /* tp_init */
400 0, /* tp_alloc */
400 0, /* tp_alloc */
401 dirstate_item_new, /* tp_new */
401 dirstate_item_new, /* tp_new */
402 };
402 };
403
403
404 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
404 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
405 {
405 {
406 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
406 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
407 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
407 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
408 char state, *cur, *str, *cpos;
408 char state, *cur, *str, *cpos;
409 int mode, size, mtime;
409 int mode, size, mtime;
410 unsigned int flen, pos = 40;
410 unsigned int flen, pos = 40;
411 Py_ssize_t len = 40;
411 Py_ssize_t len = 40;
412 Py_ssize_t readlen;
412 Py_ssize_t readlen;
413
413
414 if (!PyArg_ParseTuple(
414 if (!PyArg_ParseTuple(
415 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
415 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
416 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
416 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
417 goto quit;
417 goto quit;
418 }
418 }
419
419
420 len = readlen;
420 len = readlen;
421
421
422 /* read parents */
422 /* read parents */
423 if (len < 40) {
423 if (len < 40) {
424 PyErr_SetString(PyExc_ValueError,
424 PyErr_SetString(PyExc_ValueError,
425 "too little data for parents");
425 "too little data for parents");
426 goto quit;
426 goto quit;
427 }
427 }
428
428
429 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
429 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
430 str + 20, (Py_ssize_t)20);
430 str + 20, (Py_ssize_t)20);
431 if (!parents) {
431 if (!parents) {
432 goto quit;
432 goto quit;
433 }
433 }
434
434
435 /* read filenames */
435 /* read filenames */
436 while (pos >= 40 && pos < len) {
436 while (pos >= 40 && pos < len) {
437 if (pos + 17 > len) {
437 if (pos + 17 > len) {
438 PyErr_SetString(PyExc_ValueError,
438 PyErr_SetString(PyExc_ValueError,
439 "overflow in dirstate");
439 "overflow in dirstate");
440 goto quit;
440 goto quit;
441 }
441 }
442 cur = str + pos;
442 cur = str + pos;
443 /* unpack header */
443 /* unpack header */
444 state = *cur;
444 state = *cur;
445 mode = getbe32(cur + 1);
445 mode = getbe32(cur + 1);
446 size = getbe32(cur + 5);
446 size = getbe32(cur + 5);
447 mtime = getbe32(cur + 9);
447 mtime = getbe32(cur + 9);
448 flen = getbe32(cur + 13);
448 flen = getbe32(cur + 13);
449 pos += 17;
449 pos += 17;
450 cur += 17;
450 cur += 17;
451 if (flen > len - pos) {
451 if (flen > len - pos) {
452 PyErr_SetString(PyExc_ValueError,
452 PyErr_SetString(PyExc_ValueError,
453 "overflow in dirstate");
453 "overflow in dirstate");
454 goto quit;
454 goto quit;
455 }
455 }
456
456
457 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
457 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
458 size, mtime);
458 size, mtime);
459 cpos = memchr(cur, 0, flen);
459 cpos = memchr(cur, 0, flen);
460 if (cpos) {
460 if (cpos) {
461 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
461 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
462 cname = PyBytes_FromStringAndSize(
462 cname = PyBytes_FromStringAndSize(
463 cpos + 1, flen - (cpos - cur) - 1);
463 cpos + 1, flen - (cpos - cur) - 1);
464 if (!fname || !cname ||
464 if (!fname || !cname ||
465 PyDict_SetItem(cmap, fname, cname) == -1 ||
465 PyDict_SetItem(cmap, fname, cname) == -1 ||
466 PyDict_SetItem(dmap, fname, entry) == -1) {
466 PyDict_SetItem(dmap, fname, entry) == -1) {
467 goto quit;
467 goto quit;
468 }
468 }
469 Py_DECREF(cname);
469 Py_DECREF(cname);
470 } else {
470 } else {
471 fname = PyBytes_FromStringAndSize(cur, flen);
471 fname = PyBytes_FromStringAndSize(cur, flen);
472 if (!fname ||
472 if (!fname ||
473 PyDict_SetItem(dmap, fname, entry) == -1) {
473 PyDict_SetItem(dmap, fname, entry) == -1) {
474 goto quit;
474 goto quit;
475 }
475 }
476 }
476 }
477 Py_DECREF(fname);
477 Py_DECREF(fname);
478 Py_DECREF(entry);
478 Py_DECREF(entry);
479 fname = cname = entry = NULL;
479 fname = cname = entry = NULL;
480 pos += flen;
480 pos += flen;
481 }
481 }
482
482
483 ret = parents;
483 ret = parents;
484 Py_INCREF(ret);
484 Py_INCREF(ret);
485 quit:
485 quit:
486 Py_XDECREF(fname);
486 Py_XDECREF(fname);
487 Py_XDECREF(cname);
487 Py_XDECREF(cname);
488 Py_XDECREF(entry);
488 Py_XDECREF(entry);
489 Py_XDECREF(parents);
489 Py_XDECREF(parents);
490 return ret;
490 return ret;
491 }
491 }
492
492
493 /*
493 /*
494 * Build a set of non-normal and other parent entries from the dirstate dmap
494 * Build a set of non-normal and other parent entries from the dirstate dmap
495 */
495 */
496 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
496 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
497 {
497 {
498 PyObject *dmap, *fname, *v;
498 PyObject *dmap, *fname, *v;
499 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
499 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
500 Py_ssize_t pos;
500 Py_ssize_t pos;
501
501
502 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
502 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
503 &dmap)) {
503 &dmap)) {
504 goto bail;
504 goto bail;
505 }
505 }
506
506
507 nonnset = PySet_New(NULL);
507 nonnset = PySet_New(NULL);
508 if (nonnset == NULL) {
508 if (nonnset == NULL) {
509 goto bail;
509 goto bail;
510 }
510 }
511
511
512 otherpset = PySet_New(NULL);
512 otherpset = PySet_New(NULL);
513 if (otherpset == NULL) {
513 if (otherpset == NULL) {
514 goto bail;
514 goto bail;
515 }
515 }
516
516
517 pos = 0;
517 pos = 0;
518 while (PyDict_Next(dmap, &pos, &fname, &v)) {
518 while (PyDict_Next(dmap, &pos, &fname, &v)) {
519 dirstateItemObject *t;
519 dirstateItemObject *t;
520 if (!dirstate_tuple_check(v)) {
520 if (!dirstate_tuple_check(v)) {
521 PyErr_SetString(PyExc_TypeError,
521 PyErr_SetString(PyExc_TypeError,
522 "expected a dirstate tuple");
522 "expected a dirstate tuple");
523 goto bail;
523 goto bail;
524 }
524 }
525 t = (dirstateItemObject *)v;
525 t = (dirstateItemObject *)v;
526
526
527 if (t->state == 'n' && t->size == -2) {
527 if (t->state == 'n' && t->size == -2) {
528 if (PySet_Add(otherpset, fname) == -1) {
528 if (PySet_Add(otherpset, fname) == -1) {
529 goto bail;
529 goto bail;
530 }
530 }
531 }
531 }
532
532
533 if (t->state == 'n' && t->mtime != -1) {
533 if (t->state == 'n' && t->mtime != -1) {
534 continue;
534 continue;
535 }
535 }
536 if (PySet_Add(nonnset, fname) == -1) {
536 if (PySet_Add(nonnset, fname) == -1) {
537 goto bail;
537 goto bail;
538 }
538 }
539 }
539 }
540
540
541 result = Py_BuildValue("(OO)", nonnset, otherpset);
541 result = Py_BuildValue("(OO)", nonnset, otherpset);
542 if (result == NULL) {
542 if (result == NULL) {
543 goto bail;
543 goto bail;
544 }
544 }
545 Py_DECREF(nonnset);
545 Py_DECREF(nonnset);
546 Py_DECREF(otherpset);
546 Py_DECREF(otherpset);
547 return result;
547 return result;
548 bail:
548 bail:
549 Py_XDECREF(nonnset);
549 Py_XDECREF(nonnset);
550 Py_XDECREF(otherpset);
550 Py_XDECREF(otherpset);
551 Py_XDECREF(result);
551 Py_XDECREF(result);
552 return NULL;
552 return NULL;
553 }
553 }
554
554
555 /*
555 /*
556 * Efficiently pack a dirstate object into its on-disk format.
556 * Efficiently pack a dirstate object into its on-disk format.
557 */
557 */
558 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
558 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
559 {
559 {
560 PyObject *packobj = NULL;
560 PyObject *packobj = NULL;
561 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
561 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
562 Py_ssize_t nbytes, pos, l;
562 Py_ssize_t nbytes, pos, l;
563 PyObject *k, *v = NULL, *pn;
563 PyObject *k, *v = NULL, *pn;
564 char *p, *s;
564 char *p, *s;
565 int now;
565 int now;
566
566
567 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
567 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
568 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
568 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
569 &now)) {
569 &now)) {
570 return NULL;
570 return NULL;
571 }
571 }
572
572
573 if (PyTuple_Size(pl) != 2) {
573 if (PyTuple_Size(pl) != 2) {
574 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
574 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
575 return NULL;
575 return NULL;
576 }
576 }
577
577
578 /* Figure out how much we need to allocate. */
578 /* Figure out how much we need to allocate. */
579 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
579 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
580 PyObject *c;
580 PyObject *c;
581 if (!PyBytes_Check(k)) {
581 if (!PyBytes_Check(k)) {
582 PyErr_SetString(PyExc_TypeError, "expected string key");
582 PyErr_SetString(PyExc_TypeError, "expected string key");
583 goto bail;
583 goto bail;
584 }
584 }
585 nbytes += PyBytes_GET_SIZE(k) + 17;
585 nbytes += PyBytes_GET_SIZE(k) + 17;
586 c = PyDict_GetItem(copymap, k);
586 c = PyDict_GetItem(copymap, k);
587 if (c) {
587 if (c) {
588 if (!PyBytes_Check(c)) {
588 if (!PyBytes_Check(c)) {
589 PyErr_SetString(PyExc_TypeError,
589 PyErr_SetString(PyExc_TypeError,
590 "expected string key");
590 "expected string key");
591 goto bail;
591 goto bail;
592 }
592 }
593 nbytes += PyBytes_GET_SIZE(c) + 1;
593 nbytes += PyBytes_GET_SIZE(c) + 1;
594 }
594 }
595 }
595 }
596
596
597 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
597 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
598 if (packobj == NULL) {
598 if (packobj == NULL) {
599 goto bail;
599 goto bail;
600 }
600 }
601
601
602 p = PyBytes_AS_STRING(packobj);
602 p = PyBytes_AS_STRING(packobj);
603
603
604 pn = PyTuple_GET_ITEM(pl, 0);
604 pn = PyTuple_GET_ITEM(pl, 0);
605 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
605 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
606 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
606 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
607 goto bail;
607 goto bail;
608 }
608 }
609 memcpy(p, s, l);
609 memcpy(p, s, l);
610 p += 20;
610 p += 20;
611 pn = PyTuple_GET_ITEM(pl, 1);
611 pn = PyTuple_GET_ITEM(pl, 1);
612 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
612 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
613 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
613 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
614 goto bail;
614 goto bail;
615 }
615 }
616 memcpy(p, s, l);
616 memcpy(p, s, l);
617 p += 20;
617 p += 20;
618
618
619 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
619 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
620 dirstateItemObject *tuple;
620 dirstateItemObject *tuple;
621 char state;
621 char state;
622 int mode, size, mtime;
622 int mode, size, mtime;
623 Py_ssize_t len, l;
623 Py_ssize_t len, l;
624 PyObject *o;
624 PyObject *o;
625 char *t;
625 char *t;
626
626
627 if (!dirstate_tuple_check(v)) {
627 if (!dirstate_tuple_check(v)) {
628 PyErr_SetString(PyExc_TypeError,
628 PyErr_SetString(PyExc_TypeError,
629 "expected a dirstate tuple");
629 "expected a dirstate tuple");
630 goto bail;
630 goto bail;
631 }
631 }
632 tuple = (dirstateItemObject *)v;
632 tuple = (dirstateItemObject *)v;
633
633
634 state = tuple->state;
634 state = tuple->state;
635 mode = tuple->mode;
635 mode = tuple->mode;
636 size = tuple->size;
636 size = tuple->size;
637 mtime = tuple->mtime;
637 mtime = tuple->mtime;
638 if (state == 'n' && mtime == now) {
638 if (state == 'n' && mtime == now) {
639 /* See pure/parsers.py:pack_dirstate for why we do
639 /* See pure/parsers.py:pack_dirstate for why we do
640 * this. */
640 * this. */
641 mtime = -1;
641 mtime = -1;
642 mtime_unset = (PyObject *)make_dirstate_item(
642 mtime_unset = (PyObject *)make_dirstate_item(
643 state, mode, size, mtime);
643 state, mode, size, mtime);
644 if (!mtime_unset) {
644 if (!mtime_unset) {
645 goto bail;
645 goto bail;
646 }
646 }
647 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
647 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
648 goto bail;
648 goto bail;
649 }
649 }
650 Py_DECREF(mtime_unset);
650 Py_DECREF(mtime_unset);
651 mtime_unset = NULL;
651 mtime_unset = NULL;
652 }
652 }
653 *p++ = state;
653 *p++ = state;
654 putbe32((uint32_t)mode, p);
654 putbe32((uint32_t)mode, p);
655 putbe32((uint32_t)size, p + 4);
655 putbe32((uint32_t)size, p + 4);
656 putbe32((uint32_t)mtime, p + 8);
656 putbe32((uint32_t)mtime, p + 8);
657 t = p + 12;
657 t = p + 12;
658 p += 16;
658 p += 16;
659 len = PyBytes_GET_SIZE(k);
659 len = PyBytes_GET_SIZE(k);
660 memcpy(p, PyBytes_AS_STRING(k), len);
660 memcpy(p, PyBytes_AS_STRING(k), len);
661 p += len;
661 p += len;
662 o = PyDict_GetItem(copymap, k);
662 o = PyDict_GetItem(copymap, k);
663 if (o) {
663 if (o) {
664 *p++ = '\0';
664 *p++ = '\0';
665 l = PyBytes_GET_SIZE(o);
665 l = PyBytes_GET_SIZE(o);
666 memcpy(p, PyBytes_AS_STRING(o), l);
666 memcpy(p, PyBytes_AS_STRING(o), l);
667 p += l;
667 p += l;
668 len += l + 1;
668 len += l + 1;
669 }
669 }
670 putbe32((uint32_t)len, t);
670 putbe32((uint32_t)len, t);
671 }
671 }
672
672
673 pos = p - PyBytes_AS_STRING(packobj);
673 pos = p - PyBytes_AS_STRING(packobj);
674 if (pos != nbytes) {
674 if (pos != nbytes) {
675 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
675 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
676 (long)pos, (long)nbytes);
676 (long)pos, (long)nbytes);
677 goto bail;
677 goto bail;
678 }
678 }
679
679
680 return packobj;
680 return packobj;
681 bail:
681 bail:
682 Py_XDECREF(mtime_unset);
682 Py_XDECREF(mtime_unset);
683 Py_XDECREF(packobj);
683 Py_XDECREF(packobj);
684 Py_XDECREF(v);
684 Py_XDECREF(v);
685 return NULL;
685 return NULL;
686 }
686 }
687
687
688 #define BUMPED_FIX 1
688 #define BUMPED_FIX 1
689 #define USING_SHA_256 2
689 #define USING_SHA_256 2
690 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
690 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
691
691
692 static PyObject *readshas(const char *source, unsigned char num,
692 static PyObject *readshas(const char *source, unsigned char num,
693 Py_ssize_t hashwidth)
693 Py_ssize_t hashwidth)
694 {
694 {
695 int i;
695 int i;
696 PyObject *list = PyTuple_New(num);
696 PyObject *list = PyTuple_New(num);
697 if (list == NULL) {
697 if (list == NULL) {
698 return NULL;
698 return NULL;
699 }
699 }
700 for (i = 0; i < num; i++) {
700 for (i = 0; i < num; i++) {
701 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
701 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
702 if (hash == NULL) {
702 if (hash == NULL) {
703 Py_DECREF(list);
703 Py_DECREF(list);
704 return NULL;
704 return NULL;
705 }
705 }
706 PyTuple_SET_ITEM(list, i, hash);
706 PyTuple_SET_ITEM(list, i, hash);
707 source += hashwidth;
707 source += hashwidth;
708 }
708 }
709 return list;
709 return list;
710 }
710 }
711
711
712 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
712 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
713 uint32_t *msize)
713 uint32_t *msize)
714 {
714 {
715 const char *data = databegin;
715 const char *data = databegin;
716 const char *meta;
716 const char *meta;
717
717
718 double mtime;
718 double mtime;
719 int16_t tz;
719 int16_t tz;
720 uint16_t flags;
720 uint16_t flags;
721 unsigned char nsuccs, nparents, nmetadata;
721 unsigned char nsuccs, nparents, nmetadata;
722 Py_ssize_t hashwidth = 20;
722 Py_ssize_t hashwidth = 20;
723
723
724 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
724 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
725 PyObject *metadata = NULL, *ret = NULL;
725 PyObject *metadata = NULL, *ret = NULL;
726 int i;
726 int i;
727
727
728 if (data + FM1_HEADER_SIZE > dataend) {
728 if (data + FM1_HEADER_SIZE > dataend) {
729 goto overflow;
729 goto overflow;
730 }
730 }
731
731
732 *msize = getbe32(data);
732 *msize = getbe32(data);
733 data += 4;
733 data += 4;
734 mtime = getbefloat64(data);
734 mtime = getbefloat64(data);
735 data += 8;
735 data += 8;
736 tz = getbeint16(data);
736 tz = getbeint16(data);
737 data += 2;
737 data += 2;
738 flags = getbeuint16(data);
738 flags = getbeuint16(data);
739 data += 2;
739 data += 2;
740
740
741 if (flags & USING_SHA_256) {
741 if (flags & USING_SHA_256) {
742 hashwidth = 32;
742 hashwidth = 32;
743 }
743 }
744
744
745 nsuccs = (unsigned char)(*data++);
745 nsuccs = (unsigned char)(*data++);
746 nparents = (unsigned char)(*data++);
746 nparents = (unsigned char)(*data++);
747 nmetadata = (unsigned char)(*data++);
747 nmetadata = (unsigned char)(*data++);
748
748
749 if (databegin + *msize > dataend) {
749 if (databegin + *msize > dataend) {
750 goto overflow;
750 goto overflow;
751 }
751 }
752 dataend = databegin + *msize; /* narrow down to marker size */
752 dataend = databegin + *msize; /* narrow down to marker size */
753
753
754 if (data + hashwidth > dataend) {
754 if (data + hashwidth > dataend) {
755 goto overflow;
755 goto overflow;
756 }
756 }
757 prec = PyBytes_FromStringAndSize(data, hashwidth);
757 prec = PyBytes_FromStringAndSize(data, hashwidth);
758 data += hashwidth;
758 data += hashwidth;
759 if (prec == NULL) {
759 if (prec == NULL) {
760 goto bail;
760 goto bail;
761 }
761 }
762
762
763 if (data + nsuccs * hashwidth > dataend) {
763 if (data + nsuccs * hashwidth > dataend) {
764 goto overflow;
764 goto overflow;
765 }
765 }
766 succs = readshas(data, nsuccs, hashwidth);
766 succs = readshas(data, nsuccs, hashwidth);
767 if (succs == NULL) {
767 if (succs == NULL) {
768 goto bail;
768 goto bail;
769 }
769 }
770 data += nsuccs * hashwidth;
770 data += nsuccs * hashwidth;
771
771
772 if (nparents == 1 || nparents == 2) {
772 if (nparents == 1 || nparents == 2) {
773 if (data + nparents * hashwidth > dataend) {
773 if (data + nparents * hashwidth > dataend) {
774 goto overflow;
774 goto overflow;
775 }
775 }
776 parents = readshas(data, nparents, hashwidth);
776 parents = readshas(data, nparents, hashwidth);
777 if (parents == NULL) {
777 if (parents == NULL) {
778 goto bail;
778 goto bail;
779 }
779 }
780 data += nparents * hashwidth;
780 data += nparents * hashwidth;
781 } else {
781 } else {
782 parents = Py_None;
782 parents = Py_None;
783 Py_INCREF(parents);
783 Py_INCREF(parents);
784 }
784 }
785
785
786 if (data + 2 * nmetadata > dataend) {
786 if (data + 2 * nmetadata > dataend) {
787 goto overflow;
787 goto overflow;
788 }
788 }
789 meta = data + (2 * nmetadata);
789 meta = data + (2 * nmetadata);
790 metadata = PyTuple_New(nmetadata);
790 metadata = PyTuple_New(nmetadata);
791 if (metadata == NULL) {
791 if (metadata == NULL) {
792 goto bail;
792 goto bail;
793 }
793 }
794 for (i = 0; i < nmetadata; i++) {
794 for (i = 0; i < nmetadata; i++) {
795 PyObject *tmp, *left = NULL, *right = NULL;
795 PyObject *tmp, *left = NULL, *right = NULL;
796 Py_ssize_t leftsize = (unsigned char)(*data++);
796 Py_ssize_t leftsize = (unsigned char)(*data++);
797 Py_ssize_t rightsize = (unsigned char)(*data++);
797 Py_ssize_t rightsize = (unsigned char)(*data++);
798 if (meta + leftsize + rightsize > dataend) {
798 if (meta + leftsize + rightsize > dataend) {
799 goto overflow;
799 goto overflow;
800 }
800 }
801 left = PyBytes_FromStringAndSize(meta, leftsize);
801 left = PyBytes_FromStringAndSize(meta, leftsize);
802 meta += leftsize;
802 meta += leftsize;
803 right = PyBytes_FromStringAndSize(meta, rightsize);
803 right = PyBytes_FromStringAndSize(meta, rightsize);
804 meta += rightsize;
804 meta += rightsize;
805 tmp = PyTuple_New(2);
805 tmp = PyTuple_New(2);
806 if (!left || !right || !tmp) {
806 if (!left || !right || !tmp) {
807 Py_XDECREF(left);
807 Py_XDECREF(left);
808 Py_XDECREF(right);
808 Py_XDECREF(right);
809 Py_XDECREF(tmp);
809 Py_XDECREF(tmp);
810 goto bail;
810 goto bail;
811 }
811 }
812 PyTuple_SET_ITEM(tmp, 0, left);
812 PyTuple_SET_ITEM(tmp, 0, left);
813 PyTuple_SET_ITEM(tmp, 1, right);
813 PyTuple_SET_ITEM(tmp, 1, right);
814 PyTuple_SET_ITEM(metadata, i, tmp);
814 PyTuple_SET_ITEM(metadata, i, tmp);
815 }
815 }
816 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
816 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
817 (int)tz * 60, parents);
817 (int)tz * 60, parents);
818 goto bail; /* return successfully */
818 goto bail; /* return successfully */
819
819
820 overflow:
820 overflow:
821 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
821 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
822 bail:
822 bail:
823 Py_XDECREF(prec);
823 Py_XDECREF(prec);
824 Py_XDECREF(succs);
824 Py_XDECREF(succs);
825 Py_XDECREF(metadata);
825 Py_XDECREF(metadata);
826 Py_XDECREF(parents);
826 Py_XDECREF(parents);
827 return ret;
827 return ret;
828 }
828 }
829
829
830 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
830 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
831 {
831 {
832 const char *data, *dataend;
832 const char *data, *dataend;
833 Py_ssize_t datalen, offset, stop;
833 Py_ssize_t datalen, offset, stop;
834 PyObject *markers = NULL;
834 PyObject *markers = NULL;
835
835
836 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
836 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
837 &offset, &stop)) {
837 &offset, &stop)) {
838 return NULL;
838 return NULL;
839 }
839 }
840 if (offset < 0) {
840 if (offset < 0) {
841 PyErr_SetString(PyExc_ValueError,
841 PyErr_SetString(PyExc_ValueError,
842 "invalid negative offset in fm1readmarkers");
842 "invalid negative offset in fm1readmarkers");
843 return NULL;
843 return NULL;
844 }
844 }
845 if (stop > datalen) {
845 if (stop > datalen) {
846 PyErr_SetString(
846 PyErr_SetString(
847 PyExc_ValueError,
847 PyExc_ValueError,
848 "stop longer than data length in fm1readmarkers");
848 "stop longer than data length in fm1readmarkers");
849 return NULL;
849 return NULL;
850 }
850 }
851 dataend = data + datalen;
851 dataend = data + datalen;
852 data += offset;
852 data += offset;
853 markers = PyList_New(0);
853 markers = PyList_New(0);
854 if (!markers) {
854 if (!markers) {
855 return NULL;
855 return NULL;
856 }
856 }
857 while (offset < stop) {
857 while (offset < stop) {
858 uint32_t msize;
858 uint32_t msize;
859 int error;
859 int error;
860 PyObject *record = fm1readmarker(data, dataend, &msize);
860 PyObject *record = fm1readmarker(data, dataend, &msize);
861 if (!record) {
861 if (!record) {
862 goto bail;
862 goto bail;
863 }
863 }
864 error = PyList_Append(markers, record);
864 error = PyList_Append(markers, record);
865 Py_DECREF(record);
865 Py_DECREF(record);
866 if (error) {
866 if (error) {
867 goto bail;
867 goto bail;
868 }
868 }
869 data += msize;
869 data += msize;
870 offset += msize;
870 offset += msize;
871 }
871 }
872 return markers;
872 return markers;
873 bail:
873 bail:
874 Py_DECREF(markers);
874 Py_DECREF(markers);
875 return NULL;
875 return NULL;
876 }
876 }
877
877
878 static char parsers_doc[] = "Efficient content parsing.";
878 static char parsers_doc[] = "Efficient content parsing.";
879
879
880 PyObject *encodedir(PyObject *self, PyObject *args);
880 PyObject *encodedir(PyObject *self, PyObject *args);
881 PyObject *pathencode(PyObject *self, PyObject *args);
881 PyObject *pathencode(PyObject *self, PyObject *args);
882 PyObject *lowerencode(PyObject *self, PyObject *args);
882 PyObject *lowerencode(PyObject *self, PyObject *args);
883 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
883 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
884
884
885 static PyMethodDef methods[] = {
885 static PyMethodDef methods[] = {
886 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
886 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
887 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
887 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
888 "create a set containing non-normal and other parent entries of given "
888 "create a set containing non-normal and other parent entries of given "
889 "dirstate\n"},
889 "dirstate\n"},
890 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
890 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
891 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
891 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
892 "parse a revlog index\n"},
892 "parse a revlog index\n"},
893 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
893 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
894 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
894 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
895 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
895 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
896 {"dict_new_presized", dict_new_presized, METH_VARARGS,
896 {"dict_new_presized", dict_new_presized, METH_VARARGS,
897 "construct a dict with an expected size\n"},
897 "construct a dict with an expected size\n"},
898 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
898 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
899 "make file foldmap\n"},
899 "make file foldmap\n"},
900 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
900 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
901 "escape a UTF-8 byte string to JSON (fast path)\n"},
901 "escape a UTF-8 byte string to JSON (fast path)\n"},
902 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
902 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
903 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
903 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
904 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
904 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
905 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
905 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
906 "parse v1 obsolete markers\n"},
906 "parse v1 obsolete markers\n"},
907 {NULL, NULL}};
907 {NULL, NULL}};
908
908
909 void dirs_module_init(PyObject *mod);
909 void dirs_module_init(PyObject *mod);
910 void manifest_module_init(PyObject *mod);
910 void manifest_module_init(PyObject *mod);
911 void revlog_module_init(PyObject *mod);
911 void revlog_module_init(PyObject *mod);
912
912
913 static const int version = 20;
913 static const int version = 20;
914
914
915 static void module_init(PyObject *mod)
915 static void module_init(PyObject *mod)
916 {
916 {
917 PyObject *capsule = NULL;
917 PyObject *capsule = NULL;
918 PyModule_AddIntConstant(mod, "version", version);
918 PyModule_AddIntConstant(mod, "version", version);
919
919
920 /* This module constant has two purposes. First, it lets us unit test
920 /* This module constant has two purposes. First, it lets us unit test
921 * the ImportError raised without hard-coding any error text. This
921 * the ImportError raised without hard-coding any error text. This
922 * means we can change the text in the future without breaking tests,
922 * means we can change the text in the future without breaking tests,
923 * even across changesets without a recompile. Second, its presence
923 * even across changesets without a recompile. Second, its presence
924 * can be used to determine whether the version-checking logic is
924 * can be used to determine whether the version-checking logic is
925 * present, which also helps in testing across changesets without a
925 * present, which also helps in testing across changesets without a
926 * recompile. Note that this means the pure-Python version of parsers
926 * recompile. Note that this means the pure-Python version of parsers
927 * should not have this module constant. */
927 * should not have this module constant. */
928 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
928 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
929
929
930 dirs_module_init(mod);
930 dirs_module_init(mod);
931 manifest_module_init(mod);
931 manifest_module_init(mod);
932 revlog_module_init(mod);
932 revlog_module_init(mod);
933
933
934 capsule = PyCapsule_New(
934 capsule = PyCapsule_New(
935 make_dirstate_item,
935 make_dirstate_item,
936 "mercurial.cext.parsers.make_dirstate_item_CAPI", NULL);
936 "mercurial.cext.parsers.make_dirstate_item_CAPI", NULL);
937 if (capsule != NULL)
937 if (capsule != NULL)
938 PyModule_AddObject(mod, "make_dirstate_item_CAPI", capsule);
938 PyModule_AddObject(mod, "make_dirstate_item_CAPI", capsule);
939
939
940 if (PyType_Ready(&dirstateItemType) < 0) {
940 if (PyType_Ready(&dirstateItemType) < 0) {
941 return;
941 return;
942 }
942 }
943 Py_INCREF(&dirstateItemType);
943 Py_INCREF(&dirstateItemType);
944 PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
944 PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
945 }
945 }
946
946
947 static int check_python_version(void)
947 static int check_python_version(void)
948 {
948 {
949 PyObject *sys = PyImport_ImportModule("sys"), *ver;
949 PyObject *sys = PyImport_ImportModule("sys"), *ver;
950 long hexversion;
950 long hexversion;
951 if (!sys) {
951 if (!sys) {
952 return -1;
952 return -1;
953 }
953 }
954 ver = PyObject_GetAttrString(sys, "hexversion");
954 ver = PyObject_GetAttrString(sys, "hexversion");
955 Py_DECREF(sys);
955 Py_DECREF(sys);
956 if (!ver) {
956 if (!ver) {
957 return -1;
957 return -1;
958 }
958 }
959 hexversion = PyInt_AsLong(ver);
959 hexversion = PyInt_AsLong(ver);
960 Py_DECREF(ver);
960 Py_DECREF(ver);
961 /* sys.hexversion is a 32-bit number by default, so the -1 case
961 /* sys.hexversion is a 32-bit number by default, so the -1 case
962 * should only occur in unusual circumstances (e.g. if sys.hexversion
962 * should only occur in unusual circumstances (e.g. if sys.hexversion
963 * is manually set to an invalid value). */
963 * is manually set to an invalid value). */
964 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
964 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
965 PyErr_Format(PyExc_ImportError,
965 PyErr_Format(PyExc_ImportError,
966 "%s: The Mercurial extension "
966 "%s: The Mercurial extension "
967 "modules were compiled with Python " PY_VERSION
967 "modules were compiled with Python " PY_VERSION
968 ", but "
968 ", but "
969 "Mercurial is currently using Python with "
969 "Mercurial is currently using Python with "
970 "sys.hexversion=%ld: "
970 "sys.hexversion=%ld: "
971 "Python %s\n at: %s",
971 "Python %s\n at: %s",
972 versionerrortext, hexversion, Py_GetVersion(),
972 versionerrortext, hexversion, Py_GetVersion(),
973 Py_GetProgramFullPath());
973 Py_GetProgramFullPath());
974 return -1;
974 return -1;
975 }
975 }
976 return 0;
976 return 0;
977 }
977 }
978
978
979 #ifdef IS_PY3K
979 #ifdef IS_PY3K
980 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
980 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
981 parsers_doc, -1, methods};
981 parsers_doc, -1, methods};
982
982
983 PyMODINIT_FUNC PyInit_parsers(void)
983 PyMODINIT_FUNC PyInit_parsers(void)
984 {
984 {
985 PyObject *mod;
985 PyObject *mod;
986
986
987 if (check_python_version() == -1)
987 if (check_python_version() == -1)
988 return NULL;
988 return NULL;
989 mod = PyModule_Create(&parsers_module);
989 mod = PyModule_Create(&parsers_module);
990 module_init(mod);
990 module_init(mod);
991 return mod;
991 return mod;
992 }
992 }
993 #else
993 #else
994 PyMODINIT_FUNC initparsers(void)
994 PyMODINIT_FUNC initparsers(void)
995 {
995 {
996 PyObject *mod;
996 PyObject *mod;
997
997
998 if (check_python_version() == -1) {
998 if (check_python_version() == -1) {
999 return;
999 return;
1000 }
1000 }
1001 mod = Py_InitModule3("parsers", methods, parsers_doc);
1001 mod = Py_InitModule3("parsers", methods, parsers_doc);
1002 module_init(mod);
1002 module_init(mod);
1003 }
1003 }
1004 #endif
1004 #endif
General Comments 0
You need to be logged in to leave comments. Login now