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