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