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