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