##// END OF EJS Templates
dirstate: fix parse_dirstate() to error out if NULL entry created...
Yuya Nishihara -
r48839:13efd8fd default
parent child Browse files
Show More
@@ -1,1320 +1,1322 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 PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
47 static PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
48 PyObject *kwds)
48 PyObject *kwds)
49 {
49 {
50 /* We do all the initialization here and not a tp_init function because
50 /* We do all the initialization here and not a tp_init function because
51 * dirstate_item is immutable. */
51 * dirstate_item is immutable. */
52 dirstateItemObject *t;
52 dirstateItemObject *t;
53 int wc_tracked;
53 int wc_tracked;
54 int p1_tracked;
54 int p1_tracked;
55 int p2_tracked;
55 int p2_tracked;
56 int merged;
56 int merged;
57 int clean_p1;
57 int clean_p1;
58 int clean_p2;
58 int clean_p2;
59 int possibly_dirty;
59 int possibly_dirty;
60 PyObject *parentfiledata;
60 PyObject *parentfiledata;
61 static char *keywords_name[] = {
61 static char *keywords_name[] = {
62 "wc_tracked", "p1_tracked", "p2_tracked",
62 "wc_tracked", "p1_tracked", "p2_tracked",
63 "merged", "clean_p1", "clean_p2",
63 "merged", "clean_p1", "clean_p2",
64 "possibly_dirty", "parentfiledata", NULL,
64 "possibly_dirty", "parentfiledata", NULL,
65 };
65 };
66 wc_tracked = 0;
66 wc_tracked = 0;
67 p1_tracked = 0;
67 p1_tracked = 0;
68 p2_tracked = 0;
68 p2_tracked = 0;
69 merged = 0;
69 merged = 0;
70 clean_p1 = 0;
70 clean_p1 = 0;
71 clean_p2 = 0;
71 clean_p2 = 0;
72 possibly_dirty = 0;
72 possibly_dirty = 0;
73 parentfiledata = Py_None;
73 parentfiledata = Py_None;
74 if (!PyArg_ParseTupleAndKeywords(args, kwds, "iiiiiiiO", keywords_name,
74 if (!PyArg_ParseTupleAndKeywords(args, kwds, "iiiiiiiO", keywords_name,
75 &wc_tracked, &p1_tracked, &p2_tracked,
75 &wc_tracked, &p1_tracked, &p2_tracked,
76 &merged, &clean_p1, &clean_p2,
76 &merged, &clean_p1, &clean_p2,
77 &possibly_dirty, &parentfiledata
77 &possibly_dirty, &parentfiledata
78
78
79 )) {
79 )) {
80 return NULL;
80 return NULL;
81 }
81 }
82 if (merged && (clean_p1 || clean_p2)) {
82 if (merged && (clean_p1 || clean_p2)) {
83 PyErr_SetString(PyExc_RuntimeError,
83 PyErr_SetString(PyExc_RuntimeError,
84 "`merged` argument incompatible with "
84 "`merged` argument incompatible with "
85 "`clean_p1`/`clean_p2`");
85 "`clean_p1`/`clean_p2`");
86 return NULL;
86 return NULL;
87 }
87 }
88 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
88 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
89 if (!t) {
89 if (!t) {
90 return NULL;
90 return NULL;
91 }
91 }
92
92
93 t->flags = 0;
93 t->flags = 0;
94 if (wc_tracked) {
94 if (wc_tracked) {
95 t->flags |= dirstate_flag_wc_tracked;
95 t->flags |= dirstate_flag_wc_tracked;
96 }
96 }
97 if (p1_tracked) {
97 if (p1_tracked) {
98 t->flags |= dirstate_flag_p1_tracked;
98 t->flags |= dirstate_flag_p1_tracked;
99 }
99 }
100 if (p2_tracked) {
100 if (p2_tracked) {
101 t->flags |= dirstate_flag_p2_tracked;
101 t->flags |= dirstate_flag_p2_tracked;
102 }
102 }
103 if (possibly_dirty) {
103 if (possibly_dirty) {
104 t->flags |= dirstate_flag_possibly_dirty;
104 t->flags |= dirstate_flag_possibly_dirty;
105 }
105 }
106 if (merged) {
106 if (merged) {
107 t->flags |= dirstate_flag_merged;
107 t->flags |= dirstate_flag_merged;
108 }
108 }
109 if (clean_p1) {
109 if (clean_p1) {
110 t->flags |= dirstate_flag_clean_p1;
110 t->flags |= dirstate_flag_clean_p1;
111 }
111 }
112 if (clean_p2) {
112 if (clean_p2) {
113 t->flags |= dirstate_flag_clean_p2;
113 t->flags |= dirstate_flag_clean_p2;
114 }
114 }
115 t->mode = 0;
115 t->mode = 0;
116 t->size = dirstate_v1_nonnormal;
116 t->size = dirstate_v1_nonnormal;
117 t->mtime = ambiguous_time;
117 t->mtime = ambiguous_time;
118 if (parentfiledata != Py_None) {
118 if (parentfiledata != Py_None) {
119 if (!PyTuple_CheckExact(parentfiledata)) {
119 if (!PyTuple_CheckExact(parentfiledata)) {
120 PyErr_SetString(
120 PyErr_SetString(
121 PyExc_TypeError,
121 PyExc_TypeError,
122 "parentfiledata should be a Tuple or None");
122 "parentfiledata should be a Tuple or None");
123 return NULL;
123 return NULL;
124 }
124 }
125 t->mode =
125 t->mode =
126 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 0));
126 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 0));
127 t->size =
127 t->size =
128 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 1));
128 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 1));
129 t->mtime =
129 t->mtime =
130 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 2));
130 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 2));
131 }
131 }
132 return (PyObject *)t;
132 return (PyObject *)t;
133 }
133 }
134
134
135 static void dirstate_item_dealloc(PyObject *o)
135 static void dirstate_item_dealloc(PyObject *o)
136 {
136 {
137 PyObject_Del(o);
137 PyObject_Del(o);
138 }
138 }
139
139
140 static inline bool dirstate_item_c_tracked(dirstateItemObject *self)
140 static inline bool dirstate_item_c_tracked(dirstateItemObject *self)
141 {
141 {
142 return (self->flags & dirstate_flag_wc_tracked);
142 return (self->flags & dirstate_flag_wc_tracked);
143 }
143 }
144
144
145 static inline bool dirstate_item_c_added(dirstateItemObject *self)
145 static inline bool dirstate_item_c_added(dirstateItemObject *self)
146 {
146 {
147 unsigned char mask =
147 unsigned char mask =
148 (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
148 (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
149 dirstate_flag_p2_tracked);
149 dirstate_flag_p2_tracked);
150 unsigned char target = dirstate_flag_wc_tracked;
150 unsigned char target = dirstate_flag_wc_tracked;
151 return (self->flags & mask) == target;
151 return (self->flags & mask) == target;
152 }
152 }
153
153
154 static inline bool dirstate_item_c_removed(dirstateItemObject *self)
154 static inline bool dirstate_item_c_removed(dirstateItemObject *self)
155 {
155 {
156 if (self->flags & dirstate_flag_wc_tracked) {
156 if (self->flags & dirstate_flag_wc_tracked) {
157 return false;
157 return false;
158 }
158 }
159 return (self->flags &
159 return (self->flags &
160 (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked));
160 (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked));
161 }
161 }
162
162
163 static inline bool dirstate_item_c_merged(dirstateItemObject *self)
163 static inline bool dirstate_item_c_merged(dirstateItemObject *self)
164 {
164 {
165 return ((self->flags & dirstate_flag_wc_tracked) &&
165 return ((self->flags & dirstate_flag_wc_tracked) &&
166 (self->flags & dirstate_flag_merged));
166 (self->flags & dirstate_flag_merged));
167 }
167 }
168
168
169 static inline bool dirstate_item_c_merged_removed(dirstateItemObject *self)
169 static inline bool dirstate_item_c_merged_removed(dirstateItemObject *self)
170 {
170 {
171 if (!dirstate_item_c_removed(self)) {
171 if (!dirstate_item_c_removed(self)) {
172 return false;
172 return false;
173 }
173 }
174 return (self->flags & dirstate_flag_merged);
174 return (self->flags & dirstate_flag_merged);
175 }
175 }
176
176
177 static inline bool dirstate_item_c_from_p2(dirstateItemObject *self)
177 static inline bool dirstate_item_c_from_p2(dirstateItemObject *self)
178 {
178 {
179 if (!dirstate_item_c_tracked(self)) {
179 if (!dirstate_item_c_tracked(self)) {
180 return false;
180 return false;
181 }
181 }
182 return (self->flags & dirstate_flag_clean_p2);
182 return (self->flags & dirstate_flag_clean_p2);
183 }
183 }
184
184
185 static inline bool dirstate_item_c_from_p2_removed(dirstateItemObject *self)
185 static inline bool dirstate_item_c_from_p2_removed(dirstateItemObject *self)
186 {
186 {
187 if (!dirstate_item_c_removed(self)) {
187 if (!dirstate_item_c_removed(self)) {
188 return false;
188 return false;
189 }
189 }
190 return (self->flags & dirstate_flag_clean_p2);
190 return (self->flags & dirstate_flag_clean_p2);
191 }
191 }
192
192
193 static inline char dirstate_item_c_v1_state(dirstateItemObject *self)
193 static inline char dirstate_item_c_v1_state(dirstateItemObject *self)
194 {
194 {
195 if (dirstate_item_c_removed(self)) {
195 if (dirstate_item_c_removed(self)) {
196 return 'r';
196 return 'r';
197 } else if (dirstate_item_c_merged(self)) {
197 } else if (dirstate_item_c_merged(self)) {
198 return 'm';
198 return 'm';
199 } else if (dirstate_item_c_added(self)) {
199 } else if (dirstate_item_c_added(self)) {
200 return 'a';
200 return 'a';
201 } else {
201 } else {
202 return 'n';
202 return 'n';
203 }
203 }
204 }
204 }
205
205
206 static inline int dirstate_item_c_v1_mode(dirstateItemObject *self)
206 static inline int dirstate_item_c_v1_mode(dirstateItemObject *self)
207 {
207 {
208 return self->mode;
208 return self->mode;
209 }
209 }
210
210
211 static inline int dirstate_item_c_v1_size(dirstateItemObject *self)
211 static inline int dirstate_item_c_v1_size(dirstateItemObject *self)
212 {
212 {
213 if (dirstate_item_c_merged_removed(self)) {
213 if (dirstate_item_c_merged_removed(self)) {
214 return dirstate_v1_nonnormal;
214 return dirstate_v1_nonnormal;
215 } else if (dirstate_item_c_from_p2_removed(self)) {
215 } else if (dirstate_item_c_from_p2_removed(self)) {
216 return dirstate_v1_from_p2;
216 return dirstate_v1_from_p2;
217 } else if (dirstate_item_c_removed(self)) {
217 } else if (dirstate_item_c_removed(self)) {
218 return 0;
218 return 0;
219 } else if (dirstate_item_c_merged(self)) {
219 } else if (dirstate_item_c_merged(self)) {
220 return dirstate_v1_from_p2;
220 return dirstate_v1_from_p2;
221 } else if (dirstate_item_c_added(self)) {
221 } else if (dirstate_item_c_added(self)) {
222 return dirstate_v1_nonnormal;
222 return dirstate_v1_nonnormal;
223 } else if (dirstate_item_c_from_p2(self)) {
223 } else if (dirstate_item_c_from_p2(self)) {
224 return dirstate_v1_from_p2;
224 return dirstate_v1_from_p2;
225 } else if (self->flags & dirstate_flag_possibly_dirty) {
225 } else if (self->flags & dirstate_flag_possibly_dirty) {
226 return self->size; /* NON NORMAL ? */
226 return self->size; /* NON NORMAL ? */
227 } else {
227 } else {
228 return self->size;
228 return self->size;
229 }
229 }
230 }
230 }
231
231
232 static inline int dirstate_item_c_v1_mtime(dirstateItemObject *self)
232 static inline int dirstate_item_c_v1_mtime(dirstateItemObject *self)
233 {
233 {
234 if (dirstate_item_c_removed(self)) {
234 if (dirstate_item_c_removed(self)) {
235 return 0;
235 return 0;
236 } else if (self->flags & dirstate_flag_possibly_dirty) {
236 } else if (self->flags & dirstate_flag_possibly_dirty) {
237 return ambiguous_time;
237 return ambiguous_time;
238 } else if (dirstate_item_c_merged(self)) {
238 } else if (dirstate_item_c_merged(self)) {
239 return ambiguous_time;
239 return ambiguous_time;
240 } else if (dirstate_item_c_added(self)) {
240 } else if (dirstate_item_c_added(self)) {
241 return ambiguous_time;
241 return ambiguous_time;
242 } else if (dirstate_item_c_from_p2(self)) {
242 } else if (dirstate_item_c_from_p2(self)) {
243 return ambiguous_time;
243 return ambiguous_time;
244 } else {
244 } else {
245 return self->mtime;
245 return self->mtime;
246 }
246 }
247 }
247 }
248
248
249 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
249 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
250 {
250 {
251 char state = dirstate_item_c_v1_state(self);
251 char state = dirstate_item_c_v1_state(self);
252 return PyBytes_FromStringAndSize(&state, 1);
252 return PyBytes_FromStringAndSize(&state, 1);
253 };
253 };
254
254
255 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
255 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
256 {
256 {
257 return PyInt_FromLong(dirstate_item_c_v1_mode(self));
257 return PyInt_FromLong(dirstate_item_c_v1_mode(self));
258 };
258 };
259
259
260 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
260 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
261 {
261 {
262 return PyInt_FromLong(dirstate_item_c_v1_size(self));
262 return PyInt_FromLong(dirstate_item_c_v1_size(self));
263 };
263 };
264
264
265 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
265 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
266 {
266 {
267 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
267 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
268 };
268 };
269
269
270 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
270 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
271 PyObject *value)
271 PyObject *value)
272 {
272 {
273 long now;
273 long now;
274 if (!pylong_to_long(value, &now)) {
274 if (!pylong_to_long(value, &now)) {
275 return NULL;
275 return NULL;
276 }
276 }
277 if (dirstate_item_c_v1_state(self) == 'n' &&
277 if (dirstate_item_c_v1_state(self) == 'n' &&
278 dirstate_item_c_v1_mtime(self) == now) {
278 dirstate_item_c_v1_mtime(self) == now) {
279 Py_RETURN_TRUE;
279 Py_RETURN_TRUE;
280 } else {
280 } else {
281 Py_RETURN_FALSE;
281 Py_RETURN_FALSE;
282 }
282 }
283 };
283 };
284
284
285 /* This will never change since it's bound to V1
285 /* This will never change since it's bound to V1
286 */
286 */
287 static inline dirstateItemObject *
287 static inline dirstateItemObject *
288 dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
288 dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
289 {
289 {
290 dirstateItemObject *t =
290 dirstateItemObject *t =
291 PyObject_New(dirstateItemObject, &dirstateItemType);
291 PyObject_New(dirstateItemObject, &dirstateItemType);
292 if (!t) {
292 if (!t) {
293 return NULL;
293 return NULL;
294 }
294 }
295
295
296 if (state == 'm') {
296 if (state == 'm') {
297 t->flags =
297 t->flags =
298 (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
298 (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
299 dirstate_flag_p2_tracked | dirstate_flag_merged);
299 dirstate_flag_p2_tracked | dirstate_flag_merged);
300 t->mode = 0;
300 t->mode = 0;
301 t->size = dirstate_v1_from_p2;
301 t->size = dirstate_v1_from_p2;
302 t->mtime = ambiguous_time;
302 t->mtime = ambiguous_time;
303 } else if (state == 'a') {
303 } else if (state == 'a') {
304 t->flags = dirstate_flag_wc_tracked;
304 t->flags = dirstate_flag_wc_tracked;
305 t->mode = 0;
305 t->mode = 0;
306 t->size = dirstate_v1_nonnormal;
306 t->size = dirstate_v1_nonnormal;
307 t->mtime = ambiguous_time;
307 t->mtime = ambiguous_time;
308 } else if (state == 'r') {
308 } else if (state == 'r') {
309 t->mode = 0;
309 t->mode = 0;
310 t->size = 0;
310 t->size = 0;
311 t->mtime = 0;
311 t->mtime = 0;
312 if (size == dirstate_v1_nonnormal) {
312 if (size == dirstate_v1_nonnormal) {
313 t->flags =
313 t->flags =
314 (dirstate_flag_p1_tracked |
314 (dirstate_flag_p1_tracked |
315 dirstate_flag_p2_tracked | dirstate_flag_merged);
315 dirstate_flag_p2_tracked | dirstate_flag_merged);
316 } else if (size == dirstate_v1_from_p2) {
316 } else if (size == dirstate_v1_from_p2) {
317 t->flags =
317 t->flags =
318 (dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
318 (dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
319 } else {
319 } else {
320 t->flags = dirstate_flag_p1_tracked;
320 t->flags = dirstate_flag_p1_tracked;
321 }
321 }
322 } else if (state == 'n') {
322 } else if (state == 'n') {
323 if (size == dirstate_v1_from_p2) {
323 if (size == dirstate_v1_from_p2) {
324 t->flags =
324 t->flags =
325 (dirstate_flag_wc_tracked |
325 (dirstate_flag_wc_tracked |
326 dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
326 dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
327 t->mode = 0;
327 t->mode = 0;
328 t->size = dirstate_v1_from_p2;
328 t->size = dirstate_v1_from_p2;
329 t->mtime = ambiguous_time;
329 t->mtime = ambiguous_time;
330 } else if (size == dirstate_v1_nonnormal) {
330 } else if (size == dirstate_v1_nonnormal) {
331 t->flags = (dirstate_flag_wc_tracked |
331 t->flags = (dirstate_flag_wc_tracked |
332 dirstate_flag_p1_tracked |
332 dirstate_flag_p1_tracked |
333 dirstate_flag_possibly_dirty);
333 dirstate_flag_possibly_dirty);
334 t->mode = 0;
334 t->mode = 0;
335 t->size = dirstate_v1_nonnormal;
335 t->size = dirstate_v1_nonnormal;
336 t->mtime = ambiguous_time;
336 t->mtime = ambiguous_time;
337 } else if (mtime == ambiguous_time) {
337 } else if (mtime == ambiguous_time) {
338 t->flags = (dirstate_flag_wc_tracked |
338 t->flags = (dirstate_flag_wc_tracked |
339 dirstate_flag_p1_tracked |
339 dirstate_flag_p1_tracked |
340 dirstate_flag_possibly_dirty);
340 dirstate_flag_possibly_dirty);
341 t->mode = mode;
341 t->mode = mode;
342 t->size = size;
342 t->size = size;
343 t->mtime = 0;
343 t->mtime = 0;
344 } else {
344 } else {
345 t->flags = (dirstate_flag_wc_tracked |
345 t->flags = (dirstate_flag_wc_tracked |
346 dirstate_flag_p1_tracked);
346 dirstate_flag_p1_tracked);
347 t->mode = mode;
347 t->mode = mode;
348 t->size = size;
348 t->size = size;
349 t->mtime = mtime;
349 t->mtime = mtime;
350 }
350 }
351 } else {
351 } else {
352 PyErr_Format(PyExc_RuntimeError,
352 PyErr_Format(PyExc_RuntimeError,
353 "unknown state: `%c` (%d, %d, %d)", state, mode,
353 "unknown state: `%c` (%d, %d, %d)", state, mode,
354 size, mtime, NULL);
354 size, mtime, NULL);
355 return NULL;
355 return NULL;
356 }
356 }
357
357
358 return t;
358 return t;
359 }
359 }
360
360
361 /* This will never change since it's bound to V1, unlike `dirstate_item_new` */
361 /* This will never change since it's bound to V1, unlike `dirstate_item_new` */
362 static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
362 static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
363 PyObject *args)
363 PyObject *args)
364 {
364 {
365 /* We do all the initialization here and not a tp_init function because
365 /* We do all the initialization here and not a tp_init function because
366 * dirstate_item is immutable. */
366 * dirstate_item is immutable. */
367 char state;
367 char state;
368 int size, mode, mtime;
368 int size, mode, mtime;
369 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
369 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
370 return NULL;
370 return NULL;
371 }
371 }
372 return (PyObject *)dirstate_item_from_v1_data(state, mode, size, mtime);
372 return (PyObject *)dirstate_item_from_v1_data(state, mode, size, mtime);
373 };
373 };
374
374
375 /* constructor to help legacy API to build a new "added" item
375 /* constructor to help legacy API to build a new "added" item
376
376
377 Should eventually be removed */
377 Should eventually be removed */
378 static PyObject *dirstate_item_new_added(PyTypeObject *subtype)
378 static PyObject *dirstate_item_new_added(PyTypeObject *subtype)
379 {
379 {
380 dirstateItemObject *t;
380 dirstateItemObject *t;
381 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
381 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
382 if (!t) {
382 if (!t) {
383 return NULL;
383 return NULL;
384 }
384 }
385 t->flags = dirstate_flag_wc_tracked;
385 t->flags = dirstate_flag_wc_tracked;
386 t->mode = 0;
386 t->mode = 0;
387 t->size = dirstate_v1_nonnormal;
387 t->size = dirstate_v1_nonnormal;
388 t->mtime = ambiguous_time;
388 t->mtime = ambiguous_time;
389 return (PyObject *)t;
389 return (PyObject *)t;
390 };
390 };
391
391
392 /* constructor to help legacy API to build a new "merged" item
392 /* constructor to help legacy API to build a new "merged" item
393
393
394 Should eventually be removed */
394 Should eventually be removed */
395 static PyObject *dirstate_item_new_merged(PyTypeObject *subtype)
395 static PyObject *dirstate_item_new_merged(PyTypeObject *subtype)
396 {
396 {
397 dirstateItemObject *t;
397 dirstateItemObject *t;
398 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
398 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
399 if (!t) {
399 if (!t) {
400 return NULL;
400 return NULL;
401 }
401 }
402 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
402 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
403 dirstate_flag_p2_tracked | dirstate_flag_merged);
403 dirstate_flag_p2_tracked | dirstate_flag_merged);
404 t->mode = 0;
404 t->mode = 0;
405 t->size = dirstate_v1_from_p2;
405 t->size = dirstate_v1_from_p2;
406 t->mtime = ambiguous_time;
406 t->mtime = ambiguous_time;
407 return (PyObject *)t;
407 return (PyObject *)t;
408 };
408 };
409
409
410 /* constructor to help legacy API to build a new "from_p2" item
410 /* constructor to help legacy API to build a new "from_p2" item
411
411
412 Should eventually be removed */
412 Should eventually be removed */
413 static PyObject *dirstate_item_new_from_p2(PyTypeObject *subtype)
413 static PyObject *dirstate_item_new_from_p2(PyTypeObject *subtype)
414 {
414 {
415 /* We do all the initialization here and not a tp_init function because
415 /* We do all the initialization here and not a tp_init function because
416 * dirstate_item is immutable. */
416 * dirstate_item is immutable. */
417 dirstateItemObject *t;
417 dirstateItemObject *t;
418 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
418 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
419 if (!t) {
419 if (!t) {
420 return NULL;
420 return NULL;
421 }
421 }
422 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p2_tracked |
422 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p2_tracked |
423 dirstate_flag_clean_p2);
423 dirstate_flag_clean_p2);
424 t->mode = 0;
424 t->mode = 0;
425 t->size = dirstate_v1_from_p2;
425 t->size = dirstate_v1_from_p2;
426 t->mtime = ambiguous_time;
426 t->mtime = ambiguous_time;
427 return (PyObject *)t;
427 return (PyObject *)t;
428 };
428 };
429
429
430 /* constructor to help legacy API to build a new "possibly" item
430 /* constructor to help legacy API to build a new "possibly" item
431
431
432 Should eventually be removed */
432 Should eventually be removed */
433 static PyObject *dirstate_item_new_possibly_dirty(PyTypeObject *subtype)
433 static PyObject *dirstate_item_new_possibly_dirty(PyTypeObject *subtype)
434 {
434 {
435 /* We do all the initialization here and not a tp_init function because
435 /* We do all the initialization here and not a tp_init function because
436 * dirstate_item is immutable. */
436 * dirstate_item is immutable. */
437 dirstateItemObject *t;
437 dirstateItemObject *t;
438 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
438 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
439 if (!t) {
439 if (!t) {
440 return NULL;
440 return NULL;
441 }
441 }
442 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
442 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
443 dirstate_flag_possibly_dirty);
443 dirstate_flag_possibly_dirty);
444 t->mode = 0;
444 t->mode = 0;
445 t->size = dirstate_v1_nonnormal;
445 t->size = dirstate_v1_nonnormal;
446 t->mtime = ambiguous_time;
446 t->mtime = ambiguous_time;
447 return (PyObject *)t;
447 return (PyObject *)t;
448 };
448 };
449
449
450 /* constructor to help legacy API to build a new "normal" item
450 /* constructor to help legacy API to build a new "normal" item
451
451
452 Should eventually be removed */
452 Should eventually be removed */
453 static PyObject *dirstate_item_new_normal(PyTypeObject *subtype, PyObject *args)
453 static PyObject *dirstate_item_new_normal(PyTypeObject *subtype, PyObject *args)
454 {
454 {
455 /* We do all the initialization here and not a tp_init function because
455 /* We do all the initialization here and not a tp_init function because
456 * dirstate_item is immutable. */
456 * dirstate_item is immutable. */
457 dirstateItemObject *t;
457 dirstateItemObject *t;
458 int size, mode, mtime;
458 int size, mode, mtime;
459 if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
459 if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
460 return NULL;
460 return NULL;
461 }
461 }
462
462
463 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
463 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
464 if (!t) {
464 if (!t) {
465 return NULL;
465 return NULL;
466 }
466 }
467 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked);
467 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked);
468 t->mode = mode;
468 t->mode = mode;
469 t->size = size;
469 t->size = size;
470 t->mtime = mtime;
470 t->mtime = mtime;
471 return (PyObject *)t;
471 return (PyObject *)t;
472 };
472 };
473
473
474 /* This means the next status call will have to actually check its content
474 /* This means the next status call will have to actually check its content
475 to make sure it is correct. */
475 to make sure it is correct. */
476 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
476 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
477 {
477 {
478 self->flags |= dirstate_flag_possibly_dirty;
478 self->flags |= dirstate_flag_possibly_dirty;
479 Py_RETURN_NONE;
479 Py_RETURN_NONE;
480 }
480 }
481
481
482 /* See docstring of the python implementation for details */
482 /* See docstring of the python implementation for details */
483 static PyObject *dirstate_item_set_clean(dirstateItemObject *self,
483 static PyObject *dirstate_item_set_clean(dirstateItemObject *self,
484 PyObject *args)
484 PyObject *args)
485 {
485 {
486 int size, mode, mtime;
486 int size, mode, mtime;
487 if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
487 if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
488 return NULL;
488 return NULL;
489 }
489 }
490 self->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked;
490 self->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked;
491 self->mode = mode;
491 self->mode = mode;
492 self->size = size;
492 self->size = size;
493 self->mtime = mtime;
493 self->mtime = mtime;
494 Py_RETURN_NONE;
494 Py_RETURN_NONE;
495 }
495 }
496
496
497 static PyObject *dirstate_item_set_tracked(dirstateItemObject *self)
497 static PyObject *dirstate_item_set_tracked(dirstateItemObject *self)
498 {
498 {
499 self->flags |= dirstate_flag_wc_tracked;
499 self->flags |= dirstate_flag_wc_tracked;
500 self->flags |= dirstate_flag_possibly_dirty;
500 self->flags |= dirstate_flag_possibly_dirty;
501 /* size = None on the python size turn into size = NON_NORMAL when
501 /* size = None on the python size turn into size = NON_NORMAL when
502 * accessed. So the next line is currently required, but a some future
502 * accessed. So the next line is currently required, but a some future
503 * clean up would be welcome. */
503 * clean up would be welcome. */
504 self->size = dirstate_v1_nonnormal;
504 self->size = dirstate_v1_nonnormal;
505 Py_RETURN_NONE;
505 Py_RETURN_NONE;
506 }
506 }
507
507
508 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
508 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
509 {
509 {
510 self->flags &= ~dirstate_flag_wc_tracked;
510 self->flags &= ~dirstate_flag_wc_tracked;
511 self->mode = 0;
511 self->mode = 0;
512 self->mtime = 0;
512 self->mtime = 0;
513 self->size = 0;
513 self->size = 0;
514 Py_RETURN_NONE;
514 Py_RETURN_NONE;
515 }
515 }
516
516
517 static PyMethodDef dirstate_item_methods[] = {
517 static PyMethodDef dirstate_item_methods[] = {
518 {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
518 {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
519 "return a \"state\" suitable for v1 serialization"},
519 "return a \"state\" suitable for v1 serialization"},
520 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
520 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
521 "return a \"mode\" suitable for v1 serialization"},
521 "return a \"mode\" suitable for v1 serialization"},
522 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
522 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
523 "return a \"size\" suitable for v1 serialization"},
523 "return a \"size\" suitable for v1 serialization"},
524 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
524 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
525 "return a \"mtime\" suitable for v1 serialization"},
525 "return a \"mtime\" suitable for v1 serialization"},
526 {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O,
526 {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O,
527 "True if the stored mtime would be ambiguous with the current time"},
527 "True if the stored mtime would be ambiguous with the current time"},
528 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
528 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
529 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V1 data"},
529 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V1 data"},
530 {"new_added", (PyCFunction)dirstate_item_new_added,
530 {"new_added", (PyCFunction)dirstate_item_new_added,
531 METH_NOARGS | METH_CLASS,
531 METH_NOARGS | METH_CLASS,
532 "constructor to help legacy API to build a new \"added\" item"},
532 "constructor to help legacy API to build a new \"added\" item"},
533 {"new_merged", (PyCFunction)dirstate_item_new_merged,
533 {"new_merged", (PyCFunction)dirstate_item_new_merged,
534 METH_NOARGS | METH_CLASS,
534 METH_NOARGS | METH_CLASS,
535 "constructor to help legacy API to build a new \"merged\" item"},
535 "constructor to help legacy API to build a new \"merged\" item"},
536 {"new_from_p2", (PyCFunction)dirstate_item_new_from_p2,
536 {"new_from_p2", (PyCFunction)dirstate_item_new_from_p2,
537 METH_NOARGS | METH_CLASS,
537 METH_NOARGS | METH_CLASS,
538 "constructor to help legacy API to build a new \"from_p2\" item"},
538 "constructor to help legacy API to build a new \"from_p2\" item"},
539 {"new_possibly_dirty", (PyCFunction)dirstate_item_new_possibly_dirty,
539 {"new_possibly_dirty", (PyCFunction)dirstate_item_new_possibly_dirty,
540 METH_NOARGS | METH_CLASS,
540 METH_NOARGS | METH_CLASS,
541 "constructor to help legacy API to build a new \"possibly_dirty\" item"},
541 "constructor to help legacy API to build a new \"possibly_dirty\" item"},
542 {"new_normal", (PyCFunction)dirstate_item_new_normal,
542 {"new_normal", (PyCFunction)dirstate_item_new_normal,
543 METH_VARARGS | METH_CLASS,
543 METH_VARARGS | METH_CLASS,
544 "constructor to help legacy API to build a new \"normal\" item"},
544 "constructor to help legacy API to build a new \"normal\" item"},
545 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
545 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
546 METH_NOARGS, "mark a file as \"possibly dirty\""},
546 METH_NOARGS, "mark a file as \"possibly dirty\""},
547 {"set_clean", (PyCFunction)dirstate_item_set_clean, METH_VARARGS,
547 {"set_clean", (PyCFunction)dirstate_item_set_clean, METH_VARARGS,
548 "mark a file as \"clean\""},
548 "mark a file as \"clean\""},
549 {"set_tracked", (PyCFunction)dirstate_item_set_tracked, METH_NOARGS,
549 {"set_tracked", (PyCFunction)dirstate_item_set_tracked, METH_NOARGS,
550 "mark a file as \"tracked\""},
550 "mark a file as \"tracked\""},
551 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
551 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
552 "mark a file as \"untracked\""},
552 "mark a file as \"untracked\""},
553 {NULL} /* Sentinel */
553 {NULL} /* Sentinel */
554 };
554 };
555
555
556 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
556 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
557 {
557 {
558 return PyInt_FromLong(dirstate_item_c_v1_mode(self));
558 return PyInt_FromLong(dirstate_item_c_v1_mode(self));
559 };
559 };
560
560
561 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
561 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
562 {
562 {
563 return PyInt_FromLong(dirstate_item_c_v1_size(self));
563 return PyInt_FromLong(dirstate_item_c_v1_size(self));
564 };
564 };
565
565
566 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
566 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
567 {
567 {
568 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
568 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
569 };
569 };
570
570
571 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
571 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
572 {
572 {
573 char state = dirstate_item_c_v1_state(self);
573 char state = dirstate_item_c_v1_state(self);
574 return PyBytes_FromStringAndSize(&state, 1);
574 return PyBytes_FromStringAndSize(&state, 1);
575 };
575 };
576
576
577 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
577 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
578 {
578 {
579 if (dirstate_item_c_tracked(self)) {
579 if (dirstate_item_c_tracked(self)) {
580 Py_RETURN_TRUE;
580 Py_RETURN_TRUE;
581 } else {
581 } else {
582 Py_RETURN_FALSE;
582 Py_RETURN_FALSE;
583 }
583 }
584 };
584 };
585
585
586 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
586 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
587 {
587 {
588 if (dirstate_item_c_added(self)) {
588 if (dirstate_item_c_added(self)) {
589 Py_RETURN_TRUE;
589 Py_RETURN_TRUE;
590 } else {
590 } else {
591 Py_RETURN_FALSE;
591 Py_RETURN_FALSE;
592 }
592 }
593 };
593 };
594
594
595 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
595 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
596 {
596 {
597 if (dirstate_item_c_merged(self)) {
597 if (dirstate_item_c_merged(self)) {
598 Py_RETURN_TRUE;
598 Py_RETURN_TRUE;
599 } else {
599 } else {
600 Py_RETURN_FALSE;
600 Py_RETURN_FALSE;
601 }
601 }
602 };
602 };
603
603
604 static PyObject *dirstate_item_get_merged_removed(dirstateItemObject *self)
604 static PyObject *dirstate_item_get_merged_removed(dirstateItemObject *self)
605 {
605 {
606 if (dirstate_item_c_merged_removed(self)) {
606 if (dirstate_item_c_merged_removed(self)) {
607 Py_RETURN_TRUE;
607 Py_RETURN_TRUE;
608 } else {
608 } else {
609 Py_RETURN_FALSE;
609 Py_RETURN_FALSE;
610 }
610 }
611 };
611 };
612
612
613 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
613 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
614 {
614 {
615 if (dirstate_item_c_from_p2(self)) {
615 if (dirstate_item_c_from_p2(self)) {
616 Py_RETURN_TRUE;
616 Py_RETURN_TRUE;
617 } else {
617 } else {
618 Py_RETURN_FALSE;
618 Py_RETURN_FALSE;
619 }
619 }
620 };
620 };
621
621
622 static PyObject *dirstate_item_get_from_p2_removed(dirstateItemObject *self)
622 static PyObject *dirstate_item_get_from_p2_removed(dirstateItemObject *self)
623 {
623 {
624 if (dirstate_item_c_from_p2_removed(self)) {
624 if (dirstate_item_c_from_p2_removed(self)) {
625 Py_RETURN_TRUE;
625 Py_RETURN_TRUE;
626 } else {
626 } else {
627 Py_RETURN_FALSE;
627 Py_RETURN_FALSE;
628 }
628 }
629 };
629 };
630
630
631 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
631 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
632 {
632 {
633 if (dirstate_item_c_removed(self)) {
633 if (dirstate_item_c_removed(self)) {
634 Py_RETURN_TRUE;
634 Py_RETURN_TRUE;
635 } else {
635 } else {
636 Py_RETURN_FALSE;
636 Py_RETURN_FALSE;
637 }
637 }
638 };
638 };
639
639
640 static PyObject *dm_nonnormal(dirstateItemObject *self)
640 static PyObject *dm_nonnormal(dirstateItemObject *self)
641 {
641 {
642 if ((dirstate_item_c_v1_state(self) != 'n') ||
642 if ((dirstate_item_c_v1_state(self) != 'n') ||
643 (dirstate_item_c_v1_mtime(self) == ambiguous_time)) {
643 (dirstate_item_c_v1_mtime(self) == ambiguous_time)) {
644 Py_RETURN_TRUE;
644 Py_RETURN_TRUE;
645 } else {
645 } else {
646 Py_RETURN_FALSE;
646 Py_RETURN_FALSE;
647 }
647 }
648 };
648 };
649 static PyObject *dm_otherparent(dirstateItemObject *self)
649 static PyObject *dm_otherparent(dirstateItemObject *self)
650 {
650 {
651 if (dirstate_item_c_v1_mtime(self) == dirstate_v1_from_p2) {
651 if (dirstate_item_c_v1_mtime(self) == dirstate_v1_from_p2) {
652 Py_RETURN_TRUE;
652 Py_RETURN_TRUE;
653 } else {
653 } else {
654 Py_RETURN_FALSE;
654 Py_RETURN_FALSE;
655 }
655 }
656 };
656 };
657
657
658 static PyGetSetDef dirstate_item_getset[] = {
658 static PyGetSetDef dirstate_item_getset[] = {
659 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
659 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
660 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
660 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
661 {"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
661 {"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
662 {"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
662 {"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
663 {"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
663 {"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
664 {"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
664 {"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
665 {"merged_removed", (getter)dirstate_item_get_merged_removed, NULL,
665 {"merged_removed", (getter)dirstate_item_get_merged_removed, NULL,
666 "merged_removed", NULL},
666 "merged_removed", NULL},
667 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
667 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
668 {"from_p2_removed", (getter)dirstate_item_get_from_p2_removed, NULL,
668 {"from_p2_removed", (getter)dirstate_item_get_from_p2_removed, NULL,
669 "from_p2_removed", NULL},
669 "from_p2_removed", NULL},
670 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
670 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
671 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
671 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
672 {"dm_nonnormal", (getter)dm_nonnormal, NULL, "dm_nonnormal", NULL},
672 {"dm_nonnormal", (getter)dm_nonnormal, NULL, "dm_nonnormal", NULL},
673 {"dm_otherparent", (getter)dm_otherparent, NULL, "dm_otherparent", NULL},
673 {"dm_otherparent", (getter)dm_otherparent, NULL, "dm_otherparent", NULL},
674 {NULL} /* Sentinel */
674 {NULL} /* Sentinel */
675 };
675 };
676
676
677 PyTypeObject dirstateItemType = {
677 PyTypeObject dirstateItemType = {
678 PyVarObject_HEAD_INIT(NULL, 0) /* header */
678 PyVarObject_HEAD_INIT(NULL, 0) /* header */
679 "dirstate_tuple", /* tp_name */
679 "dirstate_tuple", /* tp_name */
680 sizeof(dirstateItemObject), /* tp_basicsize */
680 sizeof(dirstateItemObject), /* tp_basicsize */
681 0, /* tp_itemsize */
681 0, /* tp_itemsize */
682 (destructor)dirstate_item_dealloc, /* tp_dealloc */
682 (destructor)dirstate_item_dealloc, /* tp_dealloc */
683 0, /* tp_print */
683 0, /* tp_print */
684 0, /* tp_getattr */
684 0, /* tp_getattr */
685 0, /* tp_setattr */
685 0, /* tp_setattr */
686 0, /* tp_compare */
686 0, /* tp_compare */
687 0, /* tp_repr */
687 0, /* tp_repr */
688 0, /* tp_as_number */
688 0, /* tp_as_number */
689 0, /* tp_as_sequence */
689 0, /* tp_as_sequence */
690 0, /* tp_as_mapping */
690 0, /* tp_as_mapping */
691 0, /* tp_hash */
691 0, /* tp_hash */
692 0, /* tp_call */
692 0, /* tp_call */
693 0, /* tp_str */
693 0, /* tp_str */
694 0, /* tp_getattro */
694 0, /* tp_getattro */
695 0, /* tp_setattro */
695 0, /* tp_setattro */
696 0, /* tp_as_buffer */
696 0, /* tp_as_buffer */
697 Py_TPFLAGS_DEFAULT, /* tp_flags */
697 Py_TPFLAGS_DEFAULT, /* tp_flags */
698 "dirstate tuple", /* tp_doc */
698 "dirstate tuple", /* tp_doc */
699 0, /* tp_traverse */
699 0, /* tp_traverse */
700 0, /* tp_clear */
700 0, /* tp_clear */
701 0, /* tp_richcompare */
701 0, /* tp_richcompare */
702 0, /* tp_weaklistoffset */
702 0, /* tp_weaklistoffset */
703 0, /* tp_iter */
703 0, /* tp_iter */
704 0, /* tp_iternext */
704 0, /* tp_iternext */
705 dirstate_item_methods, /* tp_methods */
705 dirstate_item_methods, /* tp_methods */
706 0, /* tp_members */
706 0, /* tp_members */
707 dirstate_item_getset, /* tp_getset */
707 dirstate_item_getset, /* tp_getset */
708 0, /* tp_base */
708 0, /* tp_base */
709 0, /* tp_dict */
709 0, /* tp_dict */
710 0, /* tp_descr_get */
710 0, /* tp_descr_get */
711 0, /* tp_descr_set */
711 0, /* tp_descr_set */
712 0, /* tp_dictoffset */
712 0, /* tp_dictoffset */
713 0, /* tp_init */
713 0, /* tp_init */
714 0, /* tp_alloc */
714 0, /* tp_alloc */
715 dirstate_item_new, /* tp_new */
715 dirstate_item_new, /* tp_new */
716 };
716 };
717
717
718 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
718 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
719 {
719 {
720 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
720 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
721 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
721 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
722 char state, *cur, *str, *cpos;
722 char state, *cur, *str, *cpos;
723 int mode, size, mtime;
723 int mode, size, mtime;
724 unsigned int flen, pos = 40;
724 unsigned int flen, pos = 40;
725 Py_ssize_t len = 40;
725 Py_ssize_t len = 40;
726 Py_ssize_t readlen;
726 Py_ssize_t readlen;
727
727
728 if (!PyArg_ParseTuple(
728 if (!PyArg_ParseTuple(
729 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
729 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
730 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
730 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
731 goto quit;
731 goto quit;
732 }
732 }
733
733
734 len = readlen;
734 len = readlen;
735
735
736 /* read parents */
736 /* read parents */
737 if (len < 40) {
737 if (len < 40) {
738 PyErr_SetString(PyExc_ValueError,
738 PyErr_SetString(PyExc_ValueError,
739 "too little data for parents");
739 "too little data for parents");
740 goto quit;
740 goto quit;
741 }
741 }
742
742
743 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
743 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
744 str + 20, (Py_ssize_t)20);
744 str + 20, (Py_ssize_t)20);
745 if (!parents) {
745 if (!parents) {
746 goto quit;
746 goto quit;
747 }
747 }
748
748
749 /* read filenames */
749 /* read filenames */
750 while (pos >= 40 && pos < len) {
750 while (pos >= 40 && pos < len) {
751 if (pos + 17 > len) {
751 if (pos + 17 > len) {
752 PyErr_SetString(PyExc_ValueError,
752 PyErr_SetString(PyExc_ValueError,
753 "overflow in dirstate");
753 "overflow in dirstate");
754 goto quit;
754 goto quit;
755 }
755 }
756 cur = str + pos;
756 cur = str + pos;
757 /* unpack header */
757 /* unpack header */
758 state = *cur;
758 state = *cur;
759 mode = getbe32(cur + 1);
759 mode = getbe32(cur + 1);
760 size = getbe32(cur + 5);
760 size = getbe32(cur + 5);
761 mtime = getbe32(cur + 9);
761 mtime = getbe32(cur + 9);
762 flen = getbe32(cur + 13);
762 flen = getbe32(cur + 13);
763 pos += 17;
763 pos += 17;
764 cur += 17;
764 cur += 17;
765 if (flen > len - pos) {
765 if (flen > len - pos) {
766 PyErr_SetString(PyExc_ValueError,
766 PyErr_SetString(PyExc_ValueError,
767 "overflow in dirstate");
767 "overflow in dirstate");
768 goto quit;
768 goto quit;
769 }
769 }
770
770
771 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
771 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
772 size, mtime);
772 size, mtime);
773 if (!entry)
774 goto quit;
773 cpos = memchr(cur, 0, flen);
775 cpos = memchr(cur, 0, flen);
774 if (cpos) {
776 if (cpos) {
775 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
777 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
776 cname = PyBytes_FromStringAndSize(
778 cname = PyBytes_FromStringAndSize(
777 cpos + 1, flen - (cpos - cur) - 1);
779 cpos + 1, flen - (cpos - cur) - 1);
778 if (!fname || !cname ||
780 if (!fname || !cname ||
779 PyDict_SetItem(cmap, fname, cname) == -1 ||
781 PyDict_SetItem(cmap, fname, cname) == -1 ||
780 PyDict_SetItem(dmap, fname, entry) == -1) {
782 PyDict_SetItem(dmap, fname, entry) == -1) {
781 goto quit;
783 goto quit;
782 }
784 }
783 Py_DECREF(cname);
785 Py_DECREF(cname);
784 } else {
786 } else {
785 fname = PyBytes_FromStringAndSize(cur, flen);
787 fname = PyBytes_FromStringAndSize(cur, flen);
786 if (!fname ||
788 if (!fname ||
787 PyDict_SetItem(dmap, fname, entry) == -1) {
789 PyDict_SetItem(dmap, fname, entry) == -1) {
788 goto quit;
790 goto quit;
789 }
791 }
790 }
792 }
791 Py_DECREF(fname);
793 Py_DECREF(fname);
792 Py_DECREF(entry);
794 Py_DECREF(entry);
793 fname = cname = entry = NULL;
795 fname = cname = entry = NULL;
794 pos += flen;
796 pos += flen;
795 }
797 }
796
798
797 ret = parents;
799 ret = parents;
798 Py_INCREF(ret);
800 Py_INCREF(ret);
799 quit:
801 quit:
800 Py_XDECREF(fname);
802 Py_XDECREF(fname);
801 Py_XDECREF(cname);
803 Py_XDECREF(cname);
802 Py_XDECREF(entry);
804 Py_XDECREF(entry);
803 Py_XDECREF(parents);
805 Py_XDECREF(parents);
804 return ret;
806 return ret;
805 }
807 }
806
808
807 /*
809 /*
808 * Build a set of non-normal and other parent entries from the dirstate dmap
810 * Build a set of non-normal and other parent entries from the dirstate dmap
809 */
811 */
810 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
812 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
811 {
813 {
812 PyObject *dmap, *fname, *v;
814 PyObject *dmap, *fname, *v;
813 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
815 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
814 Py_ssize_t pos;
816 Py_ssize_t pos;
815
817
816 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
818 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
817 &dmap)) {
819 &dmap)) {
818 goto bail;
820 goto bail;
819 }
821 }
820
822
821 nonnset = PySet_New(NULL);
823 nonnset = PySet_New(NULL);
822 if (nonnset == NULL) {
824 if (nonnset == NULL) {
823 goto bail;
825 goto bail;
824 }
826 }
825
827
826 otherpset = PySet_New(NULL);
828 otherpset = PySet_New(NULL);
827 if (otherpset == NULL) {
829 if (otherpset == NULL) {
828 goto bail;
830 goto bail;
829 }
831 }
830
832
831 pos = 0;
833 pos = 0;
832 while (PyDict_Next(dmap, &pos, &fname, &v)) {
834 while (PyDict_Next(dmap, &pos, &fname, &v)) {
833 dirstateItemObject *t;
835 dirstateItemObject *t;
834 if (!dirstate_tuple_check(v)) {
836 if (!dirstate_tuple_check(v)) {
835 PyErr_SetString(PyExc_TypeError,
837 PyErr_SetString(PyExc_TypeError,
836 "expected a dirstate tuple");
838 "expected a dirstate tuple");
837 goto bail;
839 goto bail;
838 }
840 }
839 t = (dirstateItemObject *)v;
841 t = (dirstateItemObject *)v;
840
842
841 if (dirstate_item_c_from_p2(t)) {
843 if (dirstate_item_c_from_p2(t)) {
842 if (PySet_Add(otherpset, fname) == -1) {
844 if (PySet_Add(otherpset, fname) == -1) {
843 goto bail;
845 goto bail;
844 }
846 }
845 }
847 }
846 if (!(t->flags & dirstate_flag_wc_tracked) ||
848 if (!(t->flags & dirstate_flag_wc_tracked) ||
847 !(t->flags &
849 !(t->flags &
848 (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked)) ||
850 (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked)) ||
849 (t->flags &
851 (t->flags &
850 (dirstate_flag_possibly_dirty | dirstate_flag_merged))) {
852 (dirstate_flag_possibly_dirty | dirstate_flag_merged))) {
851 if (PySet_Add(nonnset, fname) == -1) {
853 if (PySet_Add(nonnset, fname) == -1) {
852 goto bail;
854 goto bail;
853 }
855 }
854 }
856 }
855 }
857 }
856
858
857 result = Py_BuildValue("(OO)", nonnset, otherpset);
859 result = Py_BuildValue("(OO)", nonnset, otherpset);
858 if (result == NULL) {
860 if (result == NULL) {
859 goto bail;
861 goto bail;
860 }
862 }
861 Py_DECREF(nonnset);
863 Py_DECREF(nonnset);
862 Py_DECREF(otherpset);
864 Py_DECREF(otherpset);
863 return result;
865 return result;
864 bail:
866 bail:
865 Py_XDECREF(nonnset);
867 Py_XDECREF(nonnset);
866 Py_XDECREF(otherpset);
868 Py_XDECREF(otherpset);
867 Py_XDECREF(result);
869 Py_XDECREF(result);
868 return NULL;
870 return NULL;
869 }
871 }
870
872
871 /*
873 /*
872 * Efficiently pack a dirstate object into its on-disk format.
874 * Efficiently pack a dirstate object into its on-disk format.
873 */
875 */
874 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
876 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
875 {
877 {
876 PyObject *packobj = NULL;
878 PyObject *packobj = NULL;
877 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
879 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
878 Py_ssize_t nbytes, pos, l;
880 Py_ssize_t nbytes, pos, l;
879 PyObject *k, *v = NULL, *pn;
881 PyObject *k, *v = NULL, *pn;
880 char *p, *s;
882 char *p, *s;
881 int now;
883 int now;
882
884
883 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
885 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
884 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
886 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
885 &now)) {
887 &now)) {
886 return NULL;
888 return NULL;
887 }
889 }
888
890
889 if (PyTuple_Size(pl) != 2) {
891 if (PyTuple_Size(pl) != 2) {
890 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
892 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
891 return NULL;
893 return NULL;
892 }
894 }
893
895
894 /* Figure out how much we need to allocate. */
896 /* Figure out how much we need to allocate. */
895 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
897 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
896 PyObject *c;
898 PyObject *c;
897 if (!PyBytes_Check(k)) {
899 if (!PyBytes_Check(k)) {
898 PyErr_SetString(PyExc_TypeError, "expected string key");
900 PyErr_SetString(PyExc_TypeError, "expected string key");
899 goto bail;
901 goto bail;
900 }
902 }
901 nbytes += PyBytes_GET_SIZE(k) + 17;
903 nbytes += PyBytes_GET_SIZE(k) + 17;
902 c = PyDict_GetItem(copymap, k);
904 c = PyDict_GetItem(copymap, k);
903 if (c) {
905 if (c) {
904 if (!PyBytes_Check(c)) {
906 if (!PyBytes_Check(c)) {
905 PyErr_SetString(PyExc_TypeError,
907 PyErr_SetString(PyExc_TypeError,
906 "expected string key");
908 "expected string key");
907 goto bail;
909 goto bail;
908 }
910 }
909 nbytes += PyBytes_GET_SIZE(c) + 1;
911 nbytes += PyBytes_GET_SIZE(c) + 1;
910 }
912 }
911 }
913 }
912
914
913 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
915 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
914 if (packobj == NULL) {
916 if (packobj == NULL) {
915 goto bail;
917 goto bail;
916 }
918 }
917
919
918 p = PyBytes_AS_STRING(packobj);
920 p = PyBytes_AS_STRING(packobj);
919
921
920 pn = PyTuple_GET_ITEM(pl, 0);
922 pn = PyTuple_GET_ITEM(pl, 0);
921 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
923 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
922 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
924 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
923 goto bail;
925 goto bail;
924 }
926 }
925 memcpy(p, s, l);
927 memcpy(p, s, l);
926 p += 20;
928 p += 20;
927 pn = PyTuple_GET_ITEM(pl, 1);
929 pn = PyTuple_GET_ITEM(pl, 1);
928 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
930 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
929 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
931 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
930 goto bail;
932 goto bail;
931 }
933 }
932 memcpy(p, s, l);
934 memcpy(p, s, l);
933 p += 20;
935 p += 20;
934
936
935 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
937 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
936 dirstateItemObject *tuple;
938 dirstateItemObject *tuple;
937 char state;
939 char state;
938 int mode, size, mtime;
940 int mode, size, mtime;
939 Py_ssize_t len, l;
941 Py_ssize_t len, l;
940 PyObject *o;
942 PyObject *o;
941 char *t;
943 char *t;
942
944
943 if (!dirstate_tuple_check(v)) {
945 if (!dirstate_tuple_check(v)) {
944 PyErr_SetString(PyExc_TypeError,
946 PyErr_SetString(PyExc_TypeError,
945 "expected a dirstate tuple");
947 "expected a dirstate tuple");
946 goto bail;
948 goto bail;
947 }
949 }
948 tuple = (dirstateItemObject *)v;
950 tuple = (dirstateItemObject *)v;
949
951
950 state = dirstate_item_c_v1_state(tuple);
952 state = dirstate_item_c_v1_state(tuple);
951 mode = dirstate_item_c_v1_mode(tuple);
953 mode = dirstate_item_c_v1_mode(tuple);
952 size = dirstate_item_c_v1_size(tuple);
954 size = dirstate_item_c_v1_size(tuple);
953 mtime = dirstate_item_c_v1_mtime(tuple);
955 mtime = dirstate_item_c_v1_mtime(tuple);
954 if (state == 'n' && mtime == now) {
956 if (state == 'n' && mtime == now) {
955 /* See pure/parsers.py:pack_dirstate for why we do
957 /* See pure/parsers.py:pack_dirstate for why we do
956 * this. */
958 * this. */
957 mtime = -1;
959 mtime = -1;
958 mtime_unset = (PyObject *)dirstate_item_from_v1_data(
960 mtime_unset = (PyObject *)dirstate_item_from_v1_data(
959 state, mode, size, mtime);
961 state, mode, size, mtime);
960 if (!mtime_unset) {
962 if (!mtime_unset) {
961 goto bail;
963 goto bail;
962 }
964 }
963 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
965 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
964 goto bail;
966 goto bail;
965 }
967 }
966 Py_DECREF(mtime_unset);
968 Py_DECREF(mtime_unset);
967 mtime_unset = NULL;
969 mtime_unset = NULL;
968 }
970 }
969 *p++ = state;
971 *p++ = state;
970 putbe32((uint32_t)mode, p);
972 putbe32((uint32_t)mode, p);
971 putbe32((uint32_t)size, p + 4);
973 putbe32((uint32_t)size, p + 4);
972 putbe32((uint32_t)mtime, p + 8);
974 putbe32((uint32_t)mtime, p + 8);
973 t = p + 12;
975 t = p + 12;
974 p += 16;
976 p += 16;
975 len = PyBytes_GET_SIZE(k);
977 len = PyBytes_GET_SIZE(k);
976 memcpy(p, PyBytes_AS_STRING(k), len);
978 memcpy(p, PyBytes_AS_STRING(k), len);
977 p += len;
979 p += len;
978 o = PyDict_GetItem(copymap, k);
980 o = PyDict_GetItem(copymap, k);
979 if (o) {
981 if (o) {
980 *p++ = '\0';
982 *p++ = '\0';
981 l = PyBytes_GET_SIZE(o);
983 l = PyBytes_GET_SIZE(o);
982 memcpy(p, PyBytes_AS_STRING(o), l);
984 memcpy(p, PyBytes_AS_STRING(o), l);
983 p += l;
985 p += l;
984 len += l + 1;
986 len += l + 1;
985 }
987 }
986 putbe32((uint32_t)len, t);
988 putbe32((uint32_t)len, t);
987 }
989 }
988
990
989 pos = p - PyBytes_AS_STRING(packobj);
991 pos = p - PyBytes_AS_STRING(packobj);
990 if (pos != nbytes) {
992 if (pos != nbytes) {
991 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
993 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
992 (long)pos, (long)nbytes);
994 (long)pos, (long)nbytes);
993 goto bail;
995 goto bail;
994 }
996 }
995
997
996 return packobj;
998 return packobj;
997 bail:
999 bail:
998 Py_XDECREF(mtime_unset);
1000 Py_XDECREF(mtime_unset);
999 Py_XDECREF(packobj);
1001 Py_XDECREF(packobj);
1000 Py_XDECREF(v);
1002 Py_XDECREF(v);
1001 return NULL;
1003 return NULL;
1002 }
1004 }
1003
1005
1004 #define BUMPED_FIX 1
1006 #define BUMPED_FIX 1
1005 #define USING_SHA_256 2
1007 #define USING_SHA_256 2
1006 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
1008 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
1007
1009
1008 static PyObject *readshas(const char *source, unsigned char num,
1010 static PyObject *readshas(const char *source, unsigned char num,
1009 Py_ssize_t hashwidth)
1011 Py_ssize_t hashwidth)
1010 {
1012 {
1011 int i;
1013 int i;
1012 PyObject *list = PyTuple_New(num);
1014 PyObject *list = PyTuple_New(num);
1013 if (list == NULL) {
1015 if (list == NULL) {
1014 return NULL;
1016 return NULL;
1015 }
1017 }
1016 for (i = 0; i < num; i++) {
1018 for (i = 0; i < num; i++) {
1017 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
1019 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
1018 if (hash == NULL) {
1020 if (hash == NULL) {
1019 Py_DECREF(list);
1021 Py_DECREF(list);
1020 return NULL;
1022 return NULL;
1021 }
1023 }
1022 PyTuple_SET_ITEM(list, i, hash);
1024 PyTuple_SET_ITEM(list, i, hash);
1023 source += hashwidth;
1025 source += hashwidth;
1024 }
1026 }
1025 return list;
1027 return list;
1026 }
1028 }
1027
1029
1028 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
1030 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
1029 uint32_t *msize)
1031 uint32_t *msize)
1030 {
1032 {
1031 const char *data = databegin;
1033 const char *data = databegin;
1032 const char *meta;
1034 const char *meta;
1033
1035
1034 double mtime;
1036 double mtime;
1035 int16_t tz;
1037 int16_t tz;
1036 uint16_t flags;
1038 uint16_t flags;
1037 unsigned char nsuccs, nparents, nmetadata;
1039 unsigned char nsuccs, nparents, nmetadata;
1038 Py_ssize_t hashwidth = 20;
1040 Py_ssize_t hashwidth = 20;
1039
1041
1040 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
1042 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
1041 PyObject *metadata = NULL, *ret = NULL;
1043 PyObject *metadata = NULL, *ret = NULL;
1042 int i;
1044 int i;
1043
1045
1044 if (data + FM1_HEADER_SIZE > dataend) {
1046 if (data + FM1_HEADER_SIZE > dataend) {
1045 goto overflow;
1047 goto overflow;
1046 }
1048 }
1047
1049
1048 *msize = getbe32(data);
1050 *msize = getbe32(data);
1049 data += 4;
1051 data += 4;
1050 mtime = getbefloat64(data);
1052 mtime = getbefloat64(data);
1051 data += 8;
1053 data += 8;
1052 tz = getbeint16(data);
1054 tz = getbeint16(data);
1053 data += 2;
1055 data += 2;
1054 flags = getbeuint16(data);
1056 flags = getbeuint16(data);
1055 data += 2;
1057 data += 2;
1056
1058
1057 if (flags & USING_SHA_256) {
1059 if (flags & USING_SHA_256) {
1058 hashwidth = 32;
1060 hashwidth = 32;
1059 }
1061 }
1060
1062
1061 nsuccs = (unsigned char)(*data++);
1063 nsuccs = (unsigned char)(*data++);
1062 nparents = (unsigned char)(*data++);
1064 nparents = (unsigned char)(*data++);
1063 nmetadata = (unsigned char)(*data++);
1065 nmetadata = (unsigned char)(*data++);
1064
1066
1065 if (databegin + *msize > dataend) {
1067 if (databegin + *msize > dataend) {
1066 goto overflow;
1068 goto overflow;
1067 }
1069 }
1068 dataend = databegin + *msize; /* narrow down to marker size */
1070 dataend = databegin + *msize; /* narrow down to marker size */
1069
1071
1070 if (data + hashwidth > dataend) {
1072 if (data + hashwidth > dataend) {
1071 goto overflow;
1073 goto overflow;
1072 }
1074 }
1073 prec = PyBytes_FromStringAndSize(data, hashwidth);
1075 prec = PyBytes_FromStringAndSize(data, hashwidth);
1074 data += hashwidth;
1076 data += hashwidth;
1075 if (prec == NULL) {
1077 if (prec == NULL) {
1076 goto bail;
1078 goto bail;
1077 }
1079 }
1078
1080
1079 if (data + nsuccs * hashwidth > dataend) {
1081 if (data + nsuccs * hashwidth > dataend) {
1080 goto overflow;
1082 goto overflow;
1081 }
1083 }
1082 succs = readshas(data, nsuccs, hashwidth);
1084 succs = readshas(data, nsuccs, hashwidth);
1083 if (succs == NULL) {
1085 if (succs == NULL) {
1084 goto bail;
1086 goto bail;
1085 }
1087 }
1086 data += nsuccs * hashwidth;
1088 data += nsuccs * hashwidth;
1087
1089
1088 if (nparents == 1 || nparents == 2) {
1090 if (nparents == 1 || nparents == 2) {
1089 if (data + nparents * hashwidth > dataend) {
1091 if (data + nparents * hashwidth > dataend) {
1090 goto overflow;
1092 goto overflow;
1091 }
1093 }
1092 parents = readshas(data, nparents, hashwidth);
1094 parents = readshas(data, nparents, hashwidth);
1093 if (parents == NULL) {
1095 if (parents == NULL) {
1094 goto bail;
1096 goto bail;
1095 }
1097 }
1096 data += nparents * hashwidth;
1098 data += nparents * hashwidth;
1097 } else {
1099 } else {
1098 parents = Py_None;
1100 parents = Py_None;
1099 Py_INCREF(parents);
1101 Py_INCREF(parents);
1100 }
1102 }
1101
1103
1102 if (data + 2 * nmetadata > dataend) {
1104 if (data + 2 * nmetadata > dataend) {
1103 goto overflow;
1105 goto overflow;
1104 }
1106 }
1105 meta = data + (2 * nmetadata);
1107 meta = data + (2 * nmetadata);
1106 metadata = PyTuple_New(nmetadata);
1108 metadata = PyTuple_New(nmetadata);
1107 if (metadata == NULL) {
1109 if (metadata == NULL) {
1108 goto bail;
1110 goto bail;
1109 }
1111 }
1110 for (i = 0; i < nmetadata; i++) {
1112 for (i = 0; i < nmetadata; i++) {
1111 PyObject *tmp, *left = NULL, *right = NULL;
1113 PyObject *tmp, *left = NULL, *right = NULL;
1112 Py_ssize_t leftsize = (unsigned char)(*data++);
1114 Py_ssize_t leftsize = (unsigned char)(*data++);
1113 Py_ssize_t rightsize = (unsigned char)(*data++);
1115 Py_ssize_t rightsize = (unsigned char)(*data++);
1114 if (meta + leftsize + rightsize > dataend) {
1116 if (meta + leftsize + rightsize > dataend) {
1115 goto overflow;
1117 goto overflow;
1116 }
1118 }
1117 left = PyBytes_FromStringAndSize(meta, leftsize);
1119 left = PyBytes_FromStringAndSize(meta, leftsize);
1118 meta += leftsize;
1120 meta += leftsize;
1119 right = PyBytes_FromStringAndSize(meta, rightsize);
1121 right = PyBytes_FromStringAndSize(meta, rightsize);
1120 meta += rightsize;
1122 meta += rightsize;
1121 tmp = PyTuple_New(2);
1123 tmp = PyTuple_New(2);
1122 if (!left || !right || !tmp) {
1124 if (!left || !right || !tmp) {
1123 Py_XDECREF(left);
1125 Py_XDECREF(left);
1124 Py_XDECREF(right);
1126 Py_XDECREF(right);
1125 Py_XDECREF(tmp);
1127 Py_XDECREF(tmp);
1126 goto bail;
1128 goto bail;
1127 }
1129 }
1128 PyTuple_SET_ITEM(tmp, 0, left);
1130 PyTuple_SET_ITEM(tmp, 0, left);
1129 PyTuple_SET_ITEM(tmp, 1, right);
1131 PyTuple_SET_ITEM(tmp, 1, right);
1130 PyTuple_SET_ITEM(metadata, i, tmp);
1132 PyTuple_SET_ITEM(metadata, i, tmp);
1131 }
1133 }
1132 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
1134 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
1133 (int)tz * 60, parents);
1135 (int)tz * 60, parents);
1134 goto bail; /* return successfully */
1136 goto bail; /* return successfully */
1135
1137
1136 overflow:
1138 overflow:
1137 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
1139 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
1138 bail:
1140 bail:
1139 Py_XDECREF(prec);
1141 Py_XDECREF(prec);
1140 Py_XDECREF(succs);
1142 Py_XDECREF(succs);
1141 Py_XDECREF(metadata);
1143 Py_XDECREF(metadata);
1142 Py_XDECREF(parents);
1144 Py_XDECREF(parents);
1143 return ret;
1145 return ret;
1144 }
1146 }
1145
1147
1146 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
1148 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
1147 {
1149 {
1148 const char *data, *dataend;
1150 const char *data, *dataend;
1149 Py_ssize_t datalen, offset, stop;
1151 Py_ssize_t datalen, offset, stop;
1150 PyObject *markers = NULL;
1152 PyObject *markers = NULL;
1151
1153
1152 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
1154 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
1153 &offset, &stop)) {
1155 &offset, &stop)) {
1154 return NULL;
1156 return NULL;
1155 }
1157 }
1156 if (offset < 0) {
1158 if (offset < 0) {
1157 PyErr_SetString(PyExc_ValueError,
1159 PyErr_SetString(PyExc_ValueError,
1158 "invalid negative offset in fm1readmarkers");
1160 "invalid negative offset in fm1readmarkers");
1159 return NULL;
1161 return NULL;
1160 }
1162 }
1161 if (stop > datalen) {
1163 if (stop > datalen) {
1162 PyErr_SetString(
1164 PyErr_SetString(
1163 PyExc_ValueError,
1165 PyExc_ValueError,
1164 "stop longer than data length in fm1readmarkers");
1166 "stop longer than data length in fm1readmarkers");
1165 return NULL;
1167 return NULL;
1166 }
1168 }
1167 dataend = data + datalen;
1169 dataend = data + datalen;
1168 data += offset;
1170 data += offset;
1169 markers = PyList_New(0);
1171 markers = PyList_New(0);
1170 if (!markers) {
1172 if (!markers) {
1171 return NULL;
1173 return NULL;
1172 }
1174 }
1173 while (offset < stop) {
1175 while (offset < stop) {
1174 uint32_t msize;
1176 uint32_t msize;
1175 int error;
1177 int error;
1176 PyObject *record = fm1readmarker(data, dataend, &msize);
1178 PyObject *record = fm1readmarker(data, dataend, &msize);
1177 if (!record) {
1179 if (!record) {
1178 goto bail;
1180 goto bail;
1179 }
1181 }
1180 error = PyList_Append(markers, record);
1182 error = PyList_Append(markers, record);
1181 Py_DECREF(record);
1183 Py_DECREF(record);
1182 if (error) {
1184 if (error) {
1183 goto bail;
1185 goto bail;
1184 }
1186 }
1185 data += msize;
1187 data += msize;
1186 offset += msize;
1188 offset += msize;
1187 }
1189 }
1188 return markers;
1190 return markers;
1189 bail:
1191 bail:
1190 Py_DECREF(markers);
1192 Py_DECREF(markers);
1191 return NULL;
1193 return NULL;
1192 }
1194 }
1193
1195
1194 static char parsers_doc[] = "Efficient content parsing.";
1196 static char parsers_doc[] = "Efficient content parsing.";
1195
1197
1196 PyObject *encodedir(PyObject *self, PyObject *args);
1198 PyObject *encodedir(PyObject *self, PyObject *args);
1197 PyObject *pathencode(PyObject *self, PyObject *args);
1199 PyObject *pathencode(PyObject *self, PyObject *args);
1198 PyObject *lowerencode(PyObject *self, PyObject *args);
1200 PyObject *lowerencode(PyObject *self, PyObject *args);
1199 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
1201 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
1200
1202
1201 static PyMethodDef methods[] = {
1203 static PyMethodDef methods[] = {
1202 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1204 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1203 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
1205 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
1204 "create a set containing non-normal and other parent entries of given "
1206 "create a set containing non-normal and other parent entries of given "
1205 "dirstate\n"},
1207 "dirstate\n"},
1206 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1208 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1207 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
1209 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
1208 "parse a revlog index\n"},
1210 "parse a revlog index\n"},
1209 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
1211 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
1210 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
1212 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
1211 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
1213 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
1212 {"dict_new_presized", dict_new_presized, METH_VARARGS,
1214 {"dict_new_presized", dict_new_presized, METH_VARARGS,
1213 "construct a dict with an expected size\n"},
1215 "construct a dict with an expected size\n"},
1214 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
1216 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
1215 "make file foldmap\n"},
1217 "make file foldmap\n"},
1216 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
1218 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
1217 "escape a UTF-8 byte string to JSON (fast path)\n"},
1219 "escape a UTF-8 byte string to JSON (fast path)\n"},
1218 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
1220 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
1219 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
1221 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
1220 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
1222 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
1221 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
1223 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
1222 "parse v1 obsolete markers\n"},
1224 "parse v1 obsolete markers\n"},
1223 {NULL, NULL}};
1225 {NULL, NULL}};
1224
1226
1225 void dirs_module_init(PyObject *mod);
1227 void dirs_module_init(PyObject *mod);
1226 void manifest_module_init(PyObject *mod);
1228 void manifest_module_init(PyObject *mod);
1227 void revlog_module_init(PyObject *mod);
1229 void revlog_module_init(PyObject *mod);
1228
1230
1229 static const int version = 20;
1231 static const int version = 20;
1230
1232
1231 static void module_init(PyObject *mod)
1233 static void module_init(PyObject *mod)
1232 {
1234 {
1233 PyObject *capsule = NULL;
1235 PyObject *capsule = NULL;
1234 PyModule_AddIntConstant(mod, "version", version);
1236 PyModule_AddIntConstant(mod, "version", version);
1235
1237
1236 /* This module constant has two purposes. First, it lets us unit test
1238 /* This module constant has two purposes. First, it lets us unit test
1237 * the ImportError raised without hard-coding any error text. This
1239 * the ImportError raised without hard-coding any error text. This
1238 * means we can change the text in the future without breaking tests,
1240 * means we can change the text in the future without breaking tests,
1239 * even across changesets without a recompile. Second, its presence
1241 * even across changesets without a recompile. Second, its presence
1240 * can be used to determine whether the version-checking logic is
1242 * can be used to determine whether the version-checking logic is
1241 * present, which also helps in testing across changesets without a
1243 * present, which also helps in testing across changesets without a
1242 * recompile. Note that this means the pure-Python version of parsers
1244 * recompile. Note that this means the pure-Python version of parsers
1243 * should not have this module constant. */
1245 * should not have this module constant. */
1244 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
1246 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
1245
1247
1246 dirs_module_init(mod);
1248 dirs_module_init(mod);
1247 manifest_module_init(mod);
1249 manifest_module_init(mod);
1248 revlog_module_init(mod);
1250 revlog_module_init(mod);
1249
1251
1250 capsule = PyCapsule_New(
1252 capsule = PyCapsule_New(
1251 dirstate_item_from_v1_data,
1253 dirstate_item_from_v1_data,
1252 "mercurial.cext.parsers.make_dirstate_item_CAPI", NULL);
1254 "mercurial.cext.parsers.make_dirstate_item_CAPI", NULL);
1253 if (capsule != NULL)
1255 if (capsule != NULL)
1254 PyModule_AddObject(mod, "make_dirstate_item_CAPI", capsule);
1256 PyModule_AddObject(mod, "make_dirstate_item_CAPI", capsule);
1255
1257
1256 if (PyType_Ready(&dirstateItemType) < 0) {
1258 if (PyType_Ready(&dirstateItemType) < 0) {
1257 return;
1259 return;
1258 }
1260 }
1259 Py_INCREF(&dirstateItemType);
1261 Py_INCREF(&dirstateItemType);
1260 PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
1262 PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
1261 }
1263 }
1262
1264
1263 static int check_python_version(void)
1265 static int check_python_version(void)
1264 {
1266 {
1265 PyObject *sys = PyImport_ImportModule("sys"), *ver;
1267 PyObject *sys = PyImport_ImportModule("sys"), *ver;
1266 long hexversion;
1268 long hexversion;
1267 if (!sys) {
1269 if (!sys) {
1268 return -1;
1270 return -1;
1269 }
1271 }
1270 ver = PyObject_GetAttrString(sys, "hexversion");
1272 ver = PyObject_GetAttrString(sys, "hexversion");
1271 Py_DECREF(sys);
1273 Py_DECREF(sys);
1272 if (!ver) {
1274 if (!ver) {
1273 return -1;
1275 return -1;
1274 }
1276 }
1275 hexversion = PyInt_AsLong(ver);
1277 hexversion = PyInt_AsLong(ver);
1276 Py_DECREF(ver);
1278 Py_DECREF(ver);
1277 /* sys.hexversion is a 32-bit number by default, so the -1 case
1279 /* sys.hexversion is a 32-bit number by default, so the -1 case
1278 * should only occur in unusual circumstances (e.g. if sys.hexversion
1280 * should only occur in unusual circumstances (e.g. if sys.hexversion
1279 * is manually set to an invalid value). */
1281 * is manually set to an invalid value). */
1280 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
1282 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
1281 PyErr_Format(PyExc_ImportError,
1283 PyErr_Format(PyExc_ImportError,
1282 "%s: The Mercurial extension "
1284 "%s: The Mercurial extension "
1283 "modules were compiled with Python " PY_VERSION
1285 "modules were compiled with Python " PY_VERSION
1284 ", but "
1286 ", but "
1285 "Mercurial is currently using Python with "
1287 "Mercurial is currently using Python with "
1286 "sys.hexversion=%ld: "
1288 "sys.hexversion=%ld: "
1287 "Python %s\n at: %s",
1289 "Python %s\n at: %s",
1288 versionerrortext, hexversion, Py_GetVersion(),
1290 versionerrortext, hexversion, Py_GetVersion(),
1289 Py_GetProgramFullPath());
1291 Py_GetProgramFullPath());
1290 return -1;
1292 return -1;
1291 }
1293 }
1292 return 0;
1294 return 0;
1293 }
1295 }
1294
1296
1295 #ifdef IS_PY3K
1297 #ifdef IS_PY3K
1296 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
1298 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
1297 parsers_doc, -1, methods};
1299 parsers_doc, -1, methods};
1298
1300
1299 PyMODINIT_FUNC PyInit_parsers(void)
1301 PyMODINIT_FUNC PyInit_parsers(void)
1300 {
1302 {
1301 PyObject *mod;
1303 PyObject *mod;
1302
1304
1303 if (check_python_version() == -1)
1305 if (check_python_version() == -1)
1304 return NULL;
1306 return NULL;
1305 mod = PyModule_Create(&parsers_module);
1307 mod = PyModule_Create(&parsers_module);
1306 module_init(mod);
1308 module_init(mod);
1307 return mod;
1309 return mod;
1308 }
1310 }
1309 #else
1311 #else
1310 PyMODINIT_FUNC initparsers(void)
1312 PyMODINIT_FUNC initparsers(void)
1311 {
1313 {
1312 PyObject *mod;
1314 PyObject *mod;
1313
1315
1314 if (check_python_version() == -1) {
1316 if (check_python_version() == -1) {
1315 return;
1317 return;
1316 }
1318 }
1317 mod = Py_InitModule3("parsers", methods, parsers_doc);
1319 mod = Py_InitModule3("parsers", methods, parsers_doc);
1318 module_init(mod);
1320 module_init(mod);
1319 }
1321 }
1320 #endif
1322 #endif
General Comments 0
You need to be logged in to leave comments. Login now