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