##// END OF EJS Templates
py3: bulk-replace bytes format specifier passed to Py_BuildValue()...
Yuya Nishihara -
r36637:1f8c3fad default
parent child Browse files
Show More
@@ -1,941 +1,942 b''
1 /*
1 /*
2 * manifest.c - manifest type that does on-demand parsing.
2 * manifest.c - manifest type that does on-demand parsing.
3 *
3 *
4 * Copyright 2015, Google Inc.
4 * Copyright 2015, Google Inc.
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 #include <Python.h>
9 #include <Python.h>
10
10
11 #include <assert.h>
11 #include <assert.h>
12 #include <stdlib.h>
12 #include <stdlib.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "charencode.h"
15 #include "charencode.h"
16 #include "util.h"
16 #include "util.h"
17
17
18 #define DEFAULT_LINES 100000
18 #define DEFAULT_LINES 100000
19
19
20 typedef struct {
20 typedef struct {
21 char *start;
21 char *start;
22 Py_ssize_t len; /* length of line including terminal newline */
22 Py_ssize_t len; /* length of line including terminal newline */
23 char hash_suffix;
23 char hash_suffix;
24 bool from_malloc;
24 bool from_malloc;
25 bool deleted;
25 bool deleted;
26 } line;
26 } line;
27
27
28 typedef struct {
28 typedef struct {
29 PyObject_HEAD
29 PyObject_HEAD
30 PyObject *pydata;
30 PyObject *pydata;
31 line *lines;
31 line *lines;
32 int numlines; /* number of line entries */
32 int numlines; /* number of line entries */
33 int livelines; /* number of non-deleted lines */
33 int livelines; /* number of non-deleted lines */
34 int maxlines; /* allocated number of lines */
34 int maxlines; /* allocated number of lines */
35 bool dirty;
35 bool dirty;
36 } lazymanifest;
36 } lazymanifest;
37
37
38 #define MANIFEST_OOM -1
38 #define MANIFEST_OOM -1
39 #define MANIFEST_NOT_SORTED -2
39 #define MANIFEST_NOT_SORTED -2
40 #define MANIFEST_MALFORMED -3
40 #define MANIFEST_MALFORMED -3
41
41
42 /* get the length of the path for a line */
42 /* get the length of the path for a line */
43 static size_t pathlen(line *l)
43 static size_t pathlen(line *l)
44 {
44 {
45 return strlen(l->start);
45 return strlen(l->start);
46 }
46 }
47
47
48 /* get the node value of a single line */
48 /* get the node value of a single line */
49 static PyObject *nodeof(line *l)
49 static PyObject *nodeof(line *l)
50 {
50 {
51 char *s = l->start;
51 char *s = l->start;
52 ssize_t llen = pathlen(l);
52 ssize_t llen = pathlen(l);
53 PyObject *hash = unhexlify(s + llen + 1, 40);
53 PyObject *hash = unhexlify(s + llen + 1, 40);
54 if (!hash) {
54 if (!hash) {
55 return NULL;
55 return NULL;
56 }
56 }
57 if (l->hash_suffix != '\0') {
57 if (l->hash_suffix != '\0') {
58 char newhash[21];
58 char newhash[21];
59 memcpy(newhash, PyBytes_AsString(hash), 20);
59 memcpy(newhash, PyBytes_AsString(hash), 20);
60 Py_DECREF(hash);
60 Py_DECREF(hash);
61 newhash[20] = l->hash_suffix;
61 newhash[20] = l->hash_suffix;
62 hash = PyBytes_FromStringAndSize(newhash, 21);
62 hash = PyBytes_FromStringAndSize(newhash, 21);
63 }
63 }
64 return hash;
64 return hash;
65 }
65 }
66
66
67 /* get the node hash and flags of a line as a tuple */
67 /* get the node hash and flags of a line as a tuple */
68 static PyObject *hashflags(line *l)
68 static PyObject *hashflags(line *l)
69 {
69 {
70 char *s = l->start;
70 char *s = l->start;
71 size_t plen = pathlen(l);
71 size_t plen = pathlen(l);
72 PyObject *hash = nodeof(l);
72 PyObject *hash = nodeof(l);
73
73
74 /* 40 for hash, 1 for null byte, 1 for newline */
74 /* 40 for hash, 1 for null byte, 1 for newline */
75 size_t hplen = plen + 42;
75 size_t hplen = plen + 42;
76 Py_ssize_t flen = l->len - hplen;
76 Py_ssize_t flen = l->len - hplen;
77 PyObject *flags;
77 PyObject *flags;
78 PyObject *tup;
78 PyObject *tup;
79
79
80 if (!hash)
80 if (!hash)
81 return NULL;
81 return NULL;
82 flags = PyBytes_FromStringAndSize(s + hplen - 1, flen);
82 flags = PyBytes_FromStringAndSize(s + hplen - 1, flen);
83 if (!flags) {
83 if (!flags) {
84 Py_DECREF(hash);
84 Py_DECREF(hash);
85 return NULL;
85 return NULL;
86 }
86 }
87 tup = PyTuple_Pack(2, hash, flags);
87 tup = PyTuple_Pack(2, hash, flags);
88 Py_DECREF(flags);
88 Py_DECREF(flags);
89 Py_DECREF(hash);
89 Py_DECREF(hash);
90 return tup;
90 return tup;
91 }
91 }
92
92
93 /* if we're about to run out of space in the line index, add more */
93 /* if we're about to run out of space in the line index, add more */
94 static bool realloc_if_full(lazymanifest *self)
94 static bool realloc_if_full(lazymanifest *self)
95 {
95 {
96 if (self->numlines == self->maxlines) {
96 if (self->numlines == self->maxlines) {
97 self->maxlines *= 2;
97 self->maxlines *= 2;
98 self->lines = realloc(self->lines, self->maxlines * sizeof(line));
98 self->lines = realloc(self->lines, self->maxlines * sizeof(line));
99 }
99 }
100 return !!self->lines;
100 return !!self->lines;
101 }
101 }
102
102
103 /*
103 /*
104 * Find the line boundaries in the manifest that 'data' points to and store
104 * Find the line boundaries in the manifest that 'data' points to and store
105 * information about each line in 'self'.
105 * information about each line in 'self'.
106 */
106 */
107 static int find_lines(lazymanifest *self, char *data, Py_ssize_t len)
107 static int find_lines(lazymanifest *self, char *data, Py_ssize_t len)
108 {
108 {
109 char *prev = NULL;
109 char *prev = NULL;
110 while (len > 0) {
110 while (len > 0) {
111 line *l;
111 line *l;
112 char *next = memchr(data, '\n', len);
112 char *next = memchr(data, '\n', len);
113 if (!next) {
113 if (!next) {
114 return MANIFEST_MALFORMED;
114 return MANIFEST_MALFORMED;
115 }
115 }
116 next++; /* advance past newline */
116 next++; /* advance past newline */
117 if (!realloc_if_full(self)) {
117 if (!realloc_if_full(self)) {
118 return MANIFEST_OOM; /* no memory */
118 return MANIFEST_OOM; /* no memory */
119 }
119 }
120 if (prev && strcmp(prev, data) > -1) {
120 if (prev && strcmp(prev, data) > -1) {
121 /* This data isn't sorted, so we have to abort. */
121 /* This data isn't sorted, so we have to abort. */
122 return MANIFEST_NOT_SORTED;
122 return MANIFEST_NOT_SORTED;
123 }
123 }
124 l = self->lines + ((self->numlines)++);
124 l = self->lines + ((self->numlines)++);
125 l->start = data;
125 l->start = data;
126 l->len = next - data;
126 l->len = next - data;
127 l->hash_suffix = '\0';
127 l->hash_suffix = '\0';
128 l->from_malloc = false;
128 l->from_malloc = false;
129 l->deleted = false;
129 l->deleted = false;
130 len = len - l->len;
130 len = len - l->len;
131 prev = data;
131 prev = data;
132 data = next;
132 data = next;
133 }
133 }
134 self->livelines = self->numlines;
134 self->livelines = self->numlines;
135 return 0;
135 return 0;
136 }
136 }
137
137
138 static int lazymanifest_init(lazymanifest *self, PyObject *args)
138 static int lazymanifest_init(lazymanifest *self, PyObject *args)
139 {
139 {
140 char *data;
140 char *data;
141 Py_ssize_t len;
141 Py_ssize_t len;
142 int err, ret;
142 int err, ret;
143 PyObject *pydata;
143 PyObject *pydata;
144 if (!PyArg_ParseTuple(args, "S", &pydata)) {
144 if (!PyArg_ParseTuple(args, "S", &pydata)) {
145 return -1;
145 return -1;
146 }
146 }
147 err = PyBytes_AsStringAndSize(pydata, &data, &len);
147 err = PyBytes_AsStringAndSize(pydata, &data, &len);
148
148
149 self->dirty = false;
149 self->dirty = false;
150 if (err == -1)
150 if (err == -1)
151 return -1;
151 return -1;
152 self->pydata = pydata;
152 self->pydata = pydata;
153 Py_INCREF(self->pydata);
153 Py_INCREF(self->pydata);
154 Py_BEGIN_ALLOW_THREADS
154 Py_BEGIN_ALLOW_THREADS
155 self->lines = malloc(DEFAULT_LINES * sizeof(line));
155 self->lines = malloc(DEFAULT_LINES * sizeof(line));
156 self->maxlines = DEFAULT_LINES;
156 self->maxlines = DEFAULT_LINES;
157 self->numlines = 0;
157 self->numlines = 0;
158 if (!self->lines)
158 if (!self->lines)
159 ret = MANIFEST_OOM;
159 ret = MANIFEST_OOM;
160 else
160 else
161 ret = find_lines(self, data, len);
161 ret = find_lines(self, data, len);
162 Py_END_ALLOW_THREADS
162 Py_END_ALLOW_THREADS
163 switch (ret) {
163 switch (ret) {
164 case 0:
164 case 0:
165 break;
165 break;
166 case MANIFEST_OOM:
166 case MANIFEST_OOM:
167 PyErr_NoMemory();
167 PyErr_NoMemory();
168 break;
168 break;
169 case MANIFEST_NOT_SORTED:
169 case MANIFEST_NOT_SORTED:
170 PyErr_Format(PyExc_ValueError,
170 PyErr_Format(PyExc_ValueError,
171 "Manifest lines not in sorted order.");
171 "Manifest lines not in sorted order.");
172 break;
172 break;
173 case MANIFEST_MALFORMED:
173 case MANIFEST_MALFORMED:
174 PyErr_Format(PyExc_ValueError,
174 PyErr_Format(PyExc_ValueError,
175 "Manifest did not end in a newline.");
175 "Manifest did not end in a newline.");
176 break;
176 break;
177 default:
177 default:
178 PyErr_Format(PyExc_ValueError,
178 PyErr_Format(PyExc_ValueError,
179 "Unknown problem parsing manifest.");
179 "Unknown problem parsing manifest.");
180 }
180 }
181 return ret == 0 ? 0 : -1;
181 return ret == 0 ? 0 : -1;
182 }
182 }
183
183
184 static void lazymanifest_dealloc(lazymanifest *self)
184 static void lazymanifest_dealloc(lazymanifest *self)
185 {
185 {
186 /* free any extra lines we had to allocate */
186 /* free any extra lines we had to allocate */
187 int i;
187 int i;
188 for (i = 0; i < self->numlines; i++) {
188 for (i = 0; i < self->numlines; i++) {
189 if (self->lines[i].from_malloc) {
189 if (self->lines[i].from_malloc) {
190 free(self->lines[i].start);
190 free(self->lines[i].start);
191 }
191 }
192 }
192 }
193 if (self->lines) {
193 if (self->lines) {
194 free(self->lines);
194 free(self->lines);
195 self->lines = NULL;
195 self->lines = NULL;
196 }
196 }
197 if (self->pydata) {
197 if (self->pydata) {
198 Py_DECREF(self->pydata);
198 Py_DECREF(self->pydata);
199 self->pydata = NULL;
199 self->pydata = NULL;
200 }
200 }
201 PyObject_Del(self);
201 PyObject_Del(self);
202 }
202 }
203
203
204 /* iteration support */
204 /* iteration support */
205
205
206 typedef struct {
206 typedef struct {
207 PyObject_HEAD lazymanifest *m;
207 PyObject_HEAD lazymanifest *m;
208 Py_ssize_t pos;
208 Py_ssize_t pos;
209 } lmIter;
209 } lmIter;
210
210
211 static void lmiter_dealloc(PyObject *o)
211 static void lmiter_dealloc(PyObject *o)
212 {
212 {
213 lmIter *self = (lmIter *)o;
213 lmIter *self = (lmIter *)o;
214 Py_DECREF(self->m);
214 Py_DECREF(self->m);
215 PyObject_Del(self);
215 PyObject_Del(self);
216 }
216 }
217
217
218 static line *lmiter_nextline(lmIter *self)
218 static line *lmiter_nextline(lmIter *self)
219 {
219 {
220 do {
220 do {
221 self->pos++;
221 self->pos++;
222 if (self->pos >= self->m->numlines) {
222 if (self->pos >= self->m->numlines) {
223 return NULL;
223 return NULL;
224 }
224 }
225 /* skip over deleted manifest entries */
225 /* skip over deleted manifest entries */
226 } while (self->m->lines[self->pos].deleted);
226 } while (self->m->lines[self->pos].deleted);
227 return self->m->lines + self->pos;
227 return self->m->lines + self->pos;
228 }
228 }
229
229
230 static PyObject *lmiter_iterentriesnext(PyObject *o)
230 static PyObject *lmiter_iterentriesnext(PyObject *o)
231 {
231 {
232 size_t pl;
232 size_t pl;
233 line *l;
233 line *l;
234 Py_ssize_t consumed;
234 Py_ssize_t consumed;
235 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
235 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
236 l = lmiter_nextline((lmIter *)o);
236 l = lmiter_nextline((lmIter *)o);
237 if (!l) {
237 if (!l) {
238 goto done;
238 goto done;
239 }
239 }
240 pl = pathlen(l);
240 pl = pathlen(l);
241 path = PyBytes_FromStringAndSize(l->start, pl);
241 path = PyBytes_FromStringAndSize(l->start, pl);
242 hash = nodeof(l);
242 hash = nodeof(l);
243 consumed = pl + 41;
243 consumed = pl + 41;
244 flags = PyBytes_FromStringAndSize(l->start + consumed,
244 flags = PyBytes_FromStringAndSize(l->start + consumed,
245 l->len - consumed - 1);
245 l->len - consumed - 1);
246 if (!path || !hash || !flags) {
246 if (!path || !hash || !flags) {
247 goto done;
247 goto done;
248 }
248 }
249 ret = PyTuple_Pack(3, path, hash, flags);
249 ret = PyTuple_Pack(3, path, hash, flags);
250 done:
250 done:
251 Py_XDECREF(path);
251 Py_XDECREF(path);
252 Py_XDECREF(hash);
252 Py_XDECREF(hash);
253 Py_XDECREF(flags);
253 Py_XDECREF(flags);
254 return ret;
254 return ret;
255 }
255 }
256
256
257 #ifdef IS_PY3K
257 #ifdef IS_PY3K
258 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
258 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
259 #else
259 #else
260 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
260 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
261 | Py_TPFLAGS_HAVE_ITER
261 | Py_TPFLAGS_HAVE_ITER
262 #endif
262 #endif
263
263
264 static PyTypeObject lazymanifestEntriesIterator = {
264 static PyTypeObject lazymanifestEntriesIterator = {
265 PyVarObject_HEAD_INIT(NULL, 0) /* header */
265 PyVarObject_HEAD_INIT(NULL, 0) /* header */
266 "parsers.lazymanifest.entriesiterator", /*tp_name */
266 "parsers.lazymanifest.entriesiterator", /*tp_name */
267 sizeof(lmIter), /*tp_basicsize */
267 sizeof(lmIter), /*tp_basicsize */
268 0, /*tp_itemsize */
268 0, /*tp_itemsize */
269 lmiter_dealloc, /*tp_dealloc */
269 lmiter_dealloc, /*tp_dealloc */
270 0, /*tp_print */
270 0, /*tp_print */
271 0, /*tp_getattr */
271 0, /*tp_getattr */
272 0, /*tp_setattr */
272 0, /*tp_setattr */
273 0, /*tp_compare */
273 0, /*tp_compare */
274 0, /*tp_repr */
274 0, /*tp_repr */
275 0, /*tp_as_number */
275 0, /*tp_as_number */
276 0, /*tp_as_sequence */
276 0, /*tp_as_sequence */
277 0, /*tp_as_mapping */
277 0, /*tp_as_mapping */
278 0, /*tp_hash */
278 0, /*tp_hash */
279 0, /*tp_call */
279 0, /*tp_call */
280 0, /*tp_str */
280 0, /*tp_str */
281 0, /*tp_getattro */
281 0, /*tp_getattro */
282 0, /*tp_setattro */
282 0, /*tp_setattro */
283 0, /*tp_as_buffer */
283 0, /*tp_as_buffer */
284 LAZYMANIFESTENTRIESITERATOR_TPFLAGS, /* tp_flags */
284 LAZYMANIFESTENTRIESITERATOR_TPFLAGS, /* tp_flags */
285 "Iterator for 3-tuples in a lazymanifest.", /* tp_doc */
285 "Iterator for 3-tuples in a lazymanifest.", /* tp_doc */
286 0, /* tp_traverse */
286 0, /* tp_traverse */
287 0, /* tp_clear */
287 0, /* tp_clear */
288 0, /* tp_richcompare */
288 0, /* tp_richcompare */
289 0, /* tp_weaklistoffset */
289 0, /* tp_weaklistoffset */
290 PyObject_SelfIter, /* tp_iter: __iter__() method */
290 PyObject_SelfIter, /* tp_iter: __iter__() method */
291 lmiter_iterentriesnext, /* tp_iternext: next() method */
291 lmiter_iterentriesnext, /* tp_iternext: next() method */
292 };
292 };
293
293
294 static PyObject *lmiter_iterkeysnext(PyObject *o)
294 static PyObject *lmiter_iterkeysnext(PyObject *o)
295 {
295 {
296 size_t pl;
296 size_t pl;
297 line *l = lmiter_nextline((lmIter *)o);
297 line *l = lmiter_nextline((lmIter *)o);
298 if (!l) {
298 if (!l) {
299 return NULL;
299 return NULL;
300 }
300 }
301 pl = pathlen(l);
301 pl = pathlen(l);
302 return PyBytes_FromStringAndSize(l->start, pl);
302 return PyBytes_FromStringAndSize(l->start, pl);
303 }
303 }
304
304
305 #ifdef IS_PY3K
305 #ifdef IS_PY3K
306 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
306 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
307 #else
307 #else
308 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
308 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
309 | Py_TPFLAGS_HAVE_ITER
309 | Py_TPFLAGS_HAVE_ITER
310 #endif
310 #endif
311
311
312 static PyTypeObject lazymanifestKeysIterator = {
312 static PyTypeObject lazymanifestKeysIterator = {
313 PyVarObject_HEAD_INIT(NULL, 0) /* header */
313 PyVarObject_HEAD_INIT(NULL, 0) /* header */
314 "parsers.lazymanifest.keysiterator", /*tp_name */
314 "parsers.lazymanifest.keysiterator", /*tp_name */
315 sizeof(lmIter), /*tp_basicsize */
315 sizeof(lmIter), /*tp_basicsize */
316 0, /*tp_itemsize */
316 0, /*tp_itemsize */
317 lmiter_dealloc, /*tp_dealloc */
317 lmiter_dealloc, /*tp_dealloc */
318 0, /*tp_print */
318 0, /*tp_print */
319 0, /*tp_getattr */
319 0, /*tp_getattr */
320 0, /*tp_setattr */
320 0, /*tp_setattr */
321 0, /*tp_compare */
321 0, /*tp_compare */
322 0, /*tp_repr */
322 0, /*tp_repr */
323 0, /*tp_as_number */
323 0, /*tp_as_number */
324 0, /*tp_as_sequence */
324 0, /*tp_as_sequence */
325 0, /*tp_as_mapping */
325 0, /*tp_as_mapping */
326 0, /*tp_hash */
326 0, /*tp_hash */
327 0, /*tp_call */
327 0, /*tp_call */
328 0, /*tp_str */
328 0, /*tp_str */
329 0, /*tp_getattro */
329 0, /*tp_getattro */
330 0, /*tp_setattro */
330 0, /*tp_setattro */
331 0, /*tp_as_buffer */
331 0, /*tp_as_buffer */
332 LAZYMANIFESTKEYSITERATOR_TPFLAGS, /* tp_flags */
332 LAZYMANIFESTKEYSITERATOR_TPFLAGS, /* tp_flags */
333 "Keys iterator for a lazymanifest.", /* tp_doc */
333 "Keys iterator for a lazymanifest.", /* tp_doc */
334 0, /* tp_traverse */
334 0, /* tp_traverse */
335 0, /* tp_clear */
335 0, /* tp_clear */
336 0, /* tp_richcompare */
336 0, /* tp_richcompare */
337 0, /* tp_weaklistoffset */
337 0, /* tp_weaklistoffset */
338 PyObject_SelfIter, /* tp_iter: __iter__() method */
338 PyObject_SelfIter, /* tp_iter: __iter__() method */
339 lmiter_iterkeysnext, /* tp_iternext: next() method */
339 lmiter_iterkeysnext, /* tp_iternext: next() method */
340 };
340 };
341
341
342 static lazymanifest *lazymanifest_copy(lazymanifest *self);
342 static lazymanifest *lazymanifest_copy(lazymanifest *self);
343
343
344 static PyObject *lazymanifest_getentriesiter(lazymanifest *self)
344 static PyObject *lazymanifest_getentriesiter(lazymanifest *self)
345 {
345 {
346 lmIter *i = NULL;
346 lmIter *i = NULL;
347 lazymanifest *t = lazymanifest_copy(self);
347 lazymanifest *t = lazymanifest_copy(self);
348 if (!t) {
348 if (!t) {
349 PyErr_NoMemory();
349 PyErr_NoMemory();
350 return NULL;
350 return NULL;
351 }
351 }
352 i = PyObject_New(lmIter, &lazymanifestEntriesIterator);
352 i = PyObject_New(lmIter, &lazymanifestEntriesIterator);
353 if (i) {
353 if (i) {
354 i->m = t;
354 i->m = t;
355 i->pos = -1;
355 i->pos = -1;
356 } else {
356 } else {
357 Py_DECREF(t);
357 Py_DECREF(t);
358 PyErr_NoMemory();
358 PyErr_NoMemory();
359 }
359 }
360 return (PyObject *)i;
360 return (PyObject *)i;
361 }
361 }
362
362
363 static PyObject *lazymanifest_getkeysiter(lazymanifest *self)
363 static PyObject *lazymanifest_getkeysiter(lazymanifest *self)
364 {
364 {
365 lmIter *i = NULL;
365 lmIter *i = NULL;
366 lazymanifest *t = lazymanifest_copy(self);
366 lazymanifest *t = lazymanifest_copy(self);
367 if (!t) {
367 if (!t) {
368 PyErr_NoMemory();
368 PyErr_NoMemory();
369 return NULL;
369 return NULL;
370 }
370 }
371 i = PyObject_New(lmIter, &lazymanifestKeysIterator);
371 i = PyObject_New(lmIter, &lazymanifestKeysIterator);
372 if (i) {
372 if (i) {
373 i->m = t;
373 i->m = t;
374 i->pos = -1;
374 i->pos = -1;
375 } else {
375 } else {
376 Py_DECREF(t);
376 Py_DECREF(t);
377 PyErr_NoMemory();
377 PyErr_NoMemory();
378 }
378 }
379 return (PyObject *)i;
379 return (PyObject *)i;
380 }
380 }
381
381
382 /* __getitem__ and __setitem__ support */
382 /* __getitem__ and __setitem__ support */
383
383
384 static Py_ssize_t lazymanifest_size(lazymanifest *self)
384 static Py_ssize_t lazymanifest_size(lazymanifest *self)
385 {
385 {
386 return self->livelines;
386 return self->livelines;
387 }
387 }
388
388
389 static int linecmp(const void *left, const void *right)
389 static int linecmp(const void *left, const void *right)
390 {
390 {
391 return strcmp(((const line *)left)->start,
391 return strcmp(((const line *)left)->start,
392 ((const line *)right)->start);
392 ((const line *)right)->start);
393 }
393 }
394
394
395 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
395 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
396 {
396 {
397 line needle;
397 line needle;
398 line *hit;
398 line *hit;
399 if (!PyBytes_Check(key)) {
399 if (!PyBytes_Check(key)) {
400 PyErr_Format(PyExc_TypeError,
400 PyErr_Format(PyExc_TypeError,
401 "getitem: manifest keys must be a string.");
401 "getitem: manifest keys must be a string.");
402 return NULL;
402 return NULL;
403 }
403 }
404 needle.start = PyBytes_AsString(key);
404 needle.start = PyBytes_AsString(key);
405 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
405 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
406 &linecmp);
406 &linecmp);
407 if (!hit || hit->deleted) {
407 if (!hit || hit->deleted) {
408 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
408 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
409 return NULL;
409 return NULL;
410 }
410 }
411 return hashflags(hit);
411 return hashflags(hit);
412 }
412 }
413
413
414 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
414 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
415 {
415 {
416 line needle;
416 line needle;
417 line *hit;
417 line *hit;
418 if (!PyBytes_Check(key)) {
418 if (!PyBytes_Check(key)) {
419 PyErr_Format(PyExc_TypeError,
419 PyErr_Format(PyExc_TypeError,
420 "delitem: manifest keys must be a string.");
420 "delitem: manifest keys must be a string.");
421 return -1;
421 return -1;
422 }
422 }
423 needle.start = PyBytes_AsString(key);
423 needle.start = PyBytes_AsString(key);
424 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
424 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
425 &linecmp);
425 &linecmp);
426 if (!hit || hit->deleted) {
426 if (!hit || hit->deleted) {
427 PyErr_Format(PyExc_KeyError,
427 PyErr_Format(PyExc_KeyError,
428 "Tried to delete nonexistent manifest entry.");
428 "Tried to delete nonexistent manifest entry.");
429 return -1;
429 return -1;
430 }
430 }
431 self->dirty = true;
431 self->dirty = true;
432 hit->deleted = true;
432 hit->deleted = true;
433 self->livelines--;
433 self->livelines--;
434 return 0;
434 return 0;
435 }
435 }
436
436
437 /* Do a binary search for the insertion point for new, creating the
437 /* Do a binary search for the insertion point for new, creating the
438 * new entry if needed. */
438 * new entry if needed. */
439 static int internalsetitem(lazymanifest *self, line *new)
439 static int internalsetitem(lazymanifest *self, line *new)
440 {
440 {
441 int start = 0, end = self->numlines;
441 int start = 0, end = self->numlines;
442 while (start < end) {
442 while (start < end) {
443 int pos = start + (end - start) / 2;
443 int pos = start + (end - start) / 2;
444 int c = linecmp(new, self->lines + pos);
444 int c = linecmp(new, self->lines + pos);
445 if (c < 0)
445 if (c < 0)
446 end = pos;
446 end = pos;
447 else if (c > 0)
447 else if (c > 0)
448 start = pos + 1;
448 start = pos + 1;
449 else {
449 else {
450 if (self->lines[pos].deleted)
450 if (self->lines[pos].deleted)
451 self->livelines++;
451 self->livelines++;
452 if (self->lines[pos].from_malloc)
452 if (self->lines[pos].from_malloc)
453 free(self->lines[pos].start);
453 free(self->lines[pos].start);
454 start = pos;
454 start = pos;
455 goto finish;
455 goto finish;
456 }
456 }
457 }
457 }
458 /* being here means we need to do an insert */
458 /* being here means we need to do an insert */
459 if (!realloc_if_full(self)) {
459 if (!realloc_if_full(self)) {
460 PyErr_NoMemory();
460 PyErr_NoMemory();
461 return -1;
461 return -1;
462 }
462 }
463 memmove(self->lines + start + 1, self->lines + start,
463 memmove(self->lines + start + 1, self->lines + start,
464 (self->numlines - start) * sizeof(line));
464 (self->numlines - start) * sizeof(line));
465 self->numlines++;
465 self->numlines++;
466 self->livelines++;
466 self->livelines++;
467 finish:
467 finish:
468 self->lines[start] = *new;
468 self->lines[start] = *new;
469 self->dirty = true;
469 self->dirty = true;
470 return 0;
470 return 0;
471 }
471 }
472
472
473 static int lazymanifest_setitem(
473 static int lazymanifest_setitem(
474 lazymanifest *self, PyObject *key, PyObject *value)
474 lazymanifest *self, PyObject *key, PyObject *value)
475 {
475 {
476 char *path;
476 char *path;
477 Py_ssize_t plen;
477 Py_ssize_t plen;
478 PyObject *pyhash;
478 PyObject *pyhash;
479 Py_ssize_t hlen;
479 Py_ssize_t hlen;
480 char *hash;
480 char *hash;
481 PyObject *pyflags;
481 PyObject *pyflags;
482 char *flags;
482 char *flags;
483 Py_ssize_t flen;
483 Py_ssize_t flen;
484 size_t dlen;
484 size_t dlen;
485 char *dest;
485 char *dest;
486 int i;
486 int i;
487 line new;
487 line new;
488 if (!PyBytes_Check(key)) {
488 if (!PyBytes_Check(key)) {
489 PyErr_Format(PyExc_TypeError,
489 PyErr_Format(PyExc_TypeError,
490 "setitem: manifest keys must be a string.");
490 "setitem: manifest keys must be a string.");
491 return -1;
491 return -1;
492 }
492 }
493 if (!value) {
493 if (!value) {
494 return lazymanifest_delitem(self, key);
494 return lazymanifest_delitem(self, key);
495 }
495 }
496 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
496 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
497 PyErr_Format(PyExc_TypeError,
497 PyErr_Format(PyExc_TypeError,
498 "Manifest values must be a tuple of (node, flags).");
498 "Manifest values must be a tuple of (node, flags).");
499 return -1;
499 return -1;
500 }
500 }
501 if (PyBytes_AsStringAndSize(key, &path, &plen) == -1) {
501 if (PyBytes_AsStringAndSize(key, &path, &plen) == -1) {
502 return -1;
502 return -1;
503 }
503 }
504
504
505 pyhash = PyTuple_GetItem(value, 0);
505 pyhash = PyTuple_GetItem(value, 0);
506 if (!PyBytes_Check(pyhash)) {
506 if (!PyBytes_Check(pyhash)) {
507 PyErr_Format(PyExc_TypeError,
507 PyErr_Format(PyExc_TypeError,
508 "node must be a 20-byte string");
508 "node must be a 20-byte string");
509 return -1;
509 return -1;
510 }
510 }
511 hlen = PyBytes_Size(pyhash);
511 hlen = PyBytes_Size(pyhash);
512 /* Some parts of the codebase try and set 21 or 22
512 /* Some parts of the codebase try and set 21 or 22
513 * byte "hash" values in order to perturb things for
513 * byte "hash" values in order to perturb things for
514 * status. We have to preserve at least the 21st
514 * status. We have to preserve at least the 21st
515 * byte. Sigh. If there's a 22nd byte, we drop it on
515 * byte. Sigh. If there's a 22nd byte, we drop it on
516 * the floor, which works fine.
516 * the floor, which works fine.
517 */
517 */
518 if (hlen != 20 && hlen != 21 && hlen != 22) {
518 if (hlen != 20 && hlen != 21 && hlen != 22) {
519 PyErr_Format(PyExc_TypeError,
519 PyErr_Format(PyExc_TypeError,
520 "node must be a 20-byte string");
520 "node must be a 20-byte string");
521 return -1;
521 return -1;
522 }
522 }
523 hash = PyBytes_AsString(pyhash);
523 hash = PyBytes_AsString(pyhash);
524
524
525 pyflags = PyTuple_GetItem(value, 1);
525 pyflags = PyTuple_GetItem(value, 1);
526 if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
526 if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
527 PyErr_Format(PyExc_TypeError,
527 PyErr_Format(PyExc_TypeError,
528 "flags must a 0 or 1 byte string");
528 "flags must a 0 or 1 byte string");
529 return -1;
529 return -1;
530 }
530 }
531 if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
531 if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
532 return -1;
532 return -1;
533 }
533 }
534 /* one null byte and one newline */
534 /* one null byte and one newline */
535 dlen = plen + 41 + flen + 1;
535 dlen = plen + 41 + flen + 1;
536 dest = malloc(dlen);
536 dest = malloc(dlen);
537 if (!dest) {
537 if (!dest) {
538 PyErr_NoMemory();
538 PyErr_NoMemory();
539 return -1;
539 return -1;
540 }
540 }
541 memcpy(dest, path, plen + 1);
541 memcpy(dest, path, plen + 1);
542 for (i = 0; i < 20; i++) {
542 for (i = 0; i < 20; i++) {
543 /* Cast to unsigned, so it will not get sign-extended when promoted
543 /* Cast to unsigned, so it will not get sign-extended when promoted
544 * to int (as is done when passing to a variadic function)
544 * to int (as is done when passing to a variadic function)
545 */
545 */
546 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
546 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
547 }
547 }
548 memcpy(dest + plen + 41, flags, flen);
548 memcpy(dest + plen + 41, flags, flen);
549 dest[plen + 41 + flen] = '\n';
549 dest[plen + 41 + flen] = '\n';
550 new.start = dest;
550 new.start = dest;
551 new.len = dlen;
551 new.len = dlen;
552 new.hash_suffix = '\0';
552 new.hash_suffix = '\0';
553 if (hlen > 20) {
553 if (hlen > 20) {
554 new.hash_suffix = hash[20];
554 new.hash_suffix = hash[20];
555 }
555 }
556 new.from_malloc = true; /* is `start` a pointer we allocated? */
556 new.from_malloc = true; /* is `start` a pointer we allocated? */
557 new.deleted = false; /* is this entry deleted? */
557 new.deleted = false; /* is this entry deleted? */
558 if (internalsetitem(self, &new)) {
558 if (internalsetitem(self, &new)) {
559 return -1;
559 return -1;
560 }
560 }
561 return 0;
561 return 0;
562 }
562 }
563
563
564 static PyMappingMethods lazymanifest_mapping_methods = {
564 static PyMappingMethods lazymanifest_mapping_methods = {
565 (lenfunc)lazymanifest_size, /* mp_length */
565 (lenfunc)lazymanifest_size, /* mp_length */
566 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
566 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
567 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
567 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
568 };
568 };
569
569
570 /* sequence methods (important or __contains__ builds an iterator) */
570 /* sequence methods (important or __contains__ builds an iterator) */
571
571
572 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
572 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
573 {
573 {
574 line needle;
574 line needle;
575 line *hit;
575 line *hit;
576 if (!PyBytes_Check(key)) {
576 if (!PyBytes_Check(key)) {
577 /* Our keys are always strings, so if the contains
577 /* Our keys are always strings, so if the contains
578 * check is for a non-string, just return false. */
578 * check is for a non-string, just return false. */
579 return 0;
579 return 0;
580 }
580 }
581 needle.start = PyBytes_AsString(key);
581 needle.start = PyBytes_AsString(key);
582 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
582 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
583 &linecmp);
583 &linecmp);
584 if (!hit || hit->deleted) {
584 if (!hit || hit->deleted) {
585 return 0;
585 return 0;
586 }
586 }
587 return 1;
587 return 1;
588 }
588 }
589
589
590 static PySequenceMethods lazymanifest_seq_meths = {
590 static PySequenceMethods lazymanifest_seq_meths = {
591 (lenfunc)lazymanifest_size, /* sq_length */
591 (lenfunc)lazymanifest_size, /* sq_length */
592 0, /* sq_concat */
592 0, /* sq_concat */
593 0, /* sq_repeat */
593 0, /* sq_repeat */
594 0, /* sq_item */
594 0, /* sq_item */
595 0, /* sq_slice */
595 0, /* sq_slice */
596 0, /* sq_ass_item */
596 0, /* sq_ass_item */
597 0, /* sq_ass_slice */
597 0, /* sq_ass_slice */
598 (objobjproc)lazymanifest_contains, /* sq_contains */
598 (objobjproc)lazymanifest_contains, /* sq_contains */
599 0, /* sq_inplace_concat */
599 0, /* sq_inplace_concat */
600 0, /* sq_inplace_repeat */
600 0, /* sq_inplace_repeat */
601 };
601 };
602
602
603
603
604 /* Other methods (copy, diff, etc) */
604 /* Other methods (copy, diff, etc) */
605 static PyTypeObject lazymanifestType;
605 static PyTypeObject lazymanifestType;
606
606
607 /* If the manifest has changes, build the new manifest text and reindex it. */
607 /* If the manifest has changes, build the new manifest text and reindex it. */
608 static int compact(lazymanifest *self)
608 static int compact(lazymanifest *self)
609 {
609 {
610 int i;
610 int i;
611 ssize_t need = 0;
611 ssize_t need = 0;
612 char *data;
612 char *data;
613 line *src, *dst;
613 line *src, *dst;
614 PyObject *pydata;
614 PyObject *pydata;
615 if (!self->dirty)
615 if (!self->dirty)
616 return 0;
616 return 0;
617 for (i = 0; i < self->numlines; i++) {
617 for (i = 0; i < self->numlines; i++) {
618 if (!self->lines[i].deleted) {
618 if (!self->lines[i].deleted) {
619 need += self->lines[i].len;
619 need += self->lines[i].len;
620 }
620 }
621 }
621 }
622 pydata = PyBytes_FromStringAndSize(NULL, need);
622 pydata = PyBytes_FromStringAndSize(NULL, need);
623 if (!pydata)
623 if (!pydata)
624 return -1;
624 return -1;
625 data = PyBytes_AsString(pydata);
625 data = PyBytes_AsString(pydata);
626 if (!data) {
626 if (!data) {
627 return -1;
627 return -1;
628 }
628 }
629 src = self->lines;
629 src = self->lines;
630 dst = self->lines;
630 dst = self->lines;
631 for (i = 0; i < self->numlines; i++, src++) {
631 for (i = 0; i < self->numlines; i++, src++) {
632 char *tofree = NULL;
632 char *tofree = NULL;
633 if (src->from_malloc) {
633 if (src->from_malloc) {
634 tofree = src->start;
634 tofree = src->start;
635 }
635 }
636 if (!src->deleted) {
636 if (!src->deleted) {
637 memcpy(data, src->start, src->len);
637 memcpy(data, src->start, src->len);
638 *dst = *src;
638 *dst = *src;
639 dst->start = data;
639 dst->start = data;
640 dst->from_malloc = false;
640 dst->from_malloc = false;
641 data += dst->len;
641 data += dst->len;
642 dst++;
642 dst++;
643 }
643 }
644 free(tofree);
644 free(tofree);
645 }
645 }
646 Py_DECREF(self->pydata);
646 Py_DECREF(self->pydata);
647 self->pydata = pydata;
647 self->pydata = pydata;
648 self->numlines = self->livelines;
648 self->numlines = self->livelines;
649 self->dirty = false;
649 self->dirty = false;
650 return 0;
650 return 0;
651 }
651 }
652
652
653 static PyObject *lazymanifest_text(lazymanifest *self)
653 static PyObject *lazymanifest_text(lazymanifest *self)
654 {
654 {
655 if (compact(self) != 0) {
655 if (compact(self) != 0) {
656 PyErr_NoMemory();
656 PyErr_NoMemory();
657 return NULL;
657 return NULL;
658 }
658 }
659 Py_INCREF(self->pydata);
659 Py_INCREF(self->pydata);
660 return self->pydata;
660 return self->pydata;
661 }
661 }
662
662
663 static lazymanifest *lazymanifest_copy(lazymanifest *self)
663 static lazymanifest *lazymanifest_copy(lazymanifest *self)
664 {
664 {
665 lazymanifest *copy = NULL;
665 lazymanifest *copy = NULL;
666 if (compact(self) != 0) {
666 if (compact(self) != 0) {
667 goto nomem;
667 goto nomem;
668 }
668 }
669 copy = PyObject_New(lazymanifest, &lazymanifestType);
669 copy = PyObject_New(lazymanifest, &lazymanifestType);
670 if (!copy) {
670 if (!copy) {
671 goto nomem;
671 goto nomem;
672 }
672 }
673 copy->numlines = self->numlines;
673 copy->numlines = self->numlines;
674 copy->livelines = self->livelines;
674 copy->livelines = self->livelines;
675 copy->dirty = false;
675 copy->dirty = false;
676 copy->lines = malloc(self->maxlines *sizeof(line));
676 copy->lines = malloc(self->maxlines *sizeof(line));
677 if (!copy->lines) {
677 if (!copy->lines) {
678 goto nomem;
678 goto nomem;
679 }
679 }
680 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
680 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
681 copy->maxlines = self->maxlines;
681 copy->maxlines = self->maxlines;
682 copy->pydata = self->pydata;
682 copy->pydata = self->pydata;
683 Py_INCREF(copy->pydata);
683 Py_INCREF(copy->pydata);
684 return copy;
684 return copy;
685 nomem:
685 nomem:
686 PyErr_NoMemory();
686 PyErr_NoMemory();
687 Py_XDECREF(copy);
687 Py_XDECREF(copy);
688 return NULL;
688 return NULL;
689 }
689 }
690
690
691 static lazymanifest *lazymanifest_filtercopy(
691 static lazymanifest *lazymanifest_filtercopy(
692 lazymanifest *self, PyObject *matchfn)
692 lazymanifest *self, PyObject *matchfn)
693 {
693 {
694 lazymanifest *copy = NULL;
694 lazymanifest *copy = NULL;
695 int i;
695 int i;
696 if (!PyCallable_Check(matchfn)) {
696 if (!PyCallable_Check(matchfn)) {
697 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
697 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
698 return NULL;
698 return NULL;
699 }
699 }
700 /* compact ourselves first to avoid double-frees later when we
700 /* compact ourselves first to avoid double-frees later when we
701 * compact tmp so that it doesn't have random pointers to our
701 * compact tmp so that it doesn't have random pointers to our
702 * underlying from_malloc-data (self->pydata is safe) */
702 * underlying from_malloc-data (self->pydata is safe) */
703 if (compact(self) != 0) {
703 if (compact(self) != 0) {
704 goto nomem;
704 goto nomem;
705 }
705 }
706 copy = PyObject_New(lazymanifest, &lazymanifestType);
706 copy = PyObject_New(lazymanifest, &lazymanifestType);
707 if (!copy) {
707 if (!copy) {
708 goto nomem;
708 goto nomem;
709 }
709 }
710 copy->dirty = true;
710 copy->dirty = true;
711 copy->lines = malloc(self->maxlines * sizeof(line));
711 copy->lines = malloc(self->maxlines * sizeof(line));
712 if (!copy->lines) {
712 if (!copy->lines) {
713 goto nomem;
713 goto nomem;
714 }
714 }
715 copy->maxlines = self->maxlines;
715 copy->maxlines = self->maxlines;
716 copy->numlines = 0;
716 copy->numlines = 0;
717 copy->pydata = self->pydata;
717 copy->pydata = self->pydata;
718 Py_INCREF(self->pydata);
718 Py_INCREF(self->pydata);
719 for (i = 0; i < self->numlines; i++) {
719 for (i = 0; i < self->numlines; i++) {
720 PyObject *arglist = NULL, *result = NULL;
720 PyObject *arglist = NULL, *result = NULL;
721 arglist = Py_BuildValue("(s)", self->lines[i].start);
721 arglist = Py_BuildValue(PY23("(s)", "(y)"),
722 self->lines[i].start);
722 if (!arglist) {
723 if (!arglist) {
723 return NULL;
724 return NULL;
724 }
725 }
725 result = PyObject_CallObject(matchfn, arglist);
726 result = PyObject_CallObject(matchfn, arglist);
726 Py_DECREF(arglist);
727 Py_DECREF(arglist);
727 /* if the callback raised an exception, just let it
728 /* if the callback raised an exception, just let it
728 * through and give up */
729 * through and give up */
729 if (!result) {
730 if (!result) {
730 free(copy->lines);
731 free(copy->lines);
731 Py_DECREF(self->pydata);
732 Py_DECREF(self->pydata);
732 return NULL;
733 return NULL;
733 }
734 }
734 if (PyObject_IsTrue(result)) {
735 if (PyObject_IsTrue(result)) {
735 assert(!(self->lines[i].from_malloc));
736 assert(!(self->lines[i].from_malloc));
736 copy->lines[copy->numlines++] = self->lines[i];
737 copy->lines[copy->numlines++] = self->lines[i];
737 }
738 }
738 Py_DECREF(result);
739 Py_DECREF(result);
739 }
740 }
740 copy->livelines = copy->numlines;
741 copy->livelines = copy->numlines;
741 return copy;
742 return copy;
742 nomem:
743 nomem:
743 PyErr_NoMemory();
744 PyErr_NoMemory();
744 Py_XDECREF(copy);
745 Py_XDECREF(copy);
745 return NULL;
746 return NULL;
746 }
747 }
747
748
748 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
749 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
749 {
750 {
750 lazymanifest *other;
751 lazymanifest *other;
751 PyObject *pyclean = NULL;
752 PyObject *pyclean = NULL;
752 bool listclean;
753 bool listclean;
753 PyObject *emptyTup = NULL, *ret = NULL;
754 PyObject *emptyTup = NULL, *ret = NULL;
754 PyObject *es;
755 PyObject *es;
755 int sneedle = 0, oneedle = 0;
756 int sneedle = 0, oneedle = 0;
756 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
757 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
757 return NULL;
758 return NULL;
758 }
759 }
759 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
760 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
760 es = PyBytes_FromString("");
761 es = PyBytes_FromString("");
761 if (!es) {
762 if (!es) {
762 goto nomem;
763 goto nomem;
763 }
764 }
764 emptyTup = PyTuple_Pack(2, Py_None, es);
765 emptyTup = PyTuple_Pack(2, Py_None, es);
765 Py_DECREF(es);
766 Py_DECREF(es);
766 if (!emptyTup) {
767 if (!emptyTup) {
767 goto nomem;
768 goto nomem;
768 }
769 }
769 ret = PyDict_New();
770 ret = PyDict_New();
770 if (!ret) {
771 if (!ret) {
771 goto nomem;
772 goto nomem;
772 }
773 }
773 while (sneedle != self->numlines || oneedle != other->numlines) {
774 while (sneedle != self->numlines || oneedle != other->numlines) {
774 line *left = self->lines + sneedle;
775 line *left = self->lines + sneedle;
775 line *right = other->lines + oneedle;
776 line *right = other->lines + oneedle;
776 int result;
777 int result;
777 PyObject *key;
778 PyObject *key;
778 PyObject *outer;
779 PyObject *outer;
779 /* If we're looking at a deleted entry and it's not
780 /* If we're looking at a deleted entry and it's not
780 * the end of the manifest, just skip it. */
781 * the end of the manifest, just skip it. */
781 if (sneedle < self->numlines && left->deleted) {
782 if (sneedle < self->numlines && left->deleted) {
782 sneedle++;
783 sneedle++;
783 continue;
784 continue;
784 }
785 }
785 if (oneedle < other->numlines && right->deleted) {
786 if (oneedle < other->numlines && right->deleted) {
786 oneedle++;
787 oneedle++;
787 continue;
788 continue;
788 }
789 }
789 /* if we're at the end of either manifest, then we
790 /* if we're at the end of either manifest, then we
790 * know the remaining items are adds so we can skip
791 * know the remaining items are adds so we can skip
791 * the strcmp. */
792 * the strcmp. */
792 if (sneedle == self->numlines) {
793 if (sneedle == self->numlines) {
793 result = 1;
794 result = 1;
794 } else if (oneedle == other->numlines) {
795 } else if (oneedle == other->numlines) {
795 result = -1;
796 result = -1;
796 } else {
797 } else {
797 result = linecmp(left, right);
798 result = linecmp(left, right);
798 }
799 }
799 key = result <= 0 ?
800 key = result <= 0 ?
800 PyBytes_FromString(left->start) :
801 PyBytes_FromString(left->start) :
801 PyBytes_FromString(right->start);
802 PyBytes_FromString(right->start);
802 if (!key)
803 if (!key)
803 goto nomem;
804 goto nomem;
804 if (result < 0) {
805 if (result < 0) {
805 PyObject *l = hashflags(left);
806 PyObject *l = hashflags(left);
806 if (!l) {
807 if (!l) {
807 goto nomem;
808 goto nomem;
808 }
809 }
809 outer = PyTuple_Pack(2, l, emptyTup);
810 outer = PyTuple_Pack(2, l, emptyTup);
810 Py_DECREF(l);
811 Py_DECREF(l);
811 if (!outer) {
812 if (!outer) {
812 goto nomem;
813 goto nomem;
813 }
814 }
814 PyDict_SetItem(ret, key, outer);
815 PyDict_SetItem(ret, key, outer);
815 Py_DECREF(outer);
816 Py_DECREF(outer);
816 sneedle++;
817 sneedle++;
817 } else if (result > 0) {
818 } else if (result > 0) {
818 PyObject *r = hashflags(right);
819 PyObject *r = hashflags(right);
819 if (!r) {
820 if (!r) {
820 goto nomem;
821 goto nomem;
821 }
822 }
822 outer = PyTuple_Pack(2, emptyTup, r);
823 outer = PyTuple_Pack(2, emptyTup, r);
823 Py_DECREF(r);
824 Py_DECREF(r);
824 if (!outer) {
825 if (!outer) {
825 goto nomem;
826 goto nomem;
826 }
827 }
827 PyDict_SetItem(ret, key, outer);
828 PyDict_SetItem(ret, key, outer);
828 Py_DECREF(outer);
829 Py_DECREF(outer);
829 oneedle++;
830 oneedle++;
830 } else {
831 } else {
831 /* file exists in both manifests */
832 /* file exists in both manifests */
832 if (left->len != right->len
833 if (left->len != right->len
833 || memcmp(left->start, right->start, left->len)
834 || memcmp(left->start, right->start, left->len)
834 || left->hash_suffix != right->hash_suffix) {
835 || left->hash_suffix != right->hash_suffix) {
835 PyObject *l = hashflags(left);
836 PyObject *l = hashflags(left);
836 PyObject *r;
837 PyObject *r;
837 if (!l) {
838 if (!l) {
838 goto nomem;
839 goto nomem;
839 }
840 }
840 r = hashflags(right);
841 r = hashflags(right);
841 if (!r) {
842 if (!r) {
842 Py_DECREF(l);
843 Py_DECREF(l);
843 goto nomem;
844 goto nomem;
844 }
845 }
845 outer = PyTuple_Pack(2, l, r);
846 outer = PyTuple_Pack(2, l, r);
846 Py_DECREF(l);
847 Py_DECREF(l);
847 Py_DECREF(r);
848 Py_DECREF(r);
848 if (!outer) {
849 if (!outer) {
849 goto nomem;
850 goto nomem;
850 }
851 }
851 PyDict_SetItem(ret, key, outer);
852 PyDict_SetItem(ret, key, outer);
852 Py_DECREF(outer);
853 Py_DECREF(outer);
853 } else if (listclean) {
854 } else if (listclean) {
854 PyDict_SetItem(ret, key, Py_None);
855 PyDict_SetItem(ret, key, Py_None);
855 }
856 }
856 sneedle++;
857 sneedle++;
857 oneedle++;
858 oneedle++;
858 }
859 }
859 Py_DECREF(key);
860 Py_DECREF(key);
860 }
861 }
861 Py_DECREF(emptyTup);
862 Py_DECREF(emptyTup);
862 return ret;
863 return ret;
863 nomem:
864 nomem:
864 PyErr_NoMemory();
865 PyErr_NoMemory();
865 Py_XDECREF(ret);
866 Py_XDECREF(ret);
866 Py_XDECREF(emptyTup);
867 Py_XDECREF(emptyTup);
867 return NULL;
868 return NULL;
868 }
869 }
869
870
870 static PyMethodDef lazymanifest_methods[] = {
871 static PyMethodDef lazymanifest_methods[] = {
871 {"iterkeys", (PyCFunction)lazymanifest_getkeysiter, METH_NOARGS,
872 {"iterkeys", (PyCFunction)lazymanifest_getkeysiter, METH_NOARGS,
872 "Iterate over file names in this lazymanifest."},
873 "Iterate over file names in this lazymanifest."},
873 {"iterentries", (PyCFunction)lazymanifest_getentriesiter, METH_NOARGS,
874 {"iterentries", (PyCFunction)lazymanifest_getentriesiter, METH_NOARGS,
874 "Iterate over (path, nodeid, flags) tuples in this lazymanifest."},
875 "Iterate over (path, nodeid, flags) tuples in this lazymanifest."},
875 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
876 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
876 "Make a copy of this lazymanifest."},
877 "Make a copy of this lazymanifest."},
877 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
878 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
878 "Make a copy of this manifest filtered by matchfn."},
879 "Make a copy of this manifest filtered by matchfn."},
879 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
880 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
880 "Compare this lazymanifest to another one."},
881 "Compare this lazymanifest to another one."},
881 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
882 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
882 "Encode this manifest to text."},
883 "Encode this manifest to text."},
883 {NULL},
884 {NULL},
884 };
885 };
885
886
886 #ifdef IS_PY3K
887 #ifdef IS_PY3K
887 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT
888 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT
888 #else
889 #else
889 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_SEQUENCE_IN
890 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_SEQUENCE_IN
890 #endif
891 #endif
891
892
892 static PyTypeObject lazymanifestType = {
893 static PyTypeObject lazymanifestType = {
893 PyVarObject_HEAD_INIT(NULL, 0) /* header */
894 PyVarObject_HEAD_INIT(NULL, 0) /* header */
894 "parsers.lazymanifest", /* tp_name */
895 "parsers.lazymanifest", /* tp_name */
895 sizeof(lazymanifest), /* tp_basicsize */
896 sizeof(lazymanifest), /* tp_basicsize */
896 0, /* tp_itemsize */
897 0, /* tp_itemsize */
897 (destructor)lazymanifest_dealloc, /* tp_dealloc */
898 (destructor)lazymanifest_dealloc, /* tp_dealloc */
898 0, /* tp_print */
899 0, /* tp_print */
899 0, /* tp_getattr */
900 0, /* tp_getattr */
900 0, /* tp_setattr */
901 0, /* tp_setattr */
901 0, /* tp_compare */
902 0, /* tp_compare */
902 0, /* tp_repr */
903 0, /* tp_repr */
903 0, /* tp_as_number */
904 0, /* tp_as_number */
904 &lazymanifest_seq_meths, /* tp_as_sequence */
905 &lazymanifest_seq_meths, /* tp_as_sequence */
905 &lazymanifest_mapping_methods, /* tp_as_mapping */
906 &lazymanifest_mapping_methods, /* tp_as_mapping */
906 0, /* tp_hash */
907 0, /* tp_hash */
907 0, /* tp_call */
908 0, /* tp_call */
908 0, /* tp_str */
909 0, /* tp_str */
909 0, /* tp_getattro */
910 0, /* tp_getattro */
910 0, /* tp_setattro */
911 0, /* tp_setattro */
911 0, /* tp_as_buffer */
912 0, /* tp_as_buffer */
912 LAZYMANIFEST_TPFLAGS, /* tp_flags */
913 LAZYMANIFEST_TPFLAGS, /* tp_flags */
913 "TODO(augie)", /* tp_doc */
914 "TODO(augie)", /* tp_doc */
914 0, /* tp_traverse */
915 0, /* tp_traverse */
915 0, /* tp_clear */
916 0, /* tp_clear */
916 0, /* tp_richcompare */
917 0, /* tp_richcompare */
917 0, /* tp_weaklistoffset */
918 0, /* tp_weaklistoffset */
918 (getiterfunc)lazymanifest_getkeysiter, /* tp_iter */
919 (getiterfunc)lazymanifest_getkeysiter, /* tp_iter */
919 0, /* tp_iternext */
920 0, /* tp_iternext */
920 lazymanifest_methods, /* tp_methods */
921 lazymanifest_methods, /* tp_methods */
921 0, /* tp_members */
922 0, /* tp_members */
922 0, /* tp_getset */
923 0, /* tp_getset */
923 0, /* tp_base */
924 0, /* tp_base */
924 0, /* tp_dict */
925 0, /* tp_dict */
925 0, /* tp_descr_get */
926 0, /* tp_descr_get */
926 0, /* tp_descr_set */
927 0, /* tp_descr_set */
927 0, /* tp_dictoffset */
928 0, /* tp_dictoffset */
928 (initproc)lazymanifest_init, /* tp_init */
929 (initproc)lazymanifest_init, /* tp_init */
929 0, /* tp_alloc */
930 0, /* tp_alloc */
930 };
931 };
931
932
932 void manifest_module_init(PyObject * mod)
933 void manifest_module_init(PyObject * mod)
933 {
934 {
934 lazymanifestType.tp_new = PyType_GenericNew;
935 lazymanifestType.tp_new = PyType_GenericNew;
935 if (PyType_Ready(&lazymanifestType) < 0)
936 if (PyType_Ready(&lazymanifestType) < 0)
936 return;
937 return;
937 Py_INCREF(&lazymanifestType);
938 Py_INCREF(&lazymanifestType);
938
939
939 PyModule_AddObject(mod, "lazymanifest",
940 PyModule_AddObject(mod, "lazymanifest",
940 (PyObject *)&lazymanifestType);
941 (PyObject *)&lazymanifestType);
941 }
942 }
@@ -1,1379 +1,1383 b''
1 /*
1 /*
2 osutil.c - native operating system services
2 osutil.c - native operating system services
3
3
4 Copyright 2007 Matt Mackall and others
4 Copyright 2007 Matt Mackall 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 _ATFILE_SOURCE
10 #define _ATFILE_SOURCE
11 #include <Python.h>
11 #include <Python.h>
12 #include <errno.h>
12 #include <errno.h>
13 #include <fcntl.h>
13 #include <fcntl.h>
14 #include <stdio.h>
14 #include <stdio.h>
15 #include <stdlib.h>
15 #include <stdlib.h>
16 #include <string.h>
16 #include <string.h>
17
17
18 #ifdef _WIN32
18 #ifdef _WIN32
19 #include <io.h>
19 #include <io.h>
20 #include <windows.h>
20 #include <windows.h>
21 #else
21 #else
22 #include <dirent.h>
22 #include <dirent.h>
23 #include <signal.h>
23 #include <signal.h>
24 #include <sys/socket.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
26 #include <sys/types.h>
27 #include <unistd.h>
27 #include <unistd.h>
28 #ifdef HAVE_LINUX_STATFS
28 #ifdef HAVE_LINUX_STATFS
29 #include <linux/magic.h>
29 #include <linux/magic.h>
30 #include <sys/vfs.h>
30 #include <sys/vfs.h>
31 #endif
31 #endif
32 #ifdef HAVE_BSD_STATFS
32 #ifdef HAVE_BSD_STATFS
33 #include <sys/mount.h>
33 #include <sys/mount.h>
34 #include <sys/param.h>
34 #include <sys/param.h>
35 #endif
35 #endif
36 #endif
36 #endif
37
37
38 #ifdef __APPLE__
38 #ifdef __APPLE__
39 #include <sys/attr.h>
39 #include <sys/attr.h>
40 #include <sys/vnode.h>
40 #include <sys/vnode.h>
41 #endif
41 #endif
42
42
43 #include "util.h"
43 #include "util.h"
44
44
45 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
45 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
46 #ifndef PATH_MAX
46 #ifndef PATH_MAX
47 #define PATH_MAX 4096
47 #define PATH_MAX 4096
48 #endif
48 #endif
49
49
50 #ifdef _WIN32
50 #ifdef _WIN32
51 /*
51 /*
52 stat struct compatible with hg expectations
52 stat struct compatible with hg expectations
53 Mercurial only uses st_mode, st_size and st_mtime
53 Mercurial only uses st_mode, st_size and st_mtime
54 the rest is kept to minimize changes between implementations
54 the rest is kept to minimize changes between implementations
55 */
55 */
56 struct hg_stat {
56 struct hg_stat {
57 int st_dev;
57 int st_dev;
58 int st_mode;
58 int st_mode;
59 int st_nlink;
59 int st_nlink;
60 __int64 st_size;
60 __int64 st_size;
61 int st_mtime;
61 int st_mtime;
62 int st_ctime;
62 int st_ctime;
63 };
63 };
64 struct listdir_stat {
64 struct listdir_stat {
65 PyObject_HEAD
65 PyObject_HEAD
66 struct hg_stat st;
66 struct hg_stat st;
67 };
67 };
68 #else
68 #else
69 struct listdir_stat {
69 struct listdir_stat {
70 PyObject_HEAD
70 PyObject_HEAD
71 struct stat st;
71 struct stat st;
72 };
72 };
73 #endif
73 #endif
74
74
75 #ifdef IS_PY3K
75 #ifdef IS_PY3K
76 #define listdir_slot(name) \
76 #define listdir_slot(name) \
77 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
77 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
78 { \
78 { \
79 return PyLong_FromLong(((struct listdir_stat *)self)->st.name); \
79 return PyLong_FromLong(((struct listdir_stat *)self)->st.name); \
80 }
80 }
81 #else
81 #else
82 #define listdir_slot(name) \
82 #define listdir_slot(name) \
83 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
83 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
84 { \
84 { \
85 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
85 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
86 }
86 }
87 #endif
87 #endif
88
88
89 listdir_slot(st_dev)
89 listdir_slot(st_dev)
90 listdir_slot(st_mode)
90 listdir_slot(st_mode)
91 listdir_slot(st_nlink)
91 listdir_slot(st_nlink)
92 #ifdef _WIN32
92 #ifdef _WIN32
93 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
93 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
94 {
94 {
95 return PyLong_FromLongLong(
95 return PyLong_FromLongLong(
96 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
96 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
97 }
97 }
98 #else
98 #else
99 listdir_slot(st_size)
99 listdir_slot(st_size)
100 #endif
100 #endif
101 listdir_slot(st_mtime)
101 listdir_slot(st_mtime)
102 listdir_slot(st_ctime)
102 listdir_slot(st_ctime)
103
103
104 static struct PyGetSetDef listdir_stat_getsets[] = {
104 static struct PyGetSetDef listdir_stat_getsets[] = {
105 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
105 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
106 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
106 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
107 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
107 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
108 {"st_size", listdir_stat_st_size, 0, 0, 0},
108 {"st_size", listdir_stat_st_size, 0, 0, 0},
109 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
109 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
110 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
110 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
111 {0, 0, 0, 0, 0}
111 {0, 0, 0, 0, 0}
112 };
112 };
113
113
114 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
114 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
115 {
115 {
116 return t->tp_alloc(t, 0);
116 return t->tp_alloc(t, 0);
117 }
117 }
118
118
119 static void listdir_stat_dealloc(PyObject *o)
119 static void listdir_stat_dealloc(PyObject *o)
120 {
120 {
121 o->ob_type->tp_free(o);
121 o->ob_type->tp_free(o);
122 }
122 }
123
123
124 static PyTypeObject listdir_stat_type = {
124 static PyTypeObject listdir_stat_type = {
125 PyVarObject_HEAD_INIT(NULL, 0) /* header */
125 PyVarObject_HEAD_INIT(NULL, 0) /* header */
126 "osutil.stat", /*tp_name*/
126 "osutil.stat", /*tp_name*/
127 sizeof(struct listdir_stat), /*tp_basicsize*/
127 sizeof(struct listdir_stat), /*tp_basicsize*/
128 0, /*tp_itemsize*/
128 0, /*tp_itemsize*/
129 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
129 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
130 0, /*tp_print*/
130 0, /*tp_print*/
131 0, /*tp_getattr*/
131 0, /*tp_getattr*/
132 0, /*tp_setattr*/
132 0, /*tp_setattr*/
133 0, /*tp_compare*/
133 0, /*tp_compare*/
134 0, /*tp_repr*/
134 0, /*tp_repr*/
135 0, /*tp_as_number*/
135 0, /*tp_as_number*/
136 0, /*tp_as_sequence*/
136 0, /*tp_as_sequence*/
137 0, /*tp_as_mapping*/
137 0, /*tp_as_mapping*/
138 0, /*tp_hash */
138 0, /*tp_hash */
139 0, /*tp_call*/
139 0, /*tp_call*/
140 0, /*tp_str*/
140 0, /*tp_str*/
141 0, /*tp_getattro*/
141 0, /*tp_getattro*/
142 0, /*tp_setattro*/
142 0, /*tp_setattro*/
143 0, /*tp_as_buffer*/
143 0, /*tp_as_buffer*/
144 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
144 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
145 "stat objects", /* tp_doc */
145 "stat objects", /* tp_doc */
146 0, /* tp_traverse */
146 0, /* tp_traverse */
147 0, /* tp_clear */
147 0, /* tp_clear */
148 0, /* tp_richcompare */
148 0, /* tp_richcompare */
149 0, /* tp_weaklistoffset */
149 0, /* tp_weaklistoffset */
150 0, /* tp_iter */
150 0, /* tp_iter */
151 0, /* tp_iternext */
151 0, /* tp_iternext */
152 0, /* tp_methods */
152 0, /* tp_methods */
153 0, /* tp_members */
153 0, /* tp_members */
154 listdir_stat_getsets, /* tp_getset */
154 listdir_stat_getsets, /* tp_getset */
155 0, /* tp_base */
155 0, /* tp_base */
156 0, /* tp_dict */
156 0, /* tp_dict */
157 0, /* tp_descr_get */
157 0, /* tp_descr_get */
158 0, /* tp_descr_set */
158 0, /* tp_descr_set */
159 0, /* tp_dictoffset */
159 0, /* tp_dictoffset */
160 0, /* tp_init */
160 0, /* tp_init */
161 0, /* tp_alloc */
161 0, /* tp_alloc */
162 listdir_stat_new, /* tp_new */
162 listdir_stat_new, /* tp_new */
163 };
163 };
164
164
165 #ifdef _WIN32
165 #ifdef _WIN32
166
166
167 static int to_python_time(const FILETIME *tm)
167 static int to_python_time(const FILETIME *tm)
168 {
168 {
169 /* number of seconds between epoch and January 1 1601 */
169 /* number of seconds between epoch and January 1 1601 */
170 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
170 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
171 /* conversion factor from 100ns to 1s */
171 /* conversion factor from 100ns to 1s */
172 const __int64 a1 = 10000000;
172 const __int64 a1 = 10000000;
173 /* explicit (int) cast to suspend compiler warnings */
173 /* explicit (int) cast to suspend compiler warnings */
174 return (int)((((__int64)tm->dwHighDateTime << 32)
174 return (int)((((__int64)tm->dwHighDateTime << 32)
175 + tm->dwLowDateTime) / a1 - a0);
175 + tm->dwLowDateTime) / a1 - a0);
176 }
176 }
177
177
178 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
178 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
179 {
179 {
180 PyObject *py_st;
180 PyObject *py_st;
181 struct hg_stat *stp;
181 struct hg_stat *stp;
182
182
183 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
183 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
184 ? _S_IFDIR : _S_IFREG;
184 ? _S_IFDIR : _S_IFREG;
185
185
186 if (!wantstat)
186 if (!wantstat)
187 return Py_BuildValue("si", fd->cFileName, kind);
187 return Py_BuildValue(PY23("si", "yi"), fd->cFileName, kind);
188
188
189 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
189 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
190 if (!py_st)
190 if (!py_st)
191 return NULL;
191 return NULL;
192
192
193 stp = &((struct listdir_stat *)py_st)->st;
193 stp = &((struct listdir_stat *)py_st)->st;
194 /*
194 /*
195 use kind as st_mode
195 use kind as st_mode
196 rwx bits on Win32 are meaningless
196 rwx bits on Win32 are meaningless
197 and Hg does not use them anyway
197 and Hg does not use them anyway
198 */
198 */
199 stp->st_mode = kind;
199 stp->st_mode = kind;
200 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
200 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
201 stp->st_ctime = to_python_time(&fd->ftCreationTime);
201 stp->st_ctime = to_python_time(&fd->ftCreationTime);
202 if (kind == _S_IFREG)
202 if (kind == _S_IFREG)
203 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
203 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
204 + fd->nFileSizeLow;
204 + fd->nFileSizeLow;
205 return Py_BuildValue("siN", fd->cFileName,
205 return Py_BuildValue(PY23("siN", "yiN"), fd->cFileName,
206 kind, py_st);
206 kind, py_st);
207 }
207 }
208
208
209 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
209 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
210 {
210 {
211 PyObject *rval = NULL; /* initialize - return value */
211 PyObject *rval = NULL; /* initialize - return value */
212 PyObject *list;
212 PyObject *list;
213 HANDLE fh;
213 HANDLE fh;
214 WIN32_FIND_DATAA fd;
214 WIN32_FIND_DATAA fd;
215 char *pattern;
215 char *pattern;
216
216
217 /* build the path + \* pattern string */
217 /* build the path + \* pattern string */
218 pattern = PyMem_Malloc(plen + 3); /* path + \* + \0 */
218 pattern = PyMem_Malloc(plen + 3); /* path + \* + \0 */
219 if (!pattern) {
219 if (!pattern) {
220 PyErr_NoMemory();
220 PyErr_NoMemory();
221 goto error_nomem;
221 goto error_nomem;
222 }
222 }
223 memcpy(pattern, path, plen);
223 memcpy(pattern, path, plen);
224
224
225 if (plen > 0) {
225 if (plen > 0) {
226 char c = path[plen-1];
226 char c = path[plen-1];
227 if (c != ':' && c != '/' && c != '\\')
227 if (c != ':' && c != '/' && c != '\\')
228 pattern[plen++] = '\\';
228 pattern[plen++] = '\\';
229 }
229 }
230 pattern[plen++] = '*';
230 pattern[plen++] = '*';
231 pattern[plen] = '\0';
231 pattern[plen] = '\0';
232
232
233 fh = FindFirstFileA(pattern, &fd);
233 fh = FindFirstFileA(pattern, &fd);
234 if (fh == INVALID_HANDLE_VALUE) {
234 if (fh == INVALID_HANDLE_VALUE) {
235 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
235 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
236 goto error_file;
236 goto error_file;
237 }
237 }
238
238
239 list = PyList_New(0);
239 list = PyList_New(0);
240 if (!list)
240 if (!list)
241 goto error_list;
241 goto error_list;
242
242
243 do {
243 do {
244 PyObject *item;
244 PyObject *item;
245
245
246 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
246 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
247 if (!strcmp(fd.cFileName, ".")
247 if (!strcmp(fd.cFileName, ".")
248 || !strcmp(fd.cFileName, ".."))
248 || !strcmp(fd.cFileName, ".."))
249 continue;
249 continue;
250
250
251 if (skip && !strcmp(fd.cFileName, skip)) {
251 if (skip && !strcmp(fd.cFileName, skip)) {
252 rval = PyList_New(0);
252 rval = PyList_New(0);
253 goto error;
253 goto error;
254 }
254 }
255 }
255 }
256
256
257 item = make_item(&fd, wantstat);
257 item = make_item(&fd, wantstat);
258 if (!item)
258 if (!item)
259 goto error;
259 goto error;
260
260
261 if (PyList_Append(list, item)) {
261 if (PyList_Append(list, item)) {
262 Py_XDECREF(item);
262 Py_XDECREF(item);
263 goto error;
263 goto error;
264 }
264 }
265
265
266 Py_XDECREF(item);
266 Py_XDECREF(item);
267 } while (FindNextFileA(fh, &fd));
267 } while (FindNextFileA(fh, &fd));
268
268
269 if (GetLastError() != ERROR_NO_MORE_FILES) {
269 if (GetLastError() != ERROR_NO_MORE_FILES) {
270 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
270 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
271 goto error;
271 goto error;
272 }
272 }
273
273
274 rval = list;
274 rval = list;
275 Py_XINCREF(rval);
275 Py_XINCREF(rval);
276 error:
276 error:
277 Py_XDECREF(list);
277 Py_XDECREF(list);
278 error_list:
278 error_list:
279 FindClose(fh);
279 FindClose(fh);
280 error_file:
280 error_file:
281 PyMem_Free(pattern);
281 PyMem_Free(pattern);
282 error_nomem:
282 error_nomem:
283 return rval;
283 return rval;
284 }
284 }
285
285
286 #else
286 #else
287
287
288 int entkind(struct dirent *ent)
288 int entkind(struct dirent *ent)
289 {
289 {
290 #ifdef DT_REG
290 #ifdef DT_REG
291 switch (ent->d_type) {
291 switch (ent->d_type) {
292 case DT_REG: return S_IFREG;
292 case DT_REG: return S_IFREG;
293 case DT_DIR: return S_IFDIR;
293 case DT_DIR: return S_IFDIR;
294 case DT_LNK: return S_IFLNK;
294 case DT_LNK: return S_IFLNK;
295 case DT_BLK: return S_IFBLK;
295 case DT_BLK: return S_IFBLK;
296 case DT_CHR: return S_IFCHR;
296 case DT_CHR: return S_IFCHR;
297 case DT_FIFO: return S_IFIFO;
297 case DT_FIFO: return S_IFIFO;
298 case DT_SOCK: return S_IFSOCK;
298 case DT_SOCK: return S_IFSOCK;
299 }
299 }
300 #endif
300 #endif
301 return -1;
301 return -1;
302 }
302 }
303
303
304 static PyObject *makestat(const struct stat *st)
304 static PyObject *makestat(const struct stat *st)
305 {
305 {
306 PyObject *stat;
306 PyObject *stat;
307
307
308 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
308 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
309 if (stat)
309 if (stat)
310 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
310 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
311 return stat;
311 return stat;
312 }
312 }
313
313
314 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
314 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
315 char *skip)
315 char *skip)
316 {
316 {
317 PyObject *list, *elem, *stat = NULL, *ret = NULL;
317 PyObject *list, *elem, *stat = NULL, *ret = NULL;
318 char fullpath[PATH_MAX + 10];
318 char fullpath[PATH_MAX + 10];
319 int kind, err;
319 int kind, err;
320 struct stat st;
320 struct stat st;
321 struct dirent *ent;
321 struct dirent *ent;
322 DIR *dir;
322 DIR *dir;
323 #ifdef AT_SYMLINK_NOFOLLOW
323 #ifdef AT_SYMLINK_NOFOLLOW
324 int dfd = -1;
324 int dfd = -1;
325 #endif
325 #endif
326
326
327 if (pathlen >= PATH_MAX) {
327 if (pathlen >= PATH_MAX) {
328 errno = ENAMETOOLONG;
328 errno = ENAMETOOLONG;
329 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
329 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
330 goto error_value;
330 goto error_value;
331 }
331 }
332 strncpy(fullpath, path, PATH_MAX);
332 strncpy(fullpath, path, PATH_MAX);
333 fullpath[pathlen] = '/';
333 fullpath[pathlen] = '/';
334
334
335 #ifdef AT_SYMLINK_NOFOLLOW
335 #ifdef AT_SYMLINK_NOFOLLOW
336 dfd = open(path, O_RDONLY);
336 dfd = open(path, O_RDONLY);
337 if (dfd == -1) {
337 if (dfd == -1) {
338 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
338 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
339 goto error_value;
339 goto error_value;
340 }
340 }
341 dir = fdopendir(dfd);
341 dir = fdopendir(dfd);
342 #else
342 #else
343 dir = opendir(path);
343 dir = opendir(path);
344 #endif
344 #endif
345 if (!dir) {
345 if (!dir) {
346 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
346 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
347 goto error_dir;
347 goto error_dir;
348 }
348 }
349
349
350 list = PyList_New(0);
350 list = PyList_New(0);
351 if (!list)
351 if (!list)
352 goto error_list;
352 goto error_list;
353
353
354 while ((ent = readdir(dir))) {
354 while ((ent = readdir(dir))) {
355 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
355 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
356 continue;
356 continue;
357
357
358 kind = entkind(ent);
358 kind = entkind(ent);
359 if (kind == -1 || keepstat) {
359 if (kind == -1 || keepstat) {
360 #ifdef AT_SYMLINK_NOFOLLOW
360 #ifdef AT_SYMLINK_NOFOLLOW
361 err = fstatat(dfd, ent->d_name, &st,
361 err = fstatat(dfd, ent->d_name, &st,
362 AT_SYMLINK_NOFOLLOW);
362 AT_SYMLINK_NOFOLLOW);
363 #else
363 #else
364 strncpy(fullpath + pathlen + 1, ent->d_name,
364 strncpy(fullpath + pathlen + 1, ent->d_name,
365 PATH_MAX - pathlen);
365 PATH_MAX - pathlen);
366 fullpath[PATH_MAX] = '\0';
366 fullpath[PATH_MAX] = '\0';
367 err = lstat(fullpath, &st);
367 err = lstat(fullpath, &st);
368 #endif
368 #endif
369 if (err == -1) {
369 if (err == -1) {
370 /* race with file deletion? */
370 /* race with file deletion? */
371 if (errno == ENOENT)
371 if (errno == ENOENT)
372 continue;
372 continue;
373 strncpy(fullpath + pathlen + 1, ent->d_name,
373 strncpy(fullpath + pathlen + 1, ent->d_name,
374 PATH_MAX - pathlen);
374 PATH_MAX - pathlen);
375 fullpath[PATH_MAX] = 0;
375 fullpath[PATH_MAX] = 0;
376 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
376 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
377 fullpath);
377 fullpath);
378 goto error;
378 goto error;
379 }
379 }
380 kind = st.st_mode & S_IFMT;
380 kind = st.st_mode & S_IFMT;
381 }
381 }
382
382
383 /* quit early? */
383 /* quit early? */
384 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
384 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
385 ret = PyList_New(0);
385 ret = PyList_New(0);
386 goto error;
386 goto error;
387 }
387 }
388
388
389 if (keepstat) {
389 if (keepstat) {
390 stat = makestat(&st);
390 stat = makestat(&st);
391 if (!stat)
391 if (!stat)
392 goto error;
392 goto error;
393 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
393 elem = Py_BuildValue(PY23("siN", "yiN"), ent->d_name,
394 kind, stat);
394 } else
395 } else
395 elem = Py_BuildValue("si", ent->d_name, kind);
396 elem = Py_BuildValue(PY23("si", "yi"), ent->d_name,
397 kind);
396 if (!elem)
398 if (!elem)
397 goto error;
399 goto error;
398 stat = NULL;
400 stat = NULL;
399
401
400 PyList_Append(list, elem);
402 PyList_Append(list, elem);
401 Py_DECREF(elem);
403 Py_DECREF(elem);
402 }
404 }
403
405
404 ret = list;
406 ret = list;
405 Py_INCREF(ret);
407 Py_INCREF(ret);
406
408
407 error:
409 error:
408 Py_DECREF(list);
410 Py_DECREF(list);
409 Py_XDECREF(stat);
411 Py_XDECREF(stat);
410 error_list:
412 error_list:
411 closedir(dir);
413 closedir(dir);
412 /* closedir also closes its dirfd */
414 /* closedir also closes its dirfd */
413 goto error_value;
415 goto error_value;
414 error_dir:
416 error_dir:
415 #ifdef AT_SYMLINK_NOFOLLOW
417 #ifdef AT_SYMLINK_NOFOLLOW
416 close(dfd);
418 close(dfd);
417 #endif
419 #endif
418 error_value:
420 error_value:
419 return ret;
421 return ret;
420 }
422 }
421
423
422 #ifdef __APPLE__
424 #ifdef __APPLE__
423
425
424 typedef struct {
426 typedef struct {
425 u_int32_t length;
427 u_int32_t length;
426 attrreference_t name;
428 attrreference_t name;
427 fsobj_type_t obj_type;
429 fsobj_type_t obj_type;
428 struct timespec mtime;
430 struct timespec mtime;
429 #if __LITTLE_ENDIAN__
431 #if __LITTLE_ENDIAN__
430 mode_t access_mask;
432 mode_t access_mask;
431 uint16_t padding;
433 uint16_t padding;
432 #else
434 #else
433 uint16_t padding;
435 uint16_t padding;
434 mode_t access_mask;
436 mode_t access_mask;
435 #endif
437 #endif
436 off_t size;
438 off_t size;
437 } __attribute__((packed)) attrbuf_entry;
439 } __attribute__((packed)) attrbuf_entry;
438
440
439 int attrkind(attrbuf_entry *entry)
441 int attrkind(attrbuf_entry *entry)
440 {
442 {
441 switch (entry->obj_type) {
443 switch (entry->obj_type) {
442 case VREG: return S_IFREG;
444 case VREG: return S_IFREG;
443 case VDIR: return S_IFDIR;
445 case VDIR: return S_IFDIR;
444 case VLNK: return S_IFLNK;
446 case VLNK: return S_IFLNK;
445 case VBLK: return S_IFBLK;
447 case VBLK: return S_IFBLK;
446 case VCHR: return S_IFCHR;
448 case VCHR: return S_IFCHR;
447 case VFIFO: return S_IFIFO;
449 case VFIFO: return S_IFIFO;
448 case VSOCK: return S_IFSOCK;
450 case VSOCK: return S_IFSOCK;
449 }
451 }
450 return -1;
452 return -1;
451 }
453 }
452
454
453 /* get these many entries at a time */
455 /* get these many entries at a time */
454 #define LISTDIR_BATCH_SIZE 50
456 #define LISTDIR_BATCH_SIZE 50
455
457
456 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
458 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
457 char *skip, bool *fallback)
459 char *skip, bool *fallback)
458 {
460 {
459 PyObject *list, *elem, *stat = NULL, *ret = NULL;
461 PyObject *list, *elem, *stat = NULL, *ret = NULL;
460 int kind, err;
462 int kind, err;
461 unsigned long index;
463 unsigned long index;
462 unsigned int count, old_state, new_state;
464 unsigned int count, old_state, new_state;
463 bool state_seen = false;
465 bool state_seen = false;
464 attrbuf_entry *entry;
466 attrbuf_entry *entry;
465 /* from the getattrlist(2) man page: a path can be no longer than
467 /* from the getattrlist(2) man page: a path can be no longer than
466 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
468 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
467 silently truncate attribute data if attrBufSize is too small." So
469 silently truncate attribute data if attrBufSize is too small." So
468 pass in a buffer big enough for the worst case. */
470 pass in a buffer big enough for the worst case. */
469 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
471 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
470 unsigned int basep_unused;
472 unsigned int basep_unused;
471
473
472 struct stat st;
474 struct stat st;
473 int dfd = -1;
475 int dfd = -1;
474
476
475 /* these must match the attrbuf_entry struct, otherwise you'll end up
477 /* these must match the attrbuf_entry struct, otherwise you'll end up
476 with garbage */
478 with garbage */
477 struct attrlist requested_attr = {0};
479 struct attrlist requested_attr = {0};
478 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
480 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
479 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
481 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
480 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
482 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
481 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
483 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
482
484
483 *fallback = false;
485 *fallback = false;
484
486
485 if (pathlen >= PATH_MAX) {
487 if (pathlen >= PATH_MAX) {
486 errno = ENAMETOOLONG;
488 errno = ENAMETOOLONG;
487 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
489 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
488 goto error_value;
490 goto error_value;
489 }
491 }
490
492
491 dfd = open(path, O_RDONLY);
493 dfd = open(path, O_RDONLY);
492 if (dfd == -1) {
494 if (dfd == -1) {
493 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
495 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
494 goto error_value;
496 goto error_value;
495 }
497 }
496
498
497 list = PyList_New(0);
499 list = PyList_New(0);
498 if (!list)
500 if (!list)
499 goto error_dir;
501 goto error_dir;
500
502
501 do {
503 do {
502 count = LISTDIR_BATCH_SIZE;
504 count = LISTDIR_BATCH_SIZE;
503 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
505 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
504 sizeof(attrbuf), &count, &basep_unused,
506 sizeof(attrbuf), &count, &basep_unused,
505 &new_state, 0);
507 &new_state, 0);
506 if (err < 0) {
508 if (err < 0) {
507 if (errno == ENOTSUP) {
509 if (errno == ENOTSUP) {
508 /* We're on a filesystem that doesn't support
510 /* We're on a filesystem that doesn't support
509 getdirentriesattr. Fall back to the
511 getdirentriesattr. Fall back to the
510 stat-based implementation. */
512 stat-based implementation. */
511 *fallback = true;
513 *fallback = true;
512 } else
514 } else
513 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
515 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
514 goto error;
516 goto error;
515 }
517 }
516
518
517 if (!state_seen) {
519 if (!state_seen) {
518 old_state = new_state;
520 old_state = new_state;
519 state_seen = true;
521 state_seen = true;
520 } else if (old_state != new_state) {
522 } else if (old_state != new_state) {
521 /* There's an edge case with getdirentriesattr. Consider
523 /* There's an edge case with getdirentriesattr. Consider
522 the following initial list of files:
524 the following initial list of files:
523
525
524 a
526 a
525 b
527 b
526 <--
528 <--
527 c
529 c
528 d
530 d
529
531
530 If the iteration is paused at the arrow, and b is
532 If the iteration is paused at the arrow, and b is
531 deleted before it is resumed, getdirentriesattr will
533 deleted before it is resumed, getdirentriesattr will
532 not return d at all! Ordinarily we're expected to
534 not return d at all! Ordinarily we're expected to
533 restart the iteration from the beginning. To avoid
535 restart the iteration from the beginning. To avoid
534 getting stuck in a retry loop here, fall back to
536 getting stuck in a retry loop here, fall back to
535 stat. */
537 stat. */
536 *fallback = true;
538 *fallback = true;
537 goto error;
539 goto error;
538 }
540 }
539
541
540 entry = (attrbuf_entry *)attrbuf;
542 entry = (attrbuf_entry *)attrbuf;
541
543
542 for (index = 0; index < count; index++) {
544 for (index = 0; index < count; index++) {
543 char *filename = ((char *)&entry->name) +
545 char *filename = ((char *)&entry->name) +
544 entry->name.attr_dataoffset;
546 entry->name.attr_dataoffset;
545
547
546 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
548 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
547 continue;
549 continue;
548
550
549 kind = attrkind(entry);
551 kind = attrkind(entry);
550 if (kind == -1) {
552 if (kind == -1) {
551 PyErr_Format(PyExc_OSError,
553 PyErr_Format(PyExc_OSError,
552 "unknown object type %u for file "
554 "unknown object type %u for file "
553 "%s%s!",
555 "%s%s!",
554 entry->obj_type, path, filename);
556 entry->obj_type, path, filename);
555 goto error;
557 goto error;
556 }
558 }
557
559
558 /* quit early? */
560 /* quit early? */
559 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
561 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
560 ret = PyList_New(0);
562 ret = PyList_New(0);
561 goto error;
563 goto error;
562 }
564 }
563
565
564 if (keepstat) {
566 if (keepstat) {
565 /* from the getattrlist(2) man page: "Only the
567 /* from the getattrlist(2) man page: "Only the
566 permission bits ... are valid". */
568 permission bits ... are valid". */
567 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
569 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
568 st.st_mtime = entry->mtime.tv_sec;
570 st.st_mtime = entry->mtime.tv_sec;
569 st.st_size = entry->size;
571 st.st_size = entry->size;
570 stat = makestat(&st);
572 stat = makestat(&st);
571 if (!stat)
573 if (!stat)
572 goto error;
574 goto error;
573 elem = Py_BuildValue("siN", filename, kind, stat);
575 elem = Py_BuildValue(PY23("siN", "yiN"),
576 filename, kind, stat);
574 } else
577 } else
575 elem = Py_BuildValue("si", filename, kind);
578 elem = Py_BuildValue(PY23("si", "yi"),
579 filename, kind);
576 if (!elem)
580 if (!elem)
577 goto error;
581 goto error;
578 stat = NULL;
582 stat = NULL;
579
583
580 PyList_Append(list, elem);
584 PyList_Append(list, elem);
581 Py_DECREF(elem);
585 Py_DECREF(elem);
582
586
583 entry = (attrbuf_entry *)((char *)entry + entry->length);
587 entry = (attrbuf_entry *)((char *)entry + entry->length);
584 }
588 }
585 } while (err == 0);
589 } while (err == 0);
586
590
587 ret = list;
591 ret = list;
588 Py_INCREF(ret);
592 Py_INCREF(ret);
589
593
590 error:
594 error:
591 Py_DECREF(list);
595 Py_DECREF(list);
592 Py_XDECREF(stat);
596 Py_XDECREF(stat);
593 error_dir:
597 error_dir:
594 close(dfd);
598 close(dfd);
595 error_value:
599 error_value:
596 return ret;
600 return ret;
597 }
601 }
598
602
599 #endif /* __APPLE__ */
603 #endif /* __APPLE__ */
600
604
601 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
605 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
602 {
606 {
603 #ifdef __APPLE__
607 #ifdef __APPLE__
604 PyObject *ret;
608 PyObject *ret;
605 bool fallback = false;
609 bool fallback = false;
606
610
607 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
611 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
608 if (ret != NULL || !fallback)
612 if (ret != NULL || !fallback)
609 return ret;
613 return ret;
610 #endif
614 #endif
611 return _listdir_stat(path, pathlen, keepstat, skip);
615 return _listdir_stat(path, pathlen, keepstat, skip);
612 }
616 }
613
617
614 static PyObject *statfiles(PyObject *self, PyObject *args)
618 static PyObject *statfiles(PyObject *self, PyObject *args)
615 {
619 {
616 PyObject *names, *stats;
620 PyObject *names, *stats;
617 Py_ssize_t i, count;
621 Py_ssize_t i, count;
618
622
619 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
623 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
620 return NULL;
624 return NULL;
621
625
622 count = PySequence_Length(names);
626 count = PySequence_Length(names);
623 if (count == -1) {
627 if (count == -1) {
624 PyErr_SetString(PyExc_TypeError, "not a sequence");
628 PyErr_SetString(PyExc_TypeError, "not a sequence");
625 return NULL;
629 return NULL;
626 }
630 }
627
631
628 stats = PyList_New(count);
632 stats = PyList_New(count);
629 if (stats == NULL)
633 if (stats == NULL)
630 return NULL;
634 return NULL;
631
635
632 for (i = 0; i < count; i++) {
636 for (i = 0; i < count; i++) {
633 PyObject *stat, *pypath;
637 PyObject *stat, *pypath;
634 struct stat st;
638 struct stat st;
635 int ret, kind;
639 int ret, kind;
636 char *path;
640 char *path;
637
641
638 /* With a large file count or on a slow filesystem,
642 /* With a large file count or on a slow filesystem,
639 don't block signals for long (issue4878). */
643 don't block signals for long (issue4878). */
640 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
644 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
641 goto bail;
645 goto bail;
642
646
643 pypath = PySequence_GetItem(names, i);
647 pypath = PySequence_GetItem(names, i);
644 if (!pypath)
648 if (!pypath)
645 goto bail;
649 goto bail;
646 path = PyBytes_AsString(pypath);
650 path = PyBytes_AsString(pypath);
647 if (path == NULL) {
651 if (path == NULL) {
648 Py_DECREF(pypath);
652 Py_DECREF(pypath);
649 PyErr_SetString(PyExc_TypeError, "not a string");
653 PyErr_SetString(PyExc_TypeError, "not a string");
650 goto bail;
654 goto bail;
651 }
655 }
652 ret = lstat(path, &st);
656 ret = lstat(path, &st);
653 Py_DECREF(pypath);
657 Py_DECREF(pypath);
654 kind = st.st_mode & S_IFMT;
658 kind = st.st_mode & S_IFMT;
655 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
659 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
656 stat = makestat(&st);
660 stat = makestat(&st);
657 if (stat == NULL)
661 if (stat == NULL)
658 goto bail;
662 goto bail;
659 PyList_SET_ITEM(stats, i, stat);
663 PyList_SET_ITEM(stats, i, stat);
660 } else {
664 } else {
661 Py_INCREF(Py_None);
665 Py_INCREF(Py_None);
662 PyList_SET_ITEM(stats, i, Py_None);
666 PyList_SET_ITEM(stats, i, Py_None);
663 }
667 }
664 }
668 }
665
669
666 return stats;
670 return stats;
667
671
668 bail:
672 bail:
669 Py_DECREF(stats);
673 Py_DECREF(stats);
670 return NULL;
674 return NULL;
671 }
675 }
672
676
673 /*
677 /*
674 * recvfds() simply does not release GIL during blocking io operation because
678 * recvfds() simply does not release GIL during blocking io operation because
675 * command server is known to be single-threaded.
679 * command server is known to be single-threaded.
676 *
680 *
677 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
681 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
678 * Currently, recvfds() is not supported on these platforms.
682 * Currently, recvfds() is not supported on these platforms.
679 */
683 */
680 #ifdef CMSG_LEN
684 #ifdef CMSG_LEN
681
685
682 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
686 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
683 {
687 {
684 char dummy[1];
688 char dummy[1];
685 struct iovec iov = {dummy, sizeof(dummy)};
689 struct iovec iov = {dummy, sizeof(dummy)};
686 struct msghdr msgh = {0};
690 struct msghdr msgh = {0};
687 struct cmsghdr *cmsg;
691 struct cmsghdr *cmsg;
688
692
689 msgh.msg_iov = &iov;
693 msgh.msg_iov = &iov;
690 msgh.msg_iovlen = 1;
694 msgh.msg_iovlen = 1;
691 msgh.msg_control = cbuf;
695 msgh.msg_control = cbuf;
692 msgh.msg_controllen = (socklen_t)cbufsize;
696 msgh.msg_controllen = (socklen_t)cbufsize;
693 if (recvmsg(sockfd, &msgh, 0) < 0)
697 if (recvmsg(sockfd, &msgh, 0) < 0)
694 return -1;
698 return -1;
695
699
696 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
700 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
697 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
701 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
698 if (cmsg->cmsg_level != SOL_SOCKET ||
702 if (cmsg->cmsg_level != SOL_SOCKET ||
699 cmsg->cmsg_type != SCM_RIGHTS)
703 cmsg->cmsg_type != SCM_RIGHTS)
700 continue;
704 continue;
701 *rfds = (int *)CMSG_DATA(cmsg);
705 *rfds = (int *)CMSG_DATA(cmsg);
702 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
706 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
703 }
707 }
704
708
705 *rfds = cbuf;
709 *rfds = cbuf;
706 return 0;
710 return 0;
707 }
711 }
708
712
709 static PyObject *recvfds(PyObject *self, PyObject *args)
713 static PyObject *recvfds(PyObject *self, PyObject *args)
710 {
714 {
711 int sockfd;
715 int sockfd;
712 int *rfds = NULL;
716 int *rfds = NULL;
713 ssize_t rfdscount, i;
717 ssize_t rfdscount, i;
714 char cbuf[256];
718 char cbuf[256];
715 PyObject *rfdslist = NULL;
719 PyObject *rfdslist = NULL;
716
720
717 if (!PyArg_ParseTuple(args, "i", &sockfd))
721 if (!PyArg_ParseTuple(args, "i", &sockfd))
718 return NULL;
722 return NULL;
719
723
720 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
724 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
721 if (rfdscount < 0)
725 if (rfdscount < 0)
722 return PyErr_SetFromErrno(PyExc_OSError);
726 return PyErr_SetFromErrno(PyExc_OSError);
723
727
724 rfdslist = PyList_New(rfdscount);
728 rfdslist = PyList_New(rfdscount);
725 if (!rfdslist)
729 if (!rfdslist)
726 goto bail;
730 goto bail;
727 for (i = 0; i < rfdscount; i++) {
731 for (i = 0; i < rfdscount; i++) {
728 PyObject *obj = PyLong_FromLong(rfds[i]);
732 PyObject *obj = PyLong_FromLong(rfds[i]);
729 if (!obj)
733 if (!obj)
730 goto bail;
734 goto bail;
731 PyList_SET_ITEM(rfdslist, i, obj);
735 PyList_SET_ITEM(rfdslist, i, obj);
732 }
736 }
733 return rfdslist;
737 return rfdslist;
734
738
735 bail:
739 bail:
736 Py_XDECREF(rfdslist);
740 Py_XDECREF(rfdslist);
737 return NULL;
741 return NULL;
738 }
742 }
739
743
740 #endif /* CMSG_LEN */
744 #endif /* CMSG_LEN */
741
745
742 #if defined(HAVE_SETPROCTITLE)
746 #if defined(HAVE_SETPROCTITLE)
743 /* setproctitle is the first choice - available in FreeBSD */
747 /* setproctitle is the first choice - available in FreeBSD */
744 #define SETPROCNAME_USE_SETPROCTITLE
748 #define SETPROCNAME_USE_SETPROCTITLE
745 #elif (defined(__linux__) || defined(__APPLE__)) && PY_MAJOR_VERSION == 2
749 #elif (defined(__linux__) || defined(__APPLE__)) && PY_MAJOR_VERSION == 2
746 /* rewrite the argv buffer in place - works in Linux and OS X. Py_GetArgcArgv
750 /* rewrite the argv buffer in place - works in Linux and OS X. Py_GetArgcArgv
747 * in Python 3 returns the copied wchar_t **argv, thus unsupported. */
751 * in Python 3 returns the copied wchar_t **argv, thus unsupported. */
748 #define SETPROCNAME_USE_ARGVREWRITE
752 #define SETPROCNAME_USE_ARGVREWRITE
749 #else
753 #else
750 #define SETPROCNAME_USE_NONE
754 #define SETPROCNAME_USE_NONE
751 #endif
755 #endif
752
756
753 #ifndef SETPROCNAME_USE_NONE
757 #ifndef SETPROCNAME_USE_NONE
754 static PyObject *setprocname(PyObject *self, PyObject *args)
758 static PyObject *setprocname(PyObject *self, PyObject *args)
755 {
759 {
756 const char *name = NULL;
760 const char *name = NULL;
757 if (!PyArg_ParseTuple(args, "s", &name))
761 if (!PyArg_ParseTuple(args, "s", &name))
758 return NULL;
762 return NULL;
759
763
760 #if defined(SETPROCNAME_USE_SETPROCTITLE)
764 #if defined(SETPROCNAME_USE_SETPROCTITLE)
761 setproctitle("%s", name);
765 setproctitle("%s", name);
762 #elif defined(SETPROCNAME_USE_ARGVREWRITE)
766 #elif defined(SETPROCNAME_USE_ARGVREWRITE)
763 {
767 {
764 static char *argvstart = NULL;
768 static char *argvstart = NULL;
765 static size_t argvsize = 0;
769 static size_t argvsize = 0;
766 if (argvstart == NULL) {
770 if (argvstart == NULL) {
767 int argc = 0, i;
771 int argc = 0, i;
768 char **argv = NULL;
772 char **argv = NULL;
769 char *argvend;
773 char *argvend;
770 extern void Py_GetArgcArgv(int *argc, char ***argv);
774 extern void Py_GetArgcArgv(int *argc, char ***argv);
771 Py_GetArgcArgv(&argc, &argv);
775 Py_GetArgcArgv(&argc, &argv);
772
776
773 /* Check the memory we can use. Typically, argv[i] and
777 /* Check the memory we can use. Typically, argv[i] and
774 * argv[i + 1] are continuous. */
778 * argv[i + 1] are continuous. */
775 argvend = argvstart = argv[0];
779 argvend = argvstart = argv[0];
776 for (i = 0; i < argc; ++i) {
780 for (i = 0; i < argc; ++i) {
777 if (argv[i] > argvend || argv[i] < argvstart)
781 if (argv[i] > argvend || argv[i] < argvstart)
778 break; /* not continuous */
782 break; /* not continuous */
779 size_t len = strlen(argv[i]);
783 size_t len = strlen(argv[i]);
780 argvend = argv[i] + len + 1 /* '\0' */;
784 argvend = argv[i] + len + 1 /* '\0' */;
781 }
785 }
782 if (argvend > argvstart) /* sanity check */
786 if (argvend > argvstart) /* sanity check */
783 argvsize = argvend - argvstart;
787 argvsize = argvend - argvstart;
784 }
788 }
785
789
786 if (argvstart && argvsize > 1) {
790 if (argvstart && argvsize > 1) {
787 int n = snprintf(argvstart, argvsize, "%s", name);
791 int n = snprintf(argvstart, argvsize, "%s", name);
788 if (n >= 0 && (size_t)n < argvsize)
792 if (n >= 0 && (size_t)n < argvsize)
789 memset(argvstart + n, 0, argvsize - n);
793 memset(argvstart + n, 0, argvsize - n);
790 }
794 }
791 }
795 }
792 #endif
796 #endif
793
797
794 Py_RETURN_NONE;
798 Py_RETURN_NONE;
795 }
799 }
796 #endif /* ndef SETPROCNAME_USE_NONE */
800 #endif /* ndef SETPROCNAME_USE_NONE */
797
801
798 #if defined(HAVE_BSD_STATFS)
802 #if defined(HAVE_BSD_STATFS)
799 static const char *describefstype(const struct statfs *pbuf)
803 static const char *describefstype(const struct statfs *pbuf)
800 {
804 {
801 /* BSD or OSX provides a f_fstypename field */
805 /* BSD or OSX provides a f_fstypename field */
802 return pbuf->f_fstypename;
806 return pbuf->f_fstypename;
803 }
807 }
804 #elif defined(HAVE_LINUX_STATFS)
808 #elif defined(HAVE_LINUX_STATFS)
805 static const char *describefstype(const struct statfs *pbuf)
809 static const char *describefstype(const struct statfs *pbuf)
806 {
810 {
807 /* Begin of Linux filesystems */
811 /* Begin of Linux filesystems */
808 #ifdef ADFS_SUPER_MAGIC
812 #ifdef ADFS_SUPER_MAGIC
809 if (pbuf->f_type == ADFS_SUPER_MAGIC)
813 if (pbuf->f_type == ADFS_SUPER_MAGIC)
810 return "adfs";
814 return "adfs";
811 #endif
815 #endif
812 #ifdef AFFS_SUPER_MAGIC
816 #ifdef AFFS_SUPER_MAGIC
813 if (pbuf->f_type == AFFS_SUPER_MAGIC)
817 if (pbuf->f_type == AFFS_SUPER_MAGIC)
814 return "affs";
818 return "affs";
815 #endif
819 #endif
816 #ifdef AUTOFS_SUPER_MAGIC
820 #ifdef AUTOFS_SUPER_MAGIC
817 if (pbuf->f_type == AUTOFS_SUPER_MAGIC)
821 if (pbuf->f_type == AUTOFS_SUPER_MAGIC)
818 return "autofs";
822 return "autofs";
819 #endif
823 #endif
820 #ifdef BDEVFS_MAGIC
824 #ifdef BDEVFS_MAGIC
821 if (pbuf->f_type == BDEVFS_MAGIC)
825 if (pbuf->f_type == BDEVFS_MAGIC)
822 return "bdevfs";
826 return "bdevfs";
823 #endif
827 #endif
824 #ifdef BEFS_SUPER_MAGIC
828 #ifdef BEFS_SUPER_MAGIC
825 if (pbuf->f_type == BEFS_SUPER_MAGIC)
829 if (pbuf->f_type == BEFS_SUPER_MAGIC)
826 return "befs";
830 return "befs";
827 #endif
831 #endif
828 #ifdef BFS_MAGIC
832 #ifdef BFS_MAGIC
829 if (pbuf->f_type == BFS_MAGIC)
833 if (pbuf->f_type == BFS_MAGIC)
830 return "bfs";
834 return "bfs";
831 #endif
835 #endif
832 #ifdef BINFMTFS_MAGIC
836 #ifdef BINFMTFS_MAGIC
833 if (pbuf->f_type == BINFMTFS_MAGIC)
837 if (pbuf->f_type == BINFMTFS_MAGIC)
834 return "binfmtfs";
838 return "binfmtfs";
835 #endif
839 #endif
836 #ifdef BTRFS_SUPER_MAGIC
840 #ifdef BTRFS_SUPER_MAGIC
837 if (pbuf->f_type == BTRFS_SUPER_MAGIC)
841 if (pbuf->f_type == BTRFS_SUPER_MAGIC)
838 return "btrfs";
842 return "btrfs";
839 #endif
843 #endif
840 #ifdef CGROUP_SUPER_MAGIC
844 #ifdef CGROUP_SUPER_MAGIC
841 if (pbuf->f_type == CGROUP_SUPER_MAGIC)
845 if (pbuf->f_type == CGROUP_SUPER_MAGIC)
842 return "cgroup";
846 return "cgroup";
843 #endif
847 #endif
844 #ifdef CIFS_MAGIC_NUMBER
848 #ifdef CIFS_MAGIC_NUMBER
845 if (pbuf->f_type == CIFS_MAGIC_NUMBER)
849 if (pbuf->f_type == CIFS_MAGIC_NUMBER)
846 return "cifs";
850 return "cifs";
847 #endif
851 #endif
848 #ifdef CODA_SUPER_MAGIC
852 #ifdef CODA_SUPER_MAGIC
849 if (pbuf->f_type == CODA_SUPER_MAGIC)
853 if (pbuf->f_type == CODA_SUPER_MAGIC)
850 return "coda";
854 return "coda";
851 #endif
855 #endif
852 #ifdef COH_SUPER_MAGIC
856 #ifdef COH_SUPER_MAGIC
853 if (pbuf->f_type == COH_SUPER_MAGIC)
857 if (pbuf->f_type == COH_SUPER_MAGIC)
854 return "coh";
858 return "coh";
855 #endif
859 #endif
856 #ifdef CRAMFS_MAGIC
860 #ifdef CRAMFS_MAGIC
857 if (pbuf->f_type == CRAMFS_MAGIC)
861 if (pbuf->f_type == CRAMFS_MAGIC)
858 return "cramfs";
862 return "cramfs";
859 #endif
863 #endif
860 #ifdef DEBUGFS_MAGIC
864 #ifdef DEBUGFS_MAGIC
861 if (pbuf->f_type == DEBUGFS_MAGIC)
865 if (pbuf->f_type == DEBUGFS_MAGIC)
862 return "debugfs";
866 return "debugfs";
863 #endif
867 #endif
864 #ifdef DEVFS_SUPER_MAGIC
868 #ifdef DEVFS_SUPER_MAGIC
865 if (pbuf->f_type == DEVFS_SUPER_MAGIC)
869 if (pbuf->f_type == DEVFS_SUPER_MAGIC)
866 return "devfs";
870 return "devfs";
867 #endif
871 #endif
868 #ifdef DEVPTS_SUPER_MAGIC
872 #ifdef DEVPTS_SUPER_MAGIC
869 if (pbuf->f_type == DEVPTS_SUPER_MAGIC)
873 if (pbuf->f_type == DEVPTS_SUPER_MAGIC)
870 return "devpts";
874 return "devpts";
871 #endif
875 #endif
872 #ifdef EFIVARFS_MAGIC
876 #ifdef EFIVARFS_MAGIC
873 if (pbuf->f_type == EFIVARFS_MAGIC)
877 if (pbuf->f_type == EFIVARFS_MAGIC)
874 return "efivarfs";
878 return "efivarfs";
875 #endif
879 #endif
876 #ifdef EFS_SUPER_MAGIC
880 #ifdef EFS_SUPER_MAGIC
877 if (pbuf->f_type == EFS_SUPER_MAGIC)
881 if (pbuf->f_type == EFS_SUPER_MAGIC)
878 return "efs";
882 return "efs";
879 #endif
883 #endif
880 #ifdef EXT_SUPER_MAGIC
884 #ifdef EXT_SUPER_MAGIC
881 if (pbuf->f_type == EXT_SUPER_MAGIC)
885 if (pbuf->f_type == EXT_SUPER_MAGIC)
882 return "ext";
886 return "ext";
883 #endif
887 #endif
884 #ifdef EXT2_OLD_SUPER_MAGIC
888 #ifdef EXT2_OLD_SUPER_MAGIC
885 if (pbuf->f_type == EXT2_OLD_SUPER_MAGIC)
889 if (pbuf->f_type == EXT2_OLD_SUPER_MAGIC)
886 return "ext2";
890 return "ext2";
887 #endif
891 #endif
888 #ifdef EXT2_SUPER_MAGIC
892 #ifdef EXT2_SUPER_MAGIC
889 if (pbuf->f_type == EXT2_SUPER_MAGIC)
893 if (pbuf->f_type == EXT2_SUPER_MAGIC)
890 return "ext2";
894 return "ext2";
891 #endif
895 #endif
892 #ifdef EXT3_SUPER_MAGIC
896 #ifdef EXT3_SUPER_MAGIC
893 if (pbuf->f_type == EXT3_SUPER_MAGIC)
897 if (pbuf->f_type == EXT3_SUPER_MAGIC)
894 return "ext3";
898 return "ext3";
895 #endif
899 #endif
896 #ifdef EXT4_SUPER_MAGIC
900 #ifdef EXT4_SUPER_MAGIC
897 if (pbuf->f_type == EXT4_SUPER_MAGIC)
901 if (pbuf->f_type == EXT4_SUPER_MAGIC)
898 return "ext4";
902 return "ext4";
899 #endif
903 #endif
900 #ifdef F2FS_SUPER_MAGIC
904 #ifdef F2FS_SUPER_MAGIC
901 if (pbuf->f_type == F2FS_SUPER_MAGIC)
905 if (pbuf->f_type == F2FS_SUPER_MAGIC)
902 return "f2fs";
906 return "f2fs";
903 #endif
907 #endif
904 #ifdef FUSE_SUPER_MAGIC
908 #ifdef FUSE_SUPER_MAGIC
905 if (pbuf->f_type == FUSE_SUPER_MAGIC)
909 if (pbuf->f_type == FUSE_SUPER_MAGIC)
906 return "fuse";
910 return "fuse";
907 #endif
911 #endif
908 #ifdef FUTEXFS_SUPER_MAGIC
912 #ifdef FUTEXFS_SUPER_MAGIC
909 if (pbuf->f_type == FUTEXFS_SUPER_MAGIC)
913 if (pbuf->f_type == FUTEXFS_SUPER_MAGIC)
910 return "futexfs";
914 return "futexfs";
911 #endif
915 #endif
912 #ifdef HFS_SUPER_MAGIC
916 #ifdef HFS_SUPER_MAGIC
913 if (pbuf->f_type == HFS_SUPER_MAGIC)
917 if (pbuf->f_type == HFS_SUPER_MAGIC)
914 return "hfs";
918 return "hfs";
915 #endif
919 #endif
916 #ifdef HOSTFS_SUPER_MAGIC
920 #ifdef HOSTFS_SUPER_MAGIC
917 if (pbuf->f_type == HOSTFS_SUPER_MAGIC)
921 if (pbuf->f_type == HOSTFS_SUPER_MAGIC)
918 return "hostfs";
922 return "hostfs";
919 #endif
923 #endif
920 #ifdef HPFS_SUPER_MAGIC
924 #ifdef HPFS_SUPER_MAGIC
921 if (pbuf->f_type == HPFS_SUPER_MAGIC)
925 if (pbuf->f_type == HPFS_SUPER_MAGIC)
922 return "hpfs";
926 return "hpfs";
923 #endif
927 #endif
924 #ifdef HUGETLBFS_MAGIC
928 #ifdef HUGETLBFS_MAGIC
925 if (pbuf->f_type == HUGETLBFS_MAGIC)
929 if (pbuf->f_type == HUGETLBFS_MAGIC)
926 return "hugetlbfs";
930 return "hugetlbfs";
927 #endif
931 #endif
928 #ifdef ISOFS_SUPER_MAGIC
932 #ifdef ISOFS_SUPER_MAGIC
929 if (pbuf->f_type == ISOFS_SUPER_MAGIC)
933 if (pbuf->f_type == ISOFS_SUPER_MAGIC)
930 return "isofs";
934 return "isofs";
931 #endif
935 #endif
932 #ifdef JFFS2_SUPER_MAGIC
936 #ifdef JFFS2_SUPER_MAGIC
933 if (pbuf->f_type == JFFS2_SUPER_MAGIC)
937 if (pbuf->f_type == JFFS2_SUPER_MAGIC)
934 return "jffs2";
938 return "jffs2";
935 #endif
939 #endif
936 #ifdef JFS_SUPER_MAGIC
940 #ifdef JFS_SUPER_MAGIC
937 if (pbuf->f_type == JFS_SUPER_MAGIC)
941 if (pbuf->f_type == JFS_SUPER_MAGIC)
938 return "jfs";
942 return "jfs";
939 #endif
943 #endif
940 #ifdef MINIX_SUPER_MAGIC
944 #ifdef MINIX_SUPER_MAGIC
941 if (pbuf->f_type == MINIX_SUPER_MAGIC)
945 if (pbuf->f_type == MINIX_SUPER_MAGIC)
942 return "minix";
946 return "minix";
943 #endif
947 #endif
944 #ifdef MINIX2_SUPER_MAGIC
948 #ifdef MINIX2_SUPER_MAGIC
945 if (pbuf->f_type == MINIX2_SUPER_MAGIC)
949 if (pbuf->f_type == MINIX2_SUPER_MAGIC)
946 return "minix2";
950 return "minix2";
947 #endif
951 #endif
948 #ifdef MINIX3_SUPER_MAGIC
952 #ifdef MINIX3_SUPER_MAGIC
949 if (pbuf->f_type == MINIX3_SUPER_MAGIC)
953 if (pbuf->f_type == MINIX3_SUPER_MAGIC)
950 return "minix3";
954 return "minix3";
951 #endif
955 #endif
952 #ifdef MQUEUE_MAGIC
956 #ifdef MQUEUE_MAGIC
953 if (pbuf->f_type == MQUEUE_MAGIC)
957 if (pbuf->f_type == MQUEUE_MAGIC)
954 return "mqueue";
958 return "mqueue";
955 #endif
959 #endif
956 #ifdef MSDOS_SUPER_MAGIC
960 #ifdef MSDOS_SUPER_MAGIC
957 if (pbuf->f_type == MSDOS_SUPER_MAGIC)
961 if (pbuf->f_type == MSDOS_SUPER_MAGIC)
958 return "msdos";
962 return "msdos";
959 #endif
963 #endif
960 #ifdef NCP_SUPER_MAGIC
964 #ifdef NCP_SUPER_MAGIC
961 if (pbuf->f_type == NCP_SUPER_MAGIC)
965 if (pbuf->f_type == NCP_SUPER_MAGIC)
962 return "ncp";
966 return "ncp";
963 #endif
967 #endif
964 #ifdef NFS_SUPER_MAGIC
968 #ifdef NFS_SUPER_MAGIC
965 if (pbuf->f_type == NFS_SUPER_MAGIC)
969 if (pbuf->f_type == NFS_SUPER_MAGIC)
966 return "nfs";
970 return "nfs";
967 #endif
971 #endif
968 #ifdef NILFS_SUPER_MAGIC
972 #ifdef NILFS_SUPER_MAGIC
969 if (pbuf->f_type == NILFS_SUPER_MAGIC)
973 if (pbuf->f_type == NILFS_SUPER_MAGIC)
970 return "nilfs";
974 return "nilfs";
971 #endif
975 #endif
972 #ifdef NTFS_SB_MAGIC
976 #ifdef NTFS_SB_MAGIC
973 if (pbuf->f_type == NTFS_SB_MAGIC)
977 if (pbuf->f_type == NTFS_SB_MAGIC)
974 return "ntfs-sb";
978 return "ntfs-sb";
975 #endif
979 #endif
976 #ifdef OCFS2_SUPER_MAGIC
980 #ifdef OCFS2_SUPER_MAGIC
977 if (pbuf->f_type == OCFS2_SUPER_MAGIC)
981 if (pbuf->f_type == OCFS2_SUPER_MAGIC)
978 return "ocfs2";
982 return "ocfs2";
979 #endif
983 #endif
980 #ifdef OPENPROM_SUPER_MAGIC
984 #ifdef OPENPROM_SUPER_MAGIC
981 if (pbuf->f_type == OPENPROM_SUPER_MAGIC)
985 if (pbuf->f_type == OPENPROM_SUPER_MAGIC)
982 return "openprom";
986 return "openprom";
983 #endif
987 #endif
984 #ifdef OVERLAYFS_SUPER_MAGIC
988 #ifdef OVERLAYFS_SUPER_MAGIC
985 if (pbuf->f_type == OVERLAYFS_SUPER_MAGIC)
989 if (pbuf->f_type == OVERLAYFS_SUPER_MAGIC)
986 return "overlay";
990 return "overlay";
987 #endif
991 #endif
988 #ifdef PIPEFS_MAGIC
992 #ifdef PIPEFS_MAGIC
989 if (pbuf->f_type == PIPEFS_MAGIC)
993 if (pbuf->f_type == PIPEFS_MAGIC)
990 return "pipefs";
994 return "pipefs";
991 #endif
995 #endif
992 #ifdef PROC_SUPER_MAGIC
996 #ifdef PROC_SUPER_MAGIC
993 if (pbuf->f_type == PROC_SUPER_MAGIC)
997 if (pbuf->f_type == PROC_SUPER_MAGIC)
994 return "proc";
998 return "proc";
995 #endif
999 #endif
996 #ifdef PSTOREFS_MAGIC
1000 #ifdef PSTOREFS_MAGIC
997 if (pbuf->f_type == PSTOREFS_MAGIC)
1001 if (pbuf->f_type == PSTOREFS_MAGIC)
998 return "pstorefs";
1002 return "pstorefs";
999 #endif
1003 #endif
1000 #ifdef QNX4_SUPER_MAGIC
1004 #ifdef QNX4_SUPER_MAGIC
1001 if (pbuf->f_type == QNX4_SUPER_MAGIC)
1005 if (pbuf->f_type == QNX4_SUPER_MAGIC)
1002 return "qnx4";
1006 return "qnx4";
1003 #endif
1007 #endif
1004 #ifdef QNX6_SUPER_MAGIC
1008 #ifdef QNX6_SUPER_MAGIC
1005 if (pbuf->f_type == QNX6_SUPER_MAGIC)
1009 if (pbuf->f_type == QNX6_SUPER_MAGIC)
1006 return "qnx6";
1010 return "qnx6";
1007 #endif
1011 #endif
1008 #ifdef RAMFS_MAGIC
1012 #ifdef RAMFS_MAGIC
1009 if (pbuf->f_type == RAMFS_MAGIC)
1013 if (pbuf->f_type == RAMFS_MAGIC)
1010 return "ramfs";
1014 return "ramfs";
1011 #endif
1015 #endif
1012 #ifdef REISERFS_SUPER_MAGIC
1016 #ifdef REISERFS_SUPER_MAGIC
1013 if (pbuf->f_type == REISERFS_SUPER_MAGIC)
1017 if (pbuf->f_type == REISERFS_SUPER_MAGIC)
1014 return "reiserfs";
1018 return "reiserfs";
1015 #endif
1019 #endif
1016 #ifdef ROMFS_MAGIC
1020 #ifdef ROMFS_MAGIC
1017 if (pbuf->f_type == ROMFS_MAGIC)
1021 if (pbuf->f_type == ROMFS_MAGIC)
1018 return "romfs";
1022 return "romfs";
1019 #endif
1023 #endif
1020 #ifdef SECURITYFS_MAGIC
1024 #ifdef SECURITYFS_MAGIC
1021 if (pbuf->f_type == SECURITYFS_MAGIC)
1025 if (pbuf->f_type == SECURITYFS_MAGIC)
1022 return "securityfs";
1026 return "securityfs";
1023 #endif
1027 #endif
1024 #ifdef SELINUX_MAGIC
1028 #ifdef SELINUX_MAGIC
1025 if (pbuf->f_type == SELINUX_MAGIC)
1029 if (pbuf->f_type == SELINUX_MAGIC)
1026 return "selinux";
1030 return "selinux";
1027 #endif
1031 #endif
1028 #ifdef SMACK_MAGIC
1032 #ifdef SMACK_MAGIC
1029 if (pbuf->f_type == SMACK_MAGIC)
1033 if (pbuf->f_type == SMACK_MAGIC)
1030 return "smack";
1034 return "smack";
1031 #endif
1035 #endif
1032 #ifdef SMB_SUPER_MAGIC
1036 #ifdef SMB_SUPER_MAGIC
1033 if (pbuf->f_type == SMB_SUPER_MAGIC)
1037 if (pbuf->f_type == SMB_SUPER_MAGIC)
1034 return "smb";
1038 return "smb";
1035 #endif
1039 #endif
1036 #ifdef SOCKFS_MAGIC
1040 #ifdef SOCKFS_MAGIC
1037 if (pbuf->f_type == SOCKFS_MAGIC)
1041 if (pbuf->f_type == SOCKFS_MAGIC)
1038 return "sockfs";
1042 return "sockfs";
1039 #endif
1043 #endif
1040 #ifdef SQUASHFS_MAGIC
1044 #ifdef SQUASHFS_MAGIC
1041 if (pbuf->f_type == SQUASHFS_MAGIC)
1045 if (pbuf->f_type == SQUASHFS_MAGIC)
1042 return "squashfs";
1046 return "squashfs";
1043 #endif
1047 #endif
1044 #ifdef SYSFS_MAGIC
1048 #ifdef SYSFS_MAGIC
1045 if (pbuf->f_type == SYSFS_MAGIC)
1049 if (pbuf->f_type == SYSFS_MAGIC)
1046 return "sysfs";
1050 return "sysfs";
1047 #endif
1051 #endif
1048 #ifdef SYSV2_SUPER_MAGIC
1052 #ifdef SYSV2_SUPER_MAGIC
1049 if (pbuf->f_type == SYSV2_SUPER_MAGIC)
1053 if (pbuf->f_type == SYSV2_SUPER_MAGIC)
1050 return "sysv2";
1054 return "sysv2";
1051 #endif
1055 #endif
1052 #ifdef SYSV4_SUPER_MAGIC
1056 #ifdef SYSV4_SUPER_MAGIC
1053 if (pbuf->f_type == SYSV4_SUPER_MAGIC)
1057 if (pbuf->f_type == SYSV4_SUPER_MAGIC)
1054 return "sysv4";
1058 return "sysv4";
1055 #endif
1059 #endif
1056 #ifdef TMPFS_MAGIC
1060 #ifdef TMPFS_MAGIC
1057 if (pbuf->f_type == TMPFS_MAGIC)
1061 if (pbuf->f_type == TMPFS_MAGIC)
1058 return "tmpfs";
1062 return "tmpfs";
1059 #endif
1063 #endif
1060 #ifdef UDF_SUPER_MAGIC
1064 #ifdef UDF_SUPER_MAGIC
1061 if (pbuf->f_type == UDF_SUPER_MAGIC)
1065 if (pbuf->f_type == UDF_SUPER_MAGIC)
1062 return "udf";
1066 return "udf";
1063 #endif
1067 #endif
1064 #ifdef UFS_MAGIC
1068 #ifdef UFS_MAGIC
1065 if (pbuf->f_type == UFS_MAGIC)
1069 if (pbuf->f_type == UFS_MAGIC)
1066 return "ufs";
1070 return "ufs";
1067 #endif
1071 #endif
1068 #ifdef USBDEVICE_SUPER_MAGIC
1072 #ifdef USBDEVICE_SUPER_MAGIC
1069 if (pbuf->f_type == USBDEVICE_SUPER_MAGIC)
1073 if (pbuf->f_type == USBDEVICE_SUPER_MAGIC)
1070 return "usbdevice";
1074 return "usbdevice";
1071 #endif
1075 #endif
1072 #ifdef V9FS_MAGIC
1076 #ifdef V9FS_MAGIC
1073 if (pbuf->f_type == V9FS_MAGIC)
1077 if (pbuf->f_type == V9FS_MAGIC)
1074 return "v9fs";
1078 return "v9fs";
1075 #endif
1079 #endif
1076 #ifdef VXFS_SUPER_MAGIC
1080 #ifdef VXFS_SUPER_MAGIC
1077 if (pbuf->f_type == VXFS_SUPER_MAGIC)
1081 if (pbuf->f_type == VXFS_SUPER_MAGIC)
1078 return "vxfs";
1082 return "vxfs";
1079 #endif
1083 #endif
1080 #ifdef XENFS_SUPER_MAGIC
1084 #ifdef XENFS_SUPER_MAGIC
1081 if (pbuf->f_type == XENFS_SUPER_MAGIC)
1085 if (pbuf->f_type == XENFS_SUPER_MAGIC)
1082 return "xenfs";
1086 return "xenfs";
1083 #endif
1087 #endif
1084 #ifdef XENIX_SUPER_MAGIC
1088 #ifdef XENIX_SUPER_MAGIC
1085 if (pbuf->f_type == XENIX_SUPER_MAGIC)
1089 if (pbuf->f_type == XENIX_SUPER_MAGIC)
1086 return "xenix";
1090 return "xenix";
1087 #endif
1091 #endif
1088 #ifdef XFS_SUPER_MAGIC
1092 #ifdef XFS_SUPER_MAGIC
1089 if (pbuf->f_type == XFS_SUPER_MAGIC)
1093 if (pbuf->f_type == XFS_SUPER_MAGIC)
1090 return "xfs";
1094 return "xfs";
1091 #endif
1095 #endif
1092 /* End of Linux filesystems */
1096 /* End of Linux filesystems */
1093 return NULL;
1097 return NULL;
1094 }
1098 }
1095 #endif /* def HAVE_LINUX_STATFS */
1099 #endif /* def HAVE_LINUX_STATFS */
1096
1100
1097 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1101 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1098 /* given a directory path, return filesystem type name (best-effort) */
1102 /* given a directory path, return filesystem type name (best-effort) */
1099 static PyObject *getfstype(PyObject *self, PyObject *args)
1103 static PyObject *getfstype(PyObject *self, PyObject *args)
1100 {
1104 {
1101 const char *path = NULL;
1105 const char *path = NULL;
1102 struct statfs buf;
1106 struct statfs buf;
1103 int r;
1107 int r;
1104 if (!PyArg_ParseTuple(args, "s", &path))
1108 if (!PyArg_ParseTuple(args, "s", &path))
1105 return NULL;
1109 return NULL;
1106
1110
1107 memset(&buf, 0, sizeof(buf));
1111 memset(&buf, 0, sizeof(buf));
1108 r = statfs(path, &buf);
1112 r = statfs(path, &buf);
1109 if (r != 0)
1113 if (r != 0)
1110 return PyErr_SetFromErrno(PyExc_OSError);
1114 return PyErr_SetFromErrno(PyExc_OSError);
1111 return Py_BuildValue("s", describefstype(&buf));
1115 return Py_BuildValue(PY23("s", "y"), describefstype(&buf));
1112 }
1116 }
1113 #endif /* defined(HAVE_LINUX_STATFS) || defined(HAVE_BSD_STATFS) */
1117 #endif /* defined(HAVE_LINUX_STATFS) || defined(HAVE_BSD_STATFS) */
1114
1118
1115 #if defined(HAVE_BSD_STATFS)
1119 #if defined(HAVE_BSD_STATFS)
1116 /* given a directory path, return filesystem mount point (best-effort) */
1120 /* given a directory path, return filesystem mount point (best-effort) */
1117 static PyObject *getfsmountpoint(PyObject *self, PyObject *args)
1121 static PyObject *getfsmountpoint(PyObject *self, PyObject *args)
1118 {
1122 {
1119 const char *path = NULL;
1123 const char *path = NULL;
1120 struct statfs buf;
1124 struct statfs buf;
1121 int r;
1125 int r;
1122 if (!PyArg_ParseTuple(args, "s", &path))
1126 if (!PyArg_ParseTuple(args, "s", &path))
1123 return NULL;
1127 return NULL;
1124
1128
1125 memset(&buf, 0, sizeof(buf));
1129 memset(&buf, 0, sizeof(buf));
1126 r = statfs(path, &buf);
1130 r = statfs(path, &buf);
1127 if (r != 0)
1131 if (r != 0)
1128 return PyErr_SetFromErrno(PyExc_OSError);
1132 return PyErr_SetFromErrno(PyExc_OSError);
1129 return Py_BuildValue("s", buf.f_mntonname);
1133 return Py_BuildValue(PY23("s", "y"), buf.f_mntonname);
1130 }
1134 }
1131 #endif /* defined(HAVE_BSD_STATFS) */
1135 #endif /* defined(HAVE_BSD_STATFS) */
1132
1136
1133 static PyObject *unblocksignal(PyObject *self, PyObject *args)
1137 static PyObject *unblocksignal(PyObject *self, PyObject *args)
1134 {
1138 {
1135 int sig = 0;
1139 int sig = 0;
1136 int r;
1140 int r;
1137 if (!PyArg_ParseTuple(args, "i", &sig))
1141 if (!PyArg_ParseTuple(args, "i", &sig))
1138 return NULL;
1142 return NULL;
1139 sigset_t set;
1143 sigset_t set;
1140 r = sigemptyset(&set);
1144 r = sigemptyset(&set);
1141 if (r != 0)
1145 if (r != 0)
1142 return PyErr_SetFromErrno(PyExc_OSError);
1146 return PyErr_SetFromErrno(PyExc_OSError);
1143 r = sigaddset(&set, sig);
1147 r = sigaddset(&set, sig);
1144 if (r != 0)
1148 if (r != 0)
1145 return PyErr_SetFromErrno(PyExc_OSError);
1149 return PyErr_SetFromErrno(PyExc_OSError);
1146 r = sigprocmask(SIG_UNBLOCK, &set, NULL);
1150 r = sigprocmask(SIG_UNBLOCK, &set, NULL);
1147 if (r != 0)
1151 if (r != 0)
1148 return PyErr_SetFromErrno(PyExc_OSError);
1152 return PyErr_SetFromErrno(PyExc_OSError);
1149 Py_RETURN_NONE;
1153 Py_RETURN_NONE;
1150 }
1154 }
1151
1155
1152 #endif /* ndef _WIN32 */
1156 #endif /* ndef _WIN32 */
1153
1157
1154 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
1158 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
1155 {
1159 {
1156 PyObject *statobj = NULL; /* initialize - optional arg */
1160 PyObject *statobj = NULL; /* initialize - optional arg */
1157 PyObject *skipobj = NULL; /* initialize - optional arg */
1161 PyObject *skipobj = NULL; /* initialize - optional arg */
1158 char *path, *skip = NULL;
1162 char *path, *skip = NULL;
1159 int wantstat, plen;
1163 int wantstat, plen;
1160
1164
1161 static char *kwlist[] = {"path", "stat", "skip", NULL};
1165 static char *kwlist[] = {"path", "stat", "skip", NULL};
1162
1166
1163 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
1167 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
1164 kwlist, &path, &plen, &statobj, &skipobj))
1168 kwlist, &path, &plen, &statobj, &skipobj))
1165 return NULL;
1169 return NULL;
1166
1170
1167 wantstat = statobj && PyObject_IsTrue(statobj);
1171 wantstat = statobj && PyObject_IsTrue(statobj);
1168
1172
1169 if (skipobj && skipobj != Py_None) {
1173 if (skipobj && skipobj != Py_None) {
1170 skip = PyBytes_AsString(skipobj);
1174 skip = PyBytes_AsString(skipobj);
1171 if (!skip)
1175 if (!skip)
1172 return NULL;
1176 return NULL;
1173 }
1177 }
1174
1178
1175 return _listdir(path, plen, wantstat, skip);
1179 return _listdir(path, plen, wantstat, skip);
1176 }
1180 }
1177
1181
1178 #ifdef _WIN32
1182 #ifdef _WIN32
1179 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
1183 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
1180 {
1184 {
1181 static char *kwlist[] = {"name", "mode", "buffering", NULL};
1185 static char *kwlist[] = {"name", "mode", "buffering", NULL};
1182 PyObject *file_obj = NULL;
1186 PyObject *file_obj = NULL;
1183 char *name = NULL;
1187 char *name = NULL;
1184 char *mode = "rb";
1188 char *mode = "rb";
1185 DWORD access = 0;
1189 DWORD access = 0;
1186 DWORD creation;
1190 DWORD creation;
1187 HANDLE handle;
1191 HANDLE handle;
1188 int fd, flags = 0;
1192 int fd, flags = 0;
1189 int bufsize = -1;
1193 int bufsize = -1;
1190 char m0, m1, m2;
1194 char m0, m1, m2;
1191 char fpmode[4];
1195 char fpmode[4];
1192 int fppos = 0;
1196 int fppos = 0;
1193 int plus;
1197 int plus;
1194 FILE *fp;
1198 FILE *fp;
1195
1199
1196 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
1200 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
1197 Py_FileSystemDefaultEncoding,
1201 Py_FileSystemDefaultEncoding,
1198 &name, &mode, &bufsize))
1202 &name, &mode, &bufsize))
1199 return NULL;
1203 return NULL;
1200
1204
1201 m0 = mode[0];
1205 m0 = mode[0];
1202 m1 = m0 ? mode[1] : '\0';
1206 m1 = m0 ? mode[1] : '\0';
1203 m2 = m1 ? mode[2] : '\0';
1207 m2 = m1 ? mode[2] : '\0';
1204 plus = m1 == '+' || m2 == '+';
1208 plus = m1 == '+' || m2 == '+';
1205
1209
1206 fpmode[fppos++] = m0;
1210 fpmode[fppos++] = m0;
1207 if (m1 == 'b' || m2 == 'b') {
1211 if (m1 == 'b' || m2 == 'b') {
1208 flags = _O_BINARY;
1212 flags = _O_BINARY;
1209 fpmode[fppos++] = 'b';
1213 fpmode[fppos++] = 'b';
1210 }
1214 }
1211 else
1215 else
1212 flags = _O_TEXT;
1216 flags = _O_TEXT;
1213 if (m0 == 'r' && !plus) {
1217 if (m0 == 'r' && !plus) {
1214 flags |= _O_RDONLY;
1218 flags |= _O_RDONLY;
1215 access = GENERIC_READ;
1219 access = GENERIC_READ;
1216 } else {
1220 } else {
1217 /*
1221 /*
1218 work around http://support.microsoft.com/kb/899149 and
1222 work around http://support.microsoft.com/kb/899149 and
1219 set _O_RDWR for 'w' and 'a', even if mode has no '+'
1223 set _O_RDWR for 'w' and 'a', even if mode has no '+'
1220 */
1224 */
1221 flags |= _O_RDWR;
1225 flags |= _O_RDWR;
1222 access = GENERIC_READ | GENERIC_WRITE;
1226 access = GENERIC_READ | GENERIC_WRITE;
1223 fpmode[fppos++] = '+';
1227 fpmode[fppos++] = '+';
1224 }
1228 }
1225 fpmode[fppos++] = '\0';
1229 fpmode[fppos++] = '\0';
1226
1230
1227 switch (m0) {
1231 switch (m0) {
1228 case 'r':
1232 case 'r':
1229 creation = OPEN_EXISTING;
1233 creation = OPEN_EXISTING;
1230 break;
1234 break;
1231 case 'w':
1235 case 'w':
1232 creation = CREATE_ALWAYS;
1236 creation = CREATE_ALWAYS;
1233 break;
1237 break;
1234 case 'a':
1238 case 'a':
1235 creation = OPEN_ALWAYS;
1239 creation = OPEN_ALWAYS;
1236 flags |= _O_APPEND;
1240 flags |= _O_APPEND;
1237 break;
1241 break;
1238 default:
1242 default:
1239 PyErr_Format(PyExc_ValueError,
1243 PyErr_Format(PyExc_ValueError,
1240 "mode string must begin with one of 'r', 'w', "
1244 "mode string must begin with one of 'r', 'w', "
1241 "or 'a', not '%c'", m0);
1245 "or 'a', not '%c'", m0);
1242 goto bail;
1246 goto bail;
1243 }
1247 }
1244
1248
1245 handle = CreateFile(name, access,
1249 handle = CreateFile(name, access,
1246 FILE_SHARE_READ | FILE_SHARE_WRITE |
1250 FILE_SHARE_READ | FILE_SHARE_WRITE |
1247 FILE_SHARE_DELETE,
1251 FILE_SHARE_DELETE,
1248 NULL,
1252 NULL,
1249 creation,
1253 creation,
1250 FILE_ATTRIBUTE_NORMAL,
1254 FILE_ATTRIBUTE_NORMAL,
1251 0);
1255 0);
1252
1256
1253 if (handle == INVALID_HANDLE_VALUE) {
1257 if (handle == INVALID_HANDLE_VALUE) {
1254 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
1258 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
1255 goto bail;
1259 goto bail;
1256 }
1260 }
1257
1261
1258 fd = _open_osfhandle((intptr_t)handle, flags);
1262 fd = _open_osfhandle((intptr_t)handle, flags);
1259
1263
1260 if (fd == -1) {
1264 if (fd == -1) {
1261 CloseHandle(handle);
1265 CloseHandle(handle);
1262 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1266 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1263 goto bail;
1267 goto bail;
1264 }
1268 }
1265 #ifndef IS_PY3K
1269 #ifndef IS_PY3K
1266 fp = _fdopen(fd, fpmode);
1270 fp = _fdopen(fd, fpmode);
1267 if (fp == NULL) {
1271 if (fp == NULL) {
1268 _close(fd);
1272 _close(fd);
1269 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1273 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1270 goto bail;
1274 goto bail;
1271 }
1275 }
1272
1276
1273 file_obj = PyFile_FromFile(fp, name, mode, fclose);
1277 file_obj = PyFile_FromFile(fp, name, mode, fclose);
1274 if (file_obj == NULL) {
1278 if (file_obj == NULL) {
1275 fclose(fp);
1279 fclose(fp);
1276 goto bail;
1280 goto bail;
1277 }
1281 }
1278
1282
1279 PyFile_SetBufSize(file_obj, bufsize);
1283 PyFile_SetBufSize(file_obj, bufsize);
1280 #else
1284 #else
1281 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
1285 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
1282 if (file_obj == NULL)
1286 if (file_obj == NULL)
1283 goto bail;
1287 goto bail;
1284 #endif
1288 #endif
1285 bail:
1289 bail:
1286 PyMem_Free(name);
1290 PyMem_Free(name);
1287 return file_obj;
1291 return file_obj;
1288 }
1292 }
1289 #endif
1293 #endif
1290
1294
1291 #ifdef __APPLE__
1295 #ifdef __APPLE__
1292 #include <ApplicationServices/ApplicationServices.h>
1296 #include <ApplicationServices/ApplicationServices.h>
1293
1297
1294 static PyObject *isgui(PyObject *self)
1298 static PyObject *isgui(PyObject *self)
1295 {
1299 {
1296 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
1300 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
1297
1301
1298 if (dict != NULL) {
1302 if (dict != NULL) {
1299 CFRelease(dict);
1303 CFRelease(dict);
1300 Py_RETURN_TRUE;
1304 Py_RETURN_TRUE;
1301 } else {
1305 } else {
1302 Py_RETURN_FALSE;
1306 Py_RETURN_FALSE;
1303 }
1307 }
1304 }
1308 }
1305 #endif
1309 #endif
1306
1310
1307 static char osutil_doc[] = "Native operating system services.";
1311 static char osutil_doc[] = "Native operating system services.";
1308
1312
1309 static PyMethodDef methods[] = {
1313 static PyMethodDef methods[] = {
1310 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
1314 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
1311 "list a directory\n"},
1315 "list a directory\n"},
1312 #ifdef _WIN32
1316 #ifdef _WIN32
1313 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
1317 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
1314 "Open a file with POSIX-like semantics.\n"
1318 "Open a file with POSIX-like semantics.\n"
1315 "On error, this function may raise either a WindowsError or an IOError."},
1319 "On error, this function may raise either a WindowsError or an IOError."},
1316 #else
1320 #else
1317 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
1321 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
1318 "stat a series of files or symlinks\n"
1322 "stat a series of files or symlinks\n"
1319 "Returns None for non-existent entries and entries of other types.\n"},
1323 "Returns None for non-existent entries and entries of other types.\n"},
1320 #ifdef CMSG_LEN
1324 #ifdef CMSG_LEN
1321 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
1325 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
1322 "receive list of file descriptors via socket\n"},
1326 "receive list of file descriptors via socket\n"},
1323 #endif
1327 #endif
1324 #ifndef SETPROCNAME_USE_NONE
1328 #ifndef SETPROCNAME_USE_NONE
1325 {"setprocname", (PyCFunction)setprocname, METH_VARARGS,
1329 {"setprocname", (PyCFunction)setprocname, METH_VARARGS,
1326 "set process title (best-effort)\n"},
1330 "set process title (best-effort)\n"},
1327 #endif
1331 #endif
1328 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1332 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1329 {"getfstype", (PyCFunction)getfstype, METH_VARARGS,
1333 {"getfstype", (PyCFunction)getfstype, METH_VARARGS,
1330 "get filesystem type (best-effort)\n"},
1334 "get filesystem type (best-effort)\n"},
1331 #endif
1335 #endif
1332 #if defined(HAVE_BSD_STATFS)
1336 #if defined(HAVE_BSD_STATFS)
1333 {"getfsmountpoint", (PyCFunction)getfsmountpoint, METH_VARARGS,
1337 {"getfsmountpoint", (PyCFunction)getfsmountpoint, METH_VARARGS,
1334 "get filesystem mount point (best-effort)\n"},
1338 "get filesystem mount point (best-effort)\n"},
1335 #endif
1339 #endif
1336 {"unblocksignal", (PyCFunction)unblocksignal, METH_VARARGS,
1340 {"unblocksignal", (PyCFunction)unblocksignal, METH_VARARGS,
1337 "change signal mask to unblock a given signal\n"},
1341 "change signal mask to unblock a given signal\n"},
1338 #endif /* ndef _WIN32 */
1342 #endif /* ndef _WIN32 */
1339 #ifdef __APPLE__
1343 #ifdef __APPLE__
1340 {
1344 {
1341 "isgui", (PyCFunction)isgui, METH_NOARGS,
1345 "isgui", (PyCFunction)isgui, METH_NOARGS,
1342 "Is a CoreGraphics session available?"
1346 "Is a CoreGraphics session available?"
1343 },
1347 },
1344 #endif
1348 #endif
1345 {NULL, NULL}
1349 {NULL, NULL}
1346 };
1350 };
1347
1351
1348 static const int version = 3;
1352 static const int version = 3;
1349
1353
1350 #ifdef IS_PY3K
1354 #ifdef IS_PY3K
1351 static struct PyModuleDef osutil_module = {
1355 static struct PyModuleDef osutil_module = {
1352 PyModuleDef_HEAD_INIT,
1356 PyModuleDef_HEAD_INIT,
1353 "osutil",
1357 "osutil",
1354 osutil_doc,
1358 osutil_doc,
1355 -1,
1359 -1,
1356 methods
1360 methods
1357 };
1361 };
1358
1362
1359 PyMODINIT_FUNC PyInit_osutil(void)
1363 PyMODINIT_FUNC PyInit_osutil(void)
1360 {
1364 {
1361 PyObject *m;
1365 PyObject *m;
1362 if (PyType_Ready(&listdir_stat_type) < 0)
1366 if (PyType_Ready(&listdir_stat_type) < 0)
1363 return NULL;
1367 return NULL;
1364
1368
1365 m = PyModule_Create(&osutil_module);
1369 m = PyModule_Create(&osutil_module);
1366 PyModule_AddIntConstant(m, "version", version);
1370 PyModule_AddIntConstant(m, "version", version);
1367 return m;
1371 return m;
1368 }
1372 }
1369 #else
1373 #else
1370 PyMODINIT_FUNC initosutil(void)
1374 PyMODINIT_FUNC initosutil(void)
1371 {
1375 {
1372 PyObject *m;
1376 PyObject *m;
1373 if (PyType_Ready(&listdir_stat_type) == -1)
1377 if (PyType_Ready(&listdir_stat_type) == -1)
1374 return;
1378 return;
1375
1379
1376 m = Py_InitModule3("osutil", methods, osutil_doc);
1380 m = Py_InitModule3("osutil", methods, osutil_doc);
1377 PyModule_AddIntConstant(m, "version", version);
1381 PyModule_AddIntConstant(m, "version", version);
1378 }
1382 }
1379 #endif
1383 #endif
@@ -1,794 +1,794 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@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 #include <Python.h>
10 #include <Python.h>
11 #include <ctype.h>
11 #include <ctype.h>
12 #include <stddef.h>
12 #include <stddef.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "bitmanipulation.h"
15 #include "bitmanipulation.h"
16 #include "charencode.h"
16 #include "charencode.h"
17 #include "util.h"
17 #include "util.h"
18
18
19 #ifdef IS_PY3K
19 #ifdef IS_PY3K
20 /* The mapping of Python types is meant to be temporary to get Python
20 /* The mapping of Python types is meant to be temporary to get Python
21 * 3 to compile. We should remove this once Python 3 support is fully
21 * 3 to compile. We should remove this once Python 3 support is fully
22 * supported and proper types are used in the extensions themselves. */
22 * supported and proper types are used in the extensions themselves. */
23 #define PyInt_Check PyLong_Check
23 #define PyInt_Check PyLong_Check
24 #define PyInt_FromLong PyLong_FromLong
24 #define PyInt_FromLong PyLong_FromLong
25 #define PyInt_FromSsize_t PyLong_FromSsize_t
25 #define PyInt_FromSsize_t PyLong_FromSsize_t
26 #define PyInt_AsLong PyLong_AsLong
26 #define PyInt_AsLong PyLong_AsLong
27 #endif
27 #endif
28
28
29 static const char *const versionerrortext = "Python minor version mismatch";
29 static const char *const versionerrortext = "Python minor version mismatch";
30
30
31 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
31 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
32 {
32 {
33 Py_ssize_t expected_size;
33 Py_ssize_t expected_size;
34
34
35 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size))
35 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size))
36 return NULL;
36 return NULL;
37
37
38 return _dict_new_presized(expected_size);
38 return _dict_new_presized(expected_size);
39 }
39 }
40
40
41 /*
41 /*
42 * This code assumes that a manifest is stitched together with newline
42 * This code assumes that a manifest is stitched together with newline
43 * ('\n') characters.
43 * ('\n') characters.
44 */
44 */
45 static PyObject *parse_manifest(PyObject *self, PyObject *args)
45 static PyObject *parse_manifest(PyObject *self, PyObject *args)
46 {
46 {
47 PyObject *mfdict, *fdict;
47 PyObject *mfdict, *fdict;
48 char *str, *start, *end;
48 char *str, *start, *end;
49 int len;
49 int len;
50
50
51 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest", &PyDict_Type,
51 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest", &PyDict_Type,
52 &mfdict, &PyDict_Type, &fdict, &str, &len))
52 &mfdict, &PyDict_Type, &fdict, &str, &len))
53 goto quit;
53 goto quit;
54
54
55 start = str;
55 start = str;
56 end = str + len;
56 end = str + len;
57 while (start < end) {
57 while (start < end) {
58 PyObject *file = NULL, *node = NULL;
58 PyObject *file = NULL, *node = NULL;
59 PyObject *flags = NULL;
59 PyObject *flags = NULL;
60 char *zero = NULL, *newline = NULL;
60 char *zero = NULL, *newline = NULL;
61 ptrdiff_t nlen;
61 ptrdiff_t nlen;
62
62
63 zero = memchr(start, '\0', end - start);
63 zero = memchr(start, '\0', end - start);
64 if (!zero) {
64 if (!zero) {
65 PyErr_SetString(PyExc_ValueError,
65 PyErr_SetString(PyExc_ValueError,
66 "manifest entry has no separator");
66 "manifest entry has no separator");
67 goto quit;
67 goto quit;
68 }
68 }
69
69
70 newline = memchr(zero + 1, '\n', end - (zero + 1));
70 newline = memchr(zero + 1, '\n', end - (zero + 1));
71 if (!newline) {
71 if (!newline) {
72 PyErr_SetString(PyExc_ValueError,
72 PyErr_SetString(PyExc_ValueError,
73 "manifest contains trailing garbage");
73 "manifest contains trailing garbage");
74 goto quit;
74 goto quit;
75 }
75 }
76
76
77 file = PyBytes_FromStringAndSize(start, zero - start);
77 file = PyBytes_FromStringAndSize(start, zero - start);
78
78
79 if (!file)
79 if (!file)
80 goto bail;
80 goto bail;
81
81
82 nlen = newline - zero - 1;
82 nlen = newline - zero - 1;
83
83
84 node = unhexlify(zero + 1, nlen > 40 ? 40 : (Py_ssize_t)nlen);
84 node = unhexlify(zero + 1, nlen > 40 ? 40 : (Py_ssize_t)nlen);
85 if (!node)
85 if (!node)
86 goto bail;
86 goto bail;
87
87
88 if (nlen > 40) {
88 if (nlen > 40) {
89 flags = PyBytes_FromStringAndSize(zero + 41, nlen - 40);
89 flags = PyBytes_FromStringAndSize(zero + 41, nlen - 40);
90 if (!flags)
90 if (!flags)
91 goto bail;
91 goto bail;
92
92
93 if (PyDict_SetItem(fdict, file, flags) == -1)
93 if (PyDict_SetItem(fdict, file, flags) == -1)
94 goto bail;
94 goto bail;
95 }
95 }
96
96
97 if (PyDict_SetItem(mfdict, file, node) == -1)
97 if (PyDict_SetItem(mfdict, file, node) == -1)
98 goto bail;
98 goto bail;
99
99
100 start = newline + 1;
100 start = newline + 1;
101
101
102 Py_XDECREF(flags);
102 Py_XDECREF(flags);
103 Py_XDECREF(node);
103 Py_XDECREF(node);
104 Py_XDECREF(file);
104 Py_XDECREF(file);
105 continue;
105 continue;
106 bail:
106 bail:
107 Py_XDECREF(flags);
107 Py_XDECREF(flags);
108 Py_XDECREF(node);
108 Py_XDECREF(node);
109 Py_XDECREF(file);
109 Py_XDECREF(file);
110 goto quit;
110 goto quit;
111 }
111 }
112
112
113 Py_INCREF(Py_None);
113 Py_INCREF(Py_None);
114 return Py_None;
114 return Py_None;
115 quit:
115 quit:
116 return NULL;
116 return NULL;
117 }
117 }
118
118
119 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
119 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
120 int size, int mtime)
120 int size, int mtime)
121 {
121 {
122 dirstateTupleObject *t =
122 dirstateTupleObject *t =
123 PyObject_New(dirstateTupleObject, &dirstateTupleType);
123 PyObject_New(dirstateTupleObject, &dirstateTupleType);
124 if (!t)
124 if (!t)
125 return NULL;
125 return NULL;
126 t->state = state;
126 t->state = state;
127 t->mode = mode;
127 t->mode = mode;
128 t->size = size;
128 t->size = size;
129 t->mtime = mtime;
129 t->mtime = mtime;
130 return t;
130 return t;
131 }
131 }
132
132
133 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
133 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
134 PyObject *kwds)
134 PyObject *kwds)
135 {
135 {
136 /* We do all the initialization here and not a tp_init function because
136 /* We do all the initialization here and not a tp_init function because
137 * dirstate_tuple is immutable. */
137 * dirstate_tuple is immutable. */
138 dirstateTupleObject *t;
138 dirstateTupleObject *t;
139 char state;
139 char state;
140 int size, mode, mtime;
140 int size, mode, mtime;
141 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
141 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
142 return NULL;
142 return NULL;
143
143
144 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
144 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
145 if (!t)
145 if (!t)
146 return NULL;
146 return NULL;
147 t->state = state;
147 t->state = state;
148 t->mode = mode;
148 t->mode = mode;
149 t->size = size;
149 t->size = size;
150 t->mtime = mtime;
150 t->mtime = mtime;
151
151
152 return (PyObject *)t;
152 return (PyObject *)t;
153 }
153 }
154
154
155 static void dirstate_tuple_dealloc(PyObject *o)
155 static void dirstate_tuple_dealloc(PyObject *o)
156 {
156 {
157 PyObject_Del(o);
157 PyObject_Del(o);
158 }
158 }
159
159
160 static Py_ssize_t dirstate_tuple_length(PyObject *o)
160 static Py_ssize_t dirstate_tuple_length(PyObject *o)
161 {
161 {
162 return 4;
162 return 4;
163 }
163 }
164
164
165 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
165 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
166 {
166 {
167 dirstateTupleObject *t = (dirstateTupleObject *)o;
167 dirstateTupleObject *t = (dirstateTupleObject *)o;
168 switch (i) {
168 switch (i) {
169 case 0:
169 case 0:
170 return PyBytes_FromStringAndSize(&t->state, 1);
170 return PyBytes_FromStringAndSize(&t->state, 1);
171 case 1:
171 case 1:
172 return PyInt_FromLong(t->mode);
172 return PyInt_FromLong(t->mode);
173 case 2:
173 case 2:
174 return PyInt_FromLong(t->size);
174 return PyInt_FromLong(t->size);
175 case 3:
175 case 3:
176 return PyInt_FromLong(t->mtime);
176 return PyInt_FromLong(t->mtime);
177 default:
177 default:
178 PyErr_SetString(PyExc_IndexError, "index out of range");
178 PyErr_SetString(PyExc_IndexError, "index out of range");
179 return NULL;
179 return NULL;
180 }
180 }
181 }
181 }
182
182
183 static PySequenceMethods dirstate_tuple_sq = {
183 static PySequenceMethods dirstate_tuple_sq = {
184 dirstate_tuple_length, /* sq_length */
184 dirstate_tuple_length, /* sq_length */
185 0, /* sq_concat */
185 0, /* sq_concat */
186 0, /* sq_repeat */
186 0, /* sq_repeat */
187 dirstate_tuple_item, /* sq_item */
187 dirstate_tuple_item, /* sq_item */
188 0, /* sq_ass_item */
188 0, /* sq_ass_item */
189 0, /* sq_contains */
189 0, /* sq_contains */
190 0, /* sq_inplace_concat */
190 0, /* sq_inplace_concat */
191 0 /* sq_inplace_repeat */
191 0 /* sq_inplace_repeat */
192 };
192 };
193
193
194 PyTypeObject dirstateTupleType = {
194 PyTypeObject dirstateTupleType = {
195 PyVarObject_HEAD_INIT(NULL, 0) /* header */
195 PyVarObject_HEAD_INIT(NULL, 0) /* header */
196 "dirstate_tuple", /* tp_name */
196 "dirstate_tuple", /* tp_name */
197 sizeof(dirstateTupleObject), /* tp_basicsize */
197 sizeof(dirstateTupleObject), /* tp_basicsize */
198 0, /* tp_itemsize */
198 0, /* tp_itemsize */
199 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
199 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
200 0, /* tp_print */
200 0, /* tp_print */
201 0, /* tp_getattr */
201 0, /* tp_getattr */
202 0, /* tp_setattr */
202 0, /* tp_setattr */
203 0, /* tp_compare */
203 0, /* tp_compare */
204 0, /* tp_repr */
204 0, /* tp_repr */
205 0, /* tp_as_number */
205 0, /* tp_as_number */
206 &dirstate_tuple_sq, /* tp_as_sequence */
206 &dirstate_tuple_sq, /* tp_as_sequence */
207 0, /* tp_as_mapping */
207 0, /* tp_as_mapping */
208 0, /* tp_hash */
208 0, /* tp_hash */
209 0, /* tp_call */
209 0, /* tp_call */
210 0, /* tp_str */
210 0, /* tp_str */
211 0, /* tp_getattro */
211 0, /* tp_getattro */
212 0, /* tp_setattro */
212 0, /* tp_setattro */
213 0, /* tp_as_buffer */
213 0, /* tp_as_buffer */
214 Py_TPFLAGS_DEFAULT, /* tp_flags */
214 Py_TPFLAGS_DEFAULT, /* tp_flags */
215 "dirstate tuple", /* tp_doc */
215 "dirstate tuple", /* tp_doc */
216 0, /* tp_traverse */
216 0, /* tp_traverse */
217 0, /* tp_clear */
217 0, /* tp_clear */
218 0, /* tp_richcompare */
218 0, /* tp_richcompare */
219 0, /* tp_weaklistoffset */
219 0, /* tp_weaklistoffset */
220 0, /* tp_iter */
220 0, /* tp_iter */
221 0, /* tp_iternext */
221 0, /* tp_iternext */
222 0, /* tp_methods */
222 0, /* tp_methods */
223 0, /* tp_members */
223 0, /* tp_members */
224 0, /* tp_getset */
224 0, /* tp_getset */
225 0, /* tp_base */
225 0, /* tp_base */
226 0, /* tp_dict */
226 0, /* tp_dict */
227 0, /* tp_descr_get */
227 0, /* tp_descr_get */
228 0, /* tp_descr_set */
228 0, /* tp_descr_set */
229 0, /* tp_dictoffset */
229 0, /* tp_dictoffset */
230 0, /* tp_init */
230 0, /* tp_init */
231 0, /* tp_alloc */
231 0, /* tp_alloc */
232 dirstate_tuple_new, /* tp_new */
232 dirstate_tuple_new, /* tp_new */
233 };
233 };
234
234
235 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
235 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
236 {
236 {
237 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
237 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
238 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
238 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
239 char state, *cur, *str, *cpos;
239 char state, *cur, *str, *cpos;
240 int mode, size, mtime;
240 int mode, size, mtime;
241 unsigned int flen, len, pos = 40;
241 unsigned int flen, len, pos = 40;
242 int readlen;
242 int readlen;
243
243
244 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate", &PyDict_Type,
244 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate", &PyDict_Type,
245 &dmap, &PyDict_Type, &cmap, &str, &readlen))
245 &dmap, &PyDict_Type, &cmap, &str, &readlen))
246 goto quit;
246 goto quit;
247
247
248 len = readlen;
248 len = readlen;
249
249
250 /* read parents */
250 /* read parents */
251 if (len < 40) {
251 if (len < 40) {
252 PyErr_SetString(PyExc_ValueError,
252 PyErr_SetString(PyExc_ValueError,
253 "too little data for parents");
253 "too little data for parents");
254 goto quit;
254 goto quit;
255 }
255 }
256
256
257 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
257 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, 20, str + 20, 20);
258 if (!parents)
258 if (!parents)
259 goto quit;
259 goto quit;
260
260
261 /* read filenames */
261 /* read filenames */
262 while (pos >= 40 && pos < len) {
262 while (pos >= 40 && pos < len) {
263 if (pos + 17 > len) {
263 if (pos + 17 > len) {
264 PyErr_SetString(PyExc_ValueError,
264 PyErr_SetString(PyExc_ValueError,
265 "overflow in dirstate");
265 "overflow in dirstate");
266 goto quit;
266 goto quit;
267 }
267 }
268 cur = str + pos;
268 cur = str + pos;
269 /* unpack header */
269 /* unpack header */
270 state = *cur;
270 state = *cur;
271 mode = getbe32(cur + 1);
271 mode = getbe32(cur + 1);
272 size = getbe32(cur + 5);
272 size = getbe32(cur + 5);
273 mtime = getbe32(cur + 9);
273 mtime = getbe32(cur + 9);
274 flen = getbe32(cur + 13);
274 flen = getbe32(cur + 13);
275 pos += 17;
275 pos += 17;
276 cur += 17;
276 cur += 17;
277 if (flen > len - pos) {
277 if (flen > len - pos) {
278 PyErr_SetString(PyExc_ValueError,
278 PyErr_SetString(PyExc_ValueError,
279 "overflow in dirstate");
279 "overflow in dirstate");
280 goto quit;
280 goto quit;
281 }
281 }
282
282
283 entry =
283 entry =
284 (PyObject *)make_dirstate_tuple(state, mode, size, mtime);
284 (PyObject *)make_dirstate_tuple(state, mode, size, mtime);
285 cpos = memchr(cur, 0, flen);
285 cpos = memchr(cur, 0, flen);
286 if (cpos) {
286 if (cpos) {
287 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
287 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
288 cname = PyBytes_FromStringAndSize(
288 cname = PyBytes_FromStringAndSize(
289 cpos + 1, flen - (cpos - cur) - 1);
289 cpos + 1, flen - (cpos - cur) - 1);
290 if (!fname || !cname ||
290 if (!fname || !cname ||
291 PyDict_SetItem(cmap, fname, cname) == -1 ||
291 PyDict_SetItem(cmap, fname, cname) == -1 ||
292 PyDict_SetItem(dmap, fname, entry) == -1)
292 PyDict_SetItem(dmap, fname, entry) == -1)
293 goto quit;
293 goto quit;
294 Py_DECREF(cname);
294 Py_DECREF(cname);
295 } else {
295 } else {
296 fname = PyBytes_FromStringAndSize(cur, flen);
296 fname = PyBytes_FromStringAndSize(cur, flen);
297 if (!fname || PyDict_SetItem(dmap, fname, entry) == -1)
297 if (!fname || PyDict_SetItem(dmap, fname, entry) == -1)
298 goto quit;
298 goto quit;
299 }
299 }
300 Py_DECREF(fname);
300 Py_DECREF(fname);
301 Py_DECREF(entry);
301 Py_DECREF(entry);
302 fname = cname = entry = NULL;
302 fname = cname = entry = NULL;
303 pos += flen;
303 pos += flen;
304 }
304 }
305
305
306 ret = parents;
306 ret = parents;
307 Py_INCREF(ret);
307 Py_INCREF(ret);
308 quit:
308 quit:
309 Py_XDECREF(fname);
309 Py_XDECREF(fname);
310 Py_XDECREF(cname);
310 Py_XDECREF(cname);
311 Py_XDECREF(entry);
311 Py_XDECREF(entry);
312 Py_XDECREF(parents);
312 Py_XDECREF(parents);
313 return ret;
313 return ret;
314 }
314 }
315
315
316 /*
316 /*
317 * Build a set of non-normal and other parent entries from the dirstate dmap
317 * Build a set of non-normal and other parent entries from the dirstate dmap
318 */
318 */
319 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
319 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
320 {
320 {
321 PyObject *dmap, *fname, *v;
321 PyObject *dmap, *fname, *v;
322 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
322 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
323 Py_ssize_t pos;
323 Py_ssize_t pos;
324
324
325 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type, &dmap))
325 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type, &dmap))
326 goto bail;
326 goto bail;
327
327
328 nonnset = PySet_New(NULL);
328 nonnset = PySet_New(NULL);
329 if (nonnset == NULL)
329 if (nonnset == NULL)
330 goto bail;
330 goto bail;
331
331
332 otherpset = PySet_New(NULL);
332 otherpset = PySet_New(NULL);
333 if (otherpset == NULL)
333 if (otherpset == NULL)
334 goto bail;
334 goto bail;
335
335
336 pos = 0;
336 pos = 0;
337 while (PyDict_Next(dmap, &pos, &fname, &v)) {
337 while (PyDict_Next(dmap, &pos, &fname, &v)) {
338 dirstateTupleObject *t;
338 dirstateTupleObject *t;
339 if (!dirstate_tuple_check(v)) {
339 if (!dirstate_tuple_check(v)) {
340 PyErr_SetString(PyExc_TypeError,
340 PyErr_SetString(PyExc_TypeError,
341 "expected a dirstate tuple");
341 "expected a dirstate tuple");
342 goto bail;
342 goto bail;
343 }
343 }
344 t = (dirstateTupleObject *)v;
344 t = (dirstateTupleObject *)v;
345
345
346 if (t->state == 'n' && t->size == -2) {
346 if (t->state == 'n' && t->size == -2) {
347 if (PySet_Add(otherpset, fname) == -1) {
347 if (PySet_Add(otherpset, fname) == -1) {
348 goto bail;
348 goto bail;
349 }
349 }
350 }
350 }
351
351
352 if (t->state == 'n' && t->mtime != -1)
352 if (t->state == 'n' && t->mtime != -1)
353 continue;
353 continue;
354 if (PySet_Add(nonnset, fname) == -1)
354 if (PySet_Add(nonnset, fname) == -1)
355 goto bail;
355 goto bail;
356 }
356 }
357
357
358 result = Py_BuildValue("(OO)", nonnset, otherpset);
358 result = Py_BuildValue("(OO)", nonnset, otherpset);
359 if (result == NULL)
359 if (result == NULL)
360 goto bail;
360 goto bail;
361 Py_DECREF(nonnset);
361 Py_DECREF(nonnset);
362 Py_DECREF(otherpset);
362 Py_DECREF(otherpset);
363 return result;
363 return result;
364 bail:
364 bail:
365 Py_XDECREF(nonnset);
365 Py_XDECREF(nonnset);
366 Py_XDECREF(otherpset);
366 Py_XDECREF(otherpset);
367 Py_XDECREF(result);
367 Py_XDECREF(result);
368 return NULL;
368 return NULL;
369 }
369 }
370
370
371 /*
371 /*
372 * Efficiently pack a dirstate object into its on-disk format.
372 * Efficiently pack a dirstate object into its on-disk format.
373 */
373 */
374 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
374 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
375 {
375 {
376 PyObject *packobj = NULL;
376 PyObject *packobj = NULL;
377 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
377 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
378 Py_ssize_t nbytes, pos, l;
378 Py_ssize_t nbytes, pos, l;
379 PyObject *k, *v = NULL, *pn;
379 PyObject *k, *v = NULL, *pn;
380 char *p, *s;
380 char *p, *s;
381 int now;
381 int now;
382
382
383 if (!PyArg_ParseTuple(args, "O!O!Oi:pack_dirstate", &PyDict_Type, &map,
383 if (!PyArg_ParseTuple(args, "O!O!Oi:pack_dirstate", &PyDict_Type, &map,
384 &PyDict_Type, &copymap, &pl, &now))
384 &PyDict_Type, &copymap, &pl, &now))
385 return NULL;
385 return NULL;
386
386
387 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
387 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
388 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
388 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
389 return NULL;
389 return NULL;
390 }
390 }
391
391
392 /* Figure out how much we need to allocate. */
392 /* Figure out how much we need to allocate. */
393 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
393 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
394 PyObject *c;
394 PyObject *c;
395 if (!PyBytes_Check(k)) {
395 if (!PyBytes_Check(k)) {
396 PyErr_SetString(PyExc_TypeError, "expected string key");
396 PyErr_SetString(PyExc_TypeError, "expected string key");
397 goto bail;
397 goto bail;
398 }
398 }
399 nbytes += PyBytes_GET_SIZE(k) + 17;
399 nbytes += PyBytes_GET_SIZE(k) + 17;
400 c = PyDict_GetItem(copymap, k);
400 c = PyDict_GetItem(copymap, k);
401 if (c) {
401 if (c) {
402 if (!PyBytes_Check(c)) {
402 if (!PyBytes_Check(c)) {
403 PyErr_SetString(PyExc_TypeError,
403 PyErr_SetString(PyExc_TypeError,
404 "expected string key");
404 "expected string key");
405 goto bail;
405 goto bail;
406 }
406 }
407 nbytes += PyBytes_GET_SIZE(c) + 1;
407 nbytes += PyBytes_GET_SIZE(c) + 1;
408 }
408 }
409 }
409 }
410
410
411 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
411 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
412 if (packobj == NULL)
412 if (packobj == NULL)
413 goto bail;
413 goto bail;
414
414
415 p = PyBytes_AS_STRING(packobj);
415 p = PyBytes_AS_STRING(packobj);
416
416
417 pn = PySequence_ITEM(pl, 0);
417 pn = PySequence_ITEM(pl, 0);
418 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
418 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
419 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
419 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
420 goto bail;
420 goto bail;
421 }
421 }
422 memcpy(p, s, l);
422 memcpy(p, s, l);
423 p += 20;
423 p += 20;
424 pn = PySequence_ITEM(pl, 1);
424 pn = PySequence_ITEM(pl, 1);
425 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
425 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
426 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
426 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
427 goto bail;
427 goto bail;
428 }
428 }
429 memcpy(p, s, l);
429 memcpy(p, s, l);
430 p += 20;
430 p += 20;
431
431
432 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
432 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
433 dirstateTupleObject *tuple;
433 dirstateTupleObject *tuple;
434 char state;
434 char state;
435 int mode, size, mtime;
435 int mode, size, mtime;
436 Py_ssize_t len, l;
436 Py_ssize_t len, l;
437 PyObject *o;
437 PyObject *o;
438 char *t;
438 char *t;
439
439
440 if (!dirstate_tuple_check(v)) {
440 if (!dirstate_tuple_check(v)) {
441 PyErr_SetString(PyExc_TypeError,
441 PyErr_SetString(PyExc_TypeError,
442 "expected a dirstate tuple");
442 "expected a dirstate tuple");
443 goto bail;
443 goto bail;
444 }
444 }
445 tuple = (dirstateTupleObject *)v;
445 tuple = (dirstateTupleObject *)v;
446
446
447 state = tuple->state;
447 state = tuple->state;
448 mode = tuple->mode;
448 mode = tuple->mode;
449 size = tuple->size;
449 size = tuple->size;
450 mtime = tuple->mtime;
450 mtime = tuple->mtime;
451 if (state == 'n' && mtime == now) {
451 if (state == 'n' && mtime == now) {
452 /* See pure/parsers.py:pack_dirstate for why we do
452 /* See pure/parsers.py:pack_dirstate for why we do
453 * this. */
453 * this. */
454 mtime = -1;
454 mtime = -1;
455 mtime_unset = (PyObject *)make_dirstate_tuple(
455 mtime_unset = (PyObject *)make_dirstate_tuple(
456 state, mode, size, mtime);
456 state, mode, size, mtime);
457 if (!mtime_unset)
457 if (!mtime_unset)
458 goto bail;
458 goto bail;
459 if (PyDict_SetItem(map, k, mtime_unset) == -1)
459 if (PyDict_SetItem(map, k, mtime_unset) == -1)
460 goto bail;
460 goto bail;
461 Py_DECREF(mtime_unset);
461 Py_DECREF(mtime_unset);
462 mtime_unset = NULL;
462 mtime_unset = NULL;
463 }
463 }
464 *p++ = state;
464 *p++ = state;
465 putbe32((uint32_t)mode, p);
465 putbe32((uint32_t)mode, p);
466 putbe32((uint32_t)size, p + 4);
466 putbe32((uint32_t)size, p + 4);
467 putbe32((uint32_t)mtime, p + 8);
467 putbe32((uint32_t)mtime, p + 8);
468 t = p + 12;
468 t = p + 12;
469 p += 16;
469 p += 16;
470 len = PyBytes_GET_SIZE(k);
470 len = PyBytes_GET_SIZE(k);
471 memcpy(p, PyBytes_AS_STRING(k), len);
471 memcpy(p, PyBytes_AS_STRING(k), len);
472 p += len;
472 p += len;
473 o = PyDict_GetItem(copymap, k);
473 o = PyDict_GetItem(copymap, k);
474 if (o) {
474 if (o) {
475 *p++ = '\0';
475 *p++ = '\0';
476 l = PyBytes_GET_SIZE(o);
476 l = PyBytes_GET_SIZE(o);
477 memcpy(p, PyBytes_AS_STRING(o), l);
477 memcpy(p, PyBytes_AS_STRING(o), l);
478 p += l;
478 p += l;
479 len += l + 1;
479 len += l + 1;
480 }
480 }
481 putbe32((uint32_t)len, t);
481 putbe32((uint32_t)len, t);
482 }
482 }
483
483
484 pos = p - PyBytes_AS_STRING(packobj);
484 pos = p - PyBytes_AS_STRING(packobj);
485 if (pos != nbytes) {
485 if (pos != nbytes) {
486 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
486 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
487 (long)pos, (long)nbytes);
487 (long)pos, (long)nbytes);
488 goto bail;
488 goto bail;
489 }
489 }
490
490
491 return packobj;
491 return packobj;
492 bail:
492 bail:
493 Py_XDECREF(mtime_unset);
493 Py_XDECREF(mtime_unset);
494 Py_XDECREF(packobj);
494 Py_XDECREF(packobj);
495 Py_XDECREF(v);
495 Py_XDECREF(v);
496 return NULL;
496 return NULL;
497 }
497 }
498
498
499 #define BUMPED_FIX 1
499 #define BUMPED_FIX 1
500 #define USING_SHA_256 2
500 #define USING_SHA_256 2
501 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
501 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
502
502
503 static PyObject *readshas(const char *source, unsigned char num,
503 static PyObject *readshas(const char *source, unsigned char num,
504 Py_ssize_t hashwidth)
504 Py_ssize_t hashwidth)
505 {
505 {
506 int i;
506 int i;
507 PyObject *list = PyTuple_New(num);
507 PyObject *list = PyTuple_New(num);
508 if (list == NULL) {
508 if (list == NULL) {
509 return NULL;
509 return NULL;
510 }
510 }
511 for (i = 0; i < num; i++) {
511 for (i = 0; i < num; i++) {
512 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
512 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
513 if (hash == NULL) {
513 if (hash == NULL) {
514 Py_DECREF(list);
514 Py_DECREF(list);
515 return NULL;
515 return NULL;
516 }
516 }
517 PyTuple_SET_ITEM(list, i, hash);
517 PyTuple_SET_ITEM(list, i, hash);
518 source += hashwidth;
518 source += hashwidth;
519 }
519 }
520 return list;
520 return list;
521 }
521 }
522
522
523 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
523 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
524 uint32_t *msize)
524 uint32_t *msize)
525 {
525 {
526 const char *data = databegin;
526 const char *data = databegin;
527 const char *meta;
527 const char *meta;
528
528
529 double mtime;
529 double mtime;
530 int16_t tz;
530 int16_t tz;
531 uint16_t flags;
531 uint16_t flags;
532 unsigned char nsuccs, nparents, nmetadata;
532 unsigned char nsuccs, nparents, nmetadata;
533 Py_ssize_t hashwidth = 20;
533 Py_ssize_t hashwidth = 20;
534
534
535 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
535 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
536 PyObject *metadata = NULL, *ret = NULL;
536 PyObject *metadata = NULL, *ret = NULL;
537 int i;
537 int i;
538
538
539 if (data + FM1_HEADER_SIZE > dataend) {
539 if (data + FM1_HEADER_SIZE > dataend) {
540 goto overflow;
540 goto overflow;
541 }
541 }
542
542
543 *msize = getbe32(data);
543 *msize = getbe32(data);
544 data += 4;
544 data += 4;
545 mtime = getbefloat64(data);
545 mtime = getbefloat64(data);
546 data += 8;
546 data += 8;
547 tz = getbeint16(data);
547 tz = getbeint16(data);
548 data += 2;
548 data += 2;
549 flags = getbeuint16(data);
549 flags = getbeuint16(data);
550 data += 2;
550 data += 2;
551
551
552 if (flags & USING_SHA_256) {
552 if (flags & USING_SHA_256) {
553 hashwidth = 32;
553 hashwidth = 32;
554 }
554 }
555
555
556 nsuccs = (unsigned char)(*data++);
556 nsuccs = (unsigned char)(*data++);
557 nparents = (unsigned char)(*data++);
557 nparents = (unsigned char)(*data++);
558 nmetadata = (unsigned char)(*data++);
558 nmetadata = (unsigned char)(*data++);
559
559
560 if (databegin + *msize > dataend) {
560 if (databegin + *msize > dataend) {
561 goto overflow;
561 goto overflow;
562 }
562 }
563 dataend = databegin + *msize; /* narrow down to marker size */
563 dataend = databegin + *msize; /* narrow down to marker size */
564
564
565 if (data + hashwidth > dataend) {
565 if (data + hashwidth > dataend) {
566 goto overflow;
566 goto overflow;
567 }
567 }
568 prec = PyBytes_FromStringAndSize(data, hashwidth);
568 prec = PyBytes_FromStringAndSize(data, hashwidth);
569 data += hashwidth;
569 data += hashwidth;
570 if (prec == NULL) {
570 if (prec == NULL) {
571 goto bail;
571 goto bail;
572 }
572 }
573
573
574 if (data + nsuccs * hashwidth > dataend) {
574 if (data + nsuccs * hashwidth > dataend) {
575 goto overflow;
575 goto overflow;
576 }
576 }
577 succs = readshas(data, nsuccs, hashwidth);
577 succs = readshas(data, nsuccs, hashwidth);
578 if (succs == NULL) {
578 if (succs == NULL) {
579 goto bail;
579 goto bail;
580 }
580 }
581 data += nsuccs * hashwidth;
581 data += nsuccs * hashwidth;
582
582
583 if (nparents == 1 || nparents == 2) {
583 if (nparents == 1 || nparents == 2) {
584 if (data + nparents * hashwidth > dataend) {
584 if (data + nparents * hashwidth > dataend) {
585 goto overflow;
585 goto overflow;
586 }
586 }
587 parents = readshas(data, nparents, hashwidth);
587 parents = readshas(data, nparents, hashwidth);
588 if (parents == NULL) {
588 if (parents == NULL) {
589 goto bail;
589 goto bail;
590 }
590 }
591 data += nparents * hashwidth;
591 data += nparents * hashwidth;
592 } else {
592 } else {
593 parents = Py_None;
593 parents = Py_None;
594 Py_INCREF(parents);
594 Py_INCREF(parents);
595 }
595 }
596
596
597 if (data + 2 * nmetadata > dataend) {
597 if (data + 2 * nmetadata > dataend) {
598 goto overflow;
598 goto overflow;
599 }
599 }
600 meta = data + (2 * nmetadata);
600 meta = data + (2 * nmetadata);
601 metadata = PyTuple_New(nmetadata);
601 metadata = PyTuple_New(nmetadata);
602 if (metadata == NULL) {
602 if (metadata == NULL) {
603 goto bail;
603 goto bail;
604 }
604 }
605 for (i = 0; i < nmetadata; i++) {
605 for (i = 0; i < nmetadata; i++) {
606 PyObject *tmp, *left = NULL, *right = NULL;
606 PyObject *tmp, *left = NULL, *right = NULL;
607 Py_ssize_t leftsize = (unsigned char)(*data++);
607 Py_ssize_t leftsize = (unsigned char)(*data++);
608 Py_ssize_t rightsize = (unsigned char)(*data++);
608 Py_ssize_t rightsize = (unsigned char)(*data++);
609 if (meta + leftsize + rightsize > dataend) {
609 if (meta + leftsize + rightsize > dataend) {
610 goto overflow;
610 goto overflow;
611 }
611 }
612 left = PyBytes_FromStringAndSize(meta, leftsize);
612 left = PyBytes_FromStringAndSize(meta, leftsize);
613 meta += leftsize;
613 meta += leftsize;
614 right = PyBytes_FromStringAndSize(meta, rightsize);
614 right = PyBytes_FromStringAndSize(meta, rightsize);
615 meta += rightsize;
615 meta += rightsize;
616 tmp = PyTuple_New(2);
616 tmp = PyTuple_New(2);
617 if (!left || !right || !tmp) {
617 if (!left || !right || !tmp) {
618 Py_XDECREF(left);
618 Py_XDECREF(left);
619 Py_XDECREF(right);
619 Py_XDECREF(right);
620 Py_XDECREF(tmp);
620 Py_XDECREF(tmp);
621 goto bail;
621 goto bail;
622 }
622 }
623 PyTuple_SET_ITEM(tmp, 0, left);
623 PyTuple_SET_ITEM(tmp, 0, left);
624 PyTuple_SET_ITEM(tmp, 1, right);
624 PyTuple_SET_ITEM(tmp, 1, right);
625 PyTuple_SET_ITEM(metadata, i, tmp);
625 PyTuple_SET_ITEM(metadata, i, tmp);
626 }
626 }
627 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
627 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
628 (int)tz * 60, parents);
628 (int)tz * 60, parents);
629 goto bail; /* return successfully */
629 goto bail; /* return successfully */
630
630
631 overflow:
631 overflow:
632 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
632 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
633 bail:
633 bail:
634 Py_XDECREF(prec);
634 Py_XDECREF(prec);
635 Py_XDECREF(succs);
635 Py_XDECREF(succs);
636 Py_XDECREF(metadata);
636 Py_XDECREF(metadata);
637 Py_XDECREF(parents);
637 Py_XDECREF(parents);
638 return ret;
638 return ret;
639 }
639 }
640
640
641 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
641 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
642 {
642 {
643 const char *data, *dataend;
643 const char *data, *dataend;
644 int datalen;
644 int datalen;
645 Py_ssize_t offset, stop;
645 Py_ssize_t offset, stop;
646 PyObject *markers = NULL;
646 PyObject *markers = NULL;
647
647
648 if (!PyArg_ParseTuple(args, "s#nn", &data, &datalen, &offset, &stop)) {
648 if (!PyArg_ParseTuple(args, "s#nn", &data, &datalen, &offset, &stop)) {
649 return NULL;
649 return NULL;
650 }
650 }
651 dataend = data + datalen;
651 dataend = data + datalen;
652 data += offset;
652 data += offset;
653 markers = PyList_New(0);
653 markers = PyList_New(0);
654 if (!markers) {
654 if (!markers) {
655 return NULL;
655 return NULL;
656 }
656 }
657 while (offset < stop) {
657 while (offset < stop) {
658 uint32_t msize;
658 uint32_t msize;
659 int error;
659 int error;
660 PyObject *record = fm1readmarker(data, dataend, &msize);
660 PyObject *record = fm1readmarker(data, dataend, &msize);
661 if (!record) {
661 if (!record) {
662 goto bail;
662 goto bail;
663 }
663 }
664 error = PyList_Append(markers, record);
664 error = PyList_Append(markers, record);
665 Py_DECREF(record);
665 Py_DECREF(record);
666 if (error) {
666 if (error) {
667 goto bail;
667 goto bail;
668 }
668 }
669 data += msize;
669 data += msize;
670 offset += msize;
670 offset += msize;
671 }
671 }
672 return markers;
672 return markers;
673 bail:
673 bail:
674 Py_DECREF(markers);
674 Py_DECREF(markers);
675 return NULL;
675 return NULL;
676 }
676 }
677
677
678 static char parsers_doc[] = "Efficient content parsing.";
678 static char parsers_doc[] = "Efficient content parsing.";
679
679
680 PyObject *encodedir(PyObject *self, PyObject *args);
680 PyObject *encodedir(PyObject *self, PyObject *args);
681 PyObject *pathencode(PyObject *self, PyObject *args);
681 PyObject *pathencode(PyObject *self, PyObject *args);
682 PyObject *lowerencode(PyObject *self, PyObject *args);
682 PyObject *lowerencode(PyObject *self, PyObject *args);
683 PyObject *parse_index2(PyObject *self, PyObject *args);
683 PyObject *parse_index2(PyObject *self, PyObject *args);
684
684
685 static PyMethodDef methods[] = {
685 static PyMethodDef methods[] = {
686 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
686 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
687 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
687 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
688 "create a set containing non-normal and other parent entries of given "
688 "create a set containing non-normal and other parent entries of given "
689 "dirstate\n"},
689 "dirstate\n"},
690 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
690 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
691 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
691 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
692 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
692 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
693 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
693 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
694 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
694 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
695 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
695 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
696 {"dict_new_presized", dict_new_presized, METH_VARARGS,
696 {"dict_new_presized", dict_new_presized, METH_VARARGS,
697 "construct a dict with an expected size\n"},
697 "construct a dict with an expected size\n"},
698 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
698 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
699 "make file foldmap\n"},
699 "make file foldmap\n"},
700 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
700 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
701 "escape a UTF-8 byte string to JSON (fast path)\n"},
701 "escape a UTF-8 byte string to JSON (fast path)\n"},
702 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
702 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
703 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
703 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
704 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
704 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
705 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
705 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
706 "parse v1 obsolete markers\n"},
706 "parse v1 obsolete markers\n"},
707 {NULL, NULL}};
707 {NULL, NULL}};
708
708
709 void dirs_module_init(PyObject *mod);
709 void dirs_module_init(PyObject *mod);
710 void manifest_module_init(PyObject *mod);
710 void manifest_module_init(PyObject *mod);
711 void revlog_module_init(PyObject *mod);
711 void revlog_module_init(PyObject *mod);
712
712
713 static const int version = 4;
713 static const int version = 4;
714
714
715 static void module_init(PyObject *mod)
715 static void module_init(PyObject *mod)
716 {
716 {
717 PyModule_AddIntConstant(mod, "version", version);
717 PyModule_AddIntConstant(mod, "version", version);
718
718
719 /* This module constant has two purposes. First, it lets us unit test
719 /* This module constant has two purposes. First, it lets us unit test
720 * the ImportError raised without hard-coding any error text. This
720 * the ImportError raised without hard-coding any error text. This
721 * means we can change the text in the future without breaking tests,
721 * means we can change the text in the future without breaking tests,
722 * even across changesets without a recompile. Second, its presence
722 * even across changesets without a recompile. Second, its presence
723 * can be used to determine whether the version-checking logic is
723 * can be used to determine whether the version-checking logic is
724 * present, which also helps in testing across changesets without a
724 * present, which also helps in testing across changesets without a
725 * recompile. Note that this means the pure-Python version of parsers
725 * recompile. Note that this means the pure-Python version of parsers
726 * should not have this module constant. */
726 * should not have this module constant. */
727 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
727 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
728
728
729 dirs_module_init(mod);
729 dirs_module_init(mod);
730 manifest_module_init(mod);
730 manifest_module_init(mod);
731 revlog_module_init(mod);
731 revlog_module_init(mod);
732
732
733 if (PyType_Ready(&dirstateTupleType) < 0)
733 if (PyType_Ready(&dirstateTupleType) < 0)
734 return;
734 return;
735 Py_INCREF(&dirstateTupleType);
735 Py_INCREF(&dirstateTupleType);
736 PyModule_AddObject(mod, "dirstatetuple",
736 PyModule_AddObject(mod, "dirstatetuple",
737 (PyObject *)&dirstateTupleType);
737 (PyObject *)&dirstateTupleType);
738 }
738 }
739
739
740 static int check_python_version(void)
740 static int check_python_version(void)
741 {
741 {
742 PyObject *sys = PyImport_ImportModule("sys"), *ver;
742 PyObject *sys = PyImport_ImportModule("sys"), *ver;
743 long hexversion;
743 long hexversion;
744 if (!sys)
744 if (!sys)
745 return -1;
745 return -1;
746 ver = PyObject_GetAttrString(sys, "hexversion");
746 ver = PyObject_GetAttrString(sys, "hexversion");
747 Py_DECREF(sys);
747 Py_DECREF(sys);
748 if (!ver)
748 if (!ver)
749 return -1;
749 return -1;
750 hexversion = PyInt_AsLong(ver);
750 hexversion = PyInt_AsLong(ver);
751 Py_DECREF(ver);
751 Py_DECREF(ver);
752 /* sys.hexversion is a 32-bit number by default, so the -1 case
752 /* sys.hexversion is a 32-bit number by default, so the -1 case
753 * should only occur in unusual circumstances (e.g. if sys.hexversion
753 * should only occur in unusual circumstances (e.g. if sys.hexversion
754 * is manually set to an invalid value). */
754 * is manually set to an invalid value). */
755 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
755 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
756 PyErr_Format(PyExc_ImportError,
756 PyErr_Format(PyExc_ImportError,
757 "%s: The Mercurial extension "
757 "%s: The Mercurial extension "
758 "modules were compiled with Python " PY_VERSION
758 "modules were compiled with Python " PY_VERSION
759 ", but "
759 ", but "
760 "Mercurial is currently using Python with "
760 "Mercurial is currently using Python with "
761 "sys.hexversion=%ld: "
761 "sys.hexversion=%ld: "
762 "Python %s\n at: %s",
762 "Python %s\n at: %s",
763 versionerrortext, hexversion, Py_GetVersion(),
763 versionerrortext, hexversion, Py_GetVersion(),
764 Py_GetProgramFullPath());
764 Py_GetProgramFullPath());
765 return -1;
765 return -1;
766 }
766 }
767 return 0;
767 return 0;
768 }
768 }
769
769
770 #ifdef IS_PY3K
770 #ifdef IS_PY3K
771 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
771 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
772 parsers_doc, -1, methods};
772 parsers_doc, -1, methods};
773
773
774 PyMODINIT_FUNC PyInit_parsers(void)
774 PyMODINIT_FUNC PyInit_parsers(void)
775 {
775 {
776 PyObject *mod;
776 PyObject *mod;
777
777
778 if (check_python_version() == -1)
778 if (check_python_version() == -1)
779 return NULL;
779 return NULL;
780 mod = PyModule_Create(&parsers_module);
780 mod = PyModule_Create(&parsers_module);
781 module_init(mod);
781 module_init(mod);
782 return mod;
782 return mod;
783 }
783 }
784 #else
784 #else
785 PyMODINIT_FUNC initparsers(void)
785 PyMODINIT_FUNC initparsers(void)
786 {
786 {
787 PyObject *mod;
787 PyObject *mod;
788
788
789 if (check_python_version() == -1)
789 if (check_python_version() == -1)
790 return;
790 return;
791 mod = Py_InitModule3("parsers", methods, parsers_doc);
791 mod = Py_InitModule3("parsers", methods, parsers_doc);
792 module_init(mod);
792 module_init(mod);
793 }
793 }
794 #endif
794 #endif
@@ -1,2084 +1,2084 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@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 #include <Python.h>
10 #include <Python.h>
11 #include <assert.h>
11 #include <assert.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_AS_LONG PyLong_AS_LONG
27 #define PyInt_AS_LONG PyLong_AS_LONG
28 #define PyInt_AsLong PyLong_AsLong
28 #define PyInt_AsLong PyLong_AsLong
29 #endif
29 #endif
30
30
31 /*
31 /*
32 * A base-16 trie for fast node->rev mapping.
32 * A base-16 trie for fast node->rev mapping.
33 *
33 *
34 * Positive value is index of the next node in the trie
34 * Positive value is index of the next node in the trie
35 * Negative value is a leaf: -(rev + 1)
35 * Negative value is a leaf: -(rev + 1)
36 * Zero is empty
36 * Zero is empty
37 */
37 */
38 typedef struct {
38 typedef struct {
39 int children[16];
39 int children[16];
40 } nodetree;
40 } nodetree;
41
41
42 /*
42 /*
43 * This class has two behaviors.
43 * This class has two behaviors.
44 *
44 *
45 * When used in a list-like way (with integer keys), we decode an
45 * When used in a list-like way (with integer keys), we decode an
46 * entry in a RevlogNG index file on demand. Our last entry is a
46 * entry in a RevlogNG index file on demand. Our last entry is a
47 * sentinel, always a nullid. We have limited support for
47 * sentinel, always a nullid. We have limited support for
48 * integer-keyed insert and delete, only at elements right before the
48 * integer-keyed insert and delete, only at elements right before the
49 * sentinel.
49 * sentinel.
50 *
50 *
51 * With string keys, we lazily perform a reverse mapping from node to
51 * With string keys, we lazily perform a reverse mapping from node to
52 * rev, using a base-16 trie.
52 * rev, using a base-16 trie.
53 */
53 */
54 typedef struct {
54 typedef struct {
55 PyObject_HEAD
55 PyObject_HEAD
56 /* Type-specific fields go here. */
56 /* Type-specific fields go here. */
57 PyObject *data; /* raw bytes of index */
57 PyObject *data; /* raw bytes of index */
58 Py_buffer buf; /* buffer of data */
58 Py_buffer buf; /* buffer of data */
59 PyObject **cache; /* cached tuples */
59 PyObject **cache; /* cached tuples */
60 const char **offsets; /* populated on demand */
60 const char **offsets; /* populated on demand */
61 Py_ssize_t raw_length; /* original number of elements */
61 Py_ssize_t raw_length; /* original number of elements */
62 Py_ssize_t length; /* current number of elements */
62 Py_ssize_t length; /* current number of elements */
63 PyObject *added; /* populated on demand */
63 PyObject *added; /* populated on demand */
64 PyObject *headrevs; /* cache, invalidated on changes */
64 PyObject *headrevs; /* cache, invalidated on changes */
65 PyObject *filteredrevs;/* filtered revs set */
65 PyObject *filteredrevs;/* filtered revs set */
66 nodetree *nt; /* base-16 trie */
66 nodetree *nt; /* base-16 trie */
67 unsigned ntlength; /* # nodes in use */
67 unsigned ntlength; /* # nodes in use */
68 unsigned ntcapacity; /* # nodes allocated */
68 unsigned ntcapacity; /* # nodes allocated */
69 int ntdepth; /* maximum depth of tree */
69 int ntdepth; /* maximum depth of tree */
70 int ntsplits; /* # splits performed */
70 int ntsplits; /* # splits performed */
71 int ntrev; /* last rev scanned */
71 int ntrev; /* last rev scanned */
72 int ntlookups; /* # lookups */
72 int ntlookups; /* # lookups */
73 int ntmisses; /* # lookups that miss the cache */
73 int ntmisses; /* # lookups that miss the cache */
74 int inlined;
74 int inlined;
75 } indexObject;
75 } indexObject;
76
76
77 static Py_ssize_t index_length(const indexObject *self)
77 static Py_ssize_t index_length(const indexObject *self)
78 {
78 {
79 if (self->added == NULL)
79 if (self->added == NULL)
80 return self->length;
80 return self->length;
81 return self->length + PyList_GET_SIZE(self->added);
81 return self->length + PyList_GET_SIZE(self->added);
82 }
82 }
83
83
84 static PyObject *nullentry;
84 static PyObject *nullentry;
85 static const char nullid[20];
85 static const char nullid[20];
86
86
87 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
87 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
88
88
89 #if LONG_MAX == 0x7fffffffL
89 #if LONG_MAX == 0x7fffffffL
90 static char *tuple_format = "Kiiiiiis#";
90 static char *tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
91 #else
91 #else
92 static char *tuple_format = "kiiiiiis#";
92 static char *tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
93 #endif
93 #endif
94
94
95 /* A RevlogNG v1 index entry is 64 bytes long. */
95 /* A RevlogNG v1 index entry is 64 bytes long. */
96 static const long v1_hdrsize = 64;
96 static const long v1_hdrsize = 64;
97
97
98 /*
98 /*
99 * Return a pointer to the beginning of a RevlogNG record.
99 * Return a pointer to the beginning of a RevlogNG record.
100 */
100 */
101 static const char *index_deref(indexObject *self, Py_ssize_t pos)
101 static const char *index_deref(indexObject *self, Py_ssize_t pos)
102 {
102 {
103 if (self->inlined && pos > 0) {
103 if (self->inlined && pos > 0) {
104 if (self->offsets == NULL) {
104 if (self->offsets == NULL) {
105 self->offsets = PyMem_Malloc(self->raw_length *
105 self->offsets = PyMem_Malloc(self->raw_length *
106 sizeof(*self->offsets));
106 sizeof(*self->offsets));
107 if (self->offsets == NULL)
107 if (self->offsets == NULL)
108 return (const char *)PyErr_NoMemory();
108 return (const char *)PyErr_NoMemory();
109 inline_scan(self, self->offsets);
109 inline_scan(self, self->offsets);
110 }
110 }
111 return self->offsets[pos];
111 return self->offsets[pos];
112 }
112 }
113
113
114 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
114 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
115 }
115 }
116
116
117 static inline int index_get_parents(indexObject *self, Py_ssize_t rev,
117 static inline int index_get_parents(indexObject *self, Py_ssize_t rev,
118 int *ps, int maxrev)
118 int *ps, int maxrev)
119 {
119 {
120 if (rev >= self->length - 1) {
120 if (rev >= self->length - 1) {
121 PyObject *tuple = PyList_GET_ITEM(self->added,
121 PyObject *tuple = PyList_GET_ITEM(self->added,
122 rev - self->length + 1);
122 rev - self->length + 1);
123 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
123 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
124 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
124 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
125 } else {
125 } else {
126 const char *data = index_deref(self, rev);
126 const char *data = index_deref(self, rev);
127 ps[0] = getbe32(data + 24);
127 ps[0] = getbe32(data + 24);
128 ps[1] = getbe32(data + 28);
128 ps[1] = getbe32(data + 28);
129 }
129 }
130 /* If index file is corrupted, ps[] may point to invalid revisions. So
130 /* If index file is corrupted, ps[] may point to invalid revisions. So
131 * there is a risk of buffer overflow to trust them unconditionally. */
131 * there is a risk of buffer overflow to trust them unconditionally. */
132 if (ps[0] > maxrev || ps[1] > maxrev) {
132 if (ps[0] > maxrev || ps[1] > maxrev) {
133 PyErr_SetString(PyExc_ValueError, "parent out of range");
133 PyErr_SetString(PyExc_ValueError, "parent out of range");
134 return -1;
134 return -1;
135 }
135 }
136 return 0;
136 return 0;
137 }
137 }
138
138
139
139
140 /*
140 /*
141 * RevlogNG format (all in big endian, data may be inlined):
141 * RevlogNG format (all in big endian, data may be inlined):
142 * 6 bytes: offset
142 * 6 bytes: offset
143 * 2 bytes: flags
143 * 2 bytes: flags
144 * 4 bytes: compressed length
144 * 4 bytes: compressed length
145 * 4 bytes: uncompressed length
145 * 4 bytes: uncompressed length
146 * 4 bytes: base revision
146 * 4 bytes: base revision
147 * 4 bytes: link revision
147 * 4 bytes: link revision
148 * 4 bytes: parent 1 revision
148 * 4 bytes: parent 1 revision
149 * 4 bytes: parent 2 revision
149 * 4 bytes: parent 2 revision
150 * 32 bytes: nodeid (only 20 bytes used)
150 * 32 bytes: nodeid (only 20 bytes used)
151 */
151 */
152 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
152 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
153 {
153 {
154 uint64_t offset_flags;
154 uint64_t offset_flags;
155 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
155 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
156 const char *c_node_id;
156 const char *c_node_id;
157 const char *data;
157 const char *data;
158 Py_ssize_t length = index_length(self);
158 Py_ssize_t length = index_length(self);
159 PyObject *entry;
159 PyObject *entry;
160
160
161 if (pos < 0)
161 if (pos < 0)
162 pos += length;
162 pos += length;
163
163
164 if (pos < 0 || pos >= length) {
164 if (pos < 0 || pos >= length) {
165 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
165 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
166 return NULL;
166 return NULL;
167 }
167 }
168
168
169 if (pos == length - 1) {
169 if (pos == length - 1) {
170 Py_INCREF(nullentry);
170 Py_INCREF(nullentry);
171 return nullentry;
171 return nullentry;
172 }
172 }
173
173
174 if (pos >= self->length - 1) {
174 if (pos >= self->length - 1) {
175 PyObject *obj;
175 PyObject *obj;
176 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
176 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
177 Py_INCREF(obj);
177 Py_INCREF(obj);
178 return obj;
178 return obj;
179 }
179 }
180
180
181 if (self->cache) {
181 if (self->cache) {
182 if (self->cache[pos]) {
182 if (self->cache[pos]) {
183 Py_INCREF(self->cache[pos]);
183 Py_INCREF(self->cache[pos]);
184 return self->cache[pos];
184 return self->cache[pos];
185 }
185 }
186 } else {
186 } else {
187 self->cache = calloc(self->raw_length, sizeof(PyObject *));
187 self->cache = calloc(self->raw_length, sizeof(PyObject *));
188 if (self->cache == NULL)
188 if (self->cache == NULL)
189 return PyErr_NoMemory();
189 return PyErr_NoMemory();
190 }
190 }
191
191
192 data = index_deref(self, pos);
192 data = index_deref(self, pos);
193 if (data == NULL)
193 if (data == NULL)
194 return NULL;
194 return NULL;
195
195
196 offset_flags = getbe32(data + 4);
196 offset_flags = getbe32(data + 4);
197 if (pos == 0) /* mask out version number for the first entry */
197 if (pos == 0) /* mask out version number for the first entry */
198 offset_flags &= 0xFFFF;
198 offset_flags &= 0xFFFF;
199 else {
199 else {
200 uint32_t offset_high = getbe32(data);
200 uint32_t offset_high = getbe32(data);
201 offset_flags |= ((uint64_t)offset_high) << 32;
201 offset_flags |= ((uint64_t)offset_high) << 32;
202 }
202 }
203
203
204 comp_len = getbe32(data + 8);
204 comp_len = getbe32(data + 8);
205 uncomp_len = getbe32(data + 12);
205 uncomp_len = getbe32(data + 12);
206 base_rev = getbe32(data + 16);
206 base_rev = getbe32(data + 16);
207 link_rev = getbe32(data + 20);
207 link_rev = getbe32(data + 20);
208 parent_1 = getbe32(data + 24);
208 parent_1 = getbe32(data + 24);
209 parent_2 = getbe32(data + 28);
209 parent_2 = getbe32(data + 28);
210 c_node_id = data + 32;
210 c_node_id = data + 32;
211
211
212 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
212 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
213 uncomp_len, base_rev, link_rev,
213 uncomp_len, base_rev, link_rev,
214 parent_1, parent_2, c_node_id, 20);
214 parent_1, parent_2, c_node_id, 20);
215
215
216 if (entry) {
216 if (entry) {
217 PyObject_GC_UnTrack(entry);
217 PyObject_GC_UnTrack(entry);
218 Py_INCREF(entry);
218 Py_INCREF(entry);
219 }
219 }
220
220
221 self->cache[pos] = entry;
221 self->cache[pos] = entry;
222
222
223 return entry;
223 return entry;
224 }
224 }
225
225
226 /*
226 /*
227 * Return the 20-byte SHA of the node corresponding to the given rev.
227 * Return the 20-byte SHA of the node corresponding to the given rev.
228 */
228 */
229 static const char *index_node(indexObject *self, Py_ssize_t pos)
229 static const char *index_node(indexObject *self, Py_ssize_t pos)
230 {
230 {
231 Py_ssize_t length = index_length(self);
231 Py_ssize_t length = index_length(self);
232 const char *data;
232 const char *data;
233
233
234 if (pos == length - 1 || pos == INT_MAX)
234 if (pos == length - 1 || pos == INT_MAX)
235 return nullid;
235 return nullid;
236
236
237 if (pos >= length)
237 if (pos >= length)
238 return NULL;
238 return NULL;
239
239
240 if (pos >= self->length - 1) {
240 if (pos >= self->length - 1) {
241 PyObject *tuple, *str;
241 PyObject *tuple, *str;
242 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
242 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
243 str = PyTuple_GetItem(tuple, 7);
243 str = PyTuple_GetItem(tuple, 7);
244 return str ? PyBytes_AS_STRING(str) : NULL;
244 return str ? PyBytes_AS_STRING(str) : NULL;
245 }
245 }
246
246
247 data = index_deref(self, pos);
247 data = index_deref(self, pos);
248 return data ? data + 32 : NULL;
248 return data ? data + 32 : NULL;
249 }
249 }
250
250
251 static int nt_insert(indexObject *self, const char *node, int rev);
251 static int nt_insert(indexObject *self, const char *node, int rev);
252
252
253 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
253 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
254 {
254 {
255 if (PyBytes_AsStringAndSize(obj, node, nodelen) == -1)
255 if (PyBytes_AsStringAndSize(obj, node, nodelen) == -1)
256 return -1;
256 return -1;
257 if (*nodelen == 20)
257 if (*nodelen == 20)
258 return 0;
258 return 0;
259 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
259 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
260 return -1;
260 return -1;
261 }
261 }
262
262
263 static PyObject *index_insert(indexObject *self, PyObject *args)
263 static PyObject *index_insert(indexObject *self, PyObject *args)
264 {
264 {
265 PyObject *obj;
265 PyObject *obj;
266 char *node;
266 char *node;
267 int index;
267 int index;
268 Py_ssize_t len, nodelen;
268 Py_ssize_t len, nodelen;
269
269
270 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
270 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
271 return NULL;
271 return NULL;
272
272
273 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
273 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
274 PyErr_SetString(PyExc_TypeError, "8-tuple required");
274 PyErr_SetString(PyExc_TypeError, "8-tuple required");
275 return NULL;
275 return NULL;
276 }
276 }
277
277
278 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
278 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
279 return NULL;
279 return NULL;
280
280
281 len = index_length(self);
281 len = index_length(self);
282
282
283 if (index < 0)
283 if (index < 0)
284 index += len;
284 index += len;
285
285
286 if (index != len - 1) {
286 if (index != len - 1) {
287 PyErr_SetString(PyExc_IndexError,
287 PyErr_SetString(PyExc_IndexError,
288 "insert only supported at index -1");
288 "insert only supported at index -1");
289 return NULL;
289 return NULL;
290 }
290 }
291
291
292 if (self->added == NULL) {
292 if (self->added == NULL) {
293 self->added = PyList_New(0);
293 self->added = PyList_New(0);
294 if (self->added == NULL)
294 if (self->added == NULL)
295 return NULL;
295 return NULL;
296 }
296 }
297
297
298 if (PyList_Append(self->added, obj) == -1)
298 if (PyList_Append(self->added, obj) == -1)
299 return NULL;
299 return NULL;
300
300
301 if (self->nt)
301 if (self->nt)
302 nt_insert(self, node, index);
302 nt_insert(self, node, index);
303
303
304 Py_CLEAR(self->headrevs);
304 Py_CLEAR(self->headrevs);
305 Py_RETURN_NONE;
305 Py_RETURN_NONE;
306 }
306 }
307
307
308 static void _index_clearcaches(indexObject *self)
308 static void _index_clearcaches(indexObject *self)
309 {
309 {
310 if (self->cache) {
310 if (self->cache) {
311 Py_ssize_t i;
311 Py_ssize_t i;
312
312
313 for (i = 0; i < self->raw_length; i++)
313 for (i = 0; i < self->raw_length; i++)
314 Py_CLEAR(self->cache[i]);
314 Py_CLEAR(self->cache[i]);
315 free(self->cache);
315 free(self->cache);
316 self->cache = NULL;
316 self->cache = NULL;
317 }
317 }
318 if (self->offsets) {
318 if (self->offsets) {
319 PyMem_Free(self->offsets);
319 PyMem_Free(self->offsets);
320 self->offsets = NULL;
320 self->offsets = NULL;
321 }
321 }
322 if (self->nt) {
322 if (self->nt) {
323 free(self->nt);
323 free(self->nt);
324 self->nt = NULL;
324 self->nt = NULL;
325 }
325 }
326 Py_CLEAR(self->headrevs);
326 Py_CLEAR(self->headrevs);
327 }
327 }
328
328
329 static PyObject *index_clearcaches(indexObject *self)
329 static PyObject *index_clearcaches(indexObject *self)
330 {
330 {
331 _index_clearcaches(self);
331 _index_clearcaches(self);
332 self->ntlength = self->ntcapacity = 0;
332 self->ntlength = self->ntcapacity = 0;
333 self->ntdepth = self->ntsplits = 0;
333 self->ntdepth = self->ntsplits = 0;
334 self->ntrev = -1;
334 self->ntrev = -1;
335 self->ntlookups = self->ntmisses = 0;
335 self->ntlookups = self->ntmisses = 0;
336 Py_RETURN_NONE;
336 Py_RETURN_NONE;
337 }
337 }
338
338
339 static PyObject *index_stats(indexObject *self)
339 static PyObject *index_stats(indexObject *self)
340 {
340 {
341 PyObject *obj = PyDict_New();
341 PyObject *obj = PyDict_New();
342 PyObject *t = NULL;
342 PyObject *t = NULL;
343
343
344 if (obj == NULL)
344 if (obj == NULL)
345 return NULL;
345 return NULL;
346
346
347 #define istat(__n, __d) \
347 #define istat(__n, __d) \
348 do { \
348 do { \
349 t = PyInt_FromSsize_t(self->__n); \
349 t = PyInt_FromSsize_t(self->__n); \
350 if (!t) \
350 if (!t) \
351 goto bail; \
351 goto bail; \
352 if (PyDict_SetItemString(obj, __d, t) == -1) \
352 if (PyDict_SetItemString(obj, __d, t) == -1) \
353 goto bail; \
353 goto bail; \
354 Py_DECREF(t); \
354 Py_DECREF(t); \
355 } while (0)
355 } while (0)
356
356
357 if (self->added) {
357 if (self->added) {
358 Py_ssize_t len = PyList_GET_SIZE(self->added);
358 Py_ssize_t len = PyList_GET_SIZE(self->added);
359 t = PyInt_FromSsize_t(len);
359 t = PyInt_FromSsize_t(len);
360 if (!t)
360 if (!t)
361 goto bail;
361 goto bail;
362 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
362 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
363 goto bail;
363 goto bail;
364 Py_DECREF(t);
364 Py_DECREF(t);
365 }
365 }
366
366
367 if (self->raw_length != self->length - 1)
367 if (self->raw_length != self->length - 1)
368 istat(raw_length, "revs on disk");
368 istat(raw_length, "revs on disk");
369 istat(length, "revs in memory");
369 istat(length, "revs in memory");
370 istat(ntcapacity, "node trie capacity");
370 istat(ntcapacity, "node trie capacity");
371 istat(ntdepth, "node trie depth");
371 istat(ntdepth, "node trie depth");
372 istat(ntlength, "node trie count");
372 istat(ntlength, "node trie count");
373 istat(ntlookups, "node trie lookups");
373 istat(ntlookups, "node trie lookups");
374 istat(ntmisses, "node trie misses");
374 istat(ntmisses, "node trie misses");
375 istat(ntrev, "node trie last rev scanned");
375 istat(ntrev, "node trie last rev scanned");
376 istat(ntsplits, "node trie splits");
376 istat(ntsplits, "node trie splits");
377
377
378 #undef istat
378 #undef istat
379
379
380 return obj;
380 return obj;
381
381
382 bail:
382 bail:
383 Py_XDECREF(obj);
383 Py_XDECREF(obj);
384 Py_XDECREF(t);
384 Py_XDECREF(t);
385 return NULL;
385 return NULL;
386 }
386 }
387
387
388 /*
388 /*
389 * When we cache a list, we want to be sure the caller can't mutate
389 * When we cache a list, we want to be sure the caller can't mutate
390 * the cached copy.
390 * the cached copy.
391 */
391 */
392 static PyObject *list_copy(PyObject *list)
392 static PyObject *list_copy(PyObject *list)
393 {
393 {
394 Py_ssize_t len = PyList_GET_SIZE(list);
394 Py_ssize_t len = PyList_GET_SIZE(list);
395 PyObject *newlist = PyList_New(len);
395 PyObject *newlist = PyList_New(len);
396 Py_ssize_t i;
396 Py_ssize_t i;
397
397
398 if (newlist == NULL)
398 if (newlist == NULL)
399 return NULL;
399 return NULL;
400
400
401 for (i = 0; i < len; i++) {
401 for (i = 0; i < len; i++) {
402 PyObject *obj = PyList_GET_ITEM(list, i);
402 PyObject *obj = PyList_GET_ITEM(list, i);
403 Py_INCREF(obj);
403 Py_INCREF(obj);
404 PyList_SET_ITEM(newlist, i, obj);
404 PyList_SET_ITEM(newlist, i, obj);
405 }
405 }
406
406
407 return newlist;
407 return newlist;
408 }
408 }
409
409
410 static int check_filter(PyObject *filter, Py_ssize_t arg)
410 static int check_filter(PyObject *filter, Py_ssize_t arg)
411 {
411 {
412 if (filter) {
412 if (filter) {
413 PyObject *arglist, *result;
413 PyObject *arglist, *result;
414 int isfiltered;
414 int isfiltered;
415
415
416 arglist = Py_BuildValue("(n)", arg);
416 arglist = Py_BuildValue("(n)", arg);
417 if (!arglist) {
417 if (!arglist) {
418 return -1;
418 return -1;
419 }
419 }
420
420
421 result = PyEval_CallObject(filter, arglist);
421 result = PyEval_CallObject(filter, arglist);
422 Py_DECREF(arglist);
422 Py_DECREF(arglist);
423 if (!result) {
423 if (!result) {
424 return -1;
424 return -1;
425 }
425 }
426
426
427 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
427 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
428 * same as this function, so we can just return it directly.*/
428 * same as this function, so we can just return it directly.*/
429 isfiltered = PyObject_IsTrue(result);
429 isfiltered = PyObject_IsTrue(result);
430 Py_DECREF(result);
430 Py_DECREF(result);
431 return isfiltered;
431 return isfiltered;
432 } else {
432 } else {
433 return 0;
433 return 0;
434 }
434 }
435 }
435 }
436
436
437 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
437 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
438 Py_ssize_t marker, char *phases)
438 Py_ssize_t marker, char *phases)
439 {
439 {
440 PyObject *iter = NULL;
440 PyObject *iter = NULL;
441 PyObject *iter_item = NULL;
441 PyObject *iter_item = NULL;
442 Py_ssize_t min_idx = index_length(self) + 1;
442 Py_ssize_t min_idx = index_length(self) + 1;
443 long iter_item_long;
443 long iter_item_long;
444
444
445 if (PyList_GET_SIZE(list) != 0) {
445 if (PyList_GET_SIZE(list) != 0) {
446 iter = PyObject_GetIter(list);
446 iter = PyObject_GetIter(list);
447 if (iter == NULL)
447 if (iter == NULL)
448 return -2;
448 return -2;
449 while ((iter_item = PyIter_Next(iter))) {
449 while ((iter_item = PyIter_Next(iter))) {
450 iter_item_long = PyInt_AS_LONG(iter_item);
450 iter_item_long = PyInt_AS_LONG(iter_item);
451 Py_DECREF(iter_item);
451 Py_DECREF(iter_item);
452 if (iter_item_long < min_idx)
452 if (iter_item_long < min_idx)
453 min_idx = iter_item_long;
453 min_idx = iter_item_long;
454 phases[iter_item_long] = marker;
454 phases[iter_item_long] = marker;
455 }
455 }
456 Py_DECREF(iter);
456 Py_DECREF(iter);
457 }
457 }
458
458
459 return min_idx;
459 return min_idx;
460 }
460 }
461
461
462 static inline void set_phase_from_parents(char *phases, int parent_1,
462 static inline void set_phase_from_parents(char *phases, int parent_1,
463 int parent_2, Py_ssize_t i)
463 int parent_2, Py_ssize_t i)
464 {
464 {
465 if (parent_1 >= 0 && phases[parent_1] > phases[i])
465 if (parent_1 >= 0 && phases[parent_1] > phases[i])
466 phases[i] = phases[parent_1];
466 phases[i] = phases[parent_1];
467 if (parent_2 >= 0 && phases[parent_2] > phases[i])
467 if (parent_2 >= 0 && phases[parent_2] > phases[i])
468 phases[i] = phases[parent_2];
468 phases[i] = phases[parent_2];
469 }
469 }
470
470
471 static PyObject *reachableroots2(indexObject *self, PyObject *args)
471 static PyObject *reachableroots2(indexObject *self, PyObject *args)
472 {
472 {
473
473
474 /* Input */
474 /* Input */
475 long minroot;
475 long minroot;
476 PyObject *includepatharg = NULL;
476 PyObject *includepatharg = NULL;
477 int includepath = 0;
477 int includepath = 0;
478 /* heads and roots are lists */
478 /* heads and roots are lists */
479 PyObject *heads = NULL;
479 PyObject *heads = NULL;
480 PyObject *roots = NULL;
480 PyObject *roots = NULL;
481 PyObject *reachable = NULL;
481 PyObject *reachable = NULL;
482
482
483 PyObject *val;
483 PyObject *val;
484 Py_ssize_t len = index_length(self) - 1;
484 Py_ssize_t len = index_length(self) - 1;
485 long revnum;
485 long revnum;
486 Py_ssize_t k;
486 Py_ssize_t k;
487 Py_ssize_t i;
487 Py_ssize_t i;
488 Py_ssize_t l;
488 Py_ssize_t l;
489 int r;
489 int r;
490 int parents[2];
490 int parents[2];
491
491
492 /* Internal data structure:
492 /* Internal data structure:
493 * tovisit: array of length len+1 (all revs + nullrev), filled upto lentovisit
493 * tovisit: array of length len+1 (all revs + nullrev), filled upto lentovisit
494 * revstates: array of length len+1 (all revs + nullrev) */
494 * revstates: array of length len+1 (all revs + nullrev) */
495 int *tovisit = NULL;
495 int *tovisit = NULL;
496 long lentovisit = 0;
496 long lentovisit = 0;
497 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
497 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
498 char *revstates = NULL;
498 char *revstates = NULL;
499
499
500 /* Get arguments */
500 /* Get arguments */
501 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
501 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
502 &PyList_Type, &roots,
502 &PyList_Type, &roots,
503 &PyBool_Type, &includepatharg))
503 &PyBool_Type, &includepatharg))
504 goto bail;
504 goto bail;
505
505
506 if (includepatharg == Py_True)
506 if (includepatharg == Py_True)
507 includepath = 1;
507 includepath = 1;
508
508
509 /* Initialize return set */
509 /* Initialize return set */
510 reachable = PyList_New(0);
510 reachable = PyList_New(0);
511 if (reachable == NULL)
511 if (reachable == NULL)
512 goto bail;
512 goto bail;
513
513
514 /* Initialize internal datastructures */
514 /* Initialize internal datastructures */
515 tovisit = (int *)malloc((len + 1) * sizeof(int));
515 tovisit = (int *)malloc((len + 1) * sizeof(int));
516 if (tovisit == NULL) {
516 if (tovisit == NULL) {
517 PyErr_NoMemory();
517 PyErr_NoMemory();
518 goto bail;
518 goto bail;
519 }
519 }
520
520
521 revstates = (char *)calloc(len + 1, 1);
521 revstates = (char *)calloc(len + 1, 1);
522 if (revstates == NULL) {
522 if (revstates == NULL) {
523 PyErr_NoMemory();
523 PyErr_NoMemory();
524 goto bail;
524 goto bail;
525 }
525 }
526
526
527 l = PyList_GET_SIZE(roots);
527 l = PyList_GET_SIZE(roots);
528 for (i = 0; i < l; i++) {
528 for (i = 0; i < l; i++) {
529 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
529 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
530 if (revnum == -1 && PyErr_Occurred())
530 if (revnum == -1 && PyErr_Occurred())
531 goto bail;
531 goto bail;
532 /* If root is out of range, e.g. wdir(), it must be unreachable
532 /* If root is out of range, e.g. wdir(), it must be unreachable
533 * from heads. So we can just ignore it. */
533 * from heads. So we can just ignore it. */
534 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
534 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
535 continue;
535 continue;
536 revstates[revnum + 1] |= RS_ROOT;
536 revstates[revnum + 1] |= RS_ROOT;
537 }
537 }
538
538
539 /* Populate tovisit with all the heads */
539 /* Populate tovisit with all the heads */
540 l = PyList_GET_SIZE(heads);
540 l = PyList_GET_SIZE(heads);
541 for (i = 0; i < l; i++) {
541 for (i = 0; i < l; i++) {
542 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
542 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
543 if (revnum == -1 && PyErr_Occurred())
543 if (revnum == -1 && PyErr_Occurred())
544 goto bail;
544 goto bail;
545 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
545 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
546 PyErr_SetString(PyExc_IndexError, "head out of range");
546 PyErr_SetString(PyExc_IndexError, "head out of range");
547 goto bail;
547 goto bail;
548 }
548 }
549 if (!(revstates[revnum + 1] & RS_SEEN)) {
549 if (!(revstates[revnum + 1] & RS_SEEN)) {
550 tovisit[lentovisit++] = (int)revnum;
550 tovisit[lentovisit++] = (int)revnum;
551 revstates[revnum + 1] |= RS_SEEN;
551 revstates[revnum + 1] |= RS_SEEN;
552 }
552 }
553 }
553 }
554
554
555 /* Visit the tovisit list and find the reachable roots */
555 /* Visit the tovisit list and find the reachable roots */
556 k = 0;
556 k = 0;
557 while (k < lentovisit) {
557 while (k < lentovisit) {
558 /* Add the node to reachable if it is a root*/
558 /* Add the node to reachable if it is a root*/
559 revnum = tovisit[k++];
559 revnum = tovisit[k++];
560 if (revstates[revnum + 1] & RS_ROOT) {
560 if (revstates[revnum + 1] & RS_ROOT) {
561 revstates[revnum + 1] |= RS_REACHABLE;
561 revstates[revnum + 1] |= RS_REACHABLE;
562 val = PyInt_FromLong(revnum);
562 val = PyInt_FromLong(revnum);
563 if (val == NULL)
563 if (val == NULL)
564 goto bail;
564 goto bail;
565 r = PyList_Append(reachable, val);
565 r = PyList_Append(reachable, val);
566 Py_DECREF(val);
566 Py_DECREF(val);
567 if (r < 0)
567 if (r < 0)
568 goto bail;
568 goto bail;
569 if (includepath == 0)
569 if (includepath == 0)
570 continue;
570 continue;
571 }
571 }
572
572
573 /* Add its parents to the list of nodes to visit */
573 /* Add its parents to the list of nodes to visit */
574 if (revnum == -1)
574 if (revnum == -1)
575 continue;
575 continue;
576 r = index_get_parents(self, revnum, parents, (int)len - 1);
576 r = index_get_parents(self, revnum, parents, (int)len - 1);
577 if (r < 0)
577 if (r < 0)
578 goto bail;
578 goto bail;
579 for (i = 0; i < 2; i++) {
579 for (i = 0; i < 2; i++) {
580 if (!(revstates[parents[i] + 1] & RS_SEEN)
580 if (!(revstates[parents[i] + 1] & RS_SEEN)
581 && parents[i] >= minroot) {
581 && parents[i] >= minroot) {
582 tovisit[lentovisit++] = parents[i];
582 tovisit[lentovisit++] = parents[i];
583 revstates[parents[i] + 1] |= RS_SEEN;
583 revstates[parents[i] + 1] |= RS_SEEN;
584 }
584 }
585 }
585 }
586 }
586 }
587
587
588 /* Find all the nodes in between the roots we found and the heads
588 /* Find all the nodes in between the roots we found and the heads
589 * and add them to the reachable set */
589 * and add them to the reachable set */
590 if (includepath == 1) {
590 if (includepath == 1) {
591 long minidx = minroot;
591 long minidx = minroot;
592 if (minidx < 0)
592 if (minidx < 0)
593 minidx = 0;
593 minidx = 0;
594 for (i = minidx; i < len; i++) {
594 for (i = minidx; i < len; i++) {
595 if (!(revstates[i + 1] & RS_SEEN))
595 if (!(revstates[i + 1] & RS_SEEN))
596 continue;
596 continue;
597 r = index_get_parents(self, i, parents, (int)len - 1);
597 r = index_get_parents(self, i, parents, (int)len - 1);
598 /* Corrupted index file, error is set from
598 /* Corrupted index file, error is set from
599 * index_get_parents */
599 * index_get_parents */
600 if (r < 0)
600 if (r < 0)
601 goto bail;
601 goto bail;
602 if (((revstates[parents[0] + 1] |
602 if (((revstates[parents[0] + 1] |
603 revstates[parents[1] + 1]) & RS_REACHABLE)
603 revstates[parents[1] + 1]) & RS_REACHABLE)
604 && !(revstates[i + 1] & RS_REACHABLE)) {
604 && !(revstates[i + 1] & RS_REACHABLE)) {
605 revstates[i + 1] |= RS_REACHABLE;
605 revstates[i + 1] |= RS_REACHABLE;
606 val = PyInt_FromLong(i);
606 val = PyInt_FromLong(i);
607 if (val == NULL)
607 if (val == NULL)
608 goto bail;
608 goto bail;
609 r = PyList_Append(reachable, val);
609 r = PyList_Append(reachable, val);
610 Py_DECREF(val);
610 Py_DECREF(val);
611 if (r < 0)
611 if (r < 0)
612 goto bail;
612 goto bail;
613 }
613 }
614 }
614 }
615 }
615 }
616
616
617 free(revstates);
617 free(revstates);
618 free(tovisit);
618 free(tovisit);
619 return reachable;
619 return reachable;
620 bail:
620 bail:
621 Py_XDECREF(reachable);
621 Py_XDECREF(reachable);
622 free(revstates);
622 free(revstates);
623 free(tovisit);
623 free(tovisit);
624 return NULL;
624 return NULL;
625 }
625 }
626
626
627 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
627 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
628 {
628 {
629 PyObject *roots = Py_None;
629 PyObject *roots = Py_None;
630 PyObject *ret = NULL;
630 PyObject *ret = NULL;
631 PyObject *phasessize = NULL;
631 PyObject *phasessize = NULL;
632 PyObject *phaseroots = NULL;
632 PyObject *phaseroots = NULL;
633 PyObject *phaseset = NULL;
633 PyObject *phaseset = NULL;
634 PyObject *phasessetlist = NULL;
634 PyObject *phasessetlist = NULL;
635 PyObject *rev = NULL;
635 PyObject *rev = NULL;
636 Py_ssize_t len = index_length(self) - 1;
636 Py_ssize_t len = index_length(self) - 1;
637 Py_ssize_t numphase = 0;
637 Py_ssize_t numphase = 0;
638 Py_ssize_t minrevallphases = 0;
638 Py_ssize_t minrevallphases = 0;
639 Py_ssize_t minrevphase = 0;
639 Py_ssize_t minrevphase = 0;
640 Py_ssize_t i = 0;
640 Py_ssize_t i = 0;
641 char *phases = NULL;
641 char *phases = NULL;
642 long phase;
642 long phase;
643
643
644 if (!PyArg_ParseTuple(args, "O", &roots))
644 if (!PyArg_ParseTuple(args, "O", &roots))
645 goto done;
645 goto done;
646 if (roots == NULL || !PyList_Check(roots))
646 if (roots == NULL || !PyList_Check(roots))
647 goto done;
647 goto done;
648
648
649 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
649 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
650 if (phases == NULL) {
650 if (phases == NULL) {
651 PyErr_NoMemory();
651 PyErr_NoMemory();
652 goto done;
652 goto done;
653 }
653 }
654 /* Put the phase information of all the roots in phases */
654 /* Put the phase information of all the roots in phases */
655 numphase = PyList_GET_SIZE(roots)+1;
655 numphase = PyList_GET_SIZE(roots)+1;
656 minrevallphases = len + 1;
656 minrevallphases = len + 1;
657 phasessetlist = PyList_New(numphase);
657 phasessetlist = PyList_New(numphase);
658 if (phasessetlist == NULL)
658 if (phasessetlist == NULL)
659 goto done;
659 goto done;
660
660
661 PyList_SET_ITEM(phasessetlist, 0, Py_None);
661 PyList_SET_ITEM(phasessetlist, 0, Py_None);
662 Py_INCREF(Py_None);
662 Py_INCREF(Py_None);
663
663
664 for (i = 0; i < numphase-1; i++) {
664 for (i = 0; i < numphase-1; i++) {
665 phaseroots = PyList_GET_ITEM(roots, i);
665 phaseroots = PyList_GET_ITEM(roots, i);
666 phaseset = PySet_New(NULL);
666 phaseset = PySet_New(NULL);
667 if (phaseset == NULL)
667 if (phaseset == NULL)
668 goto release;
668 goto release;
669 PyList_SET_ITEM(phasessetlist, i+1, phaseset);
669 PyList_SET_ITEM(phasessetlist, i+1, phaseset);
670 if (!PyList_Check(phaseroots))
670 if (!PyList_Check(phaseroots))
671 goto release;
671 goto release;
672 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
672 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
673 if (minrevphase == -2) /* Error from add_roots_get_min */
673 if (minrevphase == -2) /* Error from add_roots_get_min */
674 goto release;
674 goto release;
675 minrevallphases = MIN(minrevallphases, minrevphase);
675 minrevallphases = MIN(minrevallphases, minrevphase);
676 }
676 }
677 /* Propagate the phase information from the roots to the revs */
677 /* Propagate the phase information from the roots to the revs */
678 if (minrevallphases != -1) {
678 if (minrevallphases != -1) {
679 int parents[2];
679 int parents[2];
680 for (i = minrevallphases; i < len; i++) {
680 for (i = minrevallphases; i < len; i++) {
681 if (index_get_parents(self, i, parents,
681 if (index_get_parents(self, i, parents,
682 (int)len - 1) < 0)
682 (int)len - 1) < 0)
683 goto release;
683 goto release;
684 set_phase_from_parents(phases, parents[0], parents[1], i);
684 set_phase_from_parents(phases, parents[0], parents[1], i);
685 }
685 }
686 }
686 }
687 /* Transform phase list to a python list */
687 /* Transform phase list to a python list */
688 phasessize = PyInt_FromLong(len);
688 phasessize = PyInt_FromLong(len);
689 if (phasessize == NULL)
689 if (phasessize == NULL)
690 goto release;
690 goto release;
691 for (i = 0; i < len; i++) {
691 for (i = 0; i < len; i++) {
692 phase = phases[i];
692 phase = phases[i];
693 /* We only store the sets of phase for non public phase, the public phase
693 /* We only store the sets of phase for non public phase, the public phase
694 * is computed as a difference */
694 * is computed as a difference */
695 if (phase != 0) {
695 if (phase != 0) {
696 phaseset = PyList_GET_ITEM(phasessetlist, phase);
696 phaseset = PyList_GET_ITEM(phasessetlist, phase);
697 rev = PyInt_FromLong(i);
697 rev = PyInt_FromLong(i);
698 if (rev == NULL)
698 if (rev == NULL)
699 goto release;
699 goto release;
700 PySet_Add(phaseset, rev);
700 PySet_Add(phaseset, rev);
701 Py_XDECREF(rev);
701 Py_XDECREF(rev);
702 }
702 }
703 }
703 }
704 ret = PyTuple_Pack(2, phasessize, phasessetlist);
704 ret = PyTuple_Pack(2, phasessize, phasessetlist);
705
705
706 release:
706 release:
707 Py_XDECREF(phasessize);
707 Py_XDECREF(phasessize);
708 Py_XDECREF(phasessetlist);
708 Py_XDECREF(phasessetlist);
709 done:
709 done:
710 free(phases);
710 free(phases);
711 return ret;
711 return ret;
712 }
712 }
713
713
714 static PyObject *index_headrevs(indexObject *self, PyObject *args)
714 static PyObject *index_headrevs(indexObject *self, PyObject *args)
715 {
715 {
716 Py_ssize_t i, j, len;
716 Py_ssize_t i, j, len;
717 char *nothead = NULL;
717 char *nothead = NULL;
718 PyObject *heads = NULL;
718 PyObject *heads = NULL;
719 PyObject *filter = NULL;
719 PyObject *filter = NULL;
720 PyObject *filteredrevs = Py_None;
720 PyObject *filteredrevs = Py_None;
721
721
722 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
722 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
723 return NULL;
723 return NULL;
724 }
724 }
725
725
726 if (self->headrevs && filteredrevs == self->filteredrevs)
726 if (self->headrevs && filteredrevs == self->filteredrevs)
727 return list_copy(self->headrevs);
727 return list_copy(self->headrevs);
728
728
729 Py_DECREF(self->filteredrevs);
729 Py_DECREF(self->filteredrevs);
730 self->filteredrevs = filteredrevs;
730 self->filteredrevs = filteredrevs;
731 Py_INCREF(filteredrevs);
731 Py_INCREF(filteredrevs);
732
732
733 if (filteredrevs != Py_None) {
733 if (filteredrevs != Py_None) {
734 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
734 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
735 if (!filter) {
735 if (!filter) {
736 PyErr_SetString(PyExc_TypeError,
736 PyErr_SetString(PyExc_TypeError,
737 "filteredrevs has no attribute __contains__");
737 "filteredrevs has no attribute __contains__");
738 goto bail;
738 goto bail;
739 }
739 }
740 }
740 }
741
741
742 len = index_length(self) - 1;
742 len = index_length(self) - 1;
743 heads = PyList_New(0);
743 heads = PyList_New(0);
744 if (heads == NULL)
744 if (heads == NULL)
745 goto bail;
745 goto bail;
746 if (len == 0) {
746 if (len == 0) {
747 PyObject *nullid = PyInt_FromLong(-1);
747 PyObject *nullid = PyInt_FromLong(-1);
748 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
748 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
749 Py_XDECREF(nullid);
749 Py_XDECREF(nullid);
750 goto bail;
750 goto bail;
751 }
751 }
752 goto done;
752 goto done;
753 }
753 }
754
754
755 nothead = calloc(len, 1);
755 nothead = calloc(len, 1);
756 if (nothead == NULL) {
756 if (nothead == NULL) {
757 PyErr_NoMemory();
757 PyErr_NoMemory();
758 goto bail;
758 goto bail;
759 }
759 }
760
760
761 for (i = len - 1; i >= 0; i--) {
761 for (i = len - 1; i >= 0; i--) {
762 int isfiltered;
762 int isfiltered;
763 int parents[2];
763 int parents[2];
764
764
765 /* If nothead[i] == 1, it means we've seen an unfiltered child of this
765 /* If nothead[i] == 1, it means we've seen an unfiltered child of this
766 * node already, and therefore this node is not filtered. So we can skip
766 * node already, and therefore this node is not filtered. So we can skip
767 * the expensive check_filter step.
767 * the expensive check_filter step.
768 */
768 */
769 if (nothead[i] != 1) {
769 if (nothead[i] != 1) {
770 isfiltered = check_filter(filter, i);
770 isfiltered = check_filter(filter, i);
771 if (isfiltered == -1) {
771 if (isfiltered == -1) {
772 PyErr_SetString(PyExc_TypeError,
772 PyErr_SetString(PyExc_TypeError,
773 "unable to check filter");
773 "unable to check filter");
774 goto bail;
774 goto bail;
775 }
775 }
776
776
777 if (isfiltered) {
777 if (isfiltered) {
778 nothead[i] = 1;
778 nothead[i] = 1;
779 continue;
779 continue;
780 }
780 }
781 }
781 }
782
782
783 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
783 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
784 goto bail;
784 goto bail;
785 for (j = 0; j < 2; j++) {
785 for (j = 0; j < 2; j++) {
786 if (parents[j] >= 0)
786 if (parents[j] >= 0)
787 nothead[parents[j]] = 1;
787 nothead[parents[j]] = 1;
788 }
788 }
789 }
789 }
790
790
791 for (i = 0; i < len; i++) {
791 for (i = 0; i < len; i++) {
792 PyObject *head;
792 PyObject *head;
793
793
794 if (nothead[i])
794 if (nothead[i])
795 continue;
795 continue;
796 head = PyInt_FromSsize_t(i);
796 head = PyInt_FromSsize_t(i);
797 if (head == NULL || PyList_Append(heads, head) == -1) {
797 if (head == NULL || PyList_Append(heads, head) == -1) {
798 Py_XDECREF(head);
798 Py_XDECREF(head);
799 goto bail;
799 goto bail;
800 }
800 }
801 }
801 }
802
802
803 done:
803 done:
804 self->headrevs = heads;
804 self->headrevs = heads;
805 Py_XDECREF(filter);
805 Py_XDECREF(filter);
806 free(nothead);
806 free(nothead);
807 return list_copy(self->headrevs);
807 return list_copy(self->headrevs);
808 bail:
808 bail:
809 Py_XDECREF(filter);
809 Py_XDECREF(filter);
810 Py_XDECREF(heads);
810 Py_XDECREF(heads);
811 free(nothead);
811 free(nothead);
812 return NULL;
812 return NULL;
813 }
813 }
814
814
815 /**
815 /**
816 * Obtain the base revision index entry.
816 * Obtain the base revision index entry.
817 *
817 *
818 * Callers must ensure that rev >= 0 or illegal memory access may occur.
818 * Callers must ensure that rev >= 0 or illegal memory access may occur.
819 */
819 */
820 static inline int index_baserev(indexObject *self, int rev)
820 static inline int index_baserev(indexObject *self, int rev)
821 {
821 {
822 const char *data;
822 const char *data;
823
823
824 if (rev >= self->length - 1) {
824 if (rev >= self->length - 1) {
825 PyObject *tuple = PyList_GET_ITEM(self->added,
825 PyObject *tuple = PyList_GET_ITEM(self->added,
826 rev - self->length + 1);
826 rev - self->length + 1);
827 return (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 3));
827 return (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 3));
828 }
828 }
829 else {
829 else {
830 data = index_deref(self, rev);
830 data = index_deref(self, rev);
831 if (data == NULL) {
831 if (data == NULL) {
832 return -2;
832 return -2;
833 }
833 }
834
834
835 return getbe32(data + 16);
835 return getbe32(data + 16);
836 }
836 }
837 }
837 }
838
838
839 static PyObject *index_deltachain(indexObject *self, PyObject *args)
839 static PyObject *index_deltachain(indexObject *self, PyObject *args)
840 {
840 {
841 int rev, generaldelta;
841 int rev, generaldelta;
842 PyObject *stoparg;
842 PyObject *stoparg;
843 int stoprev, iterrev, baserev = -1;
843 int stoprev, iterrev, baserev = -1;
844 int stopped;
844 int stopped;
845 PyObject *chain = NULL, *result = NULL;
845 PyObject *chain = NULL, *result = NULL;
846 const Py_ssize_t length = index_length(self);
846 const Py_ssize_t length = index_length(self);
847
847
848 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
848 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
849 return NULL;
849 return NULL;
850 }
850 }
851
851
852 if (PyInt_Check(stoparg)) {
852 if (PyInt_Check(stoparg)) {
853 stoprev = (int)PyInt_AsLong(stoparg);
853 stoprev = (int)PyInt_AsLong(stoparg);
854 if (stoprev == -1 && PyErr_Occurred()) {
854 if (stoprev == -1 && PyErr_Occurred()) {
855 return NULL;
855 return NULL;
856 }
856 }
857 }
857 }
858 else if (stoparg == Py_None) {
858 else if (stoparg == Py_None) {
859 stoprev = -2;
859 stoprev = -2;
860 }
860 }
861 else {
861 else {
862 PyErr_SetString(PyExc_ValueError,
862 PyErr_SetString(PyExc_ValueError,
863 "stoprev must be integer or None");
863 "stoprev must be integer or None");
864 return NULL;
864 return NULL;
865 }
865 }
866
866
867 if (rev < 0 || rev >= length - 1) {
867 if (rev < 0 || rev >= length - 1) {
868 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
868 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
869 return NULL;
869 return NULL;
870 }
870 }
871
871
872 chain = PyList_New(0);
872 chain = PyList_New(0);
873 if (chain == NULL) {
873 if (chain == NULL) {
874 return NULL;
874 return NULL;
875 }
875 }
876
876
877 baserev = index_baserev(self, rev);
877 baserev = index_baserev(self, rev);
878
878
879 /* This should never happen. */
879 /* This should never happen. */
880 if (baserev <= -2) {
880 if (baserev <= -2) {
881 /* Error should be set by index_deref() */
881 /* Error should be set by index_deref() */
882 assert(PyErr_Occurred());
882 assert(PyErr_Occurred());
883 goto bail;
883 goto bail;
884 }
884 }
885
885
886 iterrev = rev;
886 iterrev = rev;
887
887
888 while (iterrev != baserev && iterrev != stoprev) {
888 while (iterrev != baserev && iterrev != stoprev) {
889 PyObject *value = PyInt_FromLong(iterrev);
889 PyObject *value = PyInt_FromLong(iterrev);
890 if (value == NULL) {
890 if (value == NULL) {
891 goto bail;
891 goto bail;
892 }
892 }
893 if (PyList_Append(chain, value)) {
893 if (PyList_Append(chain, value)) {
894 Py_DECREF(value);
894 Py_DECREF(value);
895 goto bail;
895 goto bail;
896 }
896 }
897 Py_DECREF(value);
897 Py_DECREF(value);
898
898
899 if (generaldelta) {
899 if (generaldelta) {
900 iterrev = baserev;
900 iterrev = baserev;
901 }
901 }
902 else {
902 else {
903 iterrev--;
903 iterrev--;
904 }
904 }
905
905
906 if (iterrev < 0) {
906 if (iterrev < 0) {
907 break;
907 break;
908 }
908 }
909
909
910 if (iterrev >= length - 1) {
910 if (iterrev >= length - 1) {
911 PyErr_SetString(PyExc_IndexError, "revision outside index");
911 PyErr_SetString(PyExc_IndexError, "revision outside index");
912 return NULL;
912 return NULL;
913 }
913 }
914
914
915 baserev = index_baserev(self, iterrev);
915 baserev = index_baserev(self, iterrev);
916
916
917 /* This should never happen. */
917 /* This should never happen. */
918 if (baserev <= -2) {
918 if (baserev <= -2) {
919 /* Error should be set by index_deref() */
919 /* Error should be set by index_deref() */
920 assert(PyErr_Occurred());
920 assert(PyErr_Occurred());
921 goto bail;
921 goto bail;
922 }
922 }
923 }
923 }
924
924
925 if (iterrev == stoprev) {
925 if (iterrev == stoprev) {
926 stopped = 1;
926 stopped = 1;
927 }
927 }
928 else {
928 else {
929 PyObject *value = PyInt_FromLong(iterrev);
929 PyObject *value = PyInt_FromLong(iterrev);
930 if (value == NULL) {
930 if (value == NULL) {
931 goto bail;
931 goto bail;
932 }
932 }
933 if (PyList_Append(chain, value)) {
933 if (PyList_Append(chain, value)) {
934 Py_DECREF(value);
934 Py_DECREF(value);
935 goto bail;
935 goto bail;
936 }
936 }
937 Py_DECREF(value);
937 Py_DECREF(value);
938
938
939 stopped = 0;
939 stopped = 0;
940 }
940 }
941
941
942 if (PyList_Reverse(chain)) {
942 if (PyList_Reverse(chain)) {
943 goto bail;
943 goto bail;
944 }
944 }
945
945
946 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
946 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
947 Py_DECREF(chain);
947 Py_DECREF(chain);
948 return result;
948 return result;
949
949
950 bail:
950 bail:
951 Py_DECREF(chain);
951 Py_DECREF(chain);
952 return NULL;
952 return NULL;
953 }
953 }
954
954
955 static inline int nt_level(const char *node, Py_ssize_t level)
955 static inline int nt_level(const char *node, Py_ssize_t level)
956 {
956 {
957 int v = node[level>>1];
957 int v = node[level>>1];
958 if (!(level & 1))
958 if (!(level & 1))
959 v >>= 4;
959 v >>= 4;
960 return v & 0xf;
960 return v & 0xf;
961 }
961 }
962
962
963 /*
963 /*
964 * Return values:
964 * Return values:
965 *
965 *
966 * -4: match is ambiguous (multiple candidates)
966 * -4: match is ambiguous (multiple candidates)
967 * -2: not found
967 * -2: not found
968 * rest: valid rev
968 * rest: valid rev
969 */
969 */
970 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
970 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
971 int hex)
971 int hex)
972 {
972 {
973 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
973 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
974 int level, maxlevel, off;
974 int level, maxlevel, off;
975
975
976 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
976 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
977 return -1;
977 return -1;
978
978
979 if (self->nt == NULL)
979 if (self->nt == NULL)
980 return -2;
980 return -2;
981
981
982 if (hex)
982 if (hex)
983 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
983 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
984 else
984 else
985 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
985 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
986
986
987 for (level = off = 0; level < maxlevel; level++) {
987 for (level = off = 0; level < maxlevel; level++) {
988 int k = getnybble(node, level);
988 int k = getnybble(node, level);
989 nodetree *n = &self->nt[off];
989 nodetree *n = &self->nt[off];
990 int v = n->children[k];
990 int v = n->children[k];
991
991
992 if (v < 0) {
992 if (v < 0) {
993 const char *n;
993 const char *n;
994 Py_ssize_t i;
994 Py_ssize_t i;
995
995
996 v = -(v + 1);
996 v = -(v + 1);
997 n = index_node(self, v);
997 n = index_node(self, v);
998 if (n == NULL)
998 if (n == NULL)
999 return -2;
999 return -2;
1000 for (i = level; i < maxlevel; i++)
1000 for (i = level; i < maxlevel; i++)
1001 if (getnybble(node, i) != nt_level(n, i))
1001 if (getnybble(node, i) != nt_level(n, i))
1002 return -2;
1002 return -2;
1003 return v;
1003 return v;
1004 }
1004 }
1005 if (v == 0)
1005 if (v == 0)
1006 return -2;
1006 return -2;
1007 off = v;
1007 off = v;
1008 }
1008 }
1009 /* multiple matches against an ambiguous prefix */
1009 /* multiple matches against an ambiguous prefix */
1010 return -4;
1010 return -4;
1011 }
1011 }
1012
1012
1013 static int nt_new(indexObject *self)
1013 static int nt_new(indexObject *self)
1014 {
1014 {
1015 if (self->ntlength == self->ntcapacity) {
1015 if (self->ntlength == self->ntcapacity) {
1016 if (self->ntcapacity >= INT_MAX / (sizeof(nodetree) * 2)) {
1016 if (self->ntcapacity >= INT_MAX / (sizeof(nodetree) * 2)) {
1017 PyErr_SetString(PyExc_MemoryError,
1017 PyErr_SetString(PyExc_MemoryError,
1018 "overflow in nt_new");
1018 "overflow in nt_new");
1019 return -1;
1019 return -1;
1020 }
1020 }
1021 self->ntcapacity *= 2;
1021 self->ntcapacity *= 2;
1022 self->nt = realloc(self->nt,
1022 self->nt = realloc(self->nt,
1023 self->ntcapacity * sizeof(nodetree));
1023 self->ntcapacity * sizeof(nodetree));
1024 if (self->nt == NULL) {
1024 if (self->nt == NULL) {
1025 PyErr_SetString(PyExc_MemoryError, "out of memory");
1025 PyErr_SetString(PyExc_MemoryError, "out of memory");
1026 return -1;
1026 return -1;
1027 }
1027 }
1028 memset(&self->nt[self->ntlength], 0,
1028 memset(&self->nt[self->ntlength], 0,
1029 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1029 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1030 }
1030 }
1031 return self->ntlength++;
1031 return self->ntlength++;
1032 }
1032 }
1033
1033
1034 static int nt_insert(indexObject *self, const char *node, int rev)
1034 static int nt_insert(indexObject *self, const char *node, int rev)
1035 {
1035 {
1036 int level = 0;
1036 int level = 0;
1037 int off = 0;
1037 int off = 0;
1038
1038
1039 while (level < 40) {
1039 while (level < 40) {
1040 int k = nt_level(node, level);
1040 int k = nt_level(node, level);
1041 nodetree *n;
1041 nodetree *n;
1042 int v;
1042 int v;
1043
1043
1044 n = &self->nt[off];
1044 n = &self->nt[off];
1045 v = n->children[k];
1045 v = n->children[k];
1046
1046
1047 if (v == 0) {
1047 if (v == 0) {
1048 n->children[k] = -rev - 1;
1048 n->children[k] = -rev - 1;
1049 return 0;
1049 return 0;
1050 }
1050 }
1051 if (v < 0) {
1051 if (v < 0) {
1052 const char *oldnode = index_node(self, -(v + 1));
1052 const char *oldnode = index_node(self, -(v + 1));
1053 int noff;
1053 int noff;
1054
1054
1055 if (!oldnode || !memcmp(oldnode, node, 20)) {
1055 if (!oldnode || !memcmp(oldnode, node, 20)) {
1056 n->children[k] = -rev - 1;
1056 n->children[k] = -rev - 1;
1057 return 0;
1057 return 0;
1058 }
1058 }
1059 noff = nt_new(self);
1059 noff = nt_new(self);
1060 if (noff == -1)
1060 if (noff == -1)
1061 return -1;
1061 return -1;
1062 /* self->nt may have been changed by realloc */
1062 /* self->nt may have been changed by realloc */
1063 self->nt[off].children[k] = noff;
1063 self->nt[off].children[k] = noff;
1064 off = noff;
1064 off = noff;
1065 n = &self->nt[off];
1065 n = &self->nt[off];
1066 n->children[nt_level(oldnode, ++level)] = v;
1066 n->children[nt_level(oldnode, ++level)] = v;
1067 if (level > self->ntdepth)
1067 if (level > self->ntdepth)
1068 self->ntdepth = level;
1068 self->ntdepth = level;
1069 self->ntsplits += 1;
1069 self->ntsplits += 1;
1070 } else {
1070 } else {
1071 level += 1;
1071 level += 1;
1072 off = v;
1072 off = v;
1073 }
1073 }
1074 }
1074 }
1075
1075
1076 return -1;
1076 return -1;
1077 }
1077 }
1078
1078
1079 static int nt_init(indexObject *self)
1079 static int nt_init(indexObject *self)
1080 {
1080 {
1081 if (self->nt == NULL) {
1081 if (self->nt == NULL) {
1082 if ((size_t)self->raw_length > INT_MAX / sizeof(nodetree)) {
1082 if ((size_t)self->raw_length > INT_MAX / sizeof(nodetree)) {
1083 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1083 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1084 return -1;
1084 return -1;
1085 }
1085 }
1086 self->ntcapacity = self->raw_length < 4
1086 self->ntcapacity = self->raw_length < 4
1087 ? 4 : (int)self->raw_length / 2;
1087 ? 4 : (int)self->raw_length / 2;
1088
1088
1089 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1089 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1090 if (self->nt == NULL) {
1090 if (self->nt == NULL) {
1091 PyErr_NoMemory();
1091 PyErr_NoMemory();
1092 return -1;
1092 return -1;
1093 }
1093 }
1094 self->ntlength = 1;
1094 self->ntlength = 1;
1095 self->ntrev = (int)index_length(self) - 1;
1095 self->ntrev = (int)index_length(self) - 1;
1096 self->ntlookups = 1;
1096 self->ntlookups = 1;
1097 self->ntmisses = 0;
1097 self->ntmisses = 0;
1098 if (nt_insert(self, nullid, INT_MAX) == -1)
1098 if (nt_insert(self, nullid, INT_MAX) == -1)
1099 return -1;
1099 return -1;
1100 }
1100 }
1101 return 0;
1101 return 0;
1102 }
1102 }
1103
1103
1104 /*
1104 /*
1105 * Return values:
1105 * Return values:
1106 *
1106 *
1107 * -3: error (exception set)
1107 * -3: error (exception set)
1108 * -2: not found (no exception set)
1108 * -2: not found (no exception set)
1109 * rest: valid rev
1109 * rest: valid rev
1110 */
1110 */
1111 static int index_find_node(indexObject *self,
1111 static int index_find_node(indexObject *self,
1112 const char *node, Py_ssize_t nodelen)
1112 const char *node, Py_ssize_t nodelen)
1113 {
1113 {
1114 int rev;
1114 int rev;
1115
1115
1116 self->ntlookups++;
1116 self->ntlookups++;
1117 rev = nt_find(self, node, nodelen, 0);
1117 rev = nt_find(self, node, nodelen, 0);
1118 if (rev >= -1)
1118 if (rev >= -1)
1119 return rev;
1119 return rev;
1120
1120
1121 if (nt_init(self) == -1)
1121 if (nt_init(self) == -1)
1122 return -3;
1122 return -3;
1123
1123
1124 /*
1124 /*
1125 * For the first handful of lookups, we scan the entire index,
1125 * For the first handful of lookups, we scan the entire index,
1126 * and cache only the matching nodes. This optimizes for cases
1126 * and cache only the matching nodes. This optimizes for cases
1127 * like "hg tip", where only a few nodes are accessed.
1127 * like "hg tip", where only a few nodes are accessed.
1128 *
1128 *
1129 * After that, we cache every node we visit, using a single
1129 * After that, we cache every node we visit, using a single
1130 * scan amortized over multiple lookups. This gives the best
1130 * scan amortized over multiple lookups. This gives the best
1131 * bulk performance, e.g. for "hg log".
1131 * bulk performance, e.g. for "hg log".
1132 */
1132 */
1133 if (self->ntmisses++ < 4) {
1133 if (self->ntmisses++ < 4) {
1134 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1134 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1135 const char *n = index_node(self, rev);
1135 const char *n = index_node(self, rev);
1136 if (n == NULL)
1136 if (n == NULL)
1137 return -2;
1137 return -2;
1138 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1138 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1139 if (nt_insert(self, n, rev) == -1)
1139 if (nt_insert(self, n, rev) == -1)
1140 return -3;
1140 return -3;
1141 break;
1141 break;
1142 }
1142 }
1143 }
1143 }
1144 } else {
1144 } else {
1145 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1145 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1146 const char *n = index_node(self, rev);
1146 const char *n = index_node(self, rev);
1147 if (n == NULL) {
1147 if (n == NULL) {
1148 self->ntrev = rev + 1;
1148 self->ntrev = rev + 1;
1149 return -2;
1149 return -2;
1150 }
1150 }
1151 if (nt_insert(self, n, rev) == -1) {
1151 if (nt_insert(self, n, rev) == -1) {
1152 self->ntrev = rev + 1;
1152 self->ntrev = rev + 1;
1153 return -3;
1153 return -3;
1154 }
1154 }
1155 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1155 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1156 break;
1156 break;
1157 }
1157 }
1158 }
1158 }
1159 self->ntrev = rev;
1159 self->ntrev = rev;
1160 }
1160 }
1161
1161
1162 if (rev >= 0)
1162 if (rev >= 0)
1163 return rev;
1163 return rev;
1164 return -2;
1164 return -2;
1165 }
1165 }
1166
1166
1167 static void raise_revlog_error(void)
1167 static void raise_revlog_error(void)
1168 {
1168 {
1169 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
1169 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
1170
1170
1171 mod = PyImport_ImportModule("mercurial.error");
1171 mod = PyImport_ImportModule("mercurial.error");
1172 if (mod == NULL) {
1172 if (mod == NULL) {
1173 goto cleanup;
1173 goto cleanup;
1174 }
1174 }
1175
1175
1176 dict = PyModule_GetDict(mod);
1176 dict = PyModule_GetDict(mod);
1177 if (dict == NULL) {
1177 if (dict == NULL) {
1178 goto cleanup;
1178 goto cleanup;
1179 }
1179 }
1180 Py_INCREF(dict);
1180 Py_INCREF(dict);
1181
1181
1182 errclass = PyDict_GetItemString(dict, "RevlogError");
1182 errclass = PyDict_GetItemString(dict, "RevlogError");
1183 if (errclass == NULL) {
1183 if (errclass == NULL) {
1184 PyErr_SetString(PyExc_SystemError,
1184 PyErr_SetString(PyExc_SystemError,
1185 "could not find RevlogError");
1185 "could not find RevlogError");
1186 goto cleanup;
1186 goto cleanup;
1187 }
1187 }
1188
1188
1189 /* value of exception is ignored by callers */
1189 /* value of exception is ignored by callers */
1190 PyErr_SetString(errclass, "RevlogError");
1190 PyErr_SetString(errclass, "RevlogError");
1191
1191
1192 cleanup:
1192 cleanup:
1193 Py_XDECREF(dict);
1193 Py_XDECREF(dict);
1194 Py_XDECREF(mod);
1194 Py_XDECREF(mod);
1195 }
1195 }
1196
1196
1197 static PyObject *index_getitem(indexObject *self, PyObject *value)
1197 static PyObject *index_getitem(indexObject *self, PyObject *value)
1198 {
1198 {
1199 char *node;
1199 char *node;
1200 Py_ssize_t nodelen;
1200 Py_ssize_t nodelen;
1201 int rev;
1201 int rev;
1202
1202
1203 if (PyInt_Check(value))
1203 if (PyInt_Check(value))
1204 return index_get(self, PyInt_AS_LONG(value));
1204 return index_get(self, PyInt_AS_LONG(value));
1205
1205
1206 if (node_check(value, &node, &nodelen) == -1)
1206 if (node_check(value, &node, &nodelen) == -1)
1207 return NULL;
1207 return NULL;
1208 rev = index_find_node(self, node, nodelen);
1208 rev = index_find_node(self, node, nodelen);
1209 if (rev >= -1)
1209 if (rev >= -1)
1210 return PyInt_FromLong(rev);
1210 return PyInt_FromLong(rev);
1211 if (rev == -2)
1211 if (rev == -2)
1212 raise_revlog_error();
1212 raise_revlog_error();
1213 return NULL;
1213 return NULL;
1214 }
1214 }
1215
1215
1216 static int nt_partialmatch(indexObject *self, const char *node,
1216 static int nt_partialmatch(indexObject *self, const char *node,
1217 Py_ssize_t nodelen)
1217 Py_ssize_t nodelen)
1218 {
1218 {
1219 int rev;
1219 int rev;
1220
1220
1221 if (nt_init(self) == -1)
1221 if (nt_init(self) == -1)
1222 return -3;
1222 return -3;
1223
1223
1224 if (self->ntrev > 0) {
1224 if (self->ntrev > 0) {
1225 /* ensure that the radix tree is fully populated */
1225 /* ensure that the radix tree is fully populated */
1226 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1226 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1227 const char *n = index_node(self, rev);
1227 const char *n = index_node(self, rev);
1228 if (n == NULL)
1228 if (n == NULL)
1229 return -2;
1229 return -2;
1230 if (nt_insert(self, n, rev) == -1)
1230 if (nt_insert(self, n, rev) == -1)
1231 return -3;
1231 return -3;
1232 }
1232 }
1233 self->ntrev = rev;
1233 self->ntrev = rev;
1234 }
1234 }
1235
1235
1236 return nt_find(self, node, nodelen, 1);
1236 return nt_find(self, node, nodelen, 1);
1237 }
1237 }
1238
1238
1239 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1239 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1240 {
1240 {
1241 const char *fullnode;
1241 const char *fullnode;
1242 int nodelen;
1242 int nodelen;
1243 char *node;
1243 char *node;
1244 int rev, i;
1244 int rev, i;
1245
1245
1246 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1246 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1247 return NULL;
1247 return NULL;
1248
1248
1249 if (nodelen < 4) {
1249 if (nodelen < 4) {
1250 PyErr_SetString(PyExc_ValueError, "key too short");
1250 PyErr_SetString(PyExc_ValueError, "key too short");
1251 return NULL;
1251 return NULL;
1252 }
1252 }
1253
1253
1254 if (nodelen > 40) {
1254 if (nodelen > 40) {
1255 PyErr_SetString(PyExc_ValueError, "key too long");
1255 PyErr_SetString(PyExc_ValueError, "key too long");
1256 return NULL;
1256 return NULL;
1257 }
1257 }
1258
1258
1259 for (i = 0; i < nodelen; i++)
1259 for (i = 0; i < nodelen; i++)
1260 hexdigit(node, i);
1260 hexdigit(node, i);
1261 if (PyErr_Occurred()) {
1261 if (PyErr_Occurred()) {
1262 /* input contains non-hex characters */
1262 /* input contains non-hex characters */
1263 PyErr_Clear();
1263 PyErr_Clear();
1264 Py_RETURN_NONE;
1264 Py_RETURN_NONE;
1265 }
1265 }
1266
1266
1267 rev = nt_partialmatch(self, node, nodelen);
1267 rev = nt_partialmatch(self, node, nodelen);
1268
1268
1269 switch (rev) {
1269 switch (rev) {
1270 case -4:
1270 case -4:
1271 raise_revlog_error();
1271 raise_revlog_error();
1272 case -3:
1272 case -3:
1273 return NULL;
1273 return NULL;
1274 case -2:
1274 case -2:
1275 Py_RETURN_NONE;
1275 Py_RETURN_NONE;
1276 case -1:
1276 case -1:
1277 return PyBytes_FromStringAndSize(nullid, 20);
1277 return PyBytes_FromStringAndSize(nullid, 20);
1278 }
1278 }
1279
1279
1280 fullnode = index_node(self, rev);
1280 fullnode = index_node(self, rev);
1281 if (fullnode == NULL) {
1281 if (fullnode == NULL) {
1282 PyErr_Format(PyExc_IndexError,
1282 PyErr_Format(PyExc_IndexError,
1283 "could not access rev %d", rev);
1283 "could not access rev %d", rev);
1284 return NULL;
1284 return NULL;
1285 }
1285 }
1286 return PyBytes_FromStringAndSize(fullnode, 20);
1286 return PyBytes_FromStringAndSize(fullnode, 20);
1287 }
1287 }
1288
1288
1289 static PyObject *index_m_get(indexObject *self, PyObject *args)
1289 static PyObject *index_m_get(indexObject *self, PyObject *args)
1290 {
1290 {
1291 Py_ssize_t nodelen;
1291 Py_ssize_t nodelen;
1292 PyObject *val;
1292 PyObject *val;
1293 char *node;
1293 char *node;
1294 int rev;
1294 int rev;
1295
1295
1296 if (!PyArg_ParseTuple(args, "O", &val))
1296 if (!PyArg_ParseTuple(args, "O", &val))
1297 return NULL;
1297 return NULL;
1298 if (node_check(val, &node, &nodelen) == -1)
1298 if (node_check(val, &node, &nodelen) == -1)
1299 return NULL;
1299 return NULL;
1300 rev = index_find_node(self, node, nodelen);
1300 rev = index_find_node(self, node, nodelen);
1301 if (rev == -3)
1301 if (rev == -3)
1302 return NULL;
1302 return NULL;
1303 if (rev == -2)
1303 if (rev == -2)
1304 Py_RETURN_NONE;
1304 Py_RETURN_NONE;
1305 return PyInt_FromLong(rev);
1305 return PyInt_FromLong(rev);
1306 }
1306 }
1307
1307
1308 static int index_contains(indexObject *self, PyObject *value)
1308 static int index_contains(indexObject *self, PyObject *value)
1309 {
1309 {
1310 char *node;
1310 char *node;
1311 Py_ssize_t nodelen;
1311 Py_ssize_t nodelen;
1312
1312
1313 if (PyInt_Check(value)) {
1313 if (PyInt_Check(value)) {
1314 long rev = PyInt_AS_LONG(value);
1314 long rev = PyInt_AS_LONG(value);
1315 return rev >= -1 && rev < index_length(self);
1315 return rev >= -1 && rev < index_length(self);
1316 }
1316 }
1317
1317
1318 if (node_check(value, &node, &nodelen) == -1)
1318 if (node_check(value, &node, &nodelen) == -1)
1319 return -1;
1319 return -1;
1320
1320
1321 switch (index_find_node(self, node, nodelen)) {
1321 switch (index_find_node(self, node, nodelen)) {
1322 case -3:
1322 case -3:
1323 return -1;
1323 return -1;
1324 case -2:
1324 case -2:
1325 return 0;
1325 return 0;
1326 default:
1326 default:
1327 return 1;
1327 return 1;
1328 }
1328 }
1329 }
1329 }
1330
1330
1331 typedef uint64_t bitmask;
1331 typedef uint64_t bitmask;
1332
1332
1333 /*
1333 /*
1334 * Given a disjoint set of revs, return all candidates for the
1334 * Given a disjoint set of revs, return all candidates for the
1335 * greatest common ancestor. In revset notation, this is the set
1335 * greatest common ancestor. In revset notation, this is the set
1336 * "heads(::a and ::b and ...)"
1336 * "heads(::a and ::b and ...)"
1337 */
1337 */
1338 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1338 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1339 int revcount)
1339 int revcount)
1340 {
1340 {
1341 const bitmask allseen = (1ull << revcount) - 1;
1341 const bitmask allseen = (1ull << revcount) - 1;
1342 const bitmask poison = 1ull << revcount;
1342 const bitmask poison = 1ull << revcount;
1343 PyObject *gca = PyList_New(0);
1343 PyObject *gca = PyList_New(0);
1344 int i, v, interesting;
1344 int i, v, interesting;
1345 int maxrev = -1;
1345 int maxrev = -1;
1346 bitmask sp;
1346 bitmask sp;
1347 bitmask *seen;
1347 bitmask *seen;
1348
1348
1349 if (gca == NULL)
1349 if (gca == NULL)
1350 return PyErr_NoMemory();
1350 return PyErr_NoMemory();
1351
1351
1352 for (i = 0; i < revcount; i++) {
1352 for (i = 0; i < revcount; i++) {
1353 if (revs[i] > maxrev)
1353 if (revs[i] > maxrev)
1354 maxrev = revs[i];
1354 maxrev = revs[i];
1355 }
1355 }
1356
1356
1357 seen = calloc(sizeof(*seen), maxrev + 1);
1357 seen = calloc(sizeof(*seen), maxrev + 1);
1358 if (seen == NULL) {
1358 if (seen == NULL) {
1359 Py_DECREF(gca);
1359 Py_DECREF(gca);
1360 return PyErr_NoMemory();
1360 return PyErr_NoMemory();
1361 }
1361 }
1362
1362
1363 for (i = 0; i < revcount; i++)
1363 for (i = 0; i < revcount; i++)
1364 seen[revs[i]] = 1ull << i;
1364 seen[revs[i]] = 1ull << i;
1365
1365
1366 interesting = revcount;
1366 interesting = revcount;
1367
1367
1368 for (v = maxrev; v >= 0 && interesting; v--) {
1368 for (v = maxrev; v >= 0 && interesting; v--) {
1369 bitmask sv = seen[v];
1369 bitmask sv = seen[v];
1370 int parents[2];
1370 int parents[2];
1371
1371
1372 if (!sv)
1372 if (!sv)
1373 continue;
1373 continue;
1374
1374
1375 if (sv < poison) {
1375 if (sv < poison) {
1376 interesting -= 1;
1376 interesting -= 1;
1377 if (sv == allseen) {
1377 if (sv == allseen) {
1378 PyObject *obj = PyInt_FromLong(v);
1378 PyObject *obj = PyInt_FromLong(v);
1379 if (obj == NULL)
1379 if (obj == NULL)
1380 goto bail;
1380 goto bail;
1381 if (PyList_Append(gca, obj) == -1) {
1381 if (PyList_Append(gca, obj) == -1) {
1382 Py_DECREF(obj);
1382 Py_DECREF(obj);
1383 goto bail;
1383 goto bail;
1384 }
1384 }
1385 sv |= poison;
1385 sv |= poison;
1386 for (i = 0; i < revcount; i++) {
1386 for (i = 0; i < revcount; i++) {
1387 if (revs[i] == v)
1387 if (revs[i] == v)
1388 goto done;
1388 goto done;
1389 }
1389 }
1390 }
1390 }
1391 }
1391 }
1392 if (index_get_parents(self, v, parents, maxrev) < 0)
1392 if (index_get_parents(self, v, parents, maxrev) < 0)
1393 goto bail;
1393 goto bail;
1394
1394
1395 for (i = 0; i < 2; i++) {
1395 for (i = 0; i < 2; i++) {
1396 int p = parents[i];
1396 int p = parents[i];
1397 if (p == -1)
1397 if (p == -1)
1398 continue;
1398 continue;
1399 sp = seen[p];
1399 sp = seen[p];
1400 if (sv < poison) {
1400 if (sv < poison) {
1401 if (sp == 0) {
1401 if (sp == 0) {
1402 seen[p] = sv;
1402 seen[p] = sv;
1403 interesting++;
1403 interesting++;
1404 }
1404 }
1405 else if (sp != sv)
1405 else if (sp != sv)
1406 seen[p] |= sv;
1406 seen[p] |= sv;
1407 } else {
1407 } else {
1408 if (sp && sp < poison)
1408 if (sp && sp < poison)
1409 interesting--;
1409 interesting--;
1410 seen[p] = sv;
1410 seen[p] = sv;
1411 }
1411 }
1412 }
1412 }
1413 }
1413 }
1414
1414
1415 done:
1415 done:
1416 free(seen);
1416 free(seen);
1417 return gca;
1417 return gca;
1418 bail:
1418 bail:
1419 free(seen);
1419 free(seen);
1420 Py_XDECREF(gca);
1420 Py_XDECREF(gca);
1421 return NULL;
1421 return NULL;
1422 }
1422 }
1423
1423
1424 /*
1424 /*
1425 * Given a disjoint set of revs, return the subset with the longest
1425 * Given a disjoint set of revs, return the subset with the longest
1426 * path to the root.
1426 * path to the root.
1427 */
1427 */
1428 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1428 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1429 {
1429 {
1430 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1430 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1431 static const Py_ssize_t capacity = 24;
1431 static const Py_ssize_t capacity = 24;
1432 int *depth, *interesting = NULL;
1432 int *depth, *interesting = NULL;
1433 int i, j, v, ninteresting;
1433 int i, j, v, ninteresting;
1434 PyObject *dict = NULL, *keys = NULL;
1434 PyObject *dict = NULL, *keys = NULL;
1435 long *seen = NULL;
1435 long *seen = NULL;
1436 int maxrev = -1;
1436 int maxrev = -1;
1437 long final;
1437 long final;
1438
1438
1439 if (revcount > capacity) {
1439 if (revcount > capacity) {
1440 PyErr_Format(PyExc_OverflowError,
1440 PyErr_Format(PyExc_OverflowError,
1441 "bitset size (%ld) > capacity (%ld)",
1441 "bitset size (%ld) > capacity (%ld)",
1442 (long)revcount, (long)capacity);
1442 (long)revcount, (long)capacity);
1443 return NULL;
1443 return NULL;
1444 }
1444 }
1445
1445
1446 for (i = 0; i < revcount; i++) {
1446 for (i = 0; i < revcount; i++) {
1447 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1447 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1448 if (n > maxrev)
1448 if (n > maxrev)
1449 maxrev = n;
1449 maxrev = n;
1450 }
1450 }
1451
1451
1452 depth = calloc(sizeof(*depth), maxrev + 1);
1452 depth = calloc(sizeof(*depth), maxrev + 1);
1453 if (depth == NULL)
1453 if (depth == NULL)
1454 return PyErr_NoMemory();
1454 return PyErr_NoMemory();
1455
1455
1456 seen = calloc(sizeof(*seen), maxrev + 1);
1456 seen = calloc(sizeof(*seen), maxrev + 1);
1457 if (seen == NULL) {
1457 if (seen == NULL) {
1458 PyErr_NoMemory();
1458 PyErr_NoMemory();
1459 goto bail;
1459 goto bail;
1460 }
1460 }
1461
1461
1462 interesting = calloc(sizeof(*interesting), 1 << revcount);
1462 interesting = calloc(sizeof(*interesting), 1 << revcount);
1463 if (interesting == NULL) {
1463 if (interesting == NULL) {
1464 PyErr_NoMemory();
1464 PyErr_NoMemory();
1465 goto bail;
1465 goto bail;
1466 }
1466 }
1467
1467
1468 if (PyList_Sort(revs) == -1)
1468 if (PyList_Sort(revs) == -1)
1469 goto bail;
1469 goto bail;
1470
1470
1471 for (i = 0; i < revcount; i++) {
1471 for (i = 0; i < revcount; i++) {
1472 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1472 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1473 long b = 1l << i;
1473 long b = 1l << i;
1474 depth[n] = 1;
1474 depth[n] = 1;
1475 seen[n] = b;
1475 seen[n] = b;
1476 interesting[b] = 1;
1476 interesting[b] = 1;
1477 }
1477 }
1478
1478
1479 /* invariant: ninteresting is the number of non-zero entries in
1479 /* invariant: ninteresting is the number of non-zero entries in
1480 * interesting. */
1480 * interesting. */
1481 ninteresting = (int)revcount;
1481 ninteresting = (int)revcount;
1482
1482
1483 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1483 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1484 int dv = depth[v];
1484 int dv = depth[v];
1485 int parents[2];
1485 int parents[2];
1486 long sv;
1486 long sv;
1487
1487
1488 if (dv == 0)
1488 if (dv == 0)
1489 continue;
1489 continue;
1490
1490
1491 sv = seen[v];
1491 sv = seen[v];
1492 if (index_get_parents(self, v, parents, maxrev) < 0)
1492 if (index_get_parents(self, v, parents, maxrev) < 0)
1493 goto bail;
1493 goto bail;
1494
1494
1495 for (i = 0; i < 2; i++) {
1495 for (i = 0; i < 2; i++) {
1496 int p = parents[i];
1496 int p = parents[i];
1497 long sp;
1497 long sp;
1498 int dp;
1498 int dp;
1499
1499
1500 if (p == -1)
1500 if (p == -1)
1501 continue;
1501 continue;
1502
1502
1503 dp = depth[p];
1503 dp = depth[p];
1504 sp = seen[p];
1504 sp = seen[p];
1505 if (dp <= dv) {
1505 if (dp <= dv) {
1506 depth[p] = dv + 1;
1506 depth[p] = dv + 1;
1507 if (sp != sv) {
1507 if (sp != sv) {
1508 interesting[sv] += 1;
1508 interesting[sv] += 1;
1509 seen[p] = sv;
1509 seen[p] = sv;
1510 if (sp) {
1510 if (sp) {
1511 interesting[sp] -= 1;
1511 interesting[sp] -= 1;
1512 if (interesting[sp] == 0)
1512 if (interesting[sp] == 0)
1513 ninteresting -= 1;
1513 ninteresting -= 1;
1514 }
1514 }
1515 }
1515 }
1516 }
1516 }
1517 else if (dv == dp - 1) {
1517 else if (dv == dp - 1) {
1518 long nsp = sp | sv;
1518 long nsp = sp | sv;
1519 if (nsp == sp)
1519 if (nsp == sp)
1520 continue;
1520 continue;
1521 seen[p] = nsp;
1521 seen[p] = nsp;
1522 interesting[sp] -= 1;
1522 interesting[sp] -= 1;
1523 if (interesting[sp] == 0)
1523 if (interesting[sp] == 0)
1524 ninteresting -= 1;
1524 ninteresting -= 1;
1525 if (interesting[nsp] == 0)
1525 if (interesting[nsp] == 0)
1526 ninteresting += 1;
1526 ninteresting += 1;
1527 interesting[nsp] += 1;
1527 interesting[nsp] += 1;
1528 }
1528 }
1529 }
1529 }
1530 interesting[sv] -= 1;
1530 interesting[sv] -= 1;
1531 if (interesting[sv] == 0)
1531 if (interesting[sv] == 0)
1532 ninteresting -= 1;
1532 ninteresting -= 1;
1533 }
1533 }
1534
1534
1535 final = 0;
1535 final = 0;
1536 j = ninteresting;
1536 j = ninteresting;
1537 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1537 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1538 if (interesting[i] == 0)
1538 if (interesting[i] == 0)
1539 continue;
1539 continue;
1540 final |= i;
1540 final |= i;
1541 j -= 1;
1541 j -= 1;
1542 }
1542 }
1543 if (final == 0) {
1543 if (final == 0) {
1544 keys = PyList_New(0);
1544 keys = PyList_New(0);
1545 goto bail;
1545 goto bail;
1546 }
1546 }
1547
1547
1548 dict = PyDict_New();
1548 dict = PyDict_New();
1549 if (dict == NULL)
1549 if (dict == NULL)
1550 goto bail;
1550 goto bail;
1551
1551
1552 for (i = 0; i < revcount; i++) {
1552 for (i = 0; i < revcount; i++) {
1553 PyObject *key;
1553 PyObject *key;
1554
1554
1555 if ((final & (1 << i)) == 0)
1555 if ((final & (1 << i)) == 0)
1556 continue;
1556 continue;
1557
1557
1558 key = PyList_GET_ITEM(revs, i);
1558 key = PyList_GET_ITEM(revs, i);
1559 Py_INCREF(key);
1559 Py_INCREF(key);
1560 Py_INCREF(Py_None);
1560 Py_INCREF(Py_None);
1561 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1561 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1562 Py_DECREF(key);
1562 Py_DECREF(key);
1563 Py_DECREF(Py_None);
1563 Py_DECREF(Py_None);
1564 goto bail;
1564 goto bail;
1565 }
1565 }
1566 }
1566 }
1567
1567
1568 keys = PyDict_Keys(dict);
1568 keys = PyDict_Keys(dict);
1569
1569
1570 bail:
1570 bail:
1571 free(depth);
1571 free(depth);
1572 free(seen);
1572 free(seen);
1573 free(interesting);
1573 free(interesting);
1574 Py_XDECREF(dict);
1574 Py_XDECREF(dict);
1575
1575
1576 return keys;
1576 return keys;
1577 }
1577 }
1578
1578
1579 /*
1579 /*
1580 * Given a (possibly overlapping) set of revs, return all the
1580 * Given a (possibly overlapping) set of revs, return all the
1581 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1581 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1582 */
1582 */
1583 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1583 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1584 {
1584 {
1585 PyObject *ret = NULL;
1585 PyObject *ret = NULL;
1586 Py_ssize_t argcount, i, len;
1586 Py_ssize_t argcount, i, len;
1587 bitmask repeat = 0;
1587 bitmask repeat = 0;
1588 int revcount = 0;
1588 int revcount = 0;
1589 int *revs;
1589 int *revs;
1590
1590
1591 argcount = PySequence_Length(args);
1591 argcount = PySequence_Length(args);
1592 revs = PyMem_Malloc(argcount * sizeof(*revs));
1592 revs = PyMem_Malloc(argcount * sizeof(*revs));
1593 if (argcount > 0 && revs == NULL)
1593 if (argcount > 0 && revs == NULL)
1594 return PyErr_NoMemory();
1594 return PyErr_NoMemory();
1595 len = index_length(self) - 1;
1595 len = index_length(self) - 1;
1596
1596
1597 for (i = 0; i < argcount; i++) {
1597 for (i = 0; i < argcount; i++) {
1598 static const int capacity = 24;
1598 static const int capacity = 24;
1599 PyObject *obj = PySequence_GetItem(args, i);
1599 PyObject *obj = PySequence_GetItem(args, i);
1600 bitmask x;
1600 bitmask x;
1601 long val;
1601 long val;
1602
1602
1603 if (!PyInt_Check(obj)) {
1603 if (!PyInt_Check(obj)) {
1604 PyErr_SetString(PyExc_TypeError,
1604 PyErr_SetString(PyExc_TypeError,
1605 "arguments must all be ints");
1605 "arguments must all be ints");
1606 Py_DECREF(obj);
1606 Py_DECREF(obj);
1607 goto bail;
1607 goto bail;
1608 }
1608 }
1609 val = PyInt_AsLong(obj);
1609 val = PyInt_AsLong(obj);
1610 Py_DECREF(obj);
1610 Py_DECREF(obj);
1611 if (val == -1) {
1611 if (val == -1) {
1612 ret = PyList_New(0);
1612 ret = PyList_New(0);
1613 goto done;
1613 goto done;
1614 }
1614 }
1615 if (val < 0 || val >= len) {
1615 if (val < 0 || val >= len) {
1616 PyErr_SetString(PyExc_IndexError,
1616 PyErr_SetString(PyExc_IndexError,
1617 "index out of range");
1617 "index out of range");
1618 goto bail;
1618 goto bail;
1619 }
1619 }
1620 /* this cheesy bloom filter lets us avoid some more
1620 /* this cheesy bloom filter lets us avoid some more
1621 * expensive duplicate checks in the common set-is-disjoint
1621 * expensive duplicate checks in the common set-is-disjoint
1622 * case */
1622 * case */
1623 x = 1ull << (val & 0x3f);
1623 x = 1ull << (val & 0x3f);
1624 if (repeat & x) {
1624 if (repeat & x) {
1625 int k;
1625 int k;
1626 for (k = 0; k < revcount; k++) {
1626 for (k = 0; k < revcount; k++) {
1627 if (val == revs[k])
1627 if (val == revs[k])
1628 goto duplicate;
1628 goto duplicate;
1629 }
1629 }
1630 }
1630 }
1631 else repeat |= x;
1631 else repeat |= x;
1632 if (revcount >= capacity) {
1632 if (revcount >= capacity) {
1633 PyErr_Format(PyExc_OverflowError,
1633 PyErr_Format(PyExc_OverflowError,
1634 "bitset size (%d) > capacity (%d)",
1634 "bitset size (%d) > capacity (%d)",
1635 revcount, capacity);
1635 revcount, capacity);
1636 goto bail;
1636 goto bail;
1637 }
1637 }
1638 revs[revcount++] = (int)val;
1638 revs[revcount++] = (int)val;
1639 duplicate:;
1639 duplicate:;
1640 }
1640 }
1641
1641
1642 if (revcount == 0) {
1642 if (revcount == 0) {
1643 ret = PyList_New(0);
1643 ret = PyList_New(0);
1644 goto done;
1644 goto done;
1645 }
1645 }
1646 if (revcount == 1) {
1646 if (revcount == 1) {
1647 PyObject *obj;
1647 PyObject *obj;
1648 ret = PyList_New(1);
1648 ret = PyList_New(1);
1649 if (ret == NULL)
1649 if (ret == NULL)
1650 goto bail;
1650 goto bail;
1651 obj = PyInt_FromLong(revs[0]);
1651 obj = PyInt_FromLong(revs[0]);
1652 if (obj == NULL)
1652 if (obj == NULL)
1653 goto bail;
1653 goto bail;
1654 PyList_SET_ITEM(ret, 0, obj);
1654 PyList_SET_ITEM(ret, 0, obj);
1655 goto done;
1655 goto done;
1656 }
1656 }
1657
1657
1658 ret = find_gca_candidates(self, revs, revcount);
1658 ret = find_gca_candidates(self, revs, revcount);
1659 if (ret == NULL)
1659 if (ret == NULL)
1660 goto bail;
1660 goto bail;
1661
1661
1662 done:
1662 done:
1663 PyMem_Free(revs);
1663 PyMem_Free(revs);
1664 return ret;
1664 return ret;
1665
1665
1666 bail:
1666 bail:
1667 PyMem_Free(revs);
1667 PyMem_Free(revs);
1668 Py_XDECREF(ret);
1668 Py_XDECREF(ret);
1669 return NULL;
1669 return NULL;
1670 }
1670 }
1671
1671
1672 /*
1672 /*
1673 * Given a (possibly overlapping) set of revs, return the greatest
1673 * Given a (possibly overlapping) set of revs, return the greatest
1674 * common ancestors: those with the longest path to the root.
1674 * common ancestors: those with the longest path to the root.
1675 */
1675 */
1676 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1676 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1677 {
1677 {
1678 PyObject *ret;
1678 PyObject *ret;
1679 PyObject *gca = index_commonancestorsheads(self, args);
1679 PyObject *gca = index_commonancestorsheads(self, args);
1680 if (gca == NULL)
1680 if (gca == NULL)
1681 return NULL;
1681 return NULL;
1682
1682
1683 if (PyList_GET_SIZE(gca) <= 1) {
1683 if (PyList_GET_SIZE(gca) <= 1) {
1684 return gca;
1684 return gca;
1685 }
1685 }
1686
1686
1687 ret = find_deepest(self, gca);
1687 ret = find_deepest(self, gca);
1688 Py_DECREF(gca);
1688 Py_DECREF(gca);
1689 return ret;
1689 return ret;
1690 }
1690 }
1691
1691
1692 /*
1692 /*
1693 * Invalidate any trie entries introduced by added revs.
1693 * Invalidate any trie entries introduced by added revs.
1694 */
1694 */
1695 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1695 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1696 {
1696 {
1697 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1697 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1698
1698
1699 for (i = start; i < len; i++) {
1699 for (i = start; i < len; i++) {
1700 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1700 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1701 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1701 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1702
1702
1703 nt_insert(self, PyBytes_AS_STRING(node), -1);
1703 nt_insert(self, PyBytes_AS_STRING(node), -1);
1704 }
1704 }
1705
1705
1706 if (start == 0)
1706 if (start == 0)
1707 Py_CLEAR(self->added);
1707 Py_CLEAR(self->added);
1708 }
1708 }
1709
1709
1710 /*
1710 /*
1711 * Delete a numeric range of revs, which must be at the end of the
1711 * Delete a numeric range of revs, which must be at the end of the
1712 * range, but exclude the sentinel nullid entry.
1712 * range, but exclude the sentinel nullid entry.
1713 */
1713 */
1714 static int index_slice_del(indexObject *self, PyObject *item)
1714 static int index_slice_del(indexObject *self, PyObject *item)
1715 {
1715 {
1716 Py_ssize_t start, stop, step, slicelength;
1716 Py_ssize_t start, stop, step, slicelength;
1717 Py_ssize_t length = index_length(self);
1717 Py_ssize_t length = index_length(self);
1718 int ret = 0;
1718 int ret = 0;
1719
1719
1720 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
1720 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
1721 #ifdef IS_PY3K
1721 #ifdef IS_PY3K
1722 if (PySlice_GetIndicesEx(item, length,
1722 if (PySlice_GetIndicesEx(item, length,
1723 #else
1723 #else
1724 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1724 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1725 #endif
1725 #endif
1726 &start, &stop, &step, &slicelength) < 0)
1726 &start, &stop, &step, &slicelength) < 0)
1727 return -1;
1727 return -1;
1728
1728
1729 if (slicelength <= 0)
1729 if (slicelength <= 0)
1730 return 0;
1730 return 0;
1731
1731
1732 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1732 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1733 stop = start;
1733 stop = start;
1734
1734
1735 if (step < 0) {
1735 if (step < 0) {
1736 stop = start + 1;
1736 stop = start + 1;
1737 start = stop + step*(slicelength - 1) - 1;
1737 start = stop + step*(slicelength - 1) - 1;
1738 step = -step;
1738 step = -step;
1739 }
1739 }
1740
1740
1741 if (step != 1) {
1741 if (step != 1) {
1742 PyErr_SetString(PyExc_ValueError,
1742 PyErr_SetString(PyExc_ValueError,
1743 "revlog index delete requires step size of 1");
1743 "revlog index delete requires step size of 1");
1744 return -1;
1744 return -1;
1745 }
1745 }
1746
1746
1747 if (stop != length - 1) {
1747 if (stop != length - 1) {
1748 PyErr_SetString(PyExc_IndexError,
1748 PyErr_SetString(PyExc_IndexError,
1749 "revlog index deletion indices are invalid");
1749 "revlog index deletion indices are invalid");
1750 return -1;
1750 return -1;
1751 }
1751 }
1752
1752
1753 if (start < self->length - 1) {
1753 if (start < self->length - 1) {
1754 if (self->nt) {
1754 if (self->nt) {
1755 Py_ssize_t i;
1755 Py_ssize_t i;
1756
1756
1757 for (i = start + 1; i < self->length - 1; i++) {
1757 for (i = start + 1; i < self->length - 1; i++) {
1758 const char *node = index_node(self, i);
1758 const char *node = index_node(self, i);
1759
1759
1760 if (node)
1760 if (node)
1761 nt_insert(self, node, -1);
1761 nt_insert(self, node, -1);
1762 }
1762 }
1763 if (self->added)
1763 if (self->added)
1764 nt_invalidate_added(self, 0);
1764 nt_invalidate_added(self, 0);
1765 if (self->ntrev > start)
1765 if (self->ntrev > start)
1766 self->ntrev = (int)start;
1766 self->ntrev = (int)start;
1767 }
1767 }
1768 self->length = start + 1;
1768 self->length = start + 1;
1769 if (start < self->raw_length) {
1769 if (start < self->raw_length) {
1770 if (self->cache) {
1770 if (self->cache) {
1771 Py_ssize_t i;
1771 Py_ssize_t i;
1772 for (i = start; i < self->raw_length; i++)
1772 for (i = start; i < self->raw_length; i++)
1773 Py_CLEAR(self->cache[i]);
1773 Py_CLEAR(self->cache[i]);
1774 }
1774 }
1775 self->raw_length = start;
1775 self->raw_length = start;
1776 }
1776 }
1777 goto done;
1777 goto done;
1778 }
1778 }
1779
1779
1780 if (self->nt) {
1780 if (self->nt) {
1781 nt_invalidate_added(self, start - self->length + 1);
1781 nt_invalidate_added(self, start - self->length + 1);
1782 if (self->ntrev > start)
1782 if (self->ntrev > start)
1783 self->ntrev = (int)start;
1783 self->ntrev = (int)start;
1784 }
1784 }
1785 if (self->added)
1785 if (self->added)
1786 ret = PyList_SetSlice(self->added, start - self->length + 1,
1786 ret = PyList_SetSlice(self->added, start - self->length + 1,
1787 PyList_GET_SIZE(self->added), NULL);
1787 PyList_GET_SIZE(self->added), NULL);
1788 done:
1788 done:
1789 Py_CLEAR(self->headrevs);
1789 Py_CLEAR(self->headrevs);
1790 return ret;
1790 return ret;
1791 }
1791 }
1792
1792
1793 /*
1793 /*
1794 * Supported ops:
1794 * Supported ops:
1795 *
1795 *
1796 * slice deletion
1796 * slice deletion
1797 * string assignment (extend node->rev mapping)
1797 * string assignment (extend node->rev mapping)
1798 * string deletion (shrink node->rev mapping)
1798 * string deletion (shrink node->rev mapping)
1799 */
1799 */
1800 static int index_assign_subscript(indexObject *self, PyObject *item,
1800 static int index_assign_subscript(indexObject *self, PyObject *item,
1801 PyObject *value)
1801 PyObject *value)
1802 {
1802 {
1803 char *node;
1803 char *node;
1804 Py_ssize_t nodelen;
1804 Py_ssize_t nodelen;
1805 long rev;
1805 long rev;
1806
1806
1807 if (PySlice_Check(item) && value == NULL)
1807 if (PySlice_Check(item) && value == NULL)
1808 return index_slice_del(self, item);
1808 return index_slice_del(self, item);
1809
1809
1810 if (node_check(item, &node, &nodelen) == -1)
1810 if (node_check(item, &node, &nodelen) == -1)
1811 return -1;
1811 return -1;
1812
1812
1813 if (value == NULL)
1813 if (value == NULL)
1814 return self->nt ? nt_insert(self, node, -1) : 0;
1814 return self->nt ? nt_insert(self, node, -1) : 0;
1815 rev = PyInt_AsLong(value);
1815 rev = PyInt_AsLong(value);
1816 if (rev > INT_MAX || rev < 0) {
1816 if (rev > INT_MAX || rev < 0) {
1817 if (!PyErr_Occurred())
1817 if (!PyErr_Occurred())
1818 PyErr_SetString(PyExc_ValueError, "rev out of range");
1818 PyErr_SetString(PyExc_ValueError, "rev out of range");
1819 return -1;
1819 return -1;
1820 }
1820 }
1821
1821
1822 if (nt_init(self) == -1)
1822 if (nt_init(self) == -1)
1823 return -1;
1823 return -1;
1824 return nt_insert(self, node, (int)rev);
1824 return nt_insert(self, node, (int)rev);
1825 }
1825 }
1826
1826
1827 /*
1827 /*
1828 * Find all RevlogNG entries in an index that has inline data. Update
1828 * Find all RevlogNG entries in an index that has inline data. Update
1829 * the optional "offsets" table with those entries.
1829 * the optional "offsets" table with those entries.
1830 */
1830 */
1831 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
1831 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
1832 {
1832 {
1833 const char *data = (const char *)self->buf.buf;
1833 const char *data = (const char *)self->buf.buf;
1834 Py_ssize_t pos = 0;
1834 Py_ssize_t pos = 0;
1835 Py_ssize_t end = self->buf.len;
1835 Py_ssize_t end = self->buf.len;
1836 long incr = v1_hdrsize;
1836 long incr = v1_hdrsize;
1837 Py_ssize_t len = 0;
1837 Py_ssize_t len = 0;
1838
1838
1839 while (pos + v1_hdrsize <= end && pos >= 0) {
1839 while (pos + v1_hdrsize <= end && pos >= 0) {
1840 uint32_t comp_len;
1840 uint32_t comp_len;
1841 /* 3rd element of header is length of compressed inline data */
1841 /* 3rd element of header is length of compressed inline data */
1842 comp_len = getbe32(data + pos + 8);
1842 comp_len = getbe32(data + pos + 8);
1843 incr = v1_hdrsize + comp_len;
1843 incr = v1_hdrsize + comp_len;
1844 if (offsets)
1844 if (offsets)
1845 offsets[len] = data + pos;
1845 offsets[len] = data + pos;
1846 len++;
1846 len++;
1847 pos += incr;
1847 pos += incr;
1848 }
1848 }
1849
1849
1850 if (pos != end) {
1850 if (pos != end) {
1851 if (!PyErr_Occurred())
1851 if (!PyErr_Occurred())
1852 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1852 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1853 return -1;
1853 return -1;
1854 }
1854 }
1855
1855
1856 return len;
1856 return len;
1857 }
1857 }
1858
1858
1859 static int index_init(indexObject *self, PyObject *args)
1859 static int index_init(indexObject *self, PyObject *args)
1860 {
1860 {
1861 PyObject *data_obj, *inlined_obj;
1861 PyObject *data_obj, *inlined_obj;
1862 Py_ssize_t size;
1862 Py_ssize_t size;
1863
1863
1864 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1864 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1865 self->raw_length = 0;
1865 self->raw_length = 0;
1866 self->added = NULL;
1866 self->added = NULL;
1867 self->cache = NULL;
1867 self->cache = NULL;
1868 self->data = NULL;
1868 self->data = NULL;
1869 memset(&self->buf, 0, sizeof(self->buf));
1869 memset(&self->buf, 0, sizeof(self->buf));
1870 self->headrevs = NULL;
1870 self->headrevs = NULL;
1871 self->filteredrevs = Py_None;
1871 self->filteredrevs = Py_None;
1872 Py_INCREF(Py_None);
1872 Py_INCREF(Py_None);
1873 self->nt = NULL;
1873 self->nt = NULL;
1874 self->offsets = NULL;
1874 self->offsets = NULL;
1875
1875
1876 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1876 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1877 return -1;
1877 return -1;
1878 if (!PyObject_CheckBuffer(data_obj)) {
1878 if (!PyObject_CheckBuffer(data_obj)) {
1879 PyErr_SetString(PyExc_TypeError,
1879 PyErr_SetString(PyExc_TypeError,
1880 "data does not support buffer interface");
1880 "data does not support buffer interface");
1881 return -1;
1881 return -1;
1882 }
1882 }
1883
1883
1884 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
1884 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
1885 return -1;
1885 return -1;
1886 size = self->buf.len;
1886 size = self->buf.len;
1887
1887
1888 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1888 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1889 self->data = data_obj;
1889 self->data = data_obj;
1890
1890
1891 self->ntlength = self->ntcapacity = 0;
1891 self->ntlength = self->ntcapacity = 0;
1892 self->ntdepth = self->ntsplits = 0;
1892 self->ntdepth = self->ntsplits = 0;
1893 self->ntlookups = self->ntmisses = 0;
1893 self->ntlookups = self->ntmisses = 0;
1894 self->ntrev = -1;
1894 self->ntrev = -1;
1895 Py_INCREF(self->data);
1895 Py_INCREF(self->data);
1896
1896
1897 if (self->inlined) {
1897 if (self->inlined) {
1898 Py_ssize_t len = inline_scan(self, NULL);
1898 Py_ssize_t len = inline_scan(self, NULL);
1899 if (len == -1)
1899 if (len == -1)
1900 goto bail;
1900 goto bail;
1901 self->raw_length = len;
1901 self->raw_length = len;
1902 self->length = len + 1;
1902 self->length = len + 1;
1903 } else {
1903 } else {
1904 if (size % v1_hdrsize) {
1904 if (size % v1_hdrsize) {
1905 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1905 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1906 goto bail;
1906 goto bail;
1907 }
1907 }
1908 self->raw_length = size / v1_hdrsize;
1908 self->raw_length = size / v1_hdrsize;
1909 self->length = self->raw_length + 1;
1909 self->length = self->raw_length + 1;
1910 }
1910 }
1911
1911
1912 return 0;
1912 return 0;
1913 bail:
1913 bail:
1914 return -1;
1914 return -1;
1915 }
1915 }
1916
1916
1917 static PyObject *index_nodemap(indexObject *self)
1917 static PyObject *index_nodemap(indexObject *self)
1918 {
1918 {
1919 Py_INCREF(self);
1919 Py_INCREF(self);
1920 return (PyObject *)self;
1920 return (PyObject *)self;
1921 }
1921 }
1922
1922
1923 static void index_dealloc(indexObject *self)
1923 static void index_dealloc(indexObject *self)
1924 {
1924 {
1925 _index_clearcaches(self);
1925 _index_clearcaches(self);
1926 Py_XDECREF(self->filteredrevs);
1926 Py_XDECREF(self->filteredrevs);
1927 if (self->buf.buf) {
1927 if (self->buf.buf) {
1928 PyBuffer_Release(&self->buf);
1928 PyBuffer_Release(&self->buf);
1929 memset(&self->buf, 0, sizeof(self->buf));
1929 memset(&self->buf, 0, sizeof(self->buf));
1930 }
1930 }
1931 Py_XDECREF(self->data);
1931 Py_XDECREF(self->data);
1932 Py_XDECREF(self->added);
1932 Py_XDECREF(self->added);
1933 PyObject_Del(self);
1933 PyObject_Del(self);
1934 }
1934 }
1935
1935
1936 static PySequenceMethods index_sequence_methods = {
1936 static PySequenceMethods index_sequence_methods = {
1937 (lenfunc)index_length, /* sq_length */
1937 (lenfunc)index_length, /* sq_length */
1938 0, /* sq_concat */
1938 0, /* sq_concat */
1939 0, /* sq_repeat */
1939 0, /* sq_repeat */
1940 (ssizeargfunc)index_get, /* sq_item */
1940 (ssizeargfunc)index_get, /* sq_item */
1941 0, /* sq_slice */
1941 0, /* sq_slice */
1942 0, /* sq_ass_item */
1942 0, /* sq_ass_item */
1943 0, /* sq_ass_slice */
1943 0, /* sq_ass_slice */
1944 (objobjproc)index_contains, /* sq_contains */
1944 (objobjproc)index_contains, /* sq_contains */
1945 };
1945 };
1946
1946
1947 static PyMappingMethods index_mapping_methods = {
1947 static PyMappingMethods index_mapping_methods = {
1948 (lenfunc)index_length, /* mp_length */
1948 (lenfunc)index_length, /* mp_length */
1949 (binaryfunc)index_getitem, /* mp_subscript */
1949 (binaryfunc)index_getitem, /* mp_subscript */
1950 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1950 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1951 };
1951 };
1952
1952
1953 static PyMethodDef index_methods[] = {
1953 static PyMethodDef index_methods[] = {
1954 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
1954 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
1955 "return the gca set of the given revs"},
1955 "return the gca set of the given revs"},
1956 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
1956 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
1957 METH_VARARGS,
1957 METH_VARARGS,
1958 "return the heads of the common ancestors of the given revs"},
1958 "return the heads of the common ancestors of the given revs"},
1959 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1959 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1960 "clear the index caches"},
1960 "clear the index caches"},
1961 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1961 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1962 "get an index entry"},
1962 "get an index entry"},
1963 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets,
1963 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets,
1964 METH_VARARGS, "compute phases"},
1964 METH_VARARGS, "compute phases"},
1965 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
1965 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
1966 "reachableroots"},
1966 "reachableroots"},
1967 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
1967 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
1968 "get head revisions"}, /* Can do filtering since 3.2 */
1968 "get head revisions"}, /* Can do filtering since 3.2 */
1969 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
1969 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
1970 "get filtered head revisions"}, /* Can always do filtering */
1970 "get filtered head revisions"}, /* Can always do filtering */
1971 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
1971 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
1972 "determine revisions with deltas to reconstruct fulltext"},
1972 "determine revisions with deltas to reconstruct fulltext"},
1973 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1973 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1974 "insert an index entry"},
1974 "insert an index entry"},
1975 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1975 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1976 "match a potentially ambiguous node ID"},
1976 "match a potentially ambiguous node ID"},
1977 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1977 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1978 "stats for the index"},
1978 "stats for the index"},
1979 {NULL} /* Sentinel */
1979 {NULL} /* Sentinel */
1980 };
1980 };
1981
1981
1982 static PyGetSetDef index_getset[] = {
1982 static PyGetSetDef index_getset[] = {
1983 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1983 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1984 {NULL} /* Sentinel */
1984 {NULL} /* Sentinel */
1985 };
1985 };
1986
1986
1987 static PyTypeObject indexType = {
1987 static PyTypeObject indexType = {
1988 PyVarObject_HEAD_INIT(NULL, 0) /* header */
1988 PyVarObject_HEAD_INIT(NULL, 0) /* header */
1989 "parsers.index", /* tp_name */
1989 "parsers.index", /* tp_name */
1990 sizeof(indexObject), /* tp_basicsize */
1990 sizeof(indexObject), /* tp_basicsize */
1991 0, /* tp_itemsize */
1991 0, /* tp_itemsize */
1992 (destructor)index_dealloc, /* tp_dealloc */
1992 (destructor)index_dealloc, /* tp_dealloc */
1993 0, /* tp_print */
1993 0, /* tp_print */
1994 0, /* tp_getattr */
1994 0, /* tp_getattr */
1995 0, /* tp_setattr */
1995 0, /* tp_setattr */
1996 0, /* tp_compare */
1996 0, /* tp_compare */
1997 0, /* tp_repr */
1997 0, /* tp_repr */
1998 0, /* tp_as_number */
1998 0, /* tp_as_number */
1999 &index_sequence_methods, /* tp_as_sequence */
1999 &index_sequence_methods, /* tp_as_sequence */
2000 &index_mapping_methods, /* tp_as_mapping */
2000 &index_mapping_methods, /* tp_as_mapping */
2001 0, /* tp_hash */
2001 0, /* tp_hash */
2002 0, /* tp_call */
2002 0, /* tp_call */
2003 0, /* tp_str */
2003 0, /* tp_str */
2004 0, /* tp_getattro */
2004 0, /* tp_getattro */
2005 0, /* tp_setattro */
2005 0, /* tp_setattro */
2006 0, /* tp_as_buffer */
2006 0, /* tp_as_buffer */
2007 Py_TPFLAGS_DEFAULT, /* tp_flags */
2007 Py_TPFLAGS_DEFAULT, /* tp_flags */
2008 "revlog index", /* tp_doc */
2008 "revlog index", /* tp_doc */
2009 0, /* tp_traverse */
2009 0, /* tp_traverse */
2010 0, /* tp_clear */
2010 0, /* tp_clear */
2011 0, /* tp_richcompare */
2011 0, /* tp_richcompare */
2012 0, /* tp_weaklistoffset */
2012 0, /* tp_weaklistoffset */
2013 0, /* tp_iter */
2013 0, /* tp_iter */
2014 0, /* tp_iternext */
2014 0, /* tp_iternext */
2015 index_methods, /* tp_methods */
2015 index_methods, /* tp_methods */
2016 0, /* tp_members */
2016 0, /* tp_members */
2017 index_getset, /* tp_getset */
2017 index_getset, /* tp_getset */
2018 0, /* tp_base */
2018 0, /* tp_base */
2019 0, /* tp_dict */
2019 0, /* tp_dict */
2020 0, /* tp_descr_get */
2020 0, /* tp_descr_get */
2021 0, /* tp_descr_set */
2021 0, /* tp_descr_set */
2022 0, /* tp_dictoffset */
2022 0, /* tp_dictoffset */
2023 (initproc)index_init, /* tp_init */
2023 (initproc)index_init, /* tp_init */
2024 0, /* tp_alloc */
2024 0, /* tp_alloc */
2025 };
2025 };
2026
2026
2027 /*
2027 /*
2028 * returns a tuple of the form (index, index, cache) with elements as
2028 * returns a tuple of the form (index, index, cache) with elements as
2029 * follows:
2029 * follows:
2030 *
2030 *
2031 * index: an index object that lazily parses RevlogNG records
2031 * index: an index object that lazily parses RevlogNG records
2032 * cache: if data is inlined, a tuple (0, index_file_content), else None
2032 * cache: if data is inlined, a tuple (0, index_file_content), else None
2033 * index_file_content could be a string, or a buffer
2033 * index_file_content could be a string, or a buffer
2034 *
2034 *
2035 * added complications are for backwards compatibility
2035 * added complications are for backwards compatibility
2036 */
2036 */
2037 PyObject *parse_index2(PyObject *self, PyObject *args)
2037 PyObject *parse_index2(PyObject *self, PyObject *args)
2038 {
2038 {
2039 PyObject *tuple = NULL, *cache = NULL;
2039 PyObject *tuple = NULL, *cache = NULL;
2040 indexObject *idx;
2040 indexObject *idx;
2041 int ret;
2041 int ret;
2042
2042
2043 idx = PyObject_New(indexObject, &indexType);
2043 idx = PyObject_New(indexObject, &indexType);
2044 if (idx == NULL)
2044 if (idx == NULL)
2045 goto bail;
2045 goto bail;
2046
2046
2047 ret = index_init(idx, args);
2047 ret = index_init(idx, args);
2048 if (ret == -1)
2048 if (ret == -1)
2049 goto bail;
2049 goto bail;
2050
2050
2051 if (idx->inlined) {
2051 if (idx->inlined) {
2052 cache = Py_BuildValue("iO", 0, idx->data);
2052 cache = Py_BuildValue("iO", 0, idx->data);
2053 if (cache == NULL)
2053 if (cache == NULL)
2054 goto bail;
2054 goto bail;
2055 } else {
2055 } else {
2056 cache = Py_None;
2056 cache = Py_None;
2057 Py_INCREF(cache);
2057 Py_INCREF(cache);
2058 }
2058 }
2059
2059
2060 tuple = Py_BuildValue("NN", idx, cache);
2060 tuple = Py_BuildValue("NN", idx, cache);
2061 if (!tuple)
2061 if (!tuple)
2062 goto bail;
2062 goto bail;
2063 return tuple;
2063 return tuple;
2064
2064
2065 bail:
2065 bail:
2066 Py_XDECREF(idx);
2066 Py_XDECREF(idx);
2067 Py_XDECREF(cache);
2067 Py_XDECREF(cache);
2068 Py_XDECREF(tuple);
2068 Py_XDECREF(tuple);
2069 return NULL;
2069 return NULL;
2070 }
2070 }
2071
2071
2072 void revlog_module_init(PyObject *mod)
2072 void revlog_module_init(PyObject *mod)
2073 {
2073 {
2074 indexType.tp_new = PyType_GenericNew;
2074 indexType.tp_new = PyType_GenericNew;
2075 if (PyType_Ready(&indexType) < 0)
2075 if (PyType_Ready(&indexType) < 0)
2076 return;
2076 return;
2077 Py_INCREF(&indexType);
2077 Py_INCREF(&indexType);
2078 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2078 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2079
2079
2080 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2080 nullentry = Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0,
2081 -1, -1, -1, -1, nullid, 20);
2081 -1, -1, -1, -1, nullid, 20);
2082 if (nullentry)
2082 if (nullentry)
2083 PyObject_GC_UnTrack(nullentry);
2083 PyObject_GC_UnTrack(nullentry);
2084 }
2084 }
General Comments 0
You need to be logged in to leave comments. Login now