##// END OF EJS Templates
cext: remove PY23()...
Gregory Szorc -
r49676:b0dd39b9 default
parent child Browse files
Show More
@@ -1,192 +1,192 b''
1 /*
1 /*
2 base85 codec
2 base85 codec
3
3
4 Copyright 2006 Brendan Cully <brendan@kublai.com>
4 Copyright 2006 Brendan Cully <brendan@kublai.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 Largely based on git's implementation
9 Largely based on git's implementation
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
14
15 #include "util.h"
15 #include "util.h"
16
16
17 static const char b85chars[] =
17 static const char b85chars[] =
18 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
18 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
19 "abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
19 "abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
20 static char b85dec[256];
20 static char b85dec[256];
21
21
22 static void b85prep(void)
22 static void b85prep(void)
23 {
23 {
24 unsigned i;
24 unsigned i;
25
25
26 memset(b85dec, 0, sizeof(b85dec));
26 memset(b85dec, 0, sizeof(b85dec));
27 for (i = 0; i < sizeof(b85chars); i++) {
27 for (i = 0; i < sizeof(b85chars); i++) {
28 b85dec[(int)(b85chars[i])] = i + 1;
28 b85dec[(int)(b85chars[i])] = i + 1;
29 }
29 }
30 }
30 }
31
31
32 static PyObject *b85encode(PyObject *self, PyObject *args)
32 static PyObject *b85encode(PyObject *self, PyObject *args)
33 {
33 {
34 const unsigned char *text;
34 const unsigned char *text;
35 PyObject *out;
35 PyObject *out;
36 char *dst;
36 char *dst;
37 Py_ssize_t len, olen, i;
37 Py_ssize_t len, olen, i;
38 unsigned int acc, val, ch;
38 unsigned int acc, val, ch;
39 int pad = 0;
39 int pad = 0;
40
40
41 if (!PyArg_ParseTuple(args, PY23("s#|i", "y#|i"), &text, &len, &pad)) {
41 if (!PyArg_ParseTuple(args, "y#|i", &text, &len, &pad)) {
42 return NULL;
42 return NULL;
43 }
43 }
44
44
45 if (pad) {
45 if (pad) {
46 olen = ((len + 3) / 4 * 5) - 3;
46 olen = ((len + 3) / 4 * 5) - 3;
47 } else {
47 } else {
48 olen = len % 4;
48 olen = len % 4;
49 if (olen) {
49 if (olen) {
50 olen++;
50 olen++;
51 }
51 }
52 olen += len / 4 * 5;
52 olen += len / 4 * 5;
53 }
53 }
54 if (!(out = PyBytes_FromStringAndSize(NULL, olen + 3))) {
54 if (!(out = PyBytes_FromStringAndSize(NULL, olen + 3))) {
55 return NULL;
55 return NULL;
56 }
56 }
57
57
58 dst = PyBytes_AsString(out);
58 dst = PyBytes_AsString(out);
59
59
60 while (len) {
60 while (len) {
61 acc = 0;
61 acc = 0;
62 for (i = 24; i >= 0; i -= 8) {
62 for (i = 24; i >= 0; i -= 8) {
63 ch = *text++;
63 ch = *text++;
64 acc |= ch << i;
64 acc |= ch << i;
65 if (--len == 0) {
65 if (--len == 0) {
66 break;
66 break;
67 }
67 }
68 }
68 }
69 for (i = 4; i >= 0; i--) {
69 for (i = 4; i >= 0; i--) {
70 val = acc % 85;
70 val = acc % 85;
71 acc /= 85;
71 acc /= 85;
72 dst[i] = b85chars[val];
72 dst[i] = b85chars[val];
73 }
73 }
74 dst += 5;
74 dst += 5;
75 }
75 }
76
76
77 if (!pad) {
77 if (!pad) {
78 _PyBytes_Resize(&out, olen);
78 _PyBytes_Resize(&out, olen);
79 }
79 }
80
80
81 return out;
81 return out;
82 }
82 }
83
83
84 static PyObject *b85decode(PyObject *self, PyObject *args)
84 static PyObject *b85decode(PyObject *self, PyObject *args)
85 {
85 {
86 PyObject *out = NULL;
86 PyObject *out = NULL;
87 const char *text;
87 const char *text;
88 char *dst;
88 char *dst;
89 Py_ssize_t len, i, j, olen, cap;
89 Py_ssize_t len, i, j, olen, cap;
90 int c;
90 int c;
91 unsigned int acc;
91 unsigned int acc;
92
92
93 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &text, &len)) {
93 if (!PyArg_ParseTuple(args, "y#", &text, &len)) {
94 return NULL;
94 return NULL;
95 }
95 }
96
96
97 olen = len / 5 * 4;
97 olen = len / 5 * 4;
98 i = len % 5;
98 i = len % 5;
99 if (i) {
99 if (i) {
100 olen += i - 1;
100 olen += i - 1;
101 }
101 }
102 if (!(out = PyBytes_FromStringAndSize(NULL, olen))) {
102 if (!(out = PyBytes_FromStringAndSize(NULL, olen))) {
103 return NULL;
103 return NULL;
104 }
104 }
105
105
106 dst = PyBytes_AsString(out);
106 dst = PyBytes_AsString(out);
107
107
108 i = 0;
108 i = 0;
109 while (i < len) {
109 while (i < len) {
110 acc = 0;
110 acc = 0;
111 cap = len - i - 1;
111 cap = len - i - 1;
112 if (cap > 4) {
112 if (cap > 4) {
113 cap = 4;
113 cap = 4;
114 }
114 }
115 for (j = 0; j < cap; i++, j++) {
115 for (j = 0; j < cap; i++, j++) {
116 c = b85dec[(int)*text++] - 1;
116 c = b85dec[(int)*text++] - 1;
117 if (c < 0) {
117 if (c < 0) {
118 PyErr_Format(
118 PyErr_Format(
119 PyExc_ValueError,
119 PyExc_ValueError,
120 "bad base85 character at position %d",
120 "bad base85 character at position %d",
121 (int)i);
121 (int)i);
122 goto bail;
122 goto bail;
123 }
123 }
124 acc = acc * 85 + c;
124 acc = acc * 85 + c;
125 }
125 }
126 if (i++ < len) {
126 if (i++ < len) {
127 c = b85dec[(int)*text++] - 1;
127 c = b85dec[(int)*text++] - 1;
128 if (c < 0) {
128 if (c < 0) {
129 PyErr_Format(
129 PyErr_Format(
130 PyExc_ValueError,
130 PyExc_ValueError,
131 "bad base85 character at position %d",
131 "bad base85 character at position %d",
132 (int)i);
132 (int)i);
133 goto bail;
133 goto bail;
134 }
134 }
135 /* overflow detection: 0xffffffff == "|NsC0",
135 /* overflow detection: 0xffffffff == "|NsC0",
136 * "|NsC" == 0x03030303 */
136 * "|NsC" == 0x03030303 */
137 if (acc > 0x03030303 || (acc *= 85) > 0xffffffff - c) {
137 if (acc > 0x03030303 || (acc *= 85) > 0xffffffff - c) {
138 PyErr_Format(
138 PyErr_Format(
139 PyExc_ValueError,
139 PyExc_ValueError,
140 "bad base85 sequence at position %d",
140 "bad base85 sequence at position %d",
141 (int)i);
141 (int)i);
142 goto bail;
142 goto bail;
143 }
143 }
144 acc += c;
144 acc += c;
145 }
145 }
146
146
147 cap = olen < 4 ? olen : 4;
147 cap = olen < 4 ? olen : 4;
148 olen -= cap;
148 olen -= cap;
149 for (j = 0; j < 4 - cap; j++) {
149 for (j = 0; j < 4 - cap; j++) {
150 acc *= 85;
150 acc *= 85;
151 }
151 }
152 if (cap && cap < 4) {
152 if (cap && cap < 4) {
153 acc += 0xffffff >> (cap - 1) * 8;
153 acc += 0xffffff >> (cap - 1) * 8;
154 }
154 }
155 for (j = 0; j < cap; j++) {
155 for (j = 0; j < cap; j++) {
156 acc = (acc << 8) | (acc >> 24);
156 acc = (acc << 8) | (acc >> 24);
157 *dst++ = acc;
157 *dst++ = acc;
158 }
158 }
159 }
159 }
160
160
161 return out;
161 return out;
162 bail:
162 bail:
163 Py_XDECREF(out);
163 Py_XDECREF(out);
164 return NULL;
164 return NULL;
165 }
165 }
166
166
167 static char base85_doc[] = "Base85 Data Encoding";
167 static char base85_doc[] = "Base85 Data Encoding";
168
168
169 static PyMethodDef methods[] = {
169 static PyMethodDef methods[] = {
170 {"b85encode", b85encode, METH_VARARGS,
170 {"b85encode", b85encode, METH_VARARGS,
171 "Encode text in base85.\n\n"
171 "Encode text in base85.\n\n"
172 "If the second parameter is true, pad the result to a multiple of "
172 "If the second parameter is true, pad the result to a multiple of "
173 "five characters.\n"},
173 "five characters.\n"},
174 {"b85decode", b85decode, METH_VARARGS, "Decode base85 text.\n"},
174 {"b85decode", b85decode, METH_VARARGS, "Decode base85 text.\n"},
175 {NULL, NULL},
175 {NULL, NULL},
176 };
176 };
177
177
178 static const int version = 1;
178 static const int version = 1;
179
179
180 static struct PyModuleDef base85_module = {
180 static struct PyModuleDef base85_module = {
181 PyModuleDef_HEAD_INIT, "base85", base85_doc, -1, methods,
181 PyModuleDef_HEAD_INIT, "base85", base85_doc, -1, methods,
182 };
182 };
183
183
184 PyMODINIT_FUNC PyInit_base85(void)
184 PyMODINIT_FUNC PyInit_base85(void)
185 {
185 {
186 PyObject *m;
186 PyObject *m;
187 b85prep();
187 b85prep();
188
188
189 m = PyModule_Create(&base85_module);
189 m = PyModule_Create(&base85_module);
190 PyModule_AddIntConstant(m, "version", version);
190 PyModule_AddIntConstant(m, "version", version);
191 return m;
191 return m;
192 }
192 }
@@ -1,350 +1,348 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 Olivia Mackall <olivia@selenic.com>
4 Copyright 2005, 2006 Olivia Mackall <olivia@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 <limits.h>
15 #include <stdlib.h>
15 #include <stdlib.h>
16 #include <string.h>
16 #include <string.h>
17
17
18 #include "bdiff.h"
18 #include "bdiff.h"
19 #include "bitmanipulation.h"
19 #include "bitmanipulation.h"
20 #include "thirdparty/xdiff/xdiff.h"
20 #include "thirdparty/xdiff/xdiff.h"
21 #include "util.h"
21 #include "util.h"
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
35
36 an = bdiff_splitlines(PyBytes_AsString(sa), PyBytes_Size(sa), &a);
36 an = bdiff_splitlines(PyBytes_AsString(sa), PyBytes_Size(sa), &a);
37 bn = bdiff_splitlines(PyBytes_AsString(sb), PyBytes_Size(sb), &b);
37 bn = bdiff_splitlines(PyBytes_AsString(sb), PyBytes_Size(sb), &b);
38
38
39 if (!a || !b) {
39 if (!a || !b) {
40 goto nomem;
40 goto nomem;
41 }
41 }
42
42
43 count = bdiff_diff(a, an, b, bn, &l);
43 count = bdiff_diff(a, an, b, bn, &l);
44 if (count < 0) {
44 if (count < 0) {
45 goto nomem;
45 goto nomem;
46 }
46 }
47
47
48 rl = PyList_New(count);
48 rl = PyList_New(count);
49 if (!rl) {
49 if (!rl) {
50 goto nomem;
50 goto nomem;
51 }
51 }
52
52
53 for (h = l.next; h; h = h->next) {
53 for (h = l.next; h; h = h->next) {
54 m = Py_BuildValue("iiii", h->a1, h->a2, h->b1, h->b2);
54 m = Py_BuildValue("iiii", h->a1, h->a2, h->b1, h->b2);
55 PyList_SetItem(rl, pos, m);
55 PyList_SetItem(rl, pos, m);
56 pos++;
56 pos++;
57 }
57 }
58
58
59 nomem:
59 nomem:
60 free(a);
60 free(a);
61 free(b);
61 free(b);
62 bdiff_freehunks(l.next);
62 bdiff_freehunks(l.next);
63 return rl ? rl : PyErr_NoMemory();
63 return rl ? rl : PyErr_NoMemory();
64 }
64 }
65
65
66 static PyObject *bdiff(PyObject *self, PyObject *args)
66 static PyObject *bdiff(PyObject *self, PyObject *args)
67 {
67 {
68 Py_buffer ba, bb;
68 Py_buffer ba, bb;
69 char *rb, *ia, *ib;
69 char *rb, *ia, *ib;
70 PyObject *result = NULL;
70 PyObject *result = NULL;
71 struct bdiff_line *al = NULL, *bl = NULL;
71 struct bdiff_line *al = NULL, *bl = NULL;
72 struct bdiff_hunk l, *h;
72 struct bdiff_hunk l, *h;
73 int an, bn, count;
73 int an, bn, count;
74 Py_ssize_t len = 0, la, lb, li = 0, lcommon = 0, lmax;
74 Py_ssize_t len = 0, la, lb, li = 0, lcommon = 0, lmax;
75 PyThreadState *_save = NULL;
75 PyThreadState *_save = NULL;
76
76
77 l.next = NULL;
77 l.next = NULL;
78
78
79 if (!PyArg_ParseTuple(args, PY23("s*s*:bdiff", "y*y*:bdiff"), &ba,
79 if (!PyArg_ParseTuple(args, "y*y*:bdiff", &ba, &bb)) {
80 &bb)) {
81 return NULL;
80 return NULL;
82 }
81 }
83
82
84 if (!PyBuffer_IsContiguous(&ba, 'C') || ba.ndim > 1) {
83 if (!PyBuffer_IsContiguous(&ba, 'C') || ba.ndim > 1) {
85 PyErr_SetString(PyExc_ValueError, "bdiff input not contiguous");
84 PyErr_SetString(PyExc_ValueError, "bdiff input not contiguous");
86 goto cleanup;
85 goto cleanup;
87 }
86 }
88
87
89 if (!PyBuffer_IsContiguous(&bb, 'C') || bb.ndim > 1) {
88 if (!PyBuffer_IsContiguous(&bb, 'C') || bb.ndim > 1) {
90 PyErr_SetString(PyExc_ValueError, "bdiff input not contiguous");
89 PyErr_SetString(PyExc_ValueError, "bdiff input not contiguous");
91 goto cleanup;
90 goto cleanup;
92 }
91 }
93
92
94 la = ba.len;
93 la = ba.len;
95 lb = bb.len;
94 lb = bb.len;
96
95
97 if (la > UINT_MAX || lb > UINT_MAX) {
96 if (la > UINT_MAX || lb > UINT_MAX) {
98 PyErr_SetString(PyExc_ValueError, "bdiff inputs too large");
97 PyErr_SetString(PyExc_ValueError, "bdiff inputs too large");
99 goto cleanup;
98 goto cleanup;
100 }
99 }
101
100
102 _save = PyEval_SaveThread();
101 _save = PyEval_SaveThread();
103
102
104 lmax = la > lb ? lb : la;
103 lmax = la > lb ? lb : la;
105 for (ia = ba.buf, ib = bb.buf; li < lmax && *ia == *ib;
104 for (ia = ba.buf, ib = bb.buf; li < lmax && *ia == *ib;
106 ++li, ++ia, ++ib) {
105 ++li, ++ia, ++ib) {
107 if (*ia == '\n') {
106 if (*ia == '\n') {
108 lcommon = li + 1;
107 lcommon = li + 1;
109 }
108 }
110 }
109 }
111 /* we can almost add: if (li == lmax) lcommon = li; */
110 /* we can almost add: if (li == lmax) lcommon = li; */
112
111
113 an = bdiff_splitlines((char *)ba.buf + lcommon, la - lcommon, &al);
112 an = bdiff_splitlines((char *)ba.buf + lcommon, la - lcommon, &al);
114 bn = bdiff_splitlines((char *)bb.buf + lcommon, lb - lcommon, &bl);
113 bn = bdiff_splitlines((char *)bb.buf + lcommon, lb - lcommon, &bl);
115 if (!al || !bl) {
114 if (!al || !bl) {
116 PyErr_NoMemory();
115 PyErr_NoMemory();
117 goto cleanup;
116 goto cleanup;
118 }
117 }
119
118
120 count = bdiff_diff(al, an, bl, bn, &l);
119 count = bdiff_diff(al, an, bl, bn, &l);
121 if (count < 0) {
120 if (count < 0) {
122 PyErr_NoMemory();
121 PyErr_NoMemory();
123 goto cleanup;
122 goto cleanup;
124 }
123 }
125
124
126 /* calculate length of output */
125 /* calculate length of output */
127 la = lb = 0;
126 la = lb = 0;
128 for (h = l.next; h; h = h->next) {
127 for (h = l.next; h; h = h->next) {
129 if (h->a1 != la || h->b1 != lb) {
128 if (h->a1 != la || h->b1 != lb) {
130 len += 12 + bl[h->b1].l - bl[lb].l;
129 len += 12 + bl[h->b1].l - bl[lb].l;
131 }
130 }
132 la = h->a2;
131 la = h->a2;
133 lb = h->b2;
132 lb = h->b2;
134 }
133 }
135 PyEval_RestoreThread(_save);
134 PyEval_RestoreThread(_save);
136 _save = NULL;
135 _save = NULL;
137
136
138 result = PyBytes_FromStringAndSize(NULL, len);
137 result = PyBytes_FromStringAndSize(NULL, len);
139
138
140 if (!result) {
139 if (!result) {
141 goto cleanup;
140 goto cleanup;
142 }
141 }
143
142
144 /* build binary patch */
143 /* build binary patch */
145 rb = PyBytes_AsString(result);
144 rb = PyBytes_AsString(result);
146 la = lb = 0;
145 la = lb = 0;
147
146
148 for (h = l.next; h; h = h->next) {
147 for (h = l.next; h; h = h->next) {
149 if (h->a1 != la || h->b1 != lb) {
148 if (h->a1 != la || h->b1 != lb) {
150 len = bl[h->b1].l - bl[lb].l;
149 len = bl[h->b1].l - bl[lb].l;
151 putbe32((uint32_t)(al[la].l + lcommon - al->l), rb);
150 putbe32((uint32_t)(al[la].l + lcommon - al->l), rb);
152 putbe32((uint32_t)(al[h->a1].l + lcommon - al->l),
151 putbe32((uint32_t)(al[h->a1].l + lcommon - al->l),
153 rb + 4);
152 rb + 4);
154 putbe32((uint32_t)len, rb + 8);
153 putbe32((uint32_t)len, rb + 8);
155 memcpy(rb + 12, bl[lb].l, len);
154 memcpy(rb + 12, bl[lb].l, len);
156 rb += 12 + len;
155 rb += 12 + len;
157 }
156 }
158 la = h->a2;
157 la = h->a2;
159 lb = h->b2;
158 lb = h->b2;
160 }
159 }
161
160
162 cleanup:
161 cleanup:
163 if (_save) {
162 if (_save) {
164 PyEval_RestoreThread(_save);
163 PyEval_RestoreThread(_save);
165 }
164 }
166 PyBuffer_Release(&ba);
165 PyBuffer_Release(&ba);
167 PyBuffer_Release(&bb);
166 PyBuffer_Release(&bb);
168 free(al);
167 free(al);
169 free(bl);
168 free(bl);
170 bdiff_freehunks(l.next);
169 bdiff_freehunks(l.next);
171 return result;
170 return result;
172 }
171 }
173
172
174 /*
173 /*
175 * If allws != 0, remove all whitespace (' ', \t and \r). Otherwise,
174 * If allws != 0, remove all whitespace (' ', \t and \r). Otherwise,
176 * reduce whitespace sequences to a single space and trim remaining whitespace
175 * reduce whitespace sequences to a single space and trim remaining whitespace
177 * from end of lines.
176 * from end of lines.
178 */
177 */
179 static PyObject *fixws(PyObject *self, PyObject *args)
178 static PyObject *fixws(PyObject *self, PyObject *args)
180 {
179 {
181 PyObject *s, *result = NULL;
180 PyObject *s, *result = NULL;
182 char allws, c;
181 char allws, c;
183 const char *r;
182 const char *r;
184 Py_ssize_t i, rlen, wlen = 0;
183 Py_ssize_t i, rlen, wlen = 0;
185 char *w;
184 char *w;
186
185
187 if (!PyArg_ParseTuple(args, "Sb:fixws", &s, &allws)) {
186 if (!PyArg_ParseTuple(args, "Sb:fixws", &s, &allws)) {
188 return NULL;
187 return NULL;
189 }
188 }
190 r = PyBytes_AsString(s);
189 r = PyBytes_AsString(s);
191 rlen = PyBytes_Size(s);
190 rlen = PyBytes_Size(s);
192
191
193 w = (char *)PyMem_Malloc(rlen ? rlen : 1);
192 w = (char *)PyMem_Malloc(rlen ? rlen : 1);
194 if (!w) {
193 if (!w) {
195 goto nomem;
194 goto nomem;
196 }
195 }
197
196
198 for (i = 0; i != rlen; i++) {
197 for (i = 0; i != rlen; i++) {
199 c = r[i];
198 c = r[i];
200 if (c == ' ' || c == '\t' || c == '\r') {
199 if (c == ' ' || c == '\t' || c == '\r') {
201 if (!allws && (wlen == 0 || w[wlen - 1] != ' ')) {
200 if (!allws && (wlen == 0 || w[wlen - 1] != ' ')) {
202 w[wlen++] = ' ';
201 w[wlen++] = ' ';
203 }
202 }
204 } else if (c == '\n' && !allws && wlen > 0 &&
203 } else if (c == '\n' && !allws && wlen > 0 &&
205 w[wlen - 1] == ' ') {
204 w[wlen - 1] == ' ') {
206 w[wlen - 1] = '\n';
205 w[wlen - 1] = '\n';
207 } else {
206 } else {
208 w[wlen++] = c;
207 w[wlen++] = c;
209 }
208 }
210 }
209 }
211
210
212 result = PyBytes_FromStringAndSize(w, wlen);
211 result = PyBytes_FromStringAndSize(w, wlen);
213
212
214 nomem:
213 nomem:
215 PyMem_Free(w);
214 PyMem_Free(w);
216 return result ? result : PyErr_NoMemory();
215 return result ? result : PyErr_NoMemory();
217 }
216 }
218
217
219 static bool sliceintolist(PyObject *list, Py_ssize_t destidx,
218 static bool sliceintolist(PyObject *list, Py_ssize_t destidx,
220 const char *source, Py_ssize_t len)
219 const char *source, Py_ssize_t len)
221 {
220 {
222 PyObject *sliced = PyBytes_FromStringAndSize(source, len);
221 PyObject *sliced = PyBytes_FromStringAndSize(source, len);
223 if (sliced == NULL) {
222 if (sliced == NULL) {
224 return false;
223 return false;
225 }
224 }
226 PyList_SET_ITEM(list, destidx, sliced);
225 PyList_SET_ITEM(list, destidx, sliced);
227 return true;
226 return true;
228 }
227 }
229
228
230 static PyObject *splitnewlines(PyObject *self, PyObject *args)
229 static PyObject *splitnewlines(PyObject *self, PyObject *args)
231 {
230 {
232 const char *text;
231 const char *text;
233 Py_ssize_t nelts = 0, size, i, start = 0;
232 Py_ssize_t nelts = 0, size, i, start = 0;
234 PyObject *result = NULL;
233 PyObject *result = NULL;
235
234
236 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &text, &size)) {
235 if (!PyArg_ParseTuple(args, "y#", &text, &size)) {
237 goto abort;
236 goto abort;
238 }
237 }
239 if (!size) {
238 if (!size) {
240 return PyList_New(0);
239 return PyList_New(0);
241 }
240 }
242 /* This loops to size-1 because if the last byte is a newline,
241 /* This loops to size-1 because if the last byte is a newline,
243 * we don't want to perform a split there. */
242 * we don't want to perform a split there. */
244 for (i = 0; i < size - 1; ++i) {
243 for (i = 0; i < size - 1; ++i) {
245 if (text[i] == '\n') {
244 if (text[i] == '\n') {
246 ++nelts;
245 ++nelts;
247 }
246 }
248 }
247 }
249 if ((result = PyList_New(nelts + 1)) == NULL) {
248 if ((result = PyList_New(nelts + 1)) == NULL) {
250 goto abort;
249 goto abort;
251 }
250 }
252 nelts = 0;
251 nelts = 0;
253 for (i = 0; i < size - 1; ++i) {
252 for (i = 0; i < size - 1; ++i) {
254 if (text[i] == '\n') {
253 if (text[i] == '\n') {
255 if (!sliceintolist(result, nelts++, text + start,
254 if (!sliceintolist(result, nelts++, text + start,
256 i - start + 1)) {
255 i - start + 1)) {
257 goto abort;
256 goto abort;
258 }
257 }
259 start = i + 1;
258 start = i + 1;
260 }
259 }
261 }
260 }
262 if (!sliceintolist(result, nelts++, text + start, size - start)) {
261 if (!sliceintolist(result, nelts++, text + start, size - start)) {
263 goto abort;
262 goto abort;
264 }
263 }
265 return result;
264 return result;
266 abort:
265 abort:
267 Py_XDECREF(result);
266 Py_XDECREF(result);
268 return NULL;
267 return NULL;
269 }
268 }
270
269
271 static int hunk_consumer(int64_t a1, int64_t a2, int64_t b1, int64_t b2,
270 static int hunk_consumer(int64_t a1, int64_t a2, int64_t b1, int64_t b2,
272 void *priv)
271 void *priv)
273 {
272 {
274 PyObject *rl = (PyObject *)priv;
273 PyObject *rl = (PyObject *)priv;
275 PyObject *m = Py_BuildValue("LLLL", a1, a2, b1, b2);
274 PyObject *m = Py_BuildValue("LLLL", a1, a2, b1, b2);
276 int r;
275 int r;
277 if (!m) {
276 if (!m) {
278 return -1;
277 return -1;
279 }
278 }
280 r = PyList_Append(rl, m);
279 r = PyList_Append(rl, m);
281 Py_DECREF(m);
280 Py_DECREF(m);
282 return r;
281 return r;
283 }
282 }
284
283
285 static PyObject *xdiffblocks(PyObject *self, PyObject *args)
284 static PyObject *xdiffblocks(PyObject *self, PyObject *args)
286 {
285 {
287 Py_ssize_t la, lb;
286 Py_ssize_t la, lb;
288 mmfile_t a, b;
287 mmfile_t a, b;
289 PyObject *rl;
288 PyObject *rl;
290
289
291 xpparam_t xpp = {
290 xpparam_t xpp = {
292 XDF_INDENT_HEURISTIC, /* flags */
291 XDF_INDENT_HEURISTIC, /* flags */
293 };
292 };
294 xdemitconf_t xecfg = {
293 xdemitconf_t xecfg = {
295 XDL_EMIT_BDIFFHUNK, /* flags */
294 XDL_EMIT_BDIFFHUNK, /* flags */
296 hunk_consumer, /* hunk_consume_func */
295 hunk_consumer, /* hunk_consume_func */
297 };
296 };
298 xdemitcb_t ecb = {
297 xdemitcb_t ecb = {
299 NULL, /* priv */
298 NULL, /* priv */
300 };
299 };
301
300
302 if (!PyArg_ParseTuple(args, PY23("s#s#", "y#y#"), &a.ptr, &la, &b.ptr,
301 if (!PyArg_ParseTuple(args, "y#y#", &a.ptr, &la, &b.ptr, &lb)) {
303 &lb)) {
304 return NULL;
302 return NULL;
305 }
303 }
306
304
307 a.size = la;
305 a.size = la;
308 b.size = lb;
306 b.size = lb;
309
307
310 rl = PyList_New(0);
308 rl = PyList_New(0);
311 if (!rl) {
309 if (!rl) {
312 return PyErr_NoMemory();
310 return PyErr_NoMemory();
313 }
311 }
314
312
315 ecb.priv = rl;
313 ecb.priv = rl;
316
314
317 if (xdl_diff(&a, &b, &xpp, &xecfg, &ecb) != 0) {
315 if (xdl_diff(&a, &b, &xpp, &xecfg, &ecb) != 0) {
318 Py_DECREF(rl);
316 Py_DECREF(rl);
319 return PyErr_NoMemory();
317 return PyErr_NoMemory();
320 }
318 }
321
319
322 return rl;
320 return rl;
323 }
321 }
324
322
325 static char mdiff_doc[] = "Efficient binary diff.";
323 static char mdiff_doc[] = "Efficient binary diff.";
326
324
327 static PyMethodDef methods[] = {
325 static PyMethodDef methods[] = {
328 {"bdiff", bdiff, METH_VARARGS, "calculate a binary diff\n"},
326 {"bdiff", bdiff, METH_VARARGS, "calculate a binary diff\n"},
329 {"blocks", blocks, METH_VARARGS, "find a list of matching lines\n"},
327 {"blocks", blocks, METH_VARARGS, "find a list of matching lines\n"},
330 {"fixws", fixws, METH_VARARGS, "normalize diff whitespaces\n"},
328 {"fixws", fixws, METH_VARARGS, "normalize diff whitespaces\n"},
331 {"splitnewlines", splitnewlines, METH_VARARGS,
329 {"splitnewlines", splitnewlines, METH_VARARGS,
332 "like str.splitlines, but only split on newlines\n"},
330 "like str.splitlines, but only split on newlines\n"},
333 {"xdiffblocks", xdiffblocks, METH_VARARGS,
331 {"xdiffblocks", xdiffblocks, METH_VARARGS,
334 "find a list of matching lines using xdiff algorithm\n"},
332 "find a list of matching lines using xdiff algorithm\n"},
335 {NULL, NULL},
333 {NULL, NULL},
336 };
334 };
337
335
338 static const int version = 3;
336 static const int version = 3;
339
337
340 static struct PyModuleDef bdiff_module = {
338 static struct PyModuleDef bdiff_module = {
341 PyModuleDef_HEAD_INIT, "bdiff", mdiff_doc, -1, methods,
339 PyModuleDef_HEAD_INIT, "bdiff", mdiff_doc, -1, methods,
342 };
340 };
343
341
344 PyMODINIT_FUNC PyInit_bdiff(void)
342 PyMODINIT_FUNC PyInit_bdiff(void)
345 {
343 {
346 PyObject *m;
344 PyObject *m;
347 m = PyModule_Create(&bdiff_module);
345 m = PyModule_Create(&bdiff_module);
348 PyModule_AddIntConstant(m, "version", version);
346 PyModule_AddIntConstant(m, "version", version);
349 return m;
347 return m;
350 }
348 }
@@ -1,405 +1,404 b''
1 /*
1 /*
2 charencode.c - miscellaneous character encoding
2 charencode.c - miscellaneous character encoding
3
3
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #define PY_SSIZE_T_CLEAN
10 #define PY_SSIZE_T_CLEAN
11 #include <Python.h>
11 #include <Python.h>
12 #include <assert.h>
12 #include <assert.h>
13
13
14 #include "charencode.h"
14 #include "charencode.h"
15 #include "compat.h"
15 #include "compat.h"
16 #include "util.h"
16 #include "util.h"
17
17
18 /* clang-format off */
18 /* clang-format off */
19 static const char lowertable[128] = {
19 static const char lowertable[128] = {
20 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
20 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
21 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
21 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
22 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
22 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
23 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
23 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
24 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
24 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
25 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
25 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
26 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
26 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
27 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
27 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
28 '\x40',
28 '\x40',
29 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
29 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
30 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
30 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
31 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
31 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
32 '\x78', '\x79', '\x7a', /* X-Z */
32 '\x78', '\x79', '\x7a', /* X-Z */
33 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
33 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
34 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
34 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
35 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
35 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
36 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
36 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
37 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
37 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
38 };
38 };
39
39
40 static const char uppertable[128] = {
40 static const char uppertable[128] = {
41 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
41 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
42 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
42 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
43 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
43 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
44 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
44 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
45 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
45 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
46 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
46 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
47 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
47 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
48 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
48 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
49 '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
49 '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
50 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f',
50 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f',
51 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
51 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
52 '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
52 '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
53 '\x60',
53 '\x60',
54 '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', /* a-g */
54 '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', /* a-g */
55 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', /* h-o */
55 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', /* h-o */
56 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', /* p-w */
56 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', /* p-w */
57 '\x58', '\x59', '\x5a', /* x-z */
57 '\x58', '\x59', '\x5a', /* x-z */
58 '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
58 '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
59 };
59 };
60
60
61 /* 1: no escape, 2: \<c>, 6: \u<x> */
61 /* 1: no escape, 2: \<c>, 6: \u<x> */
62 static const uint8_t jsonlentable[256] = {
62 static const uint8_t jsonlentable[256] = {
63 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, 6, 2, 2, 6, 6, /* b, t, n, f, r */
63 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, 6, 2, 2, 6, 6, /* b, t, n, f, r */
64 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
64 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
65 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* " */
65 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* " */
66 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
66 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
67 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
67 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
68 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, /* \\ */
68 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, /* \\ */
69 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
69 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
70 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, /* DEL */
70 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, /* DEL */
71 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
71 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
72 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
72 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
74 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
74 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
75 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
75 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
76 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
76 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
77 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
77 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
79 };
79 };
80
80
81 static const uint8_t jsonparanoidlentable[128] = {
81 static const uint8_t jsonparanoidlentable[128] = {
82 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, 6, 2, 2, 6, 6, /* b, t, n, f, r */
82 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, 6, 2, 2, 6, 6, /* b, t, n, f, r */
83 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
83 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
84 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* " */
84 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* " */
85 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 6, 1, /* <, > */
85 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 6, 1, /* <, > */
86 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
86 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
87 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, /* \\ */
87 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, /* \\ */
88 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
88 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
89 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, /* DEL */
89 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, /* DEL */
90 };
90 };
91
91
92 static const char hexchartable[16] = {
92 static const char hexchartable[16] = {
93 '0', '1', '2', '3', '4', '5', '6', '7',
93 '0', '1', '2', '3', '4', '5', '6', '7',
94 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
94 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
95 };
95 };
96 /* clang-format on */
96 /* clang-format on */
97
97
98 /*
98 /*
99 * Turn a hex-encoded string into binary.
99 * Turn a hex-encoded string into binary.
100 */
100 */
101 PyObject *unhexlify(const char *str, Py_ssize_t len)
101 PyObject *unhexlify(const char *str, Py_ssize_t len)
102 {
102 {
103 PyObject *ret;
103 PyObject *ret;
104 char *d;
104 char *d;
105 Py_ssize_t i;
105 Py_ssize_t i;
106
106
107 ret = PyBytes_FromStringAndSize(NULL, len / 2);
107 ret = PyBytes_FromStringAndSize(NULL, len / 2);
108
108
109 if (!ret) {
109 if (!ret) {
110 return NULL;
110 return NULL;
111 }
111 }
112
112
113 d = PyBytes_AsString(ret);
113 d = PyBytes_AsString(ret);
114
114
115 for (i = 0; i < len;) {
115 for (i = 0; i < len;) {
116 int hi = hexdigit(str, i++);
116 int hi = hexdigit(str, i++);
117 int lo = hexdigit(str, i++);
117 int lo = hexdigit(str, i++);
118 *d++ = (hi << 4) | lo;
118 *d++ = (hi << 4) | lo;
119 }
119 }
120
120
121 return ret;
121 return ret;
122 }
122 }
123
123
124 PyObject *isasciistr(PyObject *self, PyObject *args)
124 PyObject *isasciistr(PyObject *self, PyObject *args)
125 {
125 {
126 const char *buf;
126 const char *buf;
127 Py_ssize_t i, len;
127 Py_ssize_t i, len;
128 if (!PyArg_ParseTuple(args, PY23("s#:isasciistr", "y#:isasciistr"),
128 if (!PyArg_ParseTuple(args, "y#:isasciistr", &buf, &len)) {
129 &buf, &len)) {
130 return NULL;
129 return NULL;
131 }
130 }
132 i = 0;
131 i = 0;
133 /* char array in PyStringObject should be at least 4-byte aligned */
132 /* char array in PyStringObject should be at least 4-byte aligned */
134 if (((uintptr_t)buf & 3) == 0) {
133 if (((uintptr_t)buf & 3) == 0) {
135 const uint32_t *p = (const uint32_t *)buf;
134 const uint32_t *p = (const uint32_t *)buf;
136 for (; i < len / 4; i++) {
135 for (; i < len / 4; i++) {
137 if (p[i] & 0x80808080U) {
136 if (p[i] & 0x80808080U) {
138 Py_RETURN_FALSE;
137 Py_RETURN_FALSE;
139 }
138 }
140 }
139 }
141 i *= 4;
140 i *= 4;
142 }
141 }
143 for (; i < len; i++) {
142 for (; i < len; i++) {
144 if (buf[i] & 0x80) {
143 if (buf[i] & 0x80) {
145 Py_RETURN_FALSE;
144 Py_RETURN_FALSE;
146 }
145 }
147 }
146 }
148 Py_RETURN_TRUE;
147 Py_RETURN_TRUE;
149 }
148 }
150
149
151 static inline PyObject *
150 static inline PyObject *
152 _asciitransform(PyObject *str_obj, const char table[128], PyObject *fallback_fn)
151 _asciitransform(PyObject *str_obj, const char table[128], PyObject *fallback_fn)
153 {
152 {
154 char *str, *newstr;
153 char *str, *newstr;
155 Py_ssize_t i, len;
154 Py_ssize_t i, len;
156 PyObject *newobj = NULL;
155 PyObject *newobj = NULL;
157 PyObject *ret = NULL;
156 PyObject *ret = NULL;
158
157
159 str = PyBytes_AS_STRING(str_obj);
158 str = PyBytes_AS_STRING(str_obj);
160 len = PyBytes_GET_SIZE(str_obj);
159 len = PyBytes_GET_SIZE(str_obj);
161
160
162 newobj = PyBytes_FromStringAndSize(NULL, len);
161 newobj = PyBytes_FromStringAndSize(NULL, len);
163 if (!newobj) {
162 if (!newobj) {
164 goto quit;
163 goto quit;
165 }
164 }
166
165
167 newstr = PyBytes_AS_STRING(newobj);
166 newstr = PyBytes_AS_STRING(newobj);
168
167
169 for (i = 0; i < len; i++) {
168 for (i = 0; i < len; i++) {
170 char c = str[i];
169 char c = str[i];
171 if (c & 0x80) {
170 if (c & 0x80) {
172 if (fallback_fn != NULL) {
171 if (fallback_fn != NULL) {
173 ret = PyObject_CallFunctionObjArgs(
172 ret = PyObject_CallFunctionObjArgs(
174 fallback_fn, str_obj, NULL);
173 fallback_fn, str_obj, NULL);
175 } else {
174 } else {
176 PyObject *err = PyUnicodeDecodeError_Create(
175 PyObject *err = PyUnicodeDecodeError_Create(
177 "ascii", str, len, i, (i + 1),
176 "ascii", str, len, i, (i + 1),
178 "unexpected code byte");
177 "unexpected code byte");
179 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
178 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
180 Py_XDECREF(err);
179 Py_XDECREF(err);
181 }
180 }
182 goto quit;
181 goto quit;
183 }
182 }
184 newstr[i] = table[(unsigned char)c];
183 newstr[i] = table[(unsigned char)c];
185 }
184 }
186
185
187 ret = newobj;
186 ret = newobj;
188 Py_INCREF(ret);
187 Py_INCREF(ret);
189 quit:
188 quit:
190 Py_XDECREF(newobj);
189 Py_XDECREF(newobj);
191 return ret;
190 return ret;
192 }
191 }
193
192
194 PyObject *asciilower(PyObject *self, PyObject *args)
193 PyObject *asciilower(PyObject *self, PyObject *args)
195 {
194 {
196 PyObject *str_obj;
195 PyObject *str_obj;
197 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj)) {
196 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj)) {
198 return NULL;
197 return NULL;
199 }
198 }
200 return _asciitransform(str_obj, lowertable, NULL);
199 return _asciitransform(str_obj, lowertable, NULL);
201 }
200 }
202
201
203 PyObject *asciiupper(PyObject *self, PyObject *args)
202 PyObject *asciiupper(PyObject *self, PyObject *args)
204 {
203 {
205 PyObject *str_obj;
204 PyObject *str_obj;
206 if (!PyArg_ParseTuple(args, "O!:asciiupper", &PyBytes_Type, &str_obj)) {
205 if (!PyArg_ParseTuple(args, "O!:asciiupper", &PyBytes_Type, &str_obj)) {
207 return NULL;
206 return NULL;
208 }
207 }
209 return _asciitransform(str_obj, uppertable, NULL);
208 return _asciitransform(str_obj, uppertable, NULL);
210 }
209 }
211
210
212 PyObject *make_file_foldmap(PyObject *self, PyObject *args)
211 PyObject *make_file_foldmap(PyObject *self, PyObject *args)
213 {
212 {
214 PyObject *dmap, *spec_obj, *normcase_fallback;
213 PyObject *dmap, *spec_obj, *normcase_fallback;
215 PyObject *file_foldmap = NULL;
214 PyObject *file_foldmap = NULL;
216 enum normcase_spec spec;
215 enum normcase_spec spec;
217 PyObject *k, *v;
216 PyObject *k, *v;
218 dirstateItemObject *tuple;
217 dirstateItemObject *tuple;
219 Py_ssize_t pos = 0;
218 Py_ssize_t pos = 0;
220 const char *table;
219 const char *table;
221
220
222 if (!PyArg_ParseTuple(args, "O!O!O!:make_file_foldmap", &PyDict_Type,
221 if (!PyArg_ParseTuple(args, "O!O!O!:make_file_foldmap", &PyDict_Type,
223 &dmap, &PyLong_Type, &spec_obj, &PyFunction_Type,
222 &dmap, &PyLong_Type, &spec_obj, &PyFunction_Type,
224 &normcase_fallback)) {
223 &normcase_fallback)) {
225 goto quit;
224 goto quit;
226 }
225 }
227
226
228 spec = (int)PyLong_AS_LONG(spec_obj);
227 spec = (int)PyLong_AS_LONG(spec_obj);
229 switch (spec) {
228 switch (spec) {
230 case NORMCASE_LOWER:
229 case NORMCASE_LOWER:
231 table = lowertable;
230 table = lowertable;
232 break;
231 break;
233 case NORMCASE_UPPER:
232 case NORMCASE_UPPER:
234 table = uppertable;
233 table = uppertable;
235 break;
234 break;
236 case NORMCASE_OTHER:
235 case NORMCASE_OTHER:
237 table = NULL;
236 table = NULL;
238 break;
237 break;
239 default:
238 default:
240 PyErr_SetString(PyExc_TypeError, "invalid normcasespec");
239 PyErr_SetString(PyExc_TypeError, "invalid normcasespec");
241 goto quit;
240 goto quit;
242 }
241 }
243
242
244 /* Add some more entries to deal with additions outside this
243 /* Add some more entries to deal with additions outside this
245 function. */
244 function. */
246 file_foldmap = _dict_new_presized((PyDict_Size(dmap) / 10) * 11);
245 file_foldmap = _dict_new_presized((PyDict_Size(dmap) / 10) * 11);
247 if (file_foldmap == NULL) {
246 if (file_foldmap == NULL) {
248 goto quit;
247 goto quit;
249 }
248 }
250
249
251 while (PyDict_Next(dmap, &pos, &k, &v)) {
250 while (PyDict_Next(dmap, &pos, &k, &v)) {
252 if (!dirstate_tuple_check(v)) {
251 if (!dirstate_tuple_check(v)) {
253 PyErr_SetString(PyExc_TypeError,
252 PyErr_SetString(PyExc_TypeError,
254 "expected a dirstate tuple");
253 "expected a dirstate tuple");
255 goto quit;
254 goto quit;
256 }
255 }
257
256
258 tuple = (dirstateItemObject *)v;
257 tuple = (dirstateItemObject *)v;
259 if (tuple->flags | dirstate_flag_wc_tracked) {
258 if (tuple->flags | dirstate_flag_wc_tracked) {
260 PyObject *normed;
259 PyObject *normed;
261 if (table != NULL) {
260 if (table != NULL) {
262 normed = _asciitransform(k, table,
261 normed = _asciitransform(k, table,
263 normcase_fallback);
262 normcase_fallback);
264 } else {
263 } else {
265 normed = PyObject_CallFunctionObjArgs(
264 normed = PyObject_CallFunctionObjArgs(
266 normcase_fallback, k, NULL);
265 normcase_fallback, k, NULL);
267 }
266 }
268
267
269 if (normed == NULL) {
268 if (normed == NULL) {
270 goto quit;
269 goto quit;
271 }
270 }
272 if (PyDict_SetItem(file_foldmap, normed, k) == -1) {
271 if (PyDict_SetItem(file_foldmap, normed, k) == -1) {
273 Py_DECREF(normed);
272 Py_DECREF(normed);
274 goto quit;
273 goto quit;
275 }
274 }
276 Py_DECREF(normed);
275 Py_DECREF(normed);
277 }
276 }
278 }
277 }
279 return file_foldmap;
278 return file_foldmap;
280 quit:
279 quit:
281 Py_XDECREF(file_foldmap);
280 Py_XDECREF(file_foldmap);
282 return NULL;
281 return NULL;
283 }
282 }
284
283
285 /* calculate length of JSON-escaped string; returns -1 if unsupported */
284 /* calculate length of JSON-escaped string; returns -1 if unsupported */
286 static Py_ssize_t jsonescapelen(const char *buf, Py_ssize_t len, bool paranoid)
285 static Py_ssize_t jsonescapelen(const char *buf, Py_ssize_t len, bool paranoid)
287 {
286 {
288 Py_ssize_t i, esclen = 0;
287 Py_ssize_t i, esclen = 0;
289
288
290 if (paranoid) {
289 if (paranoid) {
291 /* don't want to process multi-byte escapes in C */
290 /* don't want to process multi-byte escapes in C */
292 for (i = 0; i < len; i++) {
291 for (i = 0; i < len; i++) {
293 char c = buf[i];
292 char c = buf[i];
294 if (c & 0x80) {
293 if (c & 0x80) {
295 PyErr_SetString(PyExc_ValueError,
294 PyErr_SetString(PyExc_ValueError,
296 "cannot process non-ascii str");
295 "cannot process non-ascii str");
297 return -1;
296 return -1;
298 }
297 }
299 esclen += jsonparanoidlentable[(unsigned char)c];
298 esclen += jsonparanoidlentable[(unsigned char)c];
300 if (esclen < 0) {
299 if (esclen < 0) {
301 PyErr_SetString(PyExc_MemoryError,
300 PyErr_SetString(PyExc_MemoryError,
302 "overflow in jsonescapelen");
301 "overflow in jsonescapelen");
303 return -1;
302 return -1;
304 }
303 }
305 }
304 }
306 } else {
305 } else {
307 for (i = 0; i < len; i++) {
306 for (i = 0; i < len; i++) {
308 char c = buf[i];
307 char c = buf[i];
309 esclen += jsonlentable[(unsigned char)c];
308 esclen += jsonlentable[(unsigned char)c];
310 if (esclen < 0) {
309 if (esclen < 0) {
311 PyErr_SetString(PyExc_MemoryError,
310 PyErr_SetString(PyExc_MemoryError,
312 "overflow in jsonescapelen");
311 "overflow in jsonescapelen");
313 return -1;
312 return -1;
314 }
313 }
315 }
314 }
316 }
315 }
317
316
318 return esclen;
317 return esclen;
319 }
318 }
320
319
321 /* map '\<c>' escape character */
320 /* map '\<c>' escape character */
322 static char jsonescapechar2(char c)
321 static char jsonescapechar2(char c)
323 {
322 {
324 switch (c) {
323 switch (c) {
325 case '\b':
324 case '\b':
326 return 'b';
325 return 'b';
327 case '\t':
326 case '\t':
328 return 't';
327 return 't';
329 case '\n':
328 case '\n':
330 return 'n';
329 return 'n';
331 case '\f':
330 case '\f':
332 return 'f';
331 return 'f';
333 case '\r':
332 case '\r':
334 return 'r';
333 return 'r';
335 case '"':
334 case '"':
336 return '"';
335 return '"';
337 case '\\':
336 case '\\':
338 return '\\';
337 return '\\';
339 }
338 }
340 return '\0'; /* should not happen */
339 return '\0'; /* should not happen */
341 }
340 }
342
341
343 /* convert 'origbuf' to JSON-escaped form 'escbuf'; 'origbuf' should only
342 /* convert 'origbuf' to JSON-escaped form 'escbuf'; 'origbuf' should only
344 include characters mappable by json(paranoid)lentable */
343 include characters mappable by json(paranoid)lentable */
345 static void encodejsonescape(char *escbuf, Py_ssize_t esclen,
344 static void encodejsonescape(char *escbuf, Py_ssize_t esclen,
346 const char *origbuf, Py_ssize_t origlen,
345 const char *origbuf, Py_ssize_t origlen,
347 bool paranoid)
346 bool paranoid)
348 {
347 {
349 const uint8_t *lentable =
348 const uint8_t *lentable =
350 (paranoid) ? jsonparanoidlentable : jsonlentable;
349 (paranoid) ? jsonparanoidlentable : jsonlentable;
351 Py_ssize_t i, j;
350 Py_ssize_t i, j;
352
351
353 for (i = 0, j = 0; i < origlen; i++) {
352 for (i = 0, j = 0; i < origlen; i++) {
354 char c = origbuf[i];
353 char c = origbuf[i];
355 uint8_t l = lentable[(unsigned char)c];
354 uint8_t l = lentable[(unsigned char)c];
356 assert(j + l <= esclen);
355 assert(j + l <= esclen);
357 switch (l) {
356 switch (l) {
358 case 1:
357 case 1:
359 escbuf[j] = c;
358 escbuf[j] = c;
360 break;
359 break;
361 case 2:
360 case 2:
362 escbuf[j] = '\\';
361 escbuf[j] = '\\';
363 escbuf[j + 1] = jsonescapechar2(c);
362 escbuf[j + 1] = jsonescapechar2(c);
364 break;
363 break;
365 case 6:
364 case 6:
366 memcpy(escbuf + j, "\\u00", 4);
365 memcpy(escbuf + j, "\\u00", 4);
367 escbuf[j + 4] = hexchartable[(unsigned char)c >> 4];
366 escbuf[j + 4] = hexchartable[(unsigned char)c >> 4];
368 escbuf[j + 5] = hexchartable[(unsigned char)c & 0xf];
367 escbuf[j + 5] = hexchartable[(unsigned char)c & 0xf];
369 break;
368 break;
370 }
369 }
371 j += l;
370 j += l;
372 }
371 }
373 }
372 }
374
373
375 PyObject *jsonescapeu8fast(PyObject *self, PyObject *args)
374 PyObject *jsonescapeu8fast(PyObject *self, PyObject *args)
376 {
375 {
377 PyObject *origstr, *escstr;
376 PyObject *origstr, *escstr;
378 const char *origbuf;
377 const char *origbuf;
379 Py_ssize_t origlen, esclen;
378 Py_ssize_t origlen, esclen;
380 int paranoid;
379 int paranoid;
381 if (!PyArg_ParseTuple(args, "O!i:jsonescapeu8fast", &PyBytes_Type,
380 if (!PyArg_ParseTuple(args, "O!i:jsonescapeu8fast", &PyBytes_Type,
382 &origstr, &paranoid)) {
381 &origstr, &paranoid)) {
383 return NULL;
382 return NULL;
384 }
383 }
385
384
386 origbuf = PyBytes_AS_STRING(origstr);
385 origbuf = PyBytes_AS_STRING(origstr);
387 origlen = PyBytes_GET_SIZE(origstr);
386 origlen = PyBytes_GET_SIZE(origstr);
388 esclen = jsonescapelen(origbuf, origlen, paranoid);
387 esclen = jsonescapelen(origbuf, origlen, paranoid);
389 if (esclen < 0) {
388 if (esclen < 0) {
390 return NULL; /* unsupported char found or overflow */
389 return NULL; /* unsupported char found or overflow */
391 }
390 }
392 if (origlen == esclen) {
391 if (origlen == esclen) {
393 Py_INCREF(origstr);
392 Py_INCREF(origstr);
394 return origstr;
393 return origstr;
395 }
394 }
396
395
397 escstr = PyBytes_FromStringAndSize(NULL, esclen);
396 escstr = PyBytes_FromStringAndSize(NULL, esclen);
398 if (!escstr) {
397 if (!escstr) {
399 return NULL;
398 return NULL;
400 }
399 }
401 encodejsonescape(PyBytes_AS_STRING(escstr), esclen, origbuf, origlen,
400 encodejsonescape(PyBytes_AS_STRING(escstr), esclen, origbuf, origlen,
402 paranoid);
401 paranoid);
403
402
404 return escstr;
403 return escstr;
405 }
404 }
@@ -1,999 +1,999 b''
1 /*
1 /*
2 * manifest.c - manifest type that does on-demand parsing.
2 * manifest.c - manifest type that does on-demand parsing.
3 *
3 *
4 * Copyright 2015, Google Inc.
4 * Copyright 2015, Google Inc.
5 *
5 *
6 * This software may be used and distributed according to the terms of
6 * This software may be used and distributed according to the terms of
7 * the GNU General Public License, incorporated herein by reference.
7 * the GNU General Public License, incorporated herein by reference.
8 */
8 */
9 #include <Python.h>
9 #include <Python.h>
10
10
11 #include <assert.h>
11 #include <assert.h>
12 #include <stdlib.h>
12 #include <stdlib.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "charencode.h"
15 #include "charencode.h"
16 #include "util.h"
16 #include "util.h"
17
17
18 #define DEFAULT_LINES 100000
18 #define DEFAULT_LINES 100000
19
19
20 typedef struct {
20 typedef struct {
21 char *start;
21 char *start;
22 Py_ssize_t len; /* length of line including terminal newline */
22 Py_ssize_t len; /* length of line including terminal newline */
23 char hash_suffix;
23 char hash_suffix;
24 bool from_malloc;
24 bool from_malloc;
25 bool deleted;
25 bool deleted;
26 } line;
26 } line;
27
27
28 typedef struct {
28 typedef struct {
29 PyObject_HEAD
29 PyObject_HEAD
30 PyObject *pydata;
30 PyObject *pydata;
31 Py_ssize_t nodelen;
31 Py_ssize_t nodelen;
32 line *lines;
32 line *lines;
33 int numlines; /* number of line entries */
33 int numlines; /* number of line entries */
34 int livelines; /* number of non-deleted lines */
34 int livelines; /* number of non-deleted lines */
35 int maxlines; /* allocated number of lines */
35 int maxlines; /* allocated number of lines */
36 bool dirty;
36 bool dirty;
37 } lazymanifest;
37 } lazymanifest;
38
38
39 #define MANIFEST_OOM -1
39 #define MANIFEST_OOM -1
40 #define MANIFEST_NOT_SORTED -2
40 #define MANIFEST_NOT_SORTED -2
41 #define MANIFEST_MALFORMED -3
41 #define MANIFEST_MALFORMED -3
42 #define MANIFEST_BOGUS_FILENAME -4
42 #define MANIFEST_BOGUS_FILENAME -4
43 #define MANIFEST_TOO_SHORT_LINE -5
43 #define MANIFEST_TOO_SHORT_LINE -5
44
44
45 /* get the length of the path for a line */
45 /* get the length of the path for a line */
46 static Py_ssize_t pathlen(line *l)
46 static Py_ssize_t pathlen(line *l)
47 {
47 {
48 const char *end = memchr(l->start, '\0', l->len);
48 const char *end = memchr(l->start, '\0', l->len);
49 return (end) ? (Py_ssize_t)(end - l->start) : l->len;
49 return (end) ? (Py_ssize_t)(end - l->start) : l->len;
50 }
50 }
51
51
52 /* get the node value of a single line */
52 /* get the node value of a single line */
53 static PyObject *nodeof(Py_ssize_t nodelen, line *l, char *flag)
53 static PyObject *nodeof(Py_ssize_t nodelen, line *l, char *flag)
54 {
54 {
55 char *s = l->start;
55 char *s = l->start;
56 Py_ssize_t llen = pathlen(l);
56 Py_ssize_t llen = pathlen(l);
57 Py_ssize_t hlen = l->len - llen - 2;
57 Py_ssize_t hlen = l->len - llen - 2;
58 PyObject *hash;
58 PyObject *hash;
59 if (llen + 1 + 40 + 1 > l->len) { /* path '\0' hash '\n' */
59 if (llen + 1 + 40 + 1 > l->len) { /* path '\0' hash '\n' */
60 PyErr_SetString(PyExc_ValueError, "manifest line too short");
60 PyErr_SetString(PyExc_ValueError, "manifest line too short");
61 return NULL;
61 return NULL;
62 }
62 }
63 /* Detect flags after the hash first. */
63 /* Detect flags after the hash first. */
64 switch (s[llen + hlen]) {
64 switch (s[llen + hlen]) {
65 case 'l':
65 case 'l':
66 case 't':
66 case 't':
67 case 'x':
67 case 'x':
68 *flag = s[llen + hlen];
68 *flag = s[llen + hlen];
69 --hlen;
69 --hlen;
70 break;
70 break;
71 default:
71 default:
72 *flag = '\0';
72 *flag = '\0';
73 break;
73 break;
74 }
74 }
75
75
76 if (hlen != 2 * nodelen) {
76 if (hlen != 2 * nodelen) {
77 PyErr_SetString(PyExc_ValueError, "invalid node length in manifest");
77 PyErr_SetString(PyExc_ValueError, "invalid node length in manifest");
78 return NULL;
78 return NULL;
79 }
79 }
80 hash = unhexlify(s + llen + 1, nodelen * 2);
80 hash = unhexlify(s + llen + 1, nodelen * 2);
81 if (!hash) {
81 if (!hash) {
82 return NULL;
82 return NULL;
83 }
83 }
84 if (l->hash_suffix != '\0') {
84 if (l->hash_suffix != '\0') {
85 char newhash[33];
85 char newhash[33];
86 memcpy(newhash, PyBytes_AsString(hash), nodelen);
86 memcpy(newhash, PyBytes_AsString(hash), nodelen);
87 Py_DECREF(hash);
87 Py_DECREF(hash);
88 newhash[nodelen] = l->hash_suffix;
88 newhash[nodelen] = l->hash_suffix;
89 hash = PyBytes_FromStringAndSize(newhash, nodelen + 1);
89 hash = PyBytes_FromStringAndSize(newhash, nodelen + 1);
90 }
90 }
91 return hash;
91 return hash;
92 }
92 }
93
93
94 /* get the node hash and flags of a line as a tuple */
94 /* get the node hash and flags of a line as a tuple */
95 static PyObject *hashflags(Py_ssize_t nodelen, line *l)
95 static PyObject *hashflags(Py_ssize_t nodelen, line *l)
96 {
96 {
97 char flag;
97 char flag;
98 PyObject *hash = nodeof(nodelen, l, &flag);
98 PyObject *hash = nodeof(nodelen, l, &flag);
99 PyObject *flags;
99 PyObject *flags;
100 PyObject *tup;
100 PyObject *tup;
101
101
102 if (!hash)
102 if (!hash)
103 return NULL;
103 return NULL;
104 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
104 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
105 if (!flags) {
105 if (!flags) {
106 Py_DECREF(hash);
106 Py_DECREF(hash);
107 return NULL;
107 return NULL;
108 }
108 }
109 tup = PyTuple_Pack(2, hash, flags);
109 tup = PyTuple_Pack(2, hash, flags);
110 Py_DECREF(flags);
110 Py_DECREF(flags);
111 Py_DECREF(hash);
111 Py_DECREF(hash);
112 return tup;
112 return tup;
113 }
113 }
114
114
115 /* if we're about to run out of space in the line index, add more */
115 /* if we're about to run out of space in the line index, add more */
116 static bool realloc_if_full(lazymanifest *self)
116 static bool realloc_if_full(lazymanifest *self)
117 {
117 {
118 if (self->numlines == self->maxlines) {
118 if (self->numlines == self->maxlines) {
119 self->maxlines *= 2;
119 self->maxlines *= 2;
120 self->lines = realloc(self->lines, self->maxlines * sizeof(line));
120 self->lines = realloc(self->lines, self->maxlines * sizeof(line));
121 }
121 }
122 return !!self->lines;
122 return !!self->lines;
123 }
123 }
124
124
125 /*
125 /*
126 * Find the line boundaries in the manifest that 'data' points to and store
126 * Find the line boundaries in the manifest that 'data' points to and store
127 * information about each line in 'self'.
127 * information about each line in 'self'.
128 */
128 */
129 static int find_lines(lazymanifest *self, char *data, Py_ssize_t len)
129 static int find_lines(lazymanifest *self, char *data, Py_ssize_t len)
130 {
130 {
131 char *prev = NULL;
131 char *prev = NULL;
132 while (len > 0) {
132 while (len > 0) {
133 line *l;
133 line *l;
134 char *next;
134 char *next;
135 if (*data == '\0') {
135 if (*data == '\0') {
136 /* It's implausible there's no filename, don't
136 /* It's implausible there's no filename, don't
137 * even bother looking for the newline. */
137 * even bother looking for the newline. */
138 return MANIFEST_BOGUS_FILENAME;
138 return MANIFEST_BOGUS_FILENAME;
139 }
139 }
140 next = memchr(data, '\n', len);
140 next = memchr(data, '\n', len);
141 if (!next) {
141 if (!next) {
142 return MANIFEST_MALFORMED;
142 return MANIFEST_MALFORMED;
143 }
143 }
144 if ((next - data) < 42) {
144 if ((next - data) < 42) {
145 /* We should have at least 42 bytes in a line:
145 /* We should have at least 42 bytes in a line:
146 1 byte filename
146 1 byte filename
147 1 NUL
147 1 NUL
148 40 bytes of hash
148 40 bytes of hash
149 so we can give up here.
149 so we can give up here.
150 */
150 */
151 return MANIFEST_TOO_SHORT_LINE;
151 return MANIFEST_TOO_SHORT_LINE;
152 }
152 }
153 next++; /* advance past newline */
153 next++; /* advance past newline */
154 if (prev && strcmp(prev, data) > -1) {
154 if (prev && strcmp(prev, data) > -1) {
155 /* This data isn't sorted, so we have to abort. */
155 /* This data isn't sorted, so we have to abort. */
156 return MANIFEST_NOT_SORTED;
156 return MANIFEST_NOT_SORTED;
157 }
157 }
158 if (!realloc_if_full(self)) {
158 if (!realloc_if_full(self)) {
159 return MANIFEST_OOM; /* no memory */
159 return MANIFEST_OOM; /* no memory */
160 }
160 }
161 l = self->lines + ((self->numlines)++);
161 l = self->lines + ((self->numlines)++);
162 l->start = data;
162 l->start = data;
163 l->len = next - data;
163 l->len = next - data;
164 l->hash_suffix = '\0';
164 l->hash_suffix = '\0';
165 l->from_malloc = false;
165 l->from_malloc = false;
166 l->deleted = false;
166 l->deleted = false;
167 len = len - l->len;
167 len = len - l->len;
168 prev = data;
168 prev = data;
169 data = next;
169 data = next;
170 }
170 }
171 self->livelines = self->numlines;
171 self->livelines = self->numlines;
172 return 0;
172 return 0;
173 }
173 }
174
174
175 static void lazymanifest_init_early(lazymanifest *self)
175 static void lazymanifest_init_early(lazymanifest *self)
176 {
176 {
177 self->pydata = NULL;
177 self->pydata = NULL;
178 self->lines = NULL;
178 self->lines = NULL;
179 self->numlines = 0;
179 self->numlines = 0;
180 self->maxlines = 0;
180 self->maxlines = 0;
181 }
181 }
182
182
183 static int lazymanifest_init(lazymanifest *self, PyObject *args)
183 static int lazymanifest_init(lazymanifest *self, PyObject *args)
184 {
184 {
185 char *data;
185 char *data;
186 Py_ssize_t nodelen, len;
186 Py_ssize_t nodelen, len;
187 int err, ret;
187 int err, ret;
188 PyObject *pydata;
188 PyObject *pydata;
189
189
190 lazymanifest_init_early(self);
190 lazymanifest_init_early(self);
191 if (!PyArg_ParseTuple(args, "nS", &nodelen, &pydata)) {
191 if (!PyArg_ParseTuple(args, "nS", &nodelen, &pydata)) {
192 return -1;
192 return -1;
193 }
193 }
194 if (nodelen != 20 && nodelen != 32) {
194 if (nodelen != 20 && nodelen != 32) {
195 /* See fixed buffer in nodeof */
195 /* See fixed buffer in nodeof */
196 PyErr_Format(PyExc_ValueError, "Unsupported node length");
196 PyErr_Format(PyExc_ValueError, "Unsupported node length");
197 return -1;
197 return -1;
198 }
198 }
199 self->nodelen = nodelen;
199 self->nodelen = nodelen;
200 self->dirty = false;
200 self->dirty = false;
201
201
202 err = PyBytes_AsStringAndSize(pydata, &data, &len);
202 err = PyBytes_AsStringAndSize(pydata, &data, &len);
203 if (err == -1)
203 if (err == -1)
204 return -1;
204 return -1;
205 self->pydata = pydata;
205 self->pydata = pydata;
206 Py_INCREF(self->pydata);
206 Py_INCREF(self->pydata);
207 Py_BEGIN_ALLOW_THREADS
207 Py_BEGIN_ALLOW_THREADS
208 self->lines = malloc(DEFAULT_LINES * sizeof(line));
208 self->lines = malloc(DEFAULT_LINES * sizeof(line));
209 self->maxlines = DEFAULT_LINES;
209 self->maxlines = DEFAULT_LINES;
210 self->numlines = 0;
210 self->numlines = 0;
211 if (!self->lines)
211 if (!self->lines)
212 ret = MANIFEST_OOM;
212 ret = MANIFEST_OOM;
213 else
213 else
214 ret = find_lines(self, data, len);
214 ret = find_lines(self, data, len);
215 Py_END_ALLOW_THREADS
215 Py_END_ALLOW_THREADS
216 switch (ret) {
216 switch (ret) {
217 case 0:
217 case 0:
218 break;
218 break;
219 case MANIFEST_OOM:
219 case MANIFEST_OOM:
220 PyErr_NoMemory();
220 PyErr_NoMemory();
221 break;
221 break;
222 case MANIFEST_NOT_SORTED:
222 case MANIFEST_NOT_SORTED:
223 PyErr_Format(PyExc_ValueError,
223 PyErr_Format(PyExc_ValueError,
224 "Manifest lines not in sorted order.");
224 "Manifest lines not in sorted order.");
225 break;
225 break;
226 case MANIFEST_MALFORMED:
226 case MANIFEST_MALFORMED:
227 PyErr_Format(PyExc_ValueError,
227 PyErr_Format(PyExc_ValueError,
228 "Manifest did not end in a newline.");
228 "Manifest did not end in a newline.");
229 break;
229 break;
230 case MANIFEST_BOGUS_FILENAME:
230 case MANIFEST_BOGUS_FILENAME:
231 PyErr_Format(
231 PyErr_Format(
232 PyExc_ValueError,
232 PyExc_ValueError,
233 "Manifest had an entry with a zero-length filename.");
233 "Manifest had an entry with a zero-length filename.");
234 break;
234 break;
235 case MANIFEST_TOO_SHORT_LINE:
235 case MANIFEST_TOO_SHORT_LINE:
236 PyErr_Format(
236 PyErr_Format(
237 PyExc_ValueError,
237 PyExc_ValueError,
238 "Manifest had implausibly-short line.");
238 "Manifest had implausibly-short line.");
239 break;
239 break;
240 default:
240 default:
241 PyErr_Format(PyExc_ValueError,
241 PyErr_Format(PyExc_ValueError,
242 "Unknown problem parsing manifest.");
242 "Unknown problem parsing manifest.");
243 }
243 }
244 return ret == 0 ? 0 : -1;
244 return ret == 0 ? 0 : -1;
245 }
245 }
246
246
247 static void lazymanifest_dealloc(lazymanifest *self)
247 static void lazymanifest_dealloc(lazymanifest *self)
248 {
248 {
249 /* free any extra lines we had to allocate */
249 /* free any extra lines we had to allocate */
250 int i;
250 int i;
251 for (i = 0; self->lines && (i < self->numlines); i++) {
251 for (i = 0; self->lines && (i < self->numlines); i++) {
252 if (self->lines[i].from_malloc) {
252 if (self->lines[i].from_malloc) {
253 free(self->lines[i].start);
253 free(self->lines[i].start);
254 }
254 }
255 }
255 }
256 free(self->lines);
256 free(self->lines);
257 self->lines = NULL;
257 self->lines = NULL;
258 if (self->pydata) {
258 if (self->pydata) {
259 Py_DECREF(self->pydata);
259 Py_DECREF(self->pydata);
260 self->pydata = NULL;
260 self->pydata = NULL;
261 }
261 }
262 PyObject_Del(self);
262 PyObject_Del(self);
263 }
263 }
264
264
265 /* iteration support */
265 /* iteration support */
266
266
267 typedef struct {
267 typedef struct {
268 PyObject_HEAD lazymanifest *m;
268 PyObject_HEAD lazymanifest *m;
269 Py_ssize_t pos;
269 Py_ssize_t pos;
270 } lmIter;
270 } lmIter;
271
271
272 static void lmiter_dealloc(PyObject *o)
272 static void lmiter_dealloc(PyObject *o)
273 {
273 {
274 lmIter *self = (lmIter *)o;
274 lmIter *self = (lmIter *)o;
275 Py_DECREF(self->m);
275 Py_DECREF(self->m);
276 PyObject_Del(self);
276 PyObject_Del(self);
277 }
277 }
278
278
279 static line *lmiter_nextline(lmIter *self)
279 static line *lmiter_nextline(lmIter *self)
280 {
280 {
281 do {
281 do {
282 self->pos++;
282 self->pos++;
283 if (self->pos >= self->m->numlines) {
283 if (self->pos >= self->m->numlines) {
284 return NULL;
284 return NULL;
285 }
285 }
286 /* skip over deleted manifest entries */
286 /* skip over deleted manifest entries */
287 } while (self->m->lines[self->pos].deleted);
287 } while (self->m->lines[self->pos].deleted);
288 return self->m->lines + self->pos;
288 return self->m->lines + self->pos;
289 }
289 }
290
290
291 static PyObject *lmiter_iterentriesnext(PyObject *o)
291 static PyObject *lmiter_iterentriesnext(PyObject *o)
292 {
292 {
293 lmIter *self = (lmIter *)o;
293 lmIter *self = (lmIter *)o;
294 Py_ssize_t pl;
294 Py_ssize_t pl;
295 line *l;
295 line *l;
296 char flag;
296 char flag;
297 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
297 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
298 l = lmiter_nextline(self);
298 l = lmiter_nextline(self);
299 if (!l) {
299 if (!l) {
300 goto done;
300 goto done;
301 }
301 }
302 pl = pathlen(l);
302 pl = pathlen(l);
303 path = PyBytes_FromStringAndSize(l->start, pl);
303 path = PyBytes_FromStringAndSize(l->start, pl);
304 hash = nodeof(self->m->nodelen, l, &flag);
304 hash = nodeof(self->m->nodelen, l, &flag);
305 if (!path || !hash) {
305 if (!path || !hash) {
306 goto done;
306 goto done;
307 }
307 }
308 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
308 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
309 if (!flags) {
309 if (!flags) {
310 goto done;
310 goto done;
311 }
311 }
312 ret = PyTuple_Pack(3, path, hash, flags);
312 ret = PyTuple_Pack(3, path, hash, flags);
313 done:
313 done:
314 Py_XDECREF(path);
314 Py_XDECREF(path);
315 Py_XDECREF(hash);
315 Py_XDECREF(hash);
316 Py_XDECREF(flags);
316 Py_XDECREF(flags);
317 return ret;
317 return ret;
318 }
318 }
319
319
320 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
320 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
321
321
322 static PyTypeObject lazymanifestEntriesIterator = {
322 static PyTypeObject lazymanifestEntriesIterator = {
323 PyVarObject_HEAD_INIT(NULL, 0) /* header */
323 PyVarObject_HEAD_INIT(NULL, 0) /* header */
324 "parsers.lazymanifest.entriesiterator", /*tp_name */
324 "parsers.lazymanifest.entriesiterator", /*tp_name */
325 sizeof(lmIter), /*tp_basicsize */
325 sizeof(lmIter), /*tp_basicsize */
326 0, /*tp_itemsize */
326 0, /*tp_itemsize */
327 lmiter_dealloc, /*tp_dealloc */
327 lmiter_dealloc, /*tp_dealloc */
328 0, /*tp_print */
328 0, /*tp_print */
329 0, /*tp_getattr */
329 0, /*tp_getattr */
330 0, /*tp_setattr */
330 0, /*tp_setattr */
331 0, /*tp_compare */
331 0, /*tp_compare */
332 0, /*tp_repr */
332 0, /*tp_repr */
333 0, /*tp_as_number */
333 0, /*tp_as_number */
334 0, /*tp_as_sequence */
334 0, /*tp_as_sequence */
335 0, /*tp_as_mapping */
335 0, /*tp_as_mapping */
336 0, /*tp_hash */
336 0, /*tp_hash */
337 0, /*tp_call */
337 0, /*tp_call */
338 0, /*tp_str */
338 0, /*tp_str */
339 0, /*tp_getattro */
339 0, /*tp_getattro */
340 0, /*tp_setattro */
340 0, /*tp_setattro */
341 0, /*tp_as_buffer */
341 0, /*tp_as_buffer */
342 LAZYMANIFESTENTRIESITERATOR_TPFLAGS, /* tp_flags */
342 LAZYMANIFESTENTRIESITERATOR_TPFLAGS, /* tp_flags */
343 "Iterator for 3-tuples in a lazymanifest.", /* tp_doc */
343 "Iterator for 3-tuples in a lazymanifest.", /* tp_doc */
344 0, /* tp_traverse */
344 0, /* tp_traverse */
345 0, /* tp_clear */
345 0, /* tp_clear */
346 0, /* tp_richcompare */
346 0, /* tp_richcompare */
347 0, /* tp_weaklistoffset */
347 0, /* tp_weaklistoffset */
348 PyObject_SelfIter, /* tp_iter: __iter__() method */
348 PyObject_SelfIter, /* tp_iter: __iter__() method */
349 lmiter_iterentriesnext, /* tp_iternext: next() method */
349 lmiter_iterentriesnext, /* tp_iternext: next() method */
350 };
350 };
351
351
352 static PyObject *lmiter_iterkeysnext(PyObject *o)
352 static PyObject *lmiter_iterkeysnext(PyObject *o)
353 {
353 {
354 Py_ssize_t pl;
354 Py_ssize_t pl;
355 line *l = lmiter_nextline((lmIter *)o);
355 line *l = lmiter_nextline((lmIter *)o);
356 if (!l) {
356 if (!l) {
357 return NULL;
357 return NULL;
358 }
358 }
359 pl = pathlen(l);
359 pl = pathlen(l);
360 return PyBytes_FromStringAndSize(l->start, pl);
360 return PyBytes_FromStringAndSize(l->start, pl);
361 }
361 }
362
362
363 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
363 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
364
364
365 static PyTypeObject lazymanifestKeysIterator = {
365 static PyTypeObject lazymanifestKeysIterator = {
366 PyVarObject_HEAD_INIT(NULL, 0) /* header */
366 PyVarObject_HEAD_INIT(NULL, 0) /* header */
367 "parsers.lazymanifest.keysiterator", /*tp_name */
367 "parsers.lazymanifest.keysiterator", /*tp_name */
368 sizeof(lmIter), /*tp_basicsize */
368 sizeof(lmIter), /*tp_basicsize */
369 0, /*tp_itemsize */
369 0, /*tp_itemsize */
370 lmiter_dealloc, /*tp_dealloc */
370 lmiter_dealloc, /*tp_dealloc */
371 0, /*tp_print */
371 0, /*tp_print */
372 0, /*tp_getattr */
372 0, /*tp_getattr */
373 0, /*tp_setattr */
373 0, /*tp_setattr */
374 0, /*tp_compare */
374 0, /*tp_compare */
375 0, /*tp_repr */
375 0, /*tp_repr */
376 0, /*tp_as_number */
376 0, /*tp_as_number */
377 0, /*tp_as_sequence */
377 0, /*tp_as_sequence */
378 0, /*tp_as_mapping */
378 0, /*tp_as_mapping */
379 0, /*tp_hash */
379 0, /*tp_hash */
380 0, /*tp_call */
380 0, /*tp_call */
381 0, /*tp_str */
381 0, /*tp_str */
382 0, /*tp_getattro */
382 0, /*tp_getattro */
383 0, /*tp_setattro */
383 0, /*tp_setattro */
384 0, /*tp_as_buffer */
384 0, /*tp_as_buffer */
385 LAZYMANIFESTKEYSITERATOR_TPFLAGS, /* tp_flags */
385 LAZYMANIFESTKEYSITERATOR_TPFLAGS, /* tp_flags */
386 "Keys iterator for a lazymanifest.", /* tp_doc */
386 "Keys iterator for a lazymanifest.", /* tp_doc */
387 0, /* tp_traverse */
387 0, /* tp_traverse */
388 0, /* tp_clear */
388 0, /* tp_clear */
389 0, /* tp_richcompare */
389 0, /* tp_richcompare */
390 0, /* tp_weaklistoffset */
390 0, /* tp_weaklistoffset */
391 PyObject_SelfIter, /* tp_iter: __iter__() method */
391 PyObject_SelfIter, /* tp_iter: __iter__() method */
392 lmiter_iterkeysnext, /* tp_iternext: next() method */
392 lmiter_iterkeysnext, /* tp_iternext: next() method */
393 };
393 };
394
394
395 static lazymanifest *lazymanifest_copy(lazymanifest *self);
395 static lazymanifest *lazymanifest_copy(lazymanifest *self);
396
396
397 static PyObject *lazymanifest_getentriesiter(lazymanifest *self)
397 static PyObject *lazymanifest_getentriesiter(lazymanifest *self)
398 {
398 {
399 lmIter *i = NULL;
399 lmIter *i = NULL;
400 lazymanifest *t = lazymanifest_copy(self);
400 lazymanifest *t = lazymanifest_copy(self);
401 if (!t) {
401 if (!t) {
402 PyErr_NoMemory();
402 PyErr_NoMemory();
403 return NULL;
403 return NULL;
404 }
404 }
405 i = PyObject_New(lmIter, &lazymanifestEntriesIterator);
405 i = PyObject_New(lmIter, &lazymanifestEntriesIterator);
406 if (i) {
406 if (i) {
407 i->m = t;
407 i->m = t;
408 i->pos = -1;
408 i->pos = -1;
409 } else {
409 } else {
410 Py_DECREF(t);
410 Py_DECREF(t);
411 PyErr_NoMemory();
411 PyErr_NoMemory();
412 }
412 }
413 return (PyObject *)i;
413 return (PyObject *)i;
414 }
414 }
415
415
416 static PyObject *lazymanifest_getkeysiter(lazymanifest *self)
416 static PyObject *lazymanifest_getkeysiter(lazymanifest *self)
417 {
417 {
418 lmIter *i = NULL;
418 lmIter *i = NULL;
419 lazymanifest *t = lazymanifest_copy(self);
419 lazymanifest *t = lazymanifest_copy(self);
420 if (!t) {
420 if (!t) {
421 PyErr_NoMemory();
421 PyErr_NoMemory();
422 return NULL;
422 return NULL;
423 }
423 }
424 i = PyObject_New(lmIter, &lazymanifestKeysIterator);
424 i = PyObject_New(lmIter, &lazymanifestKeysIterator);
425 if (i) {
425 if (i) {
426 i->m = t;
426 i->m = t;
427 i->pos = -1;
427 i->pos = -1;
428 } else {
428 } else {
429 Py_DECREF(t);
429 Py_DECREF(t);
430 PyErr_NoMemory();
430 PyErr_NoMemory();
431 }
431 }
432 return (PyObject *)i;
432 return (PyObject *)i;
433 }
433 }
434
434
435 /* __getitem__ and __setitem__ support */
435 /* __getitem__ and __setitem__ support */
436
436
437 static Py_ssize_t lazymanifest_size(lazymanifest *self)
437 static Py_ssize_t lazymanifest_size(lazymanifest *self)
438 {
438 {
439 return self->livelines;
439 return self->livelines;
440 }
440 }
441
441
442 static int linecmp(const void *left, const void *right)
442 static int linecmp(const void *left, const void *right)
443 {
443 {
444 return strcmp(((const line *)left)->start,
444 return strcmp(((const line *)left)->start,
445 ((const line *)right)->start);
445 ((const line *)right)->start);
446 }
446 }
447
447
448 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
448 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
449 {
449 {
450 line needle;
450 line needle;
451 line *hit;
451 line *hit;
452 if (!PyBytes_Check(key)) {
452 if (!PyBytes_Check(key)) {
453 PyErr_Format(PyExc_TypeError,
453 PyErr_Format(PyExc_TypeError,
454 "getitem: manifest keys must be a string.");
454 "getitem: manifest keys must be a string.");
455 return NULL;
455 return NULL;
456 }
456 }
457 needle.start = PyBytes_AsString(key);
457 needle.start = PyBytes_AsString(key);
458 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
458 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
459 &linecmp);
459 &linecmp);
460 if (!hit || hit->deleted) {
460 if (!hit || hit->deleted) {
461 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
461 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
462 return NULL;
462 return NULL;
463 }
463 }
464 return hashflags(self->nodelen, hit);
464 return hashflags(self->nodelen, hit);
465 }
465 }
466
466
467 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
467 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
468 {
468 {
469 line needle;
469 line needle;
470 line *hit;
470 line *hit;
471 if (!PyBytes_Check(key)) {
471 if (!PyBytes_Check(key)) {
472 PyErr_Format(PyExc_TypeError,
472 PyErr_Format(PyExc_TypeError,
473 "delitem: manifest keys must be a string.");
473 "delitem: manifest keys must be a string.");
474 return -1;
474 return -1;
475 }
475 }
476 needle.start = PyBytes_AsString(key);
476 needle.start = PyBytes_AsString(key);
477 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
477 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
478 &linecmp);
478 &linecmp);
479 if (!hit || hit->deleted) {
479 if (!hit || hit->deleted) {
480 PyErr_Format(PyExc_KeyError,
480 PyErr_Format(PyExc_KeyError,
481 "Tried to delete nonexistent manifest entry.");
481 "Tried to delete nonexistent manifest entry.");
482 return -1;
482 return -1;
483 }
483 }
484 self->dirty = true;
484 self->dirty = true;
485 hit->deleted = true;
485 hit->deleted = true;
486 self->livelines--;
486 self->livelines--;
487 return 0;
487 return 0;
488 }
488 }
489
489
490 /* Do a binary search for the insertion point for new, creating the
490 /* Do a binary search for the insertion point for new, creating the
491 * new entry if needed. */
491 * new entry if needed. */
492 static int internalsetitem(lazymanifest *self, line *new)
492 static int internalsetitem(lazymanifest *self, line *new)
493 {
493 {
494 int start = 0, end = self->numlines;
494 int start = 0, end = self->numlines;
495 while (start < end) {
495 while (start < end) {
496 int pos = start + (end - start) / 2;
496 int pos = start + (end - start) / 2;
497 int c = linecmp(new, self->lines + pos);
497 int c = linecmp(new, self->lines + pos);
498 if (c < 0)
498 if (c < 0)
499 end = pos;
499 end = pos;
500 else if (c > 0)
500 else if (c > 0)
501 start = pos + 1;
501 start = pos + 1;
502 else {
502 else {
503 if (self->lines[pos].deleted)
503 if (self->lines[pos].deleted)
504 self->livelines++;
504 self->livelines++;
505 if (self->lines[pos].from_malloc)
505 if (self->lines[pos].from_malloc)
506 free(self->lines[pos].start);
506 free(self->lines[pos].start);
507 start = pos;
507 start = pos;
508 goto finish;
508 goto finish;
509 }
509 }
510 }
510 }
511 /* being here means we need to do an insert */
511 /* being here means we need to do an insert */
512 if (!realloc_if_full(self)) {
512 if (!realloc_if_full(self)) {
513 PyErr_NoMemory();
513 PyErr_NoMemory();
514 return -1;
514 return -1;
515 }
515 }
516 memmove(self->lines + start + 1, self->lines + start,
516 memmove(self->lines + start + 1, self->lines + start,
517 (self->numlines - start) * sizeof(line));
517 (self->numlines - start) * sizeof(line));
518 self->numlines++;
518 self->numlines++;
519 self->livelines++;
519 self->livelines++;
520 finish:
520 finish:
521 self->lines[start] = *new;
521 self->lines[start] = *new;
522 self->dirty = true;
522 self->dirty = true;
523 return 0;
523 return 0;
524 }
524 }
525
525
526 static int lazymanifest_setitem(
526 static int lazymanifest_setitem(
527 lazymanifest *self, PyObject *key, PyObject *value)
527 lazymanifest *self, PyObject *key, PyObject *value)
528 {
528 {
529 char *path;
529 char *path;
530 Py_ssize_t plen;
530 Py_ssize_t plen;
531 PyObject *pyhash;
531 PyObject *pyhash;
532 Py_ssize_t hlen;
532 Py_ssize_t hlen;
533 char *hash;
533 char *hash;
534 PyObject *pyflags;
534 PyObject *pyflags;
535 char *flags;
535 char *flags;
536 Py_ssize_t flen;
536 Py_ssize_t flen;
537 Py_ssize_t dlen;
537 Py_ssize_t dlen;
538 char *dest;
538 char *dest;
539 int i;
539 int i;
540 line new;
540 line new;
541 if (!PyBytes_Check(key)) {
541 if (!PyBytes_Check(key)) {
542 PyErr_Format(PyExc_TypeError,
542 PyErr_Format(PyExc_TypeError,
543 "setitem: manifest keys must be a string.");
543 "setitem: manifest keys must be a string.");
544 return -1;
544 return -1;
545 }
545 }
546 if (!value) {
546 if (!value) {
547 return lazymanifest_delitem(self, key);
547 return lazymanifest_delitem(self, key);
548 }
548 }
549 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
549 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
550 PyErr_Format(PyExc_TypeError,
550 PyErr_Format(PyExc_TypeError,
551 "Manifest values must be a tuple of (node, flags).");
551 "Manifest values must be a tuple of (node, flags).");
552 return -1;
552 return -1;
553 }
553 }
554 if (PyBytes_AsStringAndSize(key, &path, &plen) == -1) {
554 if (PyBytes_AsStringAndSize(key, &path, &plen) == -1) {
555 return -1;
555 return -1;
556 }
556 }
557
557
558 pyhash = PyTuple_GetItem(value, 0);
558 pyhash = PyTuple_GetItem(value, 0);
559 if (!PyBytes_Check(pyhash)) {
559 if (!PyBytes_Check(pyhash)) {
560 PyErr_Format(PyExc_TypeError,
560 PyErr_Format(PyExc_TypeError,
561 "node must be a %zi bytes string", self->nodelen);
561 "node must be a %zi bytes string", self->nodelen);
562 return -1;
562 return -1;
563 }
563 }
564 hlen = PyBytes_Size(pyhash);
564 hlen = PyBytes_Size(pyhash);
565 if (hlen != self->nodelen) {
565 if (hlen != self->nodelen) {
566 PyErr_Format(PyExc_TypeError,
566 PyErr_Format(PyExc_TypeError,
567 "node must be a %zi bytes string", self->nodelen);
567 "node must be a %zi bytes string", self->nodelen);
568 return -1;
568 return -1;
569 }
569 }
570 hash = PyBytes_AsString(pyhash);
570 hash = PyBytes_AsString(pyhash);
571
571
572 pyflags = PyTuple_GetItem(value, 1);
572 pyflags = PyTuple_GetItem(value, 1);
573 if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
573 if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
574 PyErr_Format(PyExc_TypeError,
574 PyErr_Format(PyExc_TypeError,
575 "flags must a 0 or 1 bytes string");
575 "flags must a 0 or 1 bytes string");
576 return -1;
576 return -1;
577 }
577 }
578 if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
578 if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
579 return -1;
579 return -1;
580 }
580 }
581 if (flen == 1) {
581 if (flen == 1) {
582 switch (*flags) {
582 switch (*flags) {
583 case 'l':
583 case 'l':
584 case 't':
584 case 't':
585 case 'x':
585 case 'x':
586 break;
586 break;
587 default:
587 default:
588 PyErr_Format(PyExc_TypeError, "invalid manifest flag");
588 PyErr_Format(PyExc_TypeError, "invalid manifest flag");
589 return -1;
589 return -1;
590 }
590 }
591 }
591 }
592 /* one null byte and one newline */
592 /* one null byte and one newline */
593 dlen = plen + hlen * 2 + 1 + flen + 1;
593 dlen = plen + hlen * 2 + 1 + flen + 1;
594 dest = malloc(dlen);
594 dest = malloc(dlen);
595 if (!dest) {
595 if (!dest) {
596 PyErr_NoMemory();
596 PyErr_NoMemory();
597 return -1;
597 return -1;
598 }
598 }
599 memcpy(dest, path, plen + 1);
599 memcpy(dest, path, plen + 1);
600 for (i = 0; i < hlen; i++) {
600 for (i = 0; i < hlen; i++) {
601 /* Cast to unsigned, so it will not get sign-extended when promoted
601 /* Cast to unsigned, so it will not get sign-extended when promoted
602 * to int (as is done when passing to a variadic function)
602 * to int (as is done when passing to a variadic function)
603 */
603 */
604 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
604 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
605 }
605 }
606 memcpy(dest + plen + 2 * hlen + 1, flags, flen);
606 memcpy(dest + plen + 2 * hlen + 1, flags, flen);
607 dest[plen + 2 * hlen + 1 + flen] = '\n';
607 dest[plen + 2 * hlen + 1 + flen] = '\n';
608 new.start = dest;
608 new.start = dest;
609 new.len = dlen;
609 new.len = dlen;
610 new.hash_suffix = '\0';
610 new.hash_suffix = '\0';
611 if (hlen > 20) {
611 if (hlen > 20) {
612 new.hash_suffix = hash[20];
612 new.hash_suffix = hash[20];
613 }
613 }
614 new.from_malloc = true; /* is `start` a pointer we allocated? */
614 new.from_malloc = true; /* is `start` a pointer we allocated? */
615 new.deleted = false; /* is this entry deleted? */
615 new.deleted = false; /* is this entry deleted? */
616 if (internalsetitem(self, &new)) {
616 if (internalsetitem(self, &new)) {
617 return -1;
617 return -1;
618 }
618 }
619 return 0;
619 return 0;
620 }
620 }
621
621
622 static PyMappingMethods lazymanifest_mapping_methods = {
622 static PyMappingMethods lazymanifest_mapping_methods = {
623 (lenfunc)lazymanifest_size, /* mp_length */
623 (lenfunc)lazymanifest_size, /* mp_length */
624 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
624 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
625 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
625 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
626 };
626 };
627
627
628 /* sequence methods (important or __contains__ builds an iterator) */
628 /* sequence methods (important or __contains__ builds an iterator) */
629
629
630 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
630 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
631 {
631 {
632 line needle;
632 line needle;
633 line *hit;
633 line *hit;
634 if (!PyBytes_Check(key)) {
634 if (!PyBytes_Check(key)) {
635 /* Our keys are always strings, so if the contains
635 /* Our keys are always strings, so if the contains
636 * check is for a non-string, just return false. */
636 * check is for a non-string, just return false. */
637 return 0;
637 return 0;
638 }
638 }
639 needle.start = PyBytes_AsString(key);
639 needle.start = PyBytes_AsString(key);
640 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
640 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
641 &linecmp);
641 &linecmp);
642 if (!hit || hit->deleted) {
642 if (!hit || hit->deleted) {
643 return 0;
643 return 0;
644 }
644 }
645 return 1;
645 return 1;
646 }
646 }
647
647
648 static PySequenceMethods lazymanifest_seq_meths = {
648 static PySequenceMethods lazymanifest_seq_meths = {
649 (lenfunc)lazymanifest_size, /* sq_length */
649 (lenfunc)lazymanifest_size, /* sq_length */
650 0, /* sq_concat */
650 0, /* sq_concat */
651 0, /* sq_repeat */
651 0, /* sq_repeat */
652 0, /* sq_item */
652 0, /* sq_item */
653 0, /* sq_slice */
653 0, /* sq_slice */
654 0, /* sq_ass_item */
654 0, /* sq_ass_item */
655 0, /* sq_ass_slice */
655 0, /* sq_ass_slice */
656 (objobjproc)lazymanifest_contains, /* sq_contains */
656 (objobjproc)lazymanifest_contains, /* sq_contains */
657 0, /* sq_inplace_concat */
657 0, /* sq_inplace_concat */
658 0, /* sq_inplace_repeat */
658 0, /* sq_inplace_repeat */
659 };
659 };
660
660
661
661
662 /* Other methods (copy, diff, etc) */
662 /* Other methods (copy, diff, etc) */
663 static PyTypeObject lazymanifestType;
663 static PyTypeObject lazymanifestType;
664
664
665 /* If the manifest has changes, build the new manifest text and reindex it. */
665 /* If the manifest has changes, build the new manifest text and reindex it. */
666 static int compact(lazymanifest *self)
666 static int compact(lazymanifest *self)
667 {
667 {
668 int i;
668 int i;
669 ssize_t need = 0;
669 ssize_t need = 0;
670 char *data;
670 char *data;
671 line *src, *dst;
671 line *src, *dst;
672 PyObject *pydata;
672 PyObject *pydata;
673 if (!self->dirty)
673 if (!self->dirty)
674 return 0;
674 return 0;
675 for (i = 0; i < self->numlines; i++) {
675 for (i = 0; i < self->numlines; i++) {
676 if (!self->lines[i].deleted) {
676 if (!self->lines[i].deleted) {
677 need += self->lines[i].len;
677 need += self->lines[i].len;
678 }
678 }
679 }
679 }
680 pydata = PyBytes_FromStringAndSize(NULL, need);
680 pydata = PyBytes_FromStringAndSize(NULL, need);
681 if (!pydata)
681 if (!pydata)
682 return -1;
682 return -1;
683 data = PyBytes_AsString(pydata);
683 data = PyBytes_AsString(pydata);
684 if (!data) {
684 if (!data) {
685 return -1;
685 return -1;
686 }
686 }
687 src = self->lines;
687 src = self->lines;
688 dst = self->lines;
688 dst = self->lines;
689 for (i = 0; i < self->numlines; i++, src++) {
689 for (i = 0; i < self->numlines; i++, src++) {
690 char *tofree = NULL;
690 char *tofree = NULL;
691 if (src->from_malloc) {
691 if (src->from_malloc) {
692 tofree = src->start;
692 tofree = src->start;
693 }
693 }
694 if (!src->deleted) {
694 if (!src->deleted) {
695 memcpy(data, src->start, src->len);
695 memcpy(data, src->start, src->len);
696 *dst = *src;
696 *dst = *src;
697 dst->start = data;
697 dst->start = data;
698 dst->from_malloc = false;
698 dst->from_malloc = false;
699 data += dst->len;
699 data += dst->len;
700 dst++;
700 dst++;
701 }
701 }
702 free(tofree);
702 free(tofree);
703 }
703 }
704 Py_DECREF(self->pydata);
704 Py_DECREF(self->pydata);
705 self->pydata = pydata;
705 self->pydata = pydata;
706 self->numlines = self->livelines;
706 self->numlines = self->livelines;
707 self->dirty = false;
707 self->dirty = false;
708 return 0;
708 return 0;
709 }
709 }
710
710
711 static PyObject *lazymanifest_text(lazymanifest *self)
711 static PyObject *lazymanifest_text(lazymanifest *self)
712 {
712 {
713 if (compact(self) != 0) {
713 if (compact(self) != 0) {
714 PyErr_NoMemory();
714 PyErr_NoMemory();
715 return NULL;
715 return NULL;
716 }
716 }
717 Py_INCREF(self->pydata);
717 Py_INCREF(self->pydata);
718 return self->pydata;
718 return self->pydata;
719 }
719 }
720
720
721 static lazymanifest *lazymanifest_copy(lazymanifest *self)
721 static lazymanifest *lazymanifest_copy(lazymanifest *self)
722 {
722 {
723 lazymanifest *copy = NULL;
723 lazymanifest *copy = NULL;
724 if (compact(self) != 0) {
724 if (compact(self) != 0) {
725 goto nomem;
725 goto nomem;
726 }
726 }
727 copy = PyObject_New(lazymanifest, &lazymanifestType);
727 copy = PyObject_New(lazymanifest, &lazymanifestType);
728 if (!copy) {
728 if (!copy) {
729 goto nomem;
729 goto nomem;
730 }
730 }
731 lazymanifest_init_early(copy);
731 lazymanifest_init_early(copy);
732 copy->nodelen = self->nodelen;
732 copy->nodelen = self->nodelen;
733 copy->numlines = self->numlines;
733 copy->numlines = self->numlines;
734 copy->livelines = self->livelines;
734 copy->livelines = self->livelines;
735 copy->dirty = false;
735 copy->dirty = false;
736 copy->lines = malloc(self->maxlines *sizeof(line));
736 copy->lines = malloc(self->maxlines *sizeof(line));
737 if (!copy->lines) {
737 if (!copy->lines) {
738 goto nomem;
738 goto nomem;
739 }
739 }
740 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
740 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
741 copy->maxlines = self->maxlines;
741 copy->maxlines = self->maxlines;
742 copy->pydata = self->pydata;
742 copy->pydata = self->pydata;
743 Py_INCREF(copy->pydata);
743 Py_INCREF(copy->pydata);
744 return copy;
744 return copy;
745 nomem:
745 nomem:
746 PyErr_NoMemory();
746 PyErr_NoMemory();
747 Py_XDECREF(copy);
747 Py_XDECREF(copy);
748 return NULL;
748 return NULL;
749 }
749 }
750
750
751 static lazymanifest *lazymanifest_filtercopy(
751 static lazymanifest *lazymanifest_filtercopy(
752 lazymanifest *self, PyObject *matchfn)
752 lazymanifest *self, PyObject *matchfn)
753 {
753 {
754 lazymanifest *copy = NULL;
754 lazymanifest *copy = NULL;
755 int i;
755 int i;
756 if (!PyCallable_Check(matchfn)) {
756 if (!PyCallable_Check(matchfn)) {
757 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
757 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
758 return NULL;
758 return NULL;
759 }
759 }
760 /* compact ourselves first to avoid double-frees later when we
760 /* compact ourselves first to avoid double-frees later when we
761 * compact tmp so that it doesn't have random pointers to our
761 * compact tmp so that it doesn't have random pointers to our
762 * underlying from_malloc-data (self->pydata is safe) */
762 * underlying from_malloc-data (self->pydata is safe) */
763 if (compact(self) != 0) {
763 if (compact(self) != 0) {
764 goto nomem;
764 goto nomem;
765 }
765 }
766 copy = PyObject_New(lazymanifest, &lazymanifestType);
766 copy = PyObject_New(lazymanifest, &lazymanifestType);
767 if (!copy) {
767 if (!copy) {
768 goto nomem;
768 goto nomem;
769 }
769 }
770 lazymanifest_init_early(copy);
770 lazymanifest_init_early(copy);
771 copy->nodelen = self->nodelen;
771 copy->nodelen = self->nodelen;
772 copy->dirty = true;
772 copy->dirty = true;
773 copy->lines = malloc(self->maxlines * sizeof(line));
773 copy->lines = malloc(self->maxlines * sizeof(line));
774 if (!copy->lines) {
774 if (!copy->lines) {
775 goto nomem;
775 goto nomem;
776 }
776 }
777 copy->maxlines = self->maxlines;
777 copy->maxlines = self->maxlines;
778 copy->numlines = 0;
778 copy->numlines = 0;
779 copy->pydata = self->pydata;
779 copy->pydata = self->pydata;
780 Py_INCREF(copy->pydata);
780 Py_INCREF(copy->pydata);
781 for (i = 0; i < self->numlines; i++) {
781 for (i = 0; i < self->numlines; i++) {
782 PyObject *arglist = NULL, *result = NULL;
782 PyObject *arglist = NULL, *result = NULL;
783 arglist = Py_BuildValue(PY23("(s)", "(y)"),
783 arglist = Py_BuildValue("(y)",
784 self->lines[i].start);
784 self->lines[i].start);
785 if (!arglist) {
785 if (!arglist) {
786 goto bail;
786 goto bail;
787 }
787 }
788 result = PyObject_CallObject(matchfn, arglist);
788 result = PyObject_CallObject(matchfn, arglist);
789 Py_DECREF(arglist);
789 Py_DECREF(arglist);
790 /* if the callback raised an exception, just let it
790 /* if the callback raised an exception, just let it
791 * through and give up */
791 * through and give up */
792 if (!result) {
792 if (!result) {
793 goto bail;
793 goto bail;
794 }
794 }
795 if (PyObject_IsTrue(result)) {
795 if (PyObject_IsTrue(result)) {
796 assert(!(self->lines[i].from_malloc));
796 assert(!(self->lines[i].from_malloc));
797 copy->lines[copy->numlines++] = self->lines[i];
797 copy->lines[copy->numlines++] = self->lines[i];
798 }
798 }
799 Py_DECREF(result);
799 Py_DECREF(result);
800 }
800 }
801 copy->livelines = copy->numlines;
801 copy->livelines = copy->numlines;
802 return copy;
802 return copy;
803 nomem:
803 nomem:
804 PyErr_NoMemory();
804 PyErr_NoMemory();
805 bail:
805 bail:
806 Py_XDECREF(copy);
806 Py_XDECREF(copy);
807 return NULL;
807 return NULL;
808 }
808 }
809
809
810 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
810 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
811 {
811 {
812 lazymanifest *other;
812 lazymanifest *other;
813 PyObject *pyclean = NULL;
813 PyObject *pyclean = NULL;
814 bool listclean;
814 bool listclean;
815 PyObject *emptyTup = NULL, *ret = NULL;
815 PyObject *emptyTup = NULL, *ret = NULL;
816 PyObject *es;
816 PyObject *es;
817 int sneedle = 0, oneedle = 0;
817 int sneedle = 0, oneedle = 0;
818 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
818 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
819 return NULL;
819 return NULL;
820 }
820 }
821 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
821 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
822 es = PyBytes_FromString("");
822 es = PyBytes_FromString("");
823 if (!es) {
823 if (!es) {
824 goto nomem;
824 goto nomem;
825 }
825 }
826 emptyTup = PyTuple_Pack(2, Py_None, es);
826 emptyTup = PyTuple_Pack(2, Py_None, es);
827 Py_DECREF(es);
827 Py_DECREF(es);
828 if (!emptyTup) {
828 if (!emptyTup) {
829 goto nomem;
829 goto nomem;
830 }
830 }
831 ret = PyDict_New();
831 ret = PyDict_New();
832 if (!ret) {
832 if (!ret) {
833 goto nomem;
833 goto nomem;
834 }
834 }
835 while (sneedle != self->numlines || oneedle != other->numlines) {
835 while (sneedle != self->numlines || oneedle != other->numlines) {
836 line *left = self->lines + sneedle;
836 line *left = self->lines + sneedle;
837 line *right = other->lines + oneedle;
837 line *right = other->lines + oneedle;
838 int result;
838 int result;
839 PyObject *key;
839 PyObject *key;
840 PyObject *outer;
840 PyObject *outer;
841 /* If we're looking at a deleted entry and it's not
841 /* If we're looking at a deleted entry and it's not
842 * the end of the manifest, just skip it. */
842 * the end of the manifest, just skip it. */
843 if (sneedle < self->numlines && left->deleted) {
843 if (sneedle < self->numlines && left->deleted) {
844 sneedle++;
844 sneedle++;
845 continue;
845 continue;
846 }
846 }
847 if (oneedle < other->numlines && right->deleted) {
847 if (oneedle < other->numlines && right->deleted) {
848 oneedle++;
848 oneedle++;
849 continue;
849 continue;
850 }
850 }
851 /* if we're at the end of either manifest, then we
851 /* if we're at the end of either manifest, then we
852 * know the remaining items are adds so we can skip
852 * know the remaining items are adds so we can skip
853 * the strcmp. */
853 * the strcmp. */
854 if (sneedle == self->numlines) {
854 if (sneedle == self->numlines) {
855 result = 1;
855 result = 1;
856 } else if (oneedle == other->numlines) {
856 } else if (oneedle == other->numlines) {
857 result = -1;
857 result = -1;
858 } else {
858 } else {
859 result = linecmp(left, right);
859 result = linecmp(left, right);
860 }
860 }
861 key = result <= 0 ?
861 key = result <= 0 ?
862 PyBytes_FromString(left->start) :
862 PyBytes_FromString(left->start) :
863 PyBytes_FromString(right->start);
863 PyBytes_FromString(right->start);
864 if (!key)
864 if (!key)
865 goto nomem;
865 goto nomem;
866 if (result < 0) {
866 if (result < 0) {
867 PyObject *l = hashflags(self->nodelen, left);
867 PyObject *l = hashflags(self->nodelen, left);
868 if (!l) {
868 if (!l) {
869 goto nomem;
869 goto nomem;
870 }
870 }
871 outer = PyTuple_Pack(2, l, emptyTup);
871 outer = PyTuple_Pack(2, l, emptyTup);
872 Py_DECREF(l);
872 Py_DECREF(l);
873 if (!outer) {
873 if (!outer) {
874 goto nomem;
874 goto nomem;
875 }
875 }
876 PyDict_SetItem(ret, key, outer);
876 PyDict_SetItem(ret, key, outer);
877 Py_DECREF(outer);
877 Py_DECREF(outer);
878 sneedle++;
878 sneedle++;
879 } else if (result > 0) {
879 } else if (result > 0) {
880 PyObject *r = hashflags(self->nodelen, right);
880 PyObject *r = hashflags(self->nodelen, right);
881 if (!r) {
881 if (!r) {
882 goto nomem;
882 goto nomem;
883 }
883 }
884 outer = PyTuple_Pack(2, emptyTup, r);
884 outer = PyTuple_Pack(2, emptyTup, r);
885 Py_DECREF(r);
885 Py_DECREF(r);
886 if (!outer) {
886 if (!outer) {
887 goto nomem;
887 goto nomem;
888 }
888 }
889 PyDict_SetItem(ret, key, outer);
889 PyDict_SetItem(ret, key, outer);
890 Py_DECREF(outer);
890 Py_DECREF(outer);
891 oneedle++;
891 oneedle++;
892 } else {
892 } else {
893 /* file exists in both manifests */
893 /* file exists in both manifests */
894 if (left->len != right->len
894 if (left->len != right->len
895 || memcmp(left->start, right->start, left->len)
895 || memcmp(left->start, right->start, left->len)
896 || left->hash_suffix != right->hash_suffix) {
896 || left->hash_suffix != right->hash_suffix) {
897 PyObject *l = hashflags(self->nodelen, left);
897 PyObject *l = hashflags(self->nodelen, left);
898 PyObject *r;
898 PyObject *r;
899 if (!l) {
899 if (!l) {
900 goto nomem;
900 goto nomem;
901 }
901 }
902 r = hashflags(self->nodelen, right);
902 r = hashflags(self->nodelen, right);
903 if (!r) {
903 if (!r) {
904 Py_DECREF(l);
904 Py_DECREF(l);
905 goto nomem;
905 goto nomem;
906 }
906 }
907 outer = PyTuple_Pack(2, l, r);
907 outer = PyTuple_Pack(2, l, r);
908 Py_DECREF(l);
908 Py_DECREF(l);
909 Py_DECREF(r);
909 Py_DECREF(r);
910 if (!outer) {
910 if (!outer) {
911 goto nomem;
911 goto nomem;
912 }
912 }
913 PyDict_SetItem(ret, key, outer);
913 PyDict_SetItem(ret, key, outer);
914 Py_DECREF(outer);
914 Py_DECREF(outer);
915 } else if (listclean) {
915 } else if (listclean) {
916 PyDict_SetItem(ret, key, Py_None);
916 PyDict_SetItem(ret, key, Py_None);
917 }
917 }
918 sneedle++;
918 sneedle++;
919 oneedle++;
919 oneedle++;
920 }
920 }
921 Py_DECREF(key);
921 Py_DECREF(key);
922 }
922 }
923 Py_DECREF(emptyTup);
923 Py_DECREF(emptyTup);
924 return ret;
924 return ret;
925 nomem:
925 nomem:
926 PyErr_NoMemory();
926 PyErr_NoMemory();
927 Py_XDECREF(ret);
927 Py_XDECREF(ret);
928 Py_XDECREF(emptyTup);
928 Py_XDECREF(emptyTup);
929 return NULL;
929 return NULL;
930 }
930 }
931
931
932 static PyMethodDef lazymanifest_methods[] = {
932 static PyMethodDef lazymanifest_methods[] = {
933 {"iterkeys", (PyCFunction)lazymanifest_getkeysiter, METH_NOARGS,
933 {"iterkeys", (PyCFunction)lazymanifest_getkeysiter, METH_NOARGS,
934 "Iterate over file names in this lazymanifest."},
934 "Iterate over file names in this lazymanifest."},
935 {"iterentries", (PyCFunction)lazymanifest_getentriesiter, METH_NOARGS,
935 {"iterentries", (PyCFunction)lazymanifest_getentriesiter, METH_NOARGS,
936 "Iterate over (path, nodeid, flags) tuples in this lazymanifest."},
936 "Iterate over (path, nodeid, flags) tuples in this lazymanifest."},
937 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
937 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
938 "Make a copy of this lazymanifest."},
938 "Make a copy of this lazymanifest."},
939 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
939 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
940 "Make a copy of this manifest filtered by matchfn."},
940 "Make a copy of this manifest filtered by matchfn."},
941 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
941 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
942 "Compare this lazymanifest to another one."},
942 "Compare this lazymanifest to another one."},
943 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
943 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
944 "Encode this manifest to text."},
944 "Encode this manifest to text."},
945 {NULL},
945 {NULL},
946 };
946 };
947
947
948 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT
948 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT
949
949
950 static PyTypeObject lazymanifestType = {
950 static PyTypeObject lazymanifestType = {
951 PyVarObject_HEAD_INIT(NULL, 0) /* header */
951 PyVarObject_HEAD_INIT(NULL, 0) /* header */
952 "parsers.lazymanifest", /* tp_name */
952 "parsers.lazymanifest", /* tp_name */
953 sizeof(lazymanifest), /* tp_basicsize */
953 sizeof(lazymanifest), /* tp_basicsize */
954 0, /* tp_itemsize */
954 0, /* tp_itemsize */
955 (destructor)lazymanifest_dealloc, /* tp_dealloc */
955 (destructor)lazymanifest_dealloc, /* tp_dealloc */
956 0, /* tp_print */
956 0, /* tp_print */
957 0, /* tp_getattr */
957 0, /* tp_getattr */
958 0, /* tp_setattr */
958 0, /* tp_setattr */
959 0, /* tp_compare */
959 0, /* tp_compare */
960 0, /* tp_repr */
960 0, /* tp_repr */
961 0, /* tp_as_number */
961 0, /* tp_as_number */
962 &lazymanifest_seq_meths, /* tp_as_sequence */
962 &lazymanifest_seq_meths, /* tp_as_sequence */
963 &lazymanifest_mapping_methods, /* tp_as_mapping */
963 &lazymanifest_mapping_methods, /* tp_as_mapping */
964 0, /* tp_hash */
964 0, /* tp_hash */
965 0, /* tp_call */
965 0, /* tp_call */
966 0, /* tp_str */
966 0, /* tp_str */
967 0, /* tp_getattro */
967 0, /* tp_getattro */
968 0, /* tp_setattro */
968 0, /* tp_setattro */
969 0, /* tp_as_buffer */
969 0, /* tp_as_buffer */
970 LAZYMANIFEST_TPFLAGS, /* tp_flags */
970 LAZYMANIFEST_TPFLAGS, /* tp_flags */
971 "TODO(augie)", /* tp_doc */
971 "TODO(augie)", /* tp_doc */
972 0, /* tp_traverse */
972 0, /* tp_traverse */
973 0, /* tp_clear */
973 0, /* tp_clear */
974 0, /* tp_richcompare */
974 0, /* tp_richcompare */
975 0, /* tp_weaklistoffset */
975 0, /* tp_weaklistoffset */
976 (getiterfunc)lazymanifest_getkeysiter, /* tp_iter */
976 (getiterfunc)lazymanifest_getkeysiter, /* tp_iter */
977 0, /* tp_iternext */
977 0, /* tp_iternext */
978 lazymanifest_methods, /* tp_methods */
978 lazymanifest_methods, /* tp_methods */
979 0, /* tp_members */
979 0, /* tp_members */
980 0, /* tp_getset */
980 0, /* tp_getset */
981 0, /* tp_base */
981 0, /* tp_base */
982 0, /* tp_dict */
982 0, /* tp_dict */
983 0, /* tp_descr_get */
983 0, /* tp_descr_get */
984 0, /* tp_descr_set */
984 0, /* tp_descr_set */
985 0, /* tp_dictoffset */
985 0, /* tp_dictoffset */
986 (initproc)lazymanifest_init, /* tp_init */
986 (initproc)lazymanifest_init, /* tp_init */
987 0, /* tp_alloc */
987 0, /* tp_alloc */
988 };
988 };
989
989
990 void manifest_module_init(PyObject * mod)
990 void manifest_module_init(PyObject * mod)
991 {
991 {
992 lazymanifestType.tp_new = PyType_GenericNew;
992 lazymanifestType.tp_new = PyType_GenericNew;
993 if (PyType_Ready(&lazymanifestType) < 0)
993 if (PyType_Ready(&lazymanifestType) < 0)
994 return;
994 return;
995 Py_INCREF(&lazymanifestType);
995 Py_INCREF(&lazymanifestType);
996
996
997 PyModule_AddObject(mod, "lazymanifest",
997 PyModule_AddObject(mod, "lazymanifest",
998 (PyObject *)&lazymanifestType);
998 (PyObject *)&lazymanifestType);
999 }
999 }
@@ -1,204 +1,203 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 Olivia Mackall <olivia@selenic.com>
17 Copyright 2005, 2006 Olivia Mackall <olivia@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 "bitmanipulation.h"
28 #include "bitmanipulation.h"
29 #include "compat.h"
29 #include "compat.h"
30 #include "mpatch.h"
30 #include "mpatch.h"
31 #include "util.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 Py_buffer buffer;
53 Py_buffer buffer;
54 struct mpatch_flist *res = NULL;
54 struct mpatch_flist *res = NULL;
55 int r;
55 int r;
56
56
57 PyObject *tmp = PyList_GetItem((PyObject *)bins, pos);
57 PyObject *tmp = PyList_GetItem((PyObject *)bins, pos);
58 if (!tmp) {
58 if (!tmp) {
59 return NULL;
59 return NULL;
60 }
60 }
61 if (PyObject_GetBuffer(tmp, &buffer, PyBUF_CONTIG_RO)) {
61 if (PyObject_GetBuffer(tmp, &buffer, PyBUF_CONTIG_RO)) {
62 return NULL;
62 return NULL;
63 }
63 }
64 if ((r = mpatch_decode(buffer.buf, buffer.len, &res)) < 0) {
64 if ((r = mpatch_decode(buffer.buf, buffer.len, &res)) < 0) {
65 if (!PyErr_Occurred()) {
65 if (!PyErr_Occurred()) {
66 setpyerr(r);
66 setpyerr(r);
67 }
67 }
68 res = NULL;
68 res = NULL;
69 }
69 }
70
70
71 PyBuffer_Release(&buffer);
71 PyBuffer_Release(&buffer);
72 return res;
72 return res;
73 }
73 }
74
74
75 static PyObject *patches(PyObject *self, PyObject *args)
75 static PyObject *patches(PyObject *self, PyObject *args)
76 {
76 {
77 PyObject *text, *bins, *result;
77 PyObject *text, *bins, *result;
78 struct mpatch_flist *patch;
78 struct mpatch_flist *patch;
79 Py_buffer buffer;
79 Py_buffer buffer;
80 int r = 0;
80 int r = 0;
81 char *out;
81 char *out;
82 Py_ssize_t len, outlen;
82 Py_ssize_t len, outlen;
83
83
84 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins)) {
84 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins)) {
85 return NULL;
85 return NULL;
86 }
86 }
87
87
88 len = PyList_Size(bins);
88 len = PyList_Size(bins);
89 if (!len) {
89 if (!len) {
90 /* nothing to do */
90 /* nothing to do */
91 Py_INCREF(text);
91 Py_INCREF(text);
92 return text;
92 return text;
93 }
93 }
94
94
95 if (PyObject_GetBuffer(text, &buffer, PyBUF_CONTIG_RO)) {
95 if (PyObject_GetBuffer(text, &buffer, PyBUF_CONTIG_RO)) {
96 return NULL;
96 return NULL;
97 }
97 }
98
98
99 patch = mpatch_fold(bins, cpygetitem, 0, len);
99 patch = mpatch_fold(bins, cpygetitem, 0, len);
100 if (!patch) { /* error already set or memory error */
100 if (!patch) { /* error already set or memory error */
101 if (!PyErr_Occurred()) {
101 if (!PyErr_Occurred()) {
102 PyErr_NoMemory();
102 PyErr_NoMemory();
103 }
103 }
104 result = NULL;
104 result = NULL;
105 goto cleanup;
105 goto cleanup;
106 }
106 }
107
107
108 outlen = mpatch_calcsize(buffer.len, patch);
108 outlen = mpatch_calcsize(buffer.len, patch);
109 if (outlen < 0) {
109 if (outlen < 0) {
110 r = (int)outlen;
110 r = (int)outlen;
111 result = NULL;
111 result = NULL;
112 goto cleanup;
112 goto cleanup;
113 }
113 }
114 result = PyBytes_FromStringAndSize(NULL, outlen);
114 result = PyBytes_FromStringAndSize(NULL, outlen);
115 if (!result) {
115 if (!result) {
116 result = NULL;
116 result = NULL;
117 goto cleanup;
117 goto cleanup;
118 }
118 }
119 out = PyBytes_AsString(result);
119 out = PyBytes_AsString(result);
120 /* clang-format off */
120 /* clang-format off */
121 {
121 {
122 Py_BEGIN_ALLOW_THREADS
122 Py_BEGIN_ALLOW_THREADS
123 r = mpatch_apply(out, buffer.buf, buffer.len, patch);
123 r = mpatch_apply(out, buffer.buf, buffer.len, patch);
124 Py_END_ALLOW_THREADS
124 Py_END_ALLOW_THREADS
125 }
125 }
126 /* clang-format on */
126 /* clang-format on */
127 if (r < 0) {
127 if (r < 0) {
128 Py_DECREF(result);
128 Py_DECREF(result);
129 result = NULL;
129 result = NULL;
130 }
130 }
131 cleanup:
131 cleanup:
132 mpatch_lfree(patch);
132 mpatch_lfree(patch);
133 PyBuffer_Release(&buffer);
133 PyBuffer_Release(&buffer);
134 if (!result && !PyErr_Occurred()) {
134 if (!result && !PyErr_Occurred()) {
135 setpyerr(r);
135 setpyerr(r);
136 }
136 }
137 return result;
137 return result;
138 }
138 }
139
139
140 /* calculate size of a patched file directly */
140 /* calculate size of a patched file directly */
141 static PyObject *patchedsize(PyObject *self, PyObject *args)
141 static PyObject *patchedsize(PyObject *self, PyObject *args)
142 {
142 {
143 long orig, start, end, len, outlen = 0, last = 0, pos = 0;
143 long orig, start, end, len, outlen = 0, last = 0, pos = 0;
144 Py_ssize_t patchlen;
144 Py_ssize_t patchlen;
145 char *bin;
145 char *bin;
146
146
147 if (!PyArg_ParseTuple(args, PY23("ls#", "ly#"), &orig, &bin,
147 if (!PyArg_ParseTuple(args, "ly#", &orig, &bin, &patchlen)) {
148 &patchlen)) {
149 return NULL;
148 return NULL;
150 }
149 }
151
150
152 while (pos >= 0 && pos < patchlen) {
151 while (pos >= 0 && pos < patchlen) {
153 start = getbe32(bin + pos);
152 start = getbe32(bin + pos);
154 end = getbe32(bin + pos + 4);
153 end = getbe32(bin + pos + 4);
155 len = getbe32(bin + pos + 8);
154 len = getbe32(bin + pos + 8);
156 if (start > end) {
155 if (start > end) {
157 break; /* sanity check */
156 break; /* sanity check */
158 }
157 }
159 pos += 12 + len;
158 pos += 12 + len;
160 outlen += start - last;
159 outlen += start - last;
161 last = end;
160 last = end;
162 outlen += len;
161 outlen += len;
163 }
162 }
164
163
165 if (pos != patchlen) {
164 if (pos != patchlen) {
166 if (!PyErr_Occurred()) {
165 if (!PyErr_Occurred()) {
167 PyErr_SetString(mpatch_Error,
166 PyErr_SetString(mpatch_Error,
168 "patch cannot be decoded");
167 "patch cannot be decoded");
169 }
168 }
170 return NULL;
169 return NULL;
171 }
170 }
172
171
173 outlen += orig - last;
172 outlen += orig - last;
174 return Py_BuildValue("l", outlen);
173 return Py_BuildValue("l", outlen);
175 }
174 }
176
175
177 static PyMethodDef methods[] = {
176 static PyMethodDef methods[] = {
178 {"patches", patches, METH_VARARGS, "apply a series of patches\n"},
177 {"patches", patches, METH_VARARGS, "apply a series of patches\n"},
179 {"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"},
178 {"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"},
180 {NULL, NULL},
179 {NULL, NULL},
181 };
180 };
182
181
183 static const int version = 1;
182 static const int version = 1;
184
183
185 static struct PyModuleDef mpatch_module = {
184 static struct PyModuleDef mpatch_module = {
186 PyModuleDef_HEAD_INIT, "mpatch", mpatch_doc, -1, methods,
185 PyModuleDef_HEAD_INIT, "mpatch", mpatch_doc, -1, methods,
187 };
186 };
188
187
189 PyMODINIT_FUNC PyInit_mpatch(void)
188 PyMODINIT_FUNC PyInit_mpatch(void)
190 {
189 {
191 PyObject *m;
190 PyObject *m;
192
191
193 m = PyModule_Create(&mpatch_module);
192 m = PyModule_Create(&mpatch_module);
194 if (m == NULL)
193 if (m == NULL)
195 return NULL;
194 return NULL;
196
195
197 mpatch_Error =
196 mpatch_Error =
198 PyErr_NewException("mercurial.cext.mpatch.mpatchError", NULL, NULL);
197 PyErr_NewException("mercurial.cext.mpatch.mpatchError", NULL, NULL);
199 Py_INCREF(mpatch_Error);
198 Py_INCREF(mpatch_Error);
200 PyModule_AddObject(m, "mpatchError", mpatch_Error);
199 PyModule_AddObject(m, "mpatchError", mpatch_Error);
201 PyModule_AddIntConstant(m, "version", version);
200 PyModule_AddIntConstant(m, "version", version);
202
201
203 return m;
202 return m;
204 }
203 }
@@ -1,1391 +1,1389 b''
1 /*
1 /*
2 osutil.c - native operating system services
2 osutil.c - native operating system services
3
3
4 Copyright 2007 Olivia Mackall and others
4 Copyright 2007 Olivia 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 #define PY_SSIZE_T_CLEAN
11 #define PY_SSIZE_T_CLEAN
12 #include <Python.h>
12 #include <Python.h>
13 #include <errno.h>
13 #include <errno.h>
14 #include <fcntl.h>
14 #include <fcntl.h>
15 #include <stdio.h>
15 #include <stdio.h>
16 #include <stdlib.h>
16 #include <stdlib.h>
17 #include <string.h>
17 #include <string.h>
18
18
19 #ifdef _WIN32
19 #ifdef _WIN32
20 #include <io.h>
20 #include <io.h>
21 #include <windows.h>
21 #include <windows.h>
22 #else
22 #else
23 #include <dirent.h>
23 #include <dirent.h>
24 #include <signal.h>
24 #include <signal.h>
25 #include <sys/socket.h>
25 #include <sys/socket.h>
26 #include <sys/stat.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
27 #include <sys/types.h>
28 #include <unistd.h>
28 #include <unistd.h>
29 #ifdef HAVE_LINUX_STATFS
29 #ifdef HAVE_LINUX_STATFS
30 #include <linux/magic.h>
30 #include <linux/magic.h>
31 #include <sys/vfs.h>
31 #include <sys/vfs.h>
32 #endif
32 #endif
33 #ifdef HAVE_BSD_STATFS
33 #ifdef HAVE_BSD_STATFS
34 #include <sys/mount.h>
34 #include <sys/mount.h>
35 #include <sys/param.h>
35 #include <sys/param.h>
36 #endif
36 #endif
37 #endif
37 #endif
38
38
39 #ifdef __APPLE__
39 #ifdef __APPLE__
40 #include <sys/attr.h>
40 #include <sys/attr.h>
41 #include <sys/vnode.h>
41 #include <sys/vnode.h>
42 #endif
42 #endif
43
43
44 #include "util.h"
44 #include "util.h"
45
45
46 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
46 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
47 #ifndef PATH_MAX
47 #ifndef PATH_MAX
48 #define PATH_MAX 4096
48 #define PATH_MAX 4096
49 #endif
49 #endif
50
50
51 #ifdef _WIN32
51 #ifdef _WIN32
52 /*
52 /*
53 stat struct compatible with hg expectations
53 stat struct compatible with hg expectations
54 Mercurial only uses st_mode, st_size and st_mtime
54 Mercurial only uses st_mode, st_size and st_mtime
55 the rest is kept to minimize changes between implementations
55 the rest is kept to minimize changes between implementations
56 */
56 */
57 struct hg_stat {
57 struct hg_stat {
58 int st_dev;
58 int st_dev;
59 int st_mode;
59 int st_mode;
60 int st_nlink;
60 int st_nlink;
61 __int64 st_size;
61 __int64 st_size;
62 int st_mtime;
62 int st_mtime;
63 int st_ctime;
63 int st_ctime;
64 };
64 };
65 struct listdir_stat {
65 struct listdir_stat {
66 PyObject_HEAD
66 PyObject_HEAD
67 struct hg_stat st;
67 struct hg_stat st;
68 };
68 };
69 #else
69 #else
70 struct listdir_stat {
70 struct listdir_stat {
71 PyObject_HEAD
71 PyObject_HEAD
72 struct stat st;
72 struct stat st;
73 };
73 };
74 #endif
74 #endif
75
75
76 #define listdir_slot(name) \
76 #define listdir_slot(name) \
77 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
77 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
78 { \
78 { \
79 return PyLong_FromLong(((struct listdir_stat *)self)->st.name); \
79 return PyLong_FromLong(((struct listdir_stat *)self)->st.name); \
80 }
80 }
81
81
82 listdir_slot(st_dev)
82 listdir_slot(st_dev)
83 listdir_slot(st_mode)
83 listdir_slot(st_mode)
84 listdir_slot(st_nlink)
84 listdir_slot(st_nlink)
85 #ifdef _WIN32
85 #ifdef _WIN32
86 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
86 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
87 {
87 {
88 return PyLong_FromLongLong(
88 return PyLong_FromLongLong(
89 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
89 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
90 }
90 }
91 #else
91 #else
92 listdir_slot(st_size)
92 listdir_slot(st_size)
93 #endif
93 #endif
94 listdir_slot(st_mtime)
94 listdir_slot(st_mtime)
95 listdir_slot(st_ctime)
95 listdir_slot(st_ctime)
96
96
97 static struct PyGetSetDef listdir_stat_getsets[] = {
97 static struct PyGetSetDef listdir_stat_getsets[] = {
98 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
98 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
99 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
99 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
100 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
100 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
101 {"st_size", listdir_stat_st_size, 0, 0, 0},
101 {"st_size", listdir_stat_st_size, 0, 0, 0},
102 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
102 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
103 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
103 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
104 {0, 0, 0, 0, 0}
104 {0, 0, 0, 0, 0}
105 };
105 };
106
106
107 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
107 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
108 {
108 {
109 return t->tp_alloc(t, 0);
109 return t->tp_alloc(t, 0);
110 }
110 }
111
111
112 static void listdir_stat_dealloc(PyObject *o)
112 static void listdir_stat_dealloc(PyObject *o)
113 {
113 {
114 Py_TYPE(o)->tp_free(o);
114 Py_TYPE(o)->tp_free(o);
115 }
115 }
116
116
117 static PyObject *listdir_stat_getitem(PyObject *self, PyObject *key)
117 static PyObject *listdir_stat_getitem(PyObject *self, PyObject *key)
118 {
118 {
119 long index = PyLong_AsLong(key);
119 long index = PyLong_AsLong(key);
120 if (index == -1 && PyErr_Occurred()) {
120 if (index == -1 && PyErr_Occurred()) {
121 return NULL;
121 return NULL;
122 }
122 }
123 if (index != 8) {
123 if (index != 8) {
124 PyErr_Format(PyExc_IndexError, "osutil.stat objects only "
124 PyErr_Format(PyExc_IndexError, "osutil.stat objects only "
125 "support stat.ST_MTIME in "
125 "support stat.ST_MTIME in "
126 "__getitem__");
126 "__getitem__");
127 return NULL;
127 return NULL;
128 }
128 }
129 return listdir_stat_st_mtime(self, NULL);
129 return listdir_stat_st_mtime(self, NULL);
130 }
130 }
131
131
132 static PyMappingMethods listdir_stat_type_mapping_methods = {
132 static PyMappingMethods listdir_stat_type_mapping_methods = {
133 (lenfunc)NULL, /* mp_length */
133 (lenfunc)NULL, /* mp_length */
134 (binaryfunc)listdir_stat_getitem, /* mp_subscript */
134 (binaryfunc)listdir_stat_getitem, /* mp_subscript */
135 (objobjargproc)NULL, /* mp_ass_subscript */
135 (objobjargproc)NULL, /* mp_ass_subscript */
136 };
136 };
137
137
138 static PyTypeObject listdir_stat_type = {
138 static PyTypeObject listdir_stat_type = {
139 PyVarObject_HEAD_INIT(NULL, 0) /* header */
139 PyVarObject_HEAD_INIT(NULL, 0) /* header */
140 "osutil.stat", /*tp_name*/
140 "osutil.stat", /*tp_name*/
141 sizeof(struct listdir_stat), /*tp_basicsize*/
141 sizeof(struct listdir_stat), /*tp_basicsize*/
142 0, /*tp_itemsize*/
142 0, /*tp_itemsize*/
143 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
143 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
144 0, /*tp_print*/
144 0, /*tp_print*/
145 0, /*tp_getattr*/
145 0, /*tp_getattr*/
146 0, /*tp_setattr*/
146 0, /*tp_setattr*/
147 0, /*tp_compare*/
147 0, /*tp_compare*/
148 0, /*tp_repr*/
148 0, /*tp_repr*/
149 0, /*tp_as_number*/
149 0, /*tp_as_number*/
150 0, /*tp_as_sequence*/
150 0, /*tp_as_sequence*/
151 &listdir_stat_type_mapping_methods, /*tp_as_mapping*/
151 &listdir_stat_type_mapping_methods, /*tp_as_mapping*/
152 0, /*tp_hash */
152 0, /*tp_hash */
153 0, /*tp_call*/
153 0, /*tp_call*/
154 0, /*tp_str*/
154 0, /*tp_str*/
155 0, /*tp_getattro*/
155 0, /*tp_getattro*/
156 0, /*tp_setattro*/
156 0, /*tp_setattro*/
157 0, /*tp_as_buffer*/
157 0, /*tp_as_buffer*/
158 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
158 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
159 "stat objects", /* tp_doc */
159 "stat objects", /* tp_doc */
160 0, /* tp_traverse */
160 0, /* tp_traverse */
161 0, /* tp_clear */
161 0, /* tp_clear */
162 0, /* tp_richcompare */
162 0, /* tp_richcompare */
163 0, /* tp_weaklistoffset */
163 0, /* tp_weaklistoffset */
164 0, /* tp_iter */
164 0, /* tp_iter */
165 0, /* tp_iternext */
165 0, /* tp_iternext */
166 0, /* tp_methods */
166 0, /* tp_methods */
167 0, /* tp_members */
167 0, /* tp_members */
168 listdir_stat_getsets, /* tp_getset */
168 listdir_stat_getsets, /* tp_getset */
169 0, /* tp_base */
169 0, /* tp_base */
170 0, /* tp_dict */
170 0, /* tp_dict */
171 0, /* tp_descr_get */
171 0, /* tp_descr_get */
172 0, /* tp_descr_set */
172 0, /* tp_descr_set */
173 0, /* tp_dictoffset */
173 0, /* tp_dictoffset */
174 0, /* tp_init */
174 0, /* tp_init */
175 0, /* tp_alloc */
175 0, /* tp_alloc */
176 listdir_stat_new, /* tp_new */
176 listdir_stat_new, /* tp_new */
177 };
177 };
178
178
179 #ifdef _WIN32
179 #ifdef _WIN32
180
180
181 static int to_python_time(const FILETIME *tm)
181 static int to_python_time(const FILETIME *tm)
182 {
182 {
183 /* number of seconds between epoch and January 1 1601 */
183 /* number of seconds between epoch and January 1 1601 */
184 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
184 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
185 /* conversion factor from 100ns to 1s */
185 /* conversion factor from 100ns to 1s */
186 const __int64 a1 = 10000000;
186 const __int64 a1 = 10000000;
187 /* explicit (int) cast to suspend compiler warnings */
187 /* explicit (int) cast to suspend compiler warnings */
188 return (int)((((__int64)tm->dwHighDateTime << 32)
188 return (int)((((__int64)tm->dwHighDateTime << 32)
189 + tm->dwLowDateTime) / a1 - a0);
189 + tm->dwLowDateTime) / a1 - a0);
190 }
190 }
191
191
192 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
192 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
193 {
193 {
194 PyObject *py_st;
194 PyObject *py_st;
195 struct hg_stat *stp;
195 struct hg_stat *stp;
196
196
197 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
197 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
198 ? _S_IFDIR : _S_IFREG;
198 ? _S_IFDIR : _S_IFREG;
199
199
200 if (!wantstat)
200 if (!wantstat)
201 return Py_BuildValue(PY23("si", "yi"), fd->cFileName, kind);
201 return Py_BuildValue("yi", fd->cFileName, kind);
202
202
203 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
203 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
204 if (!py_st)
204 if (!py_st)
205 return NULL;
205 return NULL;
206
206
207 stp = &((struct listdir_stat *)py_st)->st;
207 stp = &((struct listdir_stat *)py_st)->st;
208 /*
208 /*
209 use kind as st_mode
209 use kind as st_mode
210 rwx bits on Win32 are meaningless
210 rwx bits on Win32 are meaningless
211 and Hg does not use them anyway
211 and Hg does not use them anyway
212 */
212 */
213 stp->st_mode = kind;
213 stp->st_mode = kind;
214 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
214 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
215 stp->st_ctime = to_python_time(&fd->ftCreationTime);
215 stp->st_ctime = to_python_time(&fd->ftCreationTime);
216 if (kind == _S_IFREG)
216 if (kind == _S_IFREG)
217 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
217 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
218 + fd->nFileSizeLow;
218 + fd->nFileSizeLow;
219 return Py_BuildValue(PY23("siN", "yiN"), fd->cFileName,
219 return Py_BuildValue("yiN", fd->cFileName,
220 kind, py_st);
220 kind, py_st);
221 }
221 }
222
222
223 static PyObject *_listdir(char *path, Py_ssize_t plen, int wantstat, char *skip)
223 static PyObject *_listdir(char *path, Py_ssize_t plen, int wantstat, char *skip)
224 {
224 {
225 PyObject *rval = NULL; /* initialize - return value */
225 PyObject *rval = NULL; /* initialize - return value */
226 PyObject *list;
226 PyObject *list;
227 HANDLE fh;
227 HANDLE fh;
228 WIN32_FIND_DATAA fd;
228 WIN32_FIND_DATAA fd;
229 char *pattern;
229 char *pattern;
230
230
231 /* build the path + \* pattern string */
231 /* build the path + \* pattern string */
232 pattern = PyMem_Malloc(plen + 3); /* path + \* + \0 */
232 pattern = PyMem_Malloc(plen + 3); /* path + \* + \0 */
233 if (!pattern) {
233 if (!pattern) {
234 PyErr_NoMemory();
234 PyErr_NoMemory();
235 goto error_nomem;
235 goto error_nomem;
236 }
236 }
237 memcpy(pattern, path, plen);
237 memcpy(pattern, path, plen);
238
238
239 if (plen > 0) {
239 if (plen > 0) {
240 char c = path[plen-1];
240 char c = path[plen-1];
241 if (c != ':' && c != '/' && c != '\\')
241 if (c != ':' && c != '/' && c != '\\')
242 pattern[plen++] = '\\';
242 pattern[plen++] = '\\';
243 }
243 }
244 pattern[plen++] = '*';
244 pattern[plen++] = '*';
245 pattern[plen] = '\0';
245 pattern[plen] = '\0';
246
246
247 fh = FindFirstFileA(pattern, &fd);
247 fh = FindFirstFileA(pattern, &fd);
248 if (fh == INVALID_HANDLE_VALUE) {
248 if (fh == INVALID_HANDLE_VALUE) {
249 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
249 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
250 goto error_file;
250 goto error_file;
251 }
251 }
252
252
253 list = PyList_New(0);
253 list = PyList_New(0);
254 if (!list)
254 if (!list)
255 goto error_list;
255 goto error_list;
256
256
257 do {
257 do {
258 PyObject *item;
258 PyObject *item;
259
259
260 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
260 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
261 if (!strcmp(fd.cFileName, ".")
261 if (!strcmp(fd.cFileName, ".")
262 || !strcmp(fd.cFileName, ".."))
262 || !strcmp(fd.cFileName, ".."))
263 continue;
263 continue;
264
264
265 if (skip && !strcmp(fd.cFileName, skip)) {
265 if (skip && !strcmp(fd.cFileName, skip)) {
266 rval = PyList_New(0);
266 rval = PyList_New(0);
267 goto error;
267 goto error;
268 }
268 }
269 }
269 }
270
270
271 item = make_item(&fd, wantstat);
271 item = make_item(&fd, wantstat);
272 if (!item)
272 if (!item)
273 goto error;
273 goto error;
274
274
275 if (PyList_Append(list, item)) {
275 if (PyList_Append(list, item)) {
276 Py_XDECREF(item);
276 Py_XDECREF(item);
277 goto error;
277 goto error;
278 }
278 }
279
279
280 Py_XDECREF(item);
280 Py_XDECREF(item);
281 } while (FindNextFileA(fh, &fd));
281 } while (FindNextFileA(fh, &fd));
282
282
283 if (GetLastError() != ERROR_NO_MORE_FILES) {
283 if (GetLastError() != ERROR_NO_MORE_FILES) {
284 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
284 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
285 goto error;
285 goto error;
286 }
286 }
287
287
288 rval = list;
288 rval = list;
289 Py_XINCREF(rval);
289 Py_XINCREF(rval);
290 error:
290 error:
291 Py_XDECREF(list);
291 Py_XDECREF(list);
292 error_list:
292 error_list:
293 FindClose(fh);
293 FindClose(fh);
294 error_file:
294 error_file:
295 PyMem_Free(pattern);
295 PyMem_Free(pattern);
296 error_nomem:
296 error_nomem:
297 return rval;
297 return rval;
298 }
298 }
299
299
300 #else
300 #else
301
301
302 int entkind(struct dirent *ent)
302 int entkind(struct dirent *ent)
303 {
303 {
304 #ifdef DT_REG
304 #ifdef DT_REG
305 switch (ent->d_type) {
305 switch (ent->d_type) {
306 case DT_REG: return S_IFREG;
306 case DT_REG: return S_IFREG;
307 case DT_DIR: return S_IFDIR;
307 case DT_DIR: return S_IFDIR;
308 case DT_LNK: return S_IFLNK;
308 case DT_LNK: return S_IFLNK;
309 case DT_BLK: return S_IFBLK;
309 case DT_BLK: return S_IFBLK;
310 case DT_CHR: return S_IFCHR;
310 case DT_CHR: return S_IFCHR;
311 case DT_FIFO: return S_IFIFO;
311 case DT_FIFO: return S_IFIFO;
312 case DT_SOCK: return S_IFSOCK;
312 case DT_SOCK: return S_IFSOCK;
313 }
313 }
314 #endif
314 #endif
315 return -1;
315 return -1;
316 }
316 }
317
317
318 static PyObject *makestat(const struct stat *st)
318 static PyObject *makestat(const struct stat *st)
319 {
319 {
320 PyObject *stat;
320 PyObject *stat;
321
321
322 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
322 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
323 if (stat)
323 if (stat)
324 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
324 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
325 return stat;
325 return stat;
326 }
326 }
327
327
328 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
328 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
329 char *skip)
329 char *skip)
330 {
330 {
331 PyObject *list, *elem, *ret = NULL;
331 PyObject *list, *elem, *ret = NULL;
332 char fullpath[PATH_MAX + 10];
332 char fullpath[PATH_MAX + 10];
333 int kind, err;
333 int kind, err;
334 struct stat st;
334 struct stat st;
335 struct dirent *ent;
335 struct dirent *ent;
336 DIR *dir;
336 DIR *dir;
337 #ifdef AT_SYMLINK_NOFOLLOW
337 #ifdef AT_SYMLINK_NOFOLLOW
338 int dfd = -1;
338 int dfd = -1;
339 #endif
339 #endif
340
340
341 if (pathlen >= PATH_MAX) {
341 if (pathlen >= PATH_MAX) {
342 errno = ENAMETOOLONG;
342 errno = ENAMETOOLONG;
343 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
343 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
344 goto error_value;
344 goto error_value;
345 }
345 }
346 strncpy(fullpath, path, PATH_MAX);
346 strncpy(fullpath, path, PATH_MAX);
347 fullpath[pathlen] = '/';
347 fullpath[pathlen] = '/';
348
348
349 #ifdef AT_SYMLINK_NOFOLLOW
349 #ifdef AT_SYMLINK_NOFOLLOW
350 dfd = open(path, O_RDONLY);
350 dfd = open(path, O_RDONLY);
351 if (dfd == -1) {
351 if (dfd == -1) {
352 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
352 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
353 goto error_value;
353 goto error_value;
354 }
354 }
355 dir = fdopendir(dfd);
355 dir = fdopendir(dfd);
356 #else
356 #else
357 dir = opendir(path);
357 dir = opendir(path);
358 #endif
358 #endif
359 if (!dir) {
359 if (!dir) {
360 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
360 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
361 goto error_dir;
361 goto error_dir;
362 }
362 }
363
363
364 list = PyList_New(0);
364 list = PyList_New(0);
365 if (!list)
365 if (!list)
366 goto error_list;
366 goto error_list;
367
367
368 while ((ent = readdir(dir))) {
368 while ((ent = readdir(dir))) {
369 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
369 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
370 continue;
370 continue;
371
371
372 kind = entkind(ent);
372 kind = entkind(ent);
373 if (kind == -1 || keepstat) {
373 if (kind == -1 || keepstat) {
374 #ifdef AT_SYMLINK_NOFOLLOW
374 #ifdef AT_SYMLINK_NOFOLLOW
375 err = fstatat(dfd, ent->d_name, &st,
375 err = fstatat(dfd, ent->d_name, &st,
376 AT_SYMLINK_NOFOLLOW);
376 AT_SYMLINK_NOFOLLOW);
377 #else
377 #else
378 strncpy(fullpath + pathlen + 1, ent->d_name,
378 strncpy(fullpath + pathlen + 1, ent->d_name,
379 PATH_MAX - pathlen);
379 PATH_MAX - pathlen);
380 fullpath[PATH_MAX] = '\0';
380 fullpath[PATH_MAX] = '\0';
381 err = lstat(fullpath, &st);
381 err = lstat(fullpath, &st);
382 #endif
382 #endif
383 if (err == -1) {
383 if (err == -1) {
384 /* race with file deletion? */
384 /* race with file deletion? */
385 if (errno == ENOENT)
385 if (errno == ENOENT)
386 continue;
386 continue;
387 strncpy(fullpath + pathlen + 1, ent->d_name,
387 strncpy(fullpath + pathlen + 1, ent->d_name,
388 PATH_MAX - pathlen);
388 PATH_MAX - pathlen);
389 fullpath[PATH_MAX] = 0;
389 fullpath[PATH_MAX] = 0;
390 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
390 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
391 fullpath);
391 fullpath);
392 goto error;
392 goto error;
393 }
393 }
394 kind = st.st_mode & S_IFMT;
394 kind = st.st_mode & S_IFMT;
395 }
395 }
396
396
397 /* quit early? */
397 /* quit early? */
398 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
398 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
399 ret = PyList_New(0);
399 ret = PyList_New(0);
400 goto error;
400 goto error;
401 }
401 }
402
402
403 if (keepstat) {
403 if (keepstat) {
404 PyObject *stat = makestat(&st);
404 PyObject *stat = makestat(&st);
405 if (!stat)
405 if (!stat)
406 goto error;
406 goto error;
407 elem = Py_BuildValue(PY23("siN", "yiN"), ent->d_name,
407 elem = Py_BuildValue("yiN", ent->d_name,
408 kind, stat);
408 kind, stat);
409 } else
409 } else
410 elem = Py_BuildValue(PY23("si", "yi"), ent->d_name,
410 elem = Py_BuildValue("yi", ent->d_name,
411 kind);
411 kind);
412 if (!elem)
412 if (!elem)
413 goto error;
413 goto error;
414
414
415 PyList_Append(list, elem);
415 PyList_Append(list, elem);
416 Py_DECREF(elem);
416 Py_DECREF(elem);
417 }
417 }
418
418
419 ret = list;
419 ret = list;
420 Py_INCREF(ret);
420 Py_INCREF(ret);
421
421
422 error:
422 error:
423 Py_DECREF(list);
423 Py_DECREF(list);
424 error_list:
424 error_list:
425 closedir(dir);
425 closedir(dir);
426 /* closedir also closes its dirfd */
426 /* closedir also closes its dirfd */
427 goto error_value;
427 goto error_value;
428 error_dir:
428 error_dir:
429 #ifdef AT_SYMLINK_NOFOLLOW
429 #ifdef AT_SYMLINK_NOFOLLOW
430 close(dfd);
430 close(dfd);
431 #endif
431 #endif
432 error_value:
432 error_value:
433 return ret;
433 return ret;
434 }
434 }
435
435
436 #ifdef __APPLE__
436 #ifdef __APPLE__
437
437
438 typedef struct {
438 typedef struct {
439 u_int32_t length;
439 u_int32_t length;
440 attrreference_t name;
440 attrreference_t name;
441 fsobj_type_t obj_type;
441 fsobj_type_t obj_type;
442 struct timespec mtime;
442 struct timespec mtime;
443 #if __LITTLE_ENDIAN__
443 #if __LITTLE_ENDIAN__
444 mode_t access_mask;
444 mode_t access_mask;
445 uint16_t padding;
445 uint16_t padding;
446 #else
446 #else
447 uint16_t padding;
447 uint16_t padding;
448 mode_t access_mask;
448 mode_t access_mask;
449 #endif
449 #endif
450 off_t size;
450 off_t size;
451 } __attribute__((packed)) attrbuf_entry;
451 } __attribute__((packed)) attrbuf_entry;
452
452
453 int attrkind(attrbuf_entry *entry)
453 int attrkind(attrbuf_entry *entry)
454 {
454 {
455 switch (entry->obj_type) {
455 switch (entry->obj_type) {
456 case VREG: return S_IFREG;
456 case VREG: return S_IFREG;
457 case VDIR: return S_IFDIR;
457 case VDIR: return S_IFDIR;
458 case VLNK: return S_IFLNK;
458 case VLNK: return S_IFLNK;
459 case VBLK: return S_IFBLK;
459 case VBLK: return S_IFBLK;
460 case VCHR: return S_IFCHR;
460 case VCHR: return S_IFCHR;
461 case VFIFO: return S_IFIFO;
461 case VFIFO: return S_IFIFO;
462 case VSOCK: return S_IFSOCK;
462 case VSOCK: return S_IFSOCK;
463 }
463 }
464 return -1;
464 return -1;
465 }
465 }
466
466
467 /* get these many entries at a time */
467 /* get these many entries at a time */
468 #define LISTDIR_BATCH_SIZE 50
468 #define LISTDIR_BATCH_SIZE 50
469
469
470 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
470 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
471 char *skip, bool *fallback)
471 char *skip, bool *fallback)
472 {
472 {
473 PyObject *list, *elem, *ret = NULL;
473 PyObject *list, *elem, *ret = NULL;
474 int kind, err;
474 int kind, err;
475 unsigned long index;
475 unsigned long index;
476 unsigned int count, old_state, new_state;
476 unsigned int count, old_state, new_state;
477 bool state_seen = false;
477 bool state_seen = false;
478 attrbuf_entry *entry;
478 attrbuf_entry *entry;
479 /* from the getattrlist(2) man page: a path can be no longer than
479 /* from the getattrlist(2) man page: a path can be no longer than
480 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
480 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
481 silently truncate attribute data if attrBufSize is too small." So
481 silently truncate attribute data if attrBufSize is too small." So
482 pass in a buffer big enough for the worst case. */
482 pass in a buffer big enough for the worst case. */
483 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
483 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
484 unsigned int basep_unused;
484 unsigned int basep_unused;
485
485
486 struct stat st;
486 struct stat st;
487 int dfd = -1;
487 int dfd = -1;
488
488
489 /* these must match the attrbuf_entry struct, otherwise you'll end up
489 /* these must match the attrbuf_entry struct, otherwise you'll end up
490 with garbage */
490 with garbage */
491 struct attrlist requested_attr = {0};
491 struct attrlist requested_attr = {0};
492 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
492 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
493 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
493 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
494 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
494 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
495 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
495 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
496
496
497 *fallback = false;
497 *fallback = false;
498
498
499 if (pathlen >= PATH_MAX) {
499 if (pathlen >= PATH_MAX) {
500 errno = ENAMETOOLONG;
500 errno = ENAMETOOLONG;
501 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
501 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
502 goto error_value;
502 goto error_value;
503 }
503 }
504
504
505 dfd = open(path, O_RDONLY);
505 dfd = open(path, O_RDONLY);
506 if (dfd == -1) {
506 if (dfd == -1) {
507 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
507 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
508 goto error_value;
508 goto error_value;
509 }
509 }
510
510
511 list = PyList_New(0);
511 list = PyList_New(0);
512 if (!list)
512 if (!list)
513 goto error_dir;
513 goto error_dir;
514
514
515 do {
515 do {
516 count = LISTDIR_BATCH_SIZE;
516 count = LISTDIR_BATCH_SIZE;
517 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
517 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
518 sizeof(attrbuf), &count, &basep_unused,
518 sizeof(attrbuf), &count, &basep_unused,
519 &new_state, 0);
519 &new_state, 0);
520 if (err < 0) {
520 if (err < 0) {
521 if (errno == ENOTSUP) {
521 if (errno == ENOTSUP) {
522 /* We're on a filesystem that doesn't support
522 /* We're on a filesystem that doesn't support
523 getdirentriesattr. Fall back to the
523 getdirentriesattr. Fall back to the
524 stat-based implementation. */
524 stat-based implementation. */
525 *fallback = true;
525 *fallback = true;
526 } else
526 } else
527 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
527 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
528 goto error;
528 goto error;
529 }
529 }
530
530
531 if (!state_seen) {
531 if (!state_seen) {
532 old_state = new_state;
532 old_state = new_state;
533 state_seen = true;
533 state_seen = true;
534 } else if (old_state != new_state) {
534 } else if (old_state != new_state) {
535 /* There's an edge case with getdirentriesattr. Consider
535 /* There's an edge case with getdirentriesattr. Consider
536 the following initial list of files:
536 the following initial list of files:
537
537
538 a
538 a
539 b
539 b
540 <--
540 <--
541 c
541 c
542 d
542 d
543
543
544 If the iteration is paused at the arrow, and b is
544 If the iteration is paused at the arrow, and b is
545 deleted before it is resumed, getdirentriesattr will
545 deleted before it is resumed, getdirentriesattr will
546 not return d at all! Ordinarily we're expected to
546 not return d at all! Ordinarily we're expected to
547 restart the iteration from the beginning. To avoid
547 restart the iteration from the beginning. To avoid
548 getting stuck in a retry loop here, fall back to
548 getting stuck in a retry loop here, fall back to
549 stat. */
549 stat. */
550 *fallback = true;
550 *fallback = true;
551 goto error;
551 goto error;
552 }
552 }
553
553
554 entry = (attrbuf_entry *)attrbuf;
554 entry = (attrbuf_entry *)attrbuf;
555
555
556 for (index = 0; index < count; index++) {
556 for (index = 0; index < count; index++) {
557 char *filename = ((char *)&entry->name) +
557 char *filename = ((char *)&entry->name) +
558 entry->name.attr_dataoffset;
558 entry->name.attr_dataoffset;
559
559
560 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
560 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
561 continue;
561 continue;
562
562
563 kind = attrkind(entry);
563 kind = attrkind(entry);
564 if (kind == -1) {
564 if (kind == -1) {
565 PyErr_Format(PyExc_OSError,
565 PyErr_Format(PyExc_OSError,
566 "unknown object type %u for file "
566 "unknown object type %u for file "
567 "%s%s!",
567 "%s%s!",
568 entry->obj_type, path, filename);
568 entry->obj_type, path, filename);
569 goto error;
569 goto error;
570 }
570 }
571
571
572 /* quit early? */
572 /* quit early? */
573 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
573 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
574 ret = PyList_New(0);
574 ret = PyList_New(0);
575 goto error;
575 goto error;
576 }
576 }
577
577
578 if (keepstat) {
578 if (keepstat) {
579 PyObject *stat = NULL;
579 PyObject *stat = NULL;
580 /* from the getattrlist(2) man page: "Only the
580 /* from the getattrlist(2) man page: "Only the
581 permission bits ... are valid". */
581 permission bits ... are valid". */
582 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
582 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
583 st.st_mtime = entry->mtime.tv_sec;
583 st.st_mtime = entry->mtime.tv_sec;
584 st.st_size = entry->size;
584 st.st_size = entry->size;
585 stat = makestat(&st);
585 stat = makestat(&st);
586 if (!stat)
586 if (!stat)
587 goto error;
587 goto error;
588 elem = Py_BuildValue(PY23("siN", "yiN"),
588 elem = Py_BuildValue("yiN",
589 filename, kind, stat);
589 filename, kind, stat);
590 } else
590 } else
591 elem = Py_BuildValue(PY23("si", "yi"),
591 elem = Py_BuildValue("yi",
592 filename, kind);
592 filename, kind);
593 if (!elem)
593 if (!elem)
594 goto error;
594 goto error;
595
595
596 PyList_Append(list, elem);
596 PyList_Append(list, elem);
597 Py_DECREF(elem);
597 Py_DECREF(elem);
598
598
599 entry = (attrbuf_entry *)((char *)entry + entry->length);
599 entry = (attrbuf_entry *)((char *)entry + entry->length);
600 }
600 }
601 } while (err == 0);
601 } while (err == 0);
602
602
603 ret = list;
603 ret = list;
604 Py_INCREF(ret);
604 Py_INCREF(ret);
605
605
606 error:
606 error:
607 Py_DECREF(list);
607 Py_DECREF(list);
608 error_dir:
608 error_dir:
609 close(dfd);
609 close(dfd);
610 error_value:
610 error_value:
611 return ret;
611 return ret;
612 }
612 }
613
613
614 #endif /* __APPLE__ */
614 #endif /* __APPLE__ */
615
615
616 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
616 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
617 {
617 {
618 #ifdef __APPLE__
618 #ifdef __APPLE__
619 PyObject *ret;
619 PyObject *ret;
620 bool fallback = false;
620 bool fallback = false;
621
621
622 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
622 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
623 if (ret != NULL || !fallback)
623 if (ret != NULL || !fallback)
624 return ret;
624 return ret;
625 #endif
625 #endif
626 return _listdir_stat(path, pathlen, keepstat, skip);
626 return _listdir_stat(path, pathlen, keepstat, skip);
627 }
627 }
628
628
629 static PyObject *statfiles(PyObject *self, PyObject *args)
629 static PyObject *statfiles(PyObject *self, PyObject *args)
630 {
630 {
631 PyObject *names, *stats;
631 PyObject *names, *stats;
632 Py_ssize_t i, count;
632 Py_ssize_t i, count;
633
633
634 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
634 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
635 return NULL;
635 return NULL;
636
636
637 count = PySequence_Length(names);
637 count = PySequence_Length(names);
638 if (count == -1) {
638 if (count == -1) {
639 PyErr_SetString(PyExc_TypeError, "not a sequence");
639 PyErr_SetString(PyExc_TypeError, "not a sequence");
640 return NULL;
640 return NULL;
641 }
641 }
642
642
643 stats = PyList_New(count);
643 stats = PyList_New(count);
644 if (stats == NULL)
644 if (stats == NULL)
645 return NULL;
645 return NULL;
646
646
647 for (i = 0; i < count; i++) {
647 for (i = 0; i < count; i++) {
648 PyObject *stat, *pypath;
648 PyObject *stat, *pypath;
649 struct stat st;
649 struct stat st;
650 int ret, kind;
650 int ret, kind;
651 char *path;
651 char *path;
652
652
653 /* With a large file count or on a slow filesystem,
653 /* With a large file count or on a slow filesystem,
654 don't block signals for long (issue4878). */
654 don't block signals for long (issue4878). */
655 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
655 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
656 goto bail;
656 goto bail;
657
657
658 pypath = PySequence_GetItem(names, i);
658 pypath = PySequence_GetItem(names, i);
659 if (!pypath)
659 if (!pypath)
660 goto bail;
660 goto bail;
661 path = PyBytes_AsString(pypath);
661 path = PyBytes_AsString(pypath);
662 if (path == NULL) {
662 if (path == NULL) {
663 Py_DECREF(pypath);
663 Py_DECREF(pypath);
664 PyErr_SetString(PyExc_TypeError, "not a string");
664 PyErr_SetString(PyExc_TypeError, "not a string");
665 goto bail;
665 goto bail;
666 }
666 }
667 ret = lstat(path, &st);
667 ret = lstat(path, &st);
668 Py_DECREF(pypath);
668 Py_DECREF(pypath);
669 kind = st.st_mode & S_IFMT;
669 kind = st.st_mode & S_IFMT;
670 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
670 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
671 stat = makestat(&st);
671 stat = makestat(&st);
672 if (stat == NULL)
672 if (stat == NULL)
673 goto bail;
673 goto bail;
674 PyList_SET_ITEM(stats, i, stat);
674 PyList_SET_ITEM(stats, i, stat);
675 } else {
675 } else {
676 Py_INCREF(Py_None);
676 Py_INCREF(Py_None);
677 PyList_SET_ITEM(stats, i, Py_None);
677 PyList_SET_ITEM(stats, i, Py_None);
678 }
678 }
679 }
679 }
680
680
681 return stats;
681 return stats;
682
682
683 bail:
683 bail:
684 Py_DECREF(stats);
684 Py_DECREF(stats);
685 return NULL;
685 return NULL;
686 }
686 }
687
687
688 /*
688 /*
689 * recvfds() simply does not release GIL during blocking io operation because
689 * recvfds() simply does not release GIL during blocking io operation because
690 * command server is known to be single-threaded.
690 * command server is known to be single-threaded.
691 *
691 *
692 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
692 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
693 * Currently, recvfds() is not supported on these platforms.
693 * Currently, recvfds() is not supported on these platforms.
694 */
694 */
695 #ifdef CMSG_LEN
695 #ifdef CMSG_LEN
696
696
697 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
697 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
698 {
698 {
699 char dummy[1];
699 char dummy[1];
700 struct iovec iov = {dummy, sizeof(dummy)};
700 struct iovec iov = {dummy, sizeof(dummy)};
701 struct msghdr msgh = {0};
701 struct msghdr msgh = {0};
702 struct cmsghdr *cmsg;
702 struct cmsghdr *cmsg;
703
703
704 msgh.msg_iov = &iov;
704 msgh.msg_iov = &iov;
705 msgh.msg_iovlen = 1;
705 msgh.msg_iovlen = 1;
706 msgh.msg_control = cbuf;
706 msgh.msg_control = cbuf;
707 msgh.msg_controllen = (socklen_t)cbufsize;
707 msgh.msg_controllen = (socklen_t)cbufsize;
708 if (recvmsg(sockfd, &msgh, 0) < 0)
708 if (recvmsg(sockfd, &msgh, 0) < 0)
709 return -1;
709 return -1;
710
710
711 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
711 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
712 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
712 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
713 if (cmsg->cmsg_level != SOL_SOCKET ||
713 if (cmsg->cmsg_level != SOL_SOCKET ||
714 cmsg->cmsg_type != SCM_RIGHTS)
714 cmsg->cmsg_type != SCM_RIGHTS)
715 continue;
715 continue;
716 *rfds = (int *)CMSG_DATA(cmsg);
716 *rfds = (int *)CMSG_DATA(cmsg);
717 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
717 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
718 }
718 }
719
719
720 *rfds = cbuf;
720 *rfds = cbuf;
721 return 0;
721 return 0;
722 }
722 }
723
723
724 static PyObject *recvfds(PyObject *self, PyObject *args)
724 static PyObject *recvfds(PyObject *self, PyObject *args)
725 {
725 {
726 int sockfd;
726 int sockfd;
727 int *rfds = NULL;
727 int *rfds = NULL;
728 ssize_t rfdscount, i;
728 ssize_t rfdscount, i;
729 char cbuf[256];
729 char cbuf[256];
730 PyObject *rfdslist = NULL;
730 PyObject *rfdslist = NULL;
731
731
732 if (!PyArg_ParseTuple(args, "i", &sockfd))
732 if (!PyArg_ParseTuple(args, "i", &sockfd))
733 return NULL;
733 return NULL;
734
734
735 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
735 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
736 if (rfdscount < 0)
736 if (rfdscount < 0)
737 return PyErr_SetFromErrno(PyExc_OSError);
737 return PyErr_SetFromErrno(PyExc_OSError);
738
738
739 rfdslist = PyList_New(rfdscount);
739 rfdslist = PyList_New(rfdscount);
740 if (!rfdslist)
740 if (!rfdslist)
741 goto bail;
741 goto bail;
742 for (i = 0; i < rfdscount; i++) {
742 for (i = 0; i < rfdscount; i++) {
743 PyObject *obj = PyLong_FromLong(rfds[i]);
743 PyObject *obj = PyLong_FromLong(rfds[i]);
744 if (!obj)
744 if (!obj)
745 goto bail;
745 goto bail;
746 PyList_SET_ITEM(rfdslist, i, obj);
746 PyList_SET_ITEM(rfdslist, i, obj);
747 }
747 }
748 return rfdslist;
748 return rfdslist;
749
749
750 bail:
750 bail:
751 Py_XDECREF(rfdslist);
751 Py_XDECREF(rfdslist);
752 return NULL;
752 return NULL;
753 }
753 }
754
754
755 #endif /* CMSG_LEN */
755 #endif /* CMSG_LEN */
756
756
757 /* allow disabling setprocname via compiler flags */
757 /* allow disabling setprocname via compiler flags */
758 #ifndef SETPROCNAME_USE_NONE
758 #ifndef SETPROCNAME_USE_NONE
759 #if defined(HAVE_SETPROCTITLE)
759 #if defined(HAVE_SETPROCTITLE)
760 /* setproctitle is the first choice - available in FreeBSD */
760 /* setproctitle is the first choice - available in FreeBSD */
761 #define SETPROCNAME_USE_SETPROCTITLE
761 #define SETPROCNAME_USE_SETPROCTITLE
762 #elif (defined(__linux__) || defined(__APPLE__)) && PY_MAJOR_VERSION == 2
762 #elif (defined(__linux__) || defined(__APPLE__)) && PY_MAJOR_VERSION == 2
763 /* rewrite the argv buffer in place - works in Linux and OS X. Py_GetArgcArgv
763 /* rewrite the argv buffer in place - works in Linux and OS X. Py_GetArgcArgv
764 * in Python 3 returns the copied wchar_t **argv, thus unsupported. */
764 * in Python 3 returns the copied wchar_t **argv, thus unsupported. */
765 #define SETPROCNAME_USE_ARGVREWRITE
765 #define SETPROCNAME_USE_ARGVREWRITE
766 #else
766 #else
767 #define SETPROCNAME_USE_NONE
767 #define SETPROCNAME_USE_NONE
768 #endif
768 #endif
769 #endif /* ndef SETPROCNAME_USE_NONE */
769 #endif /* ndef SETPROCNAME_USE_NONE */
770
770
771 #ifndef SETPROCNAME_USE_NONE
771 #ifndef SETPROCNAME_USE_NONE
772 static PyObject *setprocname(PyObject *self, PyObject *args)
772 static PyObject *setprocname(PyObject *self, PyObject *args)
773 {
773 {
774 const char *name = NULL;
774 const char *name = NULL;
775 if (!PyArg_ParseTuple(args, PY23("s", "y"), &name))
775 if (!PyArg_ParseTuple(args, "y", &name))
776 return NULL;
776 return NULL;
777
777
778 #if defined(SETPROCNAME_USE_SETPROCTITLE)
778 #if defined(SETPROCNAME_USE_SETPROCTITLE)
779 setproctitle("%s", name);
779 setproctitle("%s", name);
780 #elif defined(SETPROCNAME_USE_ARGVREWRITE)
780 #elif defined(SETPROCNAME_USE_ARGVREWRITE)
781 {
781 {
782 static char *argvstart = NULL;
782 static char *argvstart = NULL;
783 static size_t argvsize = 0;
783 static size_t argvsize = 0;
784 if (argvstart == NULL) {
784 if (argvstart == NULL) {
785 int argc = 0, i;
785 int argc = 0, i;
786 char **argv = NULL;
786 char **argv = NULL;
787 char *argvend;
787 char *argvend;
788 extern void Py_GetArgcArgv(int *argc, char ***argv);
788 extern void Py_GetArgcArgv(int *argc, char ***argv);
789 Py_GetArgcArgv(&argc, &argv);
789 Py_GetArgcArgv(&argc, &argv);
790 /* Py_GetArgcArgv may not do much if a custom python
790 /* Py_GetArgcArgv may not do much if a custom python
791 * launcher is used that doesn't record the information
791 * launcher is used that doesn't record the information
792 * it needs. Let's handle this gracefully instead of
792 * it needs. Let's handle this gracefully instead of
793 * segfaulting. */
793 * segfaulting. */
794 if (argv != NULL)
794 if (argv != NULL)
795 argvend = argvstart = argv[0];
795 argvend = argvstart = argv[0];
796 else
796 else
797 argvend = argvstart = NULL;
797 argvend = argvstart = NULL;
798
798
799 /* Check the memory we can use. Typically, argv[i] and
799 /* Check the memory we can use. Typically, argv[i] and
800 * argv[i + 1] are continuous. */
800 * argv[i + 1] are continuous. */
801 for (i = 0; i < argc; ++i) {
801 for (i = 0; i < argc; ++i) {
802 size_t len;
802 size_t len;
803 if (argv[i] > argvend || argv[i] < argvstart)
803 if (argv[i] > argvend || argv[i] < argvstart)
804 break; /* not continuous */
804 break; /* not continuous */
805 len = strlen(argv[i]);
805 len = strlen(argv[i]);
806 argvend = argv[i] + len + 1 /* '\0' */;
806 argvend = argv[i] + len + 1 /* '\0' */;
807 }
807 }
808 if (argvend > argvstart) /* sanity check */
808 if (argvend > argvstart) /* sanity check */
809 argvsize = argvend - argvstart;
809 argvsize = argvend - argvstart;
810 }
810 }
811
811
812 if (argvstart && argvsize > 1) {
812 if (argvstart && argvsize > 1) {
813 int n = snprintf(argvstart, argvsize, "%s", name);
813 int n = snprintf(argvstart, argvsize, "%s", name);
814 if (n >= 0 && (size_t)n < argvsize)
814 if (n >= 0 && (size_t)n < argvsize)
815 memset(argvstart + n, 0, argvsize - n);
815 memset(argvstart + n, 0, argvsize - n);
816 }
816 }
817 }
817 }
818 #endif
818 #endif
819
819
820 Py_RETURN_NONE;
820 Py_RETURN_NONE;
821 }
821 }
822 #endif /* ndef SETPROCNAME_USE_NONE */
822 #endif /* ndef SETPROCNAME_USE_NONE */
823
823
824 #if defined(HAVE_BSD_STATFS)
824 #if defined(HAVE_BSD_STATFS)
825 static const char *describefstype(const struct statfs *pbuf)
825 static const char *describefstype(const struct statfs *pbuf)
826 {
826 {
827 /* BSD or OSX provides a f_fstypename field */
827 /* BSD or OSX provides a f_fstypename field */
828 return pbuf->f_fstypename;
828 return pbuf->f_fstypename;
829 }
829 }
830 #elif defined(HAVE_LINUX_STATFS)
830 #elif defined(HAVE_LINUX_STATFS)
831 static const char *describefstype(const struct statfs *pbuf)
831 static const char *describefstype(const struct statfs *pbuf)
832 {
832 {
833 /* Begin of Linux filesystems */
833 /* Begin of Linux filesystems */
834 #ifdef ADFS_SUPER_MAGIC
834 #ifdef ADFS_SUPER_MAGIC
835 if (pbuf->f_type == ADFS_SUPER_MAGIC)
835 if (pbuf->f_type == ADFS_SUPER_MAGIC)
836 return "adfs";
836 return "adfs";
837 #endif
837 #endif
838 #ifdef AFFS_SUPER_MAGIC
838 #ifdef AFFS_SUPER_MAGIC
839 if (pbuf->f_type == AFFS_SUPER_MAGIC)
839 if (pbuf->f_type == AFFS_SUPER_MAGIC)
840 return "affs";
840 return "affs";
841 #endif
841 #endif
842 #ifdef AUTOFS_SUPER_MAGIC
842 #ifdef AUTOFS_SUPER_MAGIC
843 if (pbuf->f_type == AUTOFS_SUPER_MAGIC)
843 if (pbuf->f_type == AUTOFS_SUPER_MAGIC)
844 return "autofs";
844 return "autofs";
845 #endif
845 #endif
846 #ifdef BDEVFS_MAGIC
846 #ifdef BDEVFS_MAGIC
847 if (pbuf->f_type == BDEVFS_MAGIC)
847 if (pbuf->f_type == BDEVFS_MAGIC)
848 return "bdevfs";
848 return "bdevfs";
849 #endif
849 #endif
850 #ifdef BEFS_SUPER_MAGIC
850 #ifdef BEFS_SUPER_MAGIC
851 if (pbuf->f_type == BEFS_SUPER_MAGIC)
851 if (pbuf->f_type == BEFS_SUPER_MAGIC)
852 return "befs";
852 return "befs";
853 #endif
853 #endif
854 #ifdef BFS_MAGIC
854 #ifdef BFS_MAGIC
855 if (pbuf->f_type == BFS_MAGIC)
855 if (pbuf->f_type == BFS_MAGIC)
856 return "bfs";
856 return "bfs";
857 #endif
857 #endif
858 #ifdef BINFMTFS_MAGIC
858 #ifdef BINFMTFS_MAGIC
859 if (pbuf->f_type == BINFMTFS_MAGIC)
859 if (pbuf->f_type == BINFMTFS_MAGIC)
860 return "binfmtfs";
860 return "binfmtfs";
861 #endif
861 #endif
862 #ifdef BTRFS_SUPER_MAGIC
862 #ifdef BTRFS_SUPER_MAGIC
863 if (pbuf->f_type == BTRFS_SUPER_MAGIC)
863 if (pbuf->f_type == BTRFS_SUPER_MAGIC)
864 return "btrfs";
864 return "btrfs";
865 #endif
865 #endif
866 #ifdef CGROUP_SUPER_MAGIC
866 #ifdef CGROUP_SUPER_MAGIC
867 if (pbuf->f_type == CGROUP_SUPER_MAGIC)
867 if (pbuf->f_type == CGROUP_SUPER_MAGIC)
868 return "cgroup";
868 return "cgroup";
869 #endif
869 #endif
870 #ifdef CIFS_MAGIC_NUMBER
870 #ifdef CIFS_MAGIC_NUMBER
871 if (pbuf->f_type == CIFS_MAGIC_NUMBER)
871 if (pbuf->f_type == CIFS_MAGIC_NUMBER)
872 return "cifs";
872 return "cifs";
873 #endif
873 #endif
874 #ifdef CODA_SUPER_MAGIC
874 #ifdef CODA_SUPER_MAGIC
875 if (pbuf->f_type == CODA_SUPER_MAGIC)
875 if (pbuf->f_type == CODA_SUPER_MAGIC)
876 return "coda";
876 return "coda";
877 #endif
877 #endif
878 #ifdef COH_SUPER_MAGIC
878 #ifdef COH_SUPER_MAGIC
879 if (pbuf->f_type == COH_SUPER_MAGIC)
879 if (pbuf->f_type == COH_SUPER_MAGIC)
880 return "coh";
880 return "coh";
881 #endif
881 #endif
882 #ifdef CRAMFS_MAGIC
882 #ifdef CRAMFS_MAGIC
883 if (pbuf->f_type == CRAMFS_MAGIC)
883 if (pbuf->f_type == CRAMFS_MAGIC)
884 return "cramfs";
884 return "cramfs";
885 #endif
885 #endif
886 #ifdef DEBUGFS_MAGIC
886 #ifdef DEBUGFS_MAGIC
887 if (pbuf->f_type == DEBUGFS_MAGIC)
887 if (pbuf->f_type == DEBUGFS_MAGIC)
888 return "debugfs";
888 return "debugfs";
889 #endif
889 #endif
890 #ifdef DEVFS_SUPER_MAGIC
890 #ifdef DEVFS_SUPER_MAGIC
891 if (pbuf->f_type == DEVFS_SUPER_MAGIC)
891 if (pbuf->f_type == DEVFS_SUPER_MAGIC)
892 return "devfs";
892 return "devfs";
893 #endif
893 #endif
894 #ifdef DEVPTS_SUPER_MAGIC
894 #ifdef DEVPTS_SUPER_MAGIC
895 if (pbuf->f_type == DEVPTS_SUPER_MAGIC)
895 if (pbuf->f_type == DEVPTS_SUPER_MAGIC)
896 return "devpts";
896 return "devpts";
897 #endif
897 #endif
898 #ifdef EFIVARFS_MAGIC
898 #ifdef EFIVARFS_MAGIC
899 if (pbuf->f_type == EFIVARFS_MAGIC)
899 if (pbuf->f_type == EFIVARFS_MAGIC)
900 return "efivarfs";
900 return "efivarfs";
901 #endif
901 #endif
902 #ifdef EFS_SUPER_MAGIC
902 #ifdef EFS_SUPER_MAGIC
903 if (pbuf->f_type == EFS_SUPER_MAGIC)
903 if (pbuf->f_type == EFS_SUPER_MAGIC)
904 return "efs";
904 return "efs";
905 #endif
905 #endif
906 #ifdef EXT_SUPER_MAGIC
906 #ifdef EXT_SUPER_MAGIC
907 if (pbuf->f_type == EXT_SUPER_MAGIC)
907 if (pbuf->f_type == EXT_SUPER_MAGIC)
908 return "ext";
908 return "ext";
909 #endif
909 #endif
910 #ifdef EXT2_OLD_SUPER_MAGIC
910 #ifdef EXT2_OLD_SUPER_MAGIC
911 if (pbuf->f_type == EXT2_OLD_SUPER_MAGIC)
911 if (pbuf->f_type == EXT2_OLD_SUPER_MAGIC)
912 return "ext2";
912 return "ext2";
913 #endif
913 #endif
914 #ifdef EXT2_SUPER_MAGIC
914 #ifdef EXT2_SUPER_MAGIC
915 if (pbuf->f_type == EXT2_SUPER_MAGIC)
915 if (pbuf->f_type == EXT2_SUPER_MAGIC)
916 return "ext2";
916 return "ext2";
917 #endif
917 #endif
918 #ifdef EXT3_SUPER_MAGIC
918 #ifdef EXT3_SUPER_MAGIC
919 if (pbuf->f_type == EXT3_SUPER_MAGIC)
919 if (pbuf->f_type == EXT3_SUPER_MAGIC)
920 return "ext3";
920 return "ext3";
921 #endif
921 #endif
922 #ifdef EXT4_SUPER_MAGIC
922 #ifdef EXT4_SUPER_MAGIC
923 if (pbuf->f_type == EXT4_SUPER_MAGIC)
923 if (pbuf->f_type == EXT4_SUPER_MAGIC)
924 return "ext4";
924 return "ext4";
925 #endif
925 #endif
926 #ifdef F2FS_SUPER_MAGIC
926 #ifdef F2FS_SUPER_MAGIC
927 if (pbuf->f_type == F2FS_SUPER_MAGIC)
927 if (pbuf->f_type == F2FS_SUPER_MAGIC)
928 return "f2fs";
928 return "f2fs";
929 #endif
929 #endif
930 #ifdef FUSE_SUPER_MAGIC
930 #ifdef FUSE_SUPER_MAGIC
931 if (pbuf->f_type == FUSE_SUPER_MAGIC)
931 if (pbuf->f_type == FUSE_SUPER_MAGIC)
932 return "fuse";
932 return "fuse";
933 #endif
933 #endif
934 #ifdef FUTEXFS_SUPER_MAGIC
934 #ifdef FUTEXFS_SUPER_MAGIC
935 if (pbuf->f_type == FUTEXFS_SUPER_MAGIC)
935 if (pbuf->f_type == FUTEXFS_SUPER_MAGIC)
936 return "futexfs";
936 return "futexfs";
937 #endif
937 #endif
938 #ifdef HFS_SUPER_MAGIC
938 #ifdef HFS_SUPER_MAGIC
939 if (pbuf->f_type == HFS_SUPER_MAGIC)
939 if (pbuf->f_type == HFS_SUPER_MAGIC)
940 return "hfs";
940 return "hfs";
941 #endif
941 #endif
942 #ifdef HOSTFS_SUPER_MAGIC
942 #ifdef HOSTFS_SUPER_MAGIC
943 if (pbuf->f_type == HOSTFS_SUPER_MAGIC)
943 if (pbuf->f_type == HOSTFS_SUPER_MAGIC)
944 return "hostfs";
944 return "hostfs";
945 #endif
945 #endif
946 #ifdef HPFS_SUPER_MAGIC
946 #ifdef HPFS_SUPER_MAGIC
947 if (pbuf->f_type == HPFS_SUPER_MAGIC)
947 if (pbuf->f_type == HPFS_SUPER_MAGIC)
948 return "hpfs";
948 return "hpfs";
949 #endif
949 #endif
950 #ifdef HUGETLBFS_MAGIC
950 #ifdef HUGETLBFS_MAGIC
951 if (pbuf->f_type == HUGETLBFS_MAGIC)
951 if (pbuf->f_type == HUGETLBFS_MAGIC)
952 return "hugetlbfs";
952 return "hugetlbfs";
953 #endif
953 #endif
954 #ifdef ISOFS_SUPER_MAGIC
954 #ifdef ISOFS_SUPER_MAGIC
955 if (pbuf->f_type == ISOFS_SUPER_MAGIC)
955 if (pbuf->f_type == ISOFS_SUPER_MAGIC)
956 return "isofs";
956 return "isofs";
957 #endif
957 #endif
958 #ifdef JFFS2_SUPER_MAGIC
958 #ifdef JFFS2_SUPER_MAGIC
959 if (pbuf->f_type == JFFS2_SUPER_MAGIC)
959 if (pbuf->f_type == JFFS2_SUPER_MAGIC)
960 return "jffs2";
960 return "jffs2";
961 #endif
961 #endif
962 #ifdef JFS_SUPER_MAGIC
962 #ifdef JFS_SUPER_MAGIC
963 if (pbuf->f_type == JFS_SUPER_MAGIC)
963 if (pbuf->f_type == JFS_SUPER_MAGIC)
964 return "jfs";
964 return "jfs";
965 #endif
965 #endif
966 #ifdef MINIX_SUPER_MAGIC
966 #ifdef MINIX_SUPER_MAGIC
967 if (pbuf->f_type == MINIX_SUPER_MAGIC)
967 if (pbuf->f_type == MINIX_SUPER_MAGIC)
968 return "minix";
968 return "minix";
969 #endif
969 #endif
970 #ifdef MINIX2_SUPER_MAGIC
970 #ifdef MINIX2_SUPER_MAGIC
971 if (pbuf->f_type == MINIX2_SUPER_MAGIC)
971 if (pbuf->f_type == MINIX2_SUPER_MAGIC)
972 return "minix2";
972 return "minix2";
973 #endif
973 #endif
974 #ifdef MINIX3_SUPER_MAGIC
974 #ifdef MINIX3_SUPER_MAGIC
975 if (pbuf->f_type == MINIX3_SUPER_MAGIC)
975 if (pbuf->f_type == MINIX3_SUPER_MAGIC)
976 return "minix3";
976 return "minix3";
977 #endif
977 #endif
978 #ifdef MQUEUE_MAGIC
978 #ifdef MQUEUE_MAGIC
979 if (pbuf->f_type == MQUEUE_MAGIC)
979 if (pbuf->f_type == MQUEUE_MAGIC)
980 return "mqueue";
980 return "mqueue";
981 #endif
981 #endif
982 #ifdef MSDOS_SUPER_MAGIC
982 #ifdef MSDOS_SUPER_MAGIC
983 if (pbuf->f_type == MSDOS_SUPER_MAGIC)
983 if (pbuf->f_type == MSDOS_SUPER_MAGIC)
984 return "msdos";
984 return "msdos";
985 #endif
985 #endif
986 #ifdef NCP_SUPER_MAGIC
986 #ifdef NCP_SUPER_MAGIC
987 if (pbuf->f_type == NCP_SUPER_MAGIC)
987 if (pbuf->f_type == NCP_SUPER_MAGIC)
988 return "ncp";
988 return "ncp";
989 #endif
989 #endif
990 #ifdef NFS_SUPER_MAGIC
990 #ifdef NFS_SUPER_MAGIC
991 if (pbuf->f_type == NFS_SUPER_MAGIC)
991 if (pbuf->f_type == NFS_SUPER_MAGIC)
992 return "nfs";
992 return "nfs";
993 #endif
993 #endif
994 #ifdef NILFS_SUPER_MAGIC
994 #ifdef NILFS_SUPER_MAGIC
995 if (pbuf->f_type == NILFS_SUPER_MAGIC)
995 if (pbuf->f_type == NILFS_SUPER_MAGIC)
996 return "nilfs";
996 return "nilfs";
997 #endif
997 #endif
998 #ifdef NTFS_SB_MAGIC
998 #ifdef NTFS_SB_MAGIC
999 if (pbuf->f_type == NTFS_SB_MAGIC)
999 if (pbuf->f_type == NTFS_SB_MAGIC)
1000 return "ntfs-sb";
1000 return "ntfs-sb";
1001 #endif
1001 #endif
1002 #ifdef OCFS2_SUPER_MAGIC
1002 #ifdef OCFS2_SUPER_MAGIC
1003 if (pbuf->f_type == OCFS2_SUPER_MAGIC)
1003 if (pbuf->f_type == OCFS2_SUPER_MAGIC)
1004 return "ocfs2";
1004 return "ocfs2";
1005 #endif
1005 #endif
1006 #ifdef OPENPROM_SUPER_MAGIC
1006 #ifdef OPENPROM_SUPER_MAGIC
1007 if (pbuf->f_type == OPENPROM_SUPER_MAGIC)
1007 if (pbuf->f_type == OPENPROM_SUPER_MAGIC)
1008 return "openprom";
1008 return "openprom";
1009 #endif
1009 #endif
1010 #ifdef OVERLAYFS_SUPER_MAGIC
1010 #ifdef OVERLAYFS_SUPER_MAGIC
1011 if (pbuf->f_type == OVERLAYFS_SUPER_MAGIC)
1011 if (pbuf->f_type == OVERLAYFS_SUPER_MAGIC)
1012 return "overlay";
1012 return "overlay";
1013 #endif
1013 #endif
1014 #ifdef PIPEFS_MAGIC
1014 #ifdef PIPEFS_MAGIC
1015 if (pbuf->f_type == PIPEFS_MAGIC)
1015 if (pbuf->f_type == PIPEFS_MAGIC)
1016 return "pipefs";
1016 return "pipefs";
1017 #endif
1017 #endif
1018 #ifdef PROC_SUPER_MAGIC
1018 #ifdef PROC_SUPER_MAGIC
1019 if (pbuf->f_type == PROC_SUPER_MAGIC)
1019 if (pbuf->f_type == PROC_SUPER_MAGIC)
1020 return "proc";
1020 return "proc";
1021 #endif
1021 #endif
1022 #ifdef PSTOREFS_MAGIC
1022 #ifdef PSTOREFS_MAGIC
1023 if (pbuf->f_type == PSTOREFS_MAGIC)
1023 if (pbuf->f_type == PSTOREFS_MAGIC)
1024 return "pstorefs";
1024 return "pstorefs";
1025 #endif
1025 #endif
1026 #ifdef QNX4_SUPER_MAGIC
1026 #ifdef QNX4_SUPER_MAGIC
1027 if (pbuf->f_type == QNX4_SUPER_MAGIC)
1027 if (pbuf->f_type == QNX4_SUPER_MAGIC)
1028 return "qnx4";
1028 return "qnx4";
1029 #endif
1029 #endif
1030 #ifdef QNX6_SUPER_MAGIC
1030 #ifdef QNX6_SUPER_MAGIC
1031 if (pbuf->f_type == QNX6_SUPER_MAGIC)
1031 if (pbuf->f_type == QNX6_SUPER_MAGIC)
1032 return "qnx6";
1032 return "qnx6";
1033 #endif
1033 #endif
1034 #ifdef RAMFS_MAGIC
1034 #ifdef RAMFS_MAGIC
1035 if (pbuf->f_type == RAMFS_MAGIC)
1035 if (pbuf->f_type == RAMFS_MAGIC)
1036 return "ramfs";
1036 return "ramfs";
1037 #endif
1037 #endif
1038 #ifdef REISERFS_SUPER_MAGIC
1038 #ifdef REISERFS_SUPER_MAGIC
1039 if (pbuf->f_type == REISERFS_SUPER_MAGIC)
1039 if (pbuf->f_type == REISERFS_SUPER_MAGIC)
1040 return "reiserfs";
1040 return "reiserfs";
1041 #endif
1041 #endif
1042 #ifdef ROMFS_MAGIC
1042 #ifdef ROMFS_MAGIC
1043 if (pbuf->f_type == ROMFS_MAGIC)
1043 if (pbuf->f_type == ROMFS_MAGIC)
1044 return "romfs";
1044 return "romfs";
1045 #endif
1045 #endif
1046 #ifdef SECURITYFS_MAGIC
1046 #ifdef SECURITYFS_MAGIC
1047 if (pbuf->f_type == SECURITYFS_MAGIC)
1047 if (pbuf->f_type == SECURITYFS_MAGIC)
1048 return "securityfs";
1048 return "securityfs";
1049 #endif
1049 #endif
1050 #ifdef SELINUX_MAGIC
1050 #ifdef SELINUX_MAGIC
1051 if (pbuf->f_type == SELINUX_MAGIC)
1051 if (pbuf->f_type == SELINUX_MAGIC)
1052 return "selinux";
1052 return "selinux";
1053 #endif
1053 #endif
1054 #ifdef SMACK_MAGIC
1054 #ifdef SMACK_MAGIC
1055 if (pbuf->f_type == SMACK_MAGIC)
1055 if (pbuf->f_type == SMACK_MAGIC)
1056 return "smack";
1056 return "smack";
1057 #endif
1057 #endif
1058 #ifdef SMB_SUPER_MAGIC
1058 #ifdef SMB_SUPER_MAGIC
1059 if (pbuf->f_type == SMB_SUPER_MAGIC)
1059 if (pbuf->f_type == SMB_SUPER_MAGIC)
1060 return "smb";
1060 return "smb";
1061 #endif
1061 #endif
1062 #ifdef SOCKFS_MAGIC
1062 #ifdef SOCKFS_MAGIC
1063 if (pbuf->f_type == SOCKFS_MAGIC)
1063 if (pbuf->f_type == SOCKFS_MAGIC)
1064 return "sockfs";
1064 return "sockfs";
1065 #endif
1065 #endif
1066 #ifdef SQUASHFS_MAGIC
1066 #ifdef SQUASHFS_MAGIC
1067 if (pbuf->f_type == SQUASHFS_MAGIC)
1067 if (pbuf->f_type == SQUASHFS_MAGIC)
1068 return "squashfs";
1068 return "squashfs";
1069 #endif
1069 #endif
1070 #ifdef SYSFS_MAGIC
1070 #ifdef SYSFS_MAGIC
1071 if (pbuf->f_type == SYSFS_MAGIC)
1071 if (pbuf->f_type == SYSFS_MAGIC)
1072 return "sysfs";
1072 return "sysfs";
1073 #endif
1073 #endif
1074 #ifdef SYSV2_SUPER_MAGIC
1074 #ifdef SYSV2_SUPER_MAGIC
1075 if (pbuf->f_type == SYSV2_SUPER_MAGIC)
1075 if (pbuf->f_type == SYSV2_SUPER_MAGIC)
1076 return "sysv2";
1076 return "sysv2";
1077 #endif
1077 #endif
1078 #ifdef SYSV4_SUPER_MAGIC
1078 #ifdef SYSV4_SUPER_MAGIC
1079 if (pbuf->f_type == SYSV4_SUPER_MAGIC)
1079 if (pbuf->f_type == SYSV4_SUPER_MAGIC)
1080 return "sysv4";
1080 return "sysv4";
1081 #endif
1081 #endif
1082 #ifdef TMPFS_MAGIC
1082 #ifdef TMPFS_MAGIC
1083 if (pbuf->f_type == TMPFS_MAGIC)
1083 if (pbuf->f_type == TMPFS_MAGIC)
1084 return "tmpfs";
1084 return "tmpfs";
1085 #endif
1085 #endif
1086 #ifdef UDF_SUPER_MAGIC
1086 #ifdef UDF_SUPER_MAGIC
1087 if (pbuf->f_type == UDF_SUPER_MAGIC)
1087 if (pbuf->f_type == UDF_SUPER_MAGIC)
1088 return "udf";
1088 return "udf";
1089 #endif
1089 #endif
1090 #ifdef UFS_MAGIC
1090 #ifdef UFS_MAGIC
1091 if (pbuf->f_type == UFS_MAGIC)
1091 if (pbuf->f_type == UFS_MAGIC)
1092 return "ufs";
1092 return "ufs";
1093 #endif
1093 #endif
1094 #ifdef USBDEVICE_SUPER_MAGIC
1094 #ifdef USBDEVICE_SUPER_MAGIC
1095 if (pbuf->f_type == USBDEVICE_SUPER_MAGIC)
1095 if (pbuf->f_type == USBDEVICE_SUPER_MAGIC)
1096 return "usbdevice";
1096 return "usbdevice";
1097 #endif
1097 #endif
1098 #ifdef V9FS_MAGIC
1098 #ifdef V9FS_MAGIC
1099 if (pbuf->f_type == V9FS_MAGIC)
1099 if (pbuf->f_type == V9FS_MAGIC)
1100 return "v9fs";
1100 return "v9fs";
1101 #endif
1101 #endif
1102 #ifdef VXFS_SUPER_MAGIC
1102 #ifdef VXFS_SUPER_MAGIC
1103 if (pbuf->f_type == VXFS_SUPER_MAGIC)
1103 if (pbuf->f_type == VXFS_SUPER_MAGIC)
1104 return "vxfs";
1104 return "vxfs";
1105 #endif
1105 #endif
1106 #ifdef XENFS_SUPER_MAGIC
1106 #ifdef XENFS_SUPER_MAGIC
1107 if (pbuf->f_type == XENFS_SUPER_MAGIC)
1107 if (pbuf->f_type == XENFS_SUPER_MAGIC)
1108 return "xenfs";
1108 return "xenfs";
1109 #endif
1109 #endif
1110 #ifdef XENIX_SUPER_MAGIC
1110 #ifdef XENIX_SUPER_MAGIC
1111 if (pbuf->f_type == XENIX_SUPER_MAGIC)
1111 if (pbuf->f_type == XENIX_SUPER_MAGIC)
1112 return "xenix";
1112 return "xenix";
1113 #endif
1113 #endif
1114 #ifdef XFS_SUPER_MAGIC
1114 #ifdef XFS_SUPER_MAGIC
1115 if (pbuf->f_type == XFS_SUPER_MAGIC)
1115 if (pbuf->f_type == XFS_SUPER_MAGIC)
1116 return "xfs";
1116 return "xfs";
1117 #endif
1117 #endif
1118 /* End of Linux filesystems */
1118 /* End of Linux filesystems */
1119 return NULL;
1119 return NULL;
1120 }
1120 }
1121 #endif /* def HAVE_LINUX_STATFS */
1121 #endif /* def HAVE_LINUX_STATFS */
1122
1122
1123 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1123 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1124 /* given a directory path, return filesystem type name (best-effort) */
1124 /* given a directory path, return filesystem type name (best-effort) */
1125 static PyObject *getfstype(PyObject *self, PyObject *args)
1125 static PyObject *getfstype(PyObject *self, PyObject *args)
1126 {
1126 {
1127 const char *path = NULL;
1127 const char *path = NULL;
1128 struct statfs buf;
1128 struct statfs buf;
1129 int r;
1129 int r;
1130 if (!PyArg_ParseTuple(args, PY23("s", "y"), &path))
1130 if (!PyArg_ParseTuple(args, "y", &path))
1131 return NULL;
1131 return NULL;
1132
1132
1133 memset(&buf, 0, sizeof(buf));
1133 memset(&buf, 0, sizeof(buf));
1134 r = statfs(path, &buf);
1134 r = statfs(path, &buf);
1135 if (r != 0)
1135 if (r != 0)
1136 return PyErr_SetFromErrno(PyExc_OSError);
1136 return PyErr_SetFromErrno(PyExc_OSError);
1137 return Py_BuildValue(PY23("s", "y"), describefstype(&buf));
1137 return Py_BuildValue("y", describefstype(&buf));
1138 }
1138 }
1139 #endif /* defined(HAVE_LINUX_STATFS) || defined(HAVE_BSD_STATFS) */
1139 #endif /* defined(HAVE_LINUX_STATFS) || defined(HAVE_BSD_STATFS) */
1140
1140
1141 #if defined(HAVE_BSD_STATFS)
1141 #if defined(HAVE_BSD_STATFS)
1142 /* given a directory path, return filesystem mount point (best-effort) */
1142 /* given a directory path, return filesystem mount point (best-effort) */
1143 static PyObject *getfsmountpoint(PyObject *self, PyObject *args)
1143 static PyObject *getfsmountpoint(PyObject *self, PyObject *args)
1144 {
1144 {
1145 const char *path = NULL;
1145 const char *path = NULL;
1146 struct statfs buf;
1146 struct statfs buf;
1147 int r;
1147 int r;
1148 if (!PyArg_ParseTuple(args, PY23("s", "y"), &path))
1148 if (!PyArg_ParseTuple(args, "y", &path))
1149 return NULL;
1149 return NULL;
1150
1150
1151 memset(&buf, 0, sizeof(buf));
1151 memset(&buf, 0, sizeof(buf));
1152 r = statfs(path, &buf);
1152 r = statfs(path, &buf);
1153 if (r != 0)
1153 if (r != 0)
1154 return PyErr_SetFromErrno(PyExc_OSError);
1154 return PyErr_SetFromErrno(PyExc_OSError);
1155 return Py_BuildValue(PY23("s", "y"), buf.f_mntonname);
1155 return Py_BuildValue("y", buf.f_mntonname);
1156 }
1156 }
1157 #endif /* defined(HAVE_BSD_STATFS) */
1157 #endif /* defined(HAVE_BSD_STATFS) */
1158
1158
1159 static PyObject *unblocksignal(PyObject *self, PyObject *args)
1159 static PyObject *unblocksignal(PyObject *self, PyObject *args)
1160 {
1160 {
1161 int sig = 0;
1161 int sig = 0;
1162 sigset_t set;
1162 sigset_t set;
1163 int r;
1163 int r;
1164 if (!PyArg_ParseTuple(args, "i", &sig))
1164 if (!PyArg_ParseTuple(args, "i", &sig))
1165 return NULL;
1165 return NULL;
1166 r = sigemptyset(&set);
1166 r = sigemptyset(&set);
1167 if (r != 0)
1167 if (r != 0)
1168 return PyErr_SetFromErrno(PyExc_OSError);
1168 return PyErr_SetFromErrno(PyExc_OSError);
1169 r = sigaddset(&set, sig);
1169 r = sigaddset(&set, sig);
1170 if (r != 0)
1170 if (r != 0)
1171 return PyErr_SetFromErrno(PyExc_OSError);
1171 return PyErr_SetFromErrno(PyExc_OSError);
1172 r = sigprocmask(SIG_UNBLOCK, &set, NULL);
1172 r = sigprocmask(SIG_UNBLOCK, &set, NULL);
1173 if (r != 0)
1173 if (r != 0)
1174 return PyErr_SetFromErrno(PyExc_OSError);
1174 return PyErr_SetFromErrno(PyExc_OSError);
1175 Py_RETURN_NONE;
1175 Py_RETURN_NONE;
1176 }
1176 }
1177
1177
1178 #endif /* ndef _WIN32 */
1178 #endif /* ndef _WIN32 */
1179
1179
1180 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
1180 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
1181 {
1181 {
1182 PyObject *statobj = NULL; /* initialize - optional arg */
1182 PyObject *statobj = NULL; /* initialize - optional arg */
1183 PyObject *skipobj = NULL; /* initialize - optional arg */
1183 PyObject *skipobj = NULL; /* initialize - optional arg */
1184 char *path, *skip = NULL;
1184 char *path, *skip = NULL;
1185 Py_ssize_t plen;
1185 Py_ssize_t plen;
1186 int wantstat;
1186 int wantstat;
1187
1187
1188 static char *kwlist[] = {"path", "stat", "skip", NULL};
1188 static char *kwlist[] = {"path", "stat", "skip", NULL};
1189
1189
1190 if (!PyArg_ParseTupleAndKeywords(args, kwargs, PY23("s#|OO:listdir",
1190 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y#|OO:listdir",
1191 "y#|OO:listdir"),
1192 kwlist, &path, &plen, &statobj, &skipobj))
1191 kwlist, &path, &plen, &statobj, &skipobj))
1193 return NULL;
1192 return NULL;
1194
1193
1195 wantstat = statobj && PyObject_IsTrue(statobj);
1194 wantstat = statobj && PyObject_IsTrue(statobj);
1196
1195
1197 if (skipobj && skipobj != Py_None) {
1196 if (skipobj && skipobj != Py_None) {
1198 skip = PyBytes_AsString(skipobj);
1197 skip = PyBytes_AsString(skipobj);
1199 if (!skip)
1198 if (!skip)
1200 return NULL;
1199 return NULL;
1201 }
1200 }
1202
1201
1203 return _listdir(path, plen, wantstat, skip);
1202 return _listdir(path, plen, wantstat, skip);
1204 }
1203 }
1205
1204
1206 #ifdef _WIN32
1205 #ifdef _WIN32
1207 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
1206 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
1208 {
1207 {
1209 static char *kwlist[] = {"name", "mode", "buffering", NULL};
1208 static char *kwlist[] = {"name", "mode", "buffering", NULL};
1210 PyObject *file_obj = NULL;
1209 PyObject *file_obj = NULL;
1211 char *name = NULL;
1210 char *name = NULL;
1212 char *mode = "rb";
1211 char *mode = "rb";
1213 DWORD access = 0;
1212 DWORD access = 0;
1214 DWORD creation;
1213 DWORD creation;
1215 HANDLE handle;
1214 HANDLE handle;
1216 int fd, flags = 0;
1215 int fd, flags = 0;
1217 int bufsize = -1;
1216 int bufsize = -1;
1218 char m0, m1, m2;
1217 char m0, m1, m2;
1219 char fpmode[4];
1218 char fpmode[4];
1220 int fppos = 0;
1219 int fppos = 0;
1221 int plus;
1220 int plus;
1222 FILE *fp;
1221 FILE *fp;
1223
1222
1224 if (!PyArg_ParseTupleAndKeywords(args, kwds, PY23("et|si:posixfile",
1223 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|yi:posixfile",
1225 "et|yi:posixfile"),
1226 kwlist,
1224 kwlist,
1227 Py_FileSystemDefaultEncoding,
1225 Py_FileSystemDefaultEncoding,
1228 &name, &mode, &bufsize))
1226 &name, &mode, &bufsize))
1229 return NULL;
1227 return NULL;
1230
1228
1231 m0 = mode[0];
1229 m0 = mode[0];
1232 m1 = m0 ? mode[1] : '\0';
1230 m1 = m0 ? mode[1] : '\0';
1233 m2 = m1 ? mode[2] : '\0';
1231 m2 = m1 ? mode[2] : '\0';
1234 plus = m1 == '+' || m2 == '+';
1232 plus = m1 == '+' || m2 == '+';
1235
1233
1236 fpmode[fppos++] = m0;
1234 fpmode[fppos++] = m0;
1237 if (m1 == 'b' || m2 == 'b') {
1235 if (m1 == 'b' || m2 == 'b') {
1238 flags = _O_BINARY;
1236 flags = _O_BINARY;
1239 fpmode[fppos++] = 'b';
1237 fpmode[fppos++] = 'b';
1240 }
1238 }
1241 else
1239 else
1242 flags = _O_TEXT;
1240 flags = _O_TEXT;
1243 if (m0 == 'r' && !plus) {
1241 if (m0 == 'r' && !plus) {
1244 flags |= _O_RDONLY;
1242 flags |= _O_RDONLY;
1245 access = GENERIC_READ;
1243 access = GENERIC_READ;
1246 } else {
1244 } else {
1247 /*
1245 /*
1248 work around http://support.microsoft.com/kb/899149 and
1246 work around http://support.microsoft.com/kb/899149 and
1249 set _O_RDWR for 'w' and 'a', even if mode has no '+'
1247 set _O_RDWR for 'w' and 'a', even if mode has no '+'
1250 */
1248 */
1251 flags |= _O_RDWR;
1249 flags |= _O_RDWR;
1252 access = GENERIC_READ | GENERIC_WRITE;
1250 access = GENERIC_READ | GENERIC_WRITE;
1253 fpmode[fppos++] = '+';
1251 fpmode[fppos++] = '+';
1254 }
1252 }
1255 fpmode[fppos++] = '\0';
1253 fpmode[fppos++] = '\0';
1256
1254
1257 switch (m0) {
1255 switch (m0) {
1258 case 'r':
1256 case 'r':
1259 creation = OPEN_EXISTING;
1257 creation = OPEN_EXISTING;
1260 break;
1258 break;
1261 case 'w':
1259 case 'w':
1262 creation = CREATE_ALWAYS;
1260 creation = CREATE_ALWAYS;
1263 break;
1261 break;
1264 case 'a':
1262 case 'a':
1265 creation = OPEN_ALWAYS;
1263 creation = OPEN_ALWAYS;
1266 flags |= _O_APPEND;
1264 flags |= _O_APPEND;
1267 break;
1265 break;
1268 default:
1266 default:
1269 PyErr_Format(PyExc_ValueError,
1267 PyErr_Format(PyExc_ValueError,
1270 "mode string must begin with one of 'r', 'w', "
1268 "mode string must begin with one of 'r', 'w', "
1271 "or 'a', not '%c'", m0);
1269 "or 'a', not '%c'", m0);
1272 goto bail;
1270 goto bail;
1273 }
1271 }
1274
1272
1275 handle = CreateFile(name, access,
1273 handle = CreateFile(name, access,
1276 FILE_SHARE_READ | FILE_SHARE_WRITE |
1274 FILE_SHARE_READ | FILE_SHARE_WRITE |
1277 FILE_SHARE_DELETE,
1275 FILE_SHARE_DELETE,
1278 NULL,
1276 NULL,
1279 creation,
1277 creation,
1280 FILE_ATTRIBUTE_NORMAL,
1278 FILE_ATTRIBUTE_NORMAL,
1281 0);
1279 0);
1282
1280
1283 if (handle == INVALID_HANDLE_VALUE) {
1281 if (handle == INVALID_HANDLE_VALUE) {
1284 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
1282 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
1285 goto bail;
1283 goto bail;
1286 }
1284 }
1287
1285
1288 fd = _open_osfhandle((intptr_t)handle, flags);
1286 fd = _open_osfhandle((intptr_t)handle, flags);
1289
1287
1290 if (fd == -1) {
1288 if (fd == -1) {
1291 CloseHandle(handle);
1289 CloseHandle(handle);
1292 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1290 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1293 goto bail;
1291 goto bail;
1294 }
1292 }
1295 fp = _fdopen(fd, fpmode);
1293 fp = _fdopen(fd, fpmode);
1296 if (fp == NULL) {
1294 if (fp == NULL) {
1297 _close(fd);
1295 _close(fd);
1298 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1296 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1299 goto bail;
1297 goto bail;
1300 }
1298 }
1301
1299
1302 file_obj = PyFile_FromFile(fp, name, mode, fclose);
1300 file_obj = PyFile_FromFile(fp, name, mode, fclose);
1303 if (file_obj == NULL) {
1301 if (file_obj == NULL) {
1304 fclose(fp);
1302 fclose(fp);
1305 goto bail;
1303 goto bail;
1306 }
1304 }
1307
1305
1308 PyFile_SetBufSize(file_obj, bufsize);
1306 PyFile_SetBufSize(file_obj, bufsize);
1309 bail:
1307 bail:
1310 PyMem_Free(name);
1308 PyMem_Free(name);
1311 return file_obj;
1309 return file_obj;
1312 }
1310 }
1313 #endif
1311 #endif
1314
1312
1315 #ifdef __APPLE__
1313 #ifdef __APPLE__
1316 #include <ApplicationServices/ApplicationServices.h>
1314 #include <ApplicationServices/ApplicationServices.h>
1317
1315
1318 static PyObject *isgui(PyObject *self)
1316 static PyObject *isgui(PyObject *self)
1319 {
1317 {
1320 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
1318 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
1321
1319
1322 if (dict != NULL) {
1320 if (dict != NULL) {
1323 CFRelease(dict);
1321 CFRelease(dict);
1324 Py_RETURN_TRUE;
1322 Py_RETURN_TRUE;
1325 } else {
1323 } else {
1326 Py_RETURN_FALSE;
1324 Py_RETURN_FALSE;
1327 }
1325 }
1328 }
1326 }
1329 #endif
1327 #endif
1330
1328
1331 static char osutil_doc[] = "Native operating system services.";
1329 static char osutil_doc[] = "Native operating system services.";
1332
1330
1333 static PyMethodDef methods[] = {
1331 static PyMethodDef methods[] = {
1334 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
1332 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
1335 "list a directory\n"},
1333 "list a directory\n"},
1336 #ifdef _WIN32
1334 #ifdef _WIN32
1337 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
1335 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
1338 "Open a file with POSIX-like semantics.\n"
1336 "Open a file with POSIX-like semantics.\n"
1339 "On error, this function may raise either a WindowsError or an IOError."},
1337 "On error, this function may raise either a WindowsError or an IOError."},
1340 #else
1338 #else
1341 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
1339 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
1342 "stat a series of files or symlinks\n"
1340 "stat a series of files or symlinks\n"
1343 "Returns None for non-existent entries and entries of other types.\n"},
1341 "Returns None for non-existent entries and entries of other types.\n"},
1344 #ifdef CMSG_LEN
1342 #ifdef CMSG_LEN
1345 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
1343 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
1346 "receive list of file descriptors via socket\n"},
1344 "receive list of file descriptors via socket\n"},
1347 #endif
1345 #endif
1348 #ifndef SETPROCNAME_USE_NONE
1346 #ifndef SETPROCNAME_USE_NONE
1349 {"setprocname", (PyCFunction)setprocname, METH_VARARGS,
1347 {"setprocname", (PyCFunction)setprocname, METH_VARARGS,
1350 "set process title (best-effort)\n"},
1348 "set process title (best-effort)\n"},
1351 #endif
1349 #endif
1352 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1350 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1353 {"getfstype", (PyCFunction)getfstype, METH_VARARGS,
1351 {"getfstype", (PyCFunction)getfstype, METH_VARARGS,
1354 "get filesystem type (best-effort)\n"},
1352 "get filesystem type (best-effort)\n"},
1355 #endif
1353 #endif
1356 #if defined(HAVE_BSD_STATFS)
1354 #if defined(HAVE_BSD_STATFS)
1357 {"getfsmountpoint", (PyCFunction)getfsmountpoint, METH_VARARGS,
1355 {"getfsmountpoint", (PyCFunction)getfsmountpoint, METH_VARARGS,
1358 "get filesystem mount point (best-effort)\n"},
1356 "get filesystem mount point (best-effort)\n"},
1359 #endif
1357 #endif
1360 {"unblocksignal", (PyCFunction)unblocksignal, METH_VARARGS,
1358 {"unblocksignal", (PyCFunction)unblocksignal, METH_VARARGS,
1361 "change signal mask to unblock a given signal\n"},
1359 "change signal mask to unblock a given signal\n"},
1362 #endif /* ndef _WIN32 */
1360 #endif /* ndef _WIN32 */
1363 #ifdef __APPLE__
1361 #ifdef __APPLE__
1364 {
1362 {
1365 "isgui", (PyCFunction)isgui, METH_NOARGS,
1363 "isgui", (PyCFunction)isgui, METH_NOARGS,
1366 "Is a CoreGraphics session available?"
1364 "Is a CoreGraphics session available?"
1367 },
1365 },
1368 #endif
1366 #endif
1369 {NULL, NULL}
1367 {NULL, NULL}
1370 };
1368 };
1371
1369
1372 static const int version = 4;
1370 static const int version = 4;
1373
1371
1374 static struct PyModuleDef osutil_module = {
1372 static struct PyModuleDef osutil_module = {
1375 PyModuleDef_HEAD_INIT,
1373 PyModuleDef_HEAD_INIT,
1376 "osutil",
1374 "osutil",
1377 osutil_doc,
1375 osutil_doc,
1378 -1,
1376 -1,
1379 methods
1377 methods
1380 };
1378 };
1381
1379
1382 PyMODINIT_FUNC PyInit_osutil(void)
1380 PyMODINIT_FUNC PyInit_osutil(void)
1383 {
1381 {
1384 PyObject *m;
1382 PyObject *m;
1385 if (PyType_Ready(&listdir_stat_type) < 0)
1383 if (PyType_Ready(&listdir_stat_type) < 0)
1386 return NULL;
1384 return NULL;
1387
1385
1388 m = PyModule_Create(&osutil_module);
1386 m = PyModule_Create(&osutil_module);
1389 PyModule_AddIntConstant(m, "version", version);
1387 PyModule_AddIntConstant(m, "version", version);
1390 return m;
1388 return m;
1391 }
1389 }
@@ -1,1306 +1,1304 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #define PY_SSIZE_T_CLEAN
10 #define PY_SSIZE_T_CLEAN
11 #include <Python.h>
11 #include <Python.h>
12 #include <ctype.h>
12 #include <ctype.h>
13 #include <stddef.h>
13 #include <stddef.h>
14 #include <string.h>
14 #include <string.h>
15
15
16 #include "bitmanipulation.h"
16 #include "bitmanipulation.h"
17 #include "charencode.h"
17 #include "charencode.h"
18 #include "util.h"
18 #include "util.h"
19
19
20 static const char *const versionerrortext = "Python minor version mismatch";
20 static const char *const versionerrortext = "Python minor version mismatch";
21
21
22 static const int dirstate_v1_from_p2 = -2;
22 static const int dirstate_v1_from_p2 = -2;
23 static const int dirstate_v1_nonnormal = -1;
23 static const int dirstate_v1_nonnormal = -1;
24 static const int ambiguous_time = -1;
24 static const int ambiguous_time = -1;
25
25
26 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
26 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
27 {
27 {
28 Py_ssize_t expected_size;
28 Py_ssize_t expected_size;
29
29
30 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
30 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
31 return NULL;
31 return NULL;
32 }
32 }
33
33
34 return _dict_new_presized(expected_size);
34 return _dict_new_presized(expected_size);
35 }
35 }
36
36
37 static PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
37 static PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
38 PyObject *kwds)
38 PyObject *kwds)
39 {
39 {
40 /* We do all the initialization here and not a tp_init function because
40 /* We do all the initialization here and not a tp_init function because
41 * dirstate_item is immutable. */
41 * dirstate_item is immutable. */
42 dirstateItemObject *t;
42 dirstateItemObject *t;
43 int wc_tracked;
43 int wc_tracked;
44 int p1_tracked;
44 int p1_tracked;
45 int p2_info;
45 int p2_info;
46 int has_meaningful_data;
46 int has_meaningful_data;
47 int has_meaningful_mtime;
47 int has_meaningful_mtime;
48 int mtime_second_ambiguous;
48 int mtime_second_ambiguous;
49 int mode;
49 int mode;
50 int size;
50 int size;
51 int mtime_s;
51 int mtime_s;
52 int mtime_ns;
52 int mtime_ns;
53 PyObject *parentfiledata;
53 PyObject *parentfiledata;
54 PyObject *mtime;
54 PyObject *mtime;
55 PyObject *fallback_exec;
55 PyObject *fallback_exec;
56 PyObject *fallback_symlink;
56 PyObject *fallback_symlink;
57 static char *keywords_name[] = {
57 static char *keywords_name[] = {
58 "wc_tracked", "p1_tracked", "p2_info",
58 "wc_tracked", "p1_tracked", "p2_info",
59 "has_meaningful_data", "has_meaningful_mtime", "parentfiledata",
59 "has_meaningful_data", "has_meaningful_mtime", "parentfiledata",
60 "fallback_exec", "fallback_symlink", NULL,
60 "fallback_exec", "fallback_symlink", NULL,
61 };
61 };
62 wc_tracked = 0;
62 wc_tracked = 0;
63 p1_tracked = 0;
63 p1_tracked = 0;
64 p2_info = 0;
64 p2_info = 0;
65 has_meaningful_mtime = 1;
65 has_meaningful_mtime = 1;
66 has_meaningful_data = 1;
66 has_meaningful_data = 1;
67 mtime_second_ambiguous = 0;
67 mtime_second_ambiguous = 0;
68 parentfiledata = Py_None;
68 parentfiledata = Py_None;
69 fallback_exec = Py_None;
69 fallback_exec = Py_None;
70 fallback_symlink = Py_None;
70 fallback_symlink = Py_None;
71 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiiiiOOO", keywords_name,
71 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiiiiOOO", keywords_name,
72 &wc_tracked, &p1_tracked, &p2_info,
72 &wc_tracked, &p1_tracked, &p2_info,
73 &has_meaningful_data,
73 &has_meaningful_data,
74 &has_meaningful_mtime, &parentfiledata,
74 &has_meaningful_mtime, &parentfiledata,
75 &fallback_exec, &fallback_symlink)) {
75 &fallback_exec, &fallback_symlink)) {
76 return NULL;
76 return NULL;
77 }
77 }
78 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
78 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
79 if (!t) {
79 if (!t) {
80 return NULL;
80 return NULL;
81 }
81 }
82
82
83 t->flags = 0;
83 t->flags = 0;
84 if (wc_tracked) {
84 if (wc_tracked) {
85 t->flags |= dirstate_flag_wc_tracked;
85 t->flags |= dirstate_flag_wc_tracked;
86 }
86 }
87 if (p1_tracked) {
87 if (p1_tracked) {
88 t->flags |= dirstate_flag_p1_tracked;
88 t->flags |= dirstate_flag_p1_tracked;
89 }
89 }
90 if (p2_info) {
90 if (p2_info) {
91 t->flags |= dirstate_flag_p2_info;
91 t->flags |= dirstate_flag_p2_info;
92 }
92 }
93
93
94 if (fallback_exec != Py_None) {
94 if (fallback_exec != Py_None) {
95 t->flags |= dirstate_flag_has_fallback_exec;
95 t->flags |= dirstate_flag_has_fallback_exec;
96 if (PyObject_IsTrue(fallback_exec)) {
96 if (PyObject_IsTrue(fallback_exec)) {
97 t->flags |= dirstate_flag_fallback_exec;
97 t->flags |= dirstate_flag_fallback_exec;
98 }
98 }
99 }
99 }
100 if (fallback_symlink != Py_None) {
100 if (fallback_symlink != Py_None) {
101 t->flags |= dirstate_flag_has_fallback_symlink;
101 t->flags |= dirstate_flag_has_fallback_symlink;
102 if (PyObject_IsTrue(fallback_symlink)) {
102 if (PyObject_IsTrue(fallback_symlink)) {
103 t->flags |= dirstate_flag_fallback_symlink;
103 t->flags |= dirstate_flag_fallback_symlink;
104 }
104 }
105 }
105 }
106
106
107 if (parentfiledata != Py_None) {
107 if (parentfiledata != Py_None) {
108 if (!PyArg_ParseTuple(parentfiledata, "iiO", &mode, &size,
108 if (!PyArg_ParseTuple(parentfiledata, "iiO", &mode, &size,
109 &mtime)) {
109 &mtime)) {
110 return NULL;
110 return NULL;
111 }
111 }
112 if (mtime != Py_None) {
112 if (mtime != Py_None) {
113 if (!PyArg_ParseTuple(mtime, "iii", &mtime_s, &mtime_ns,
113 if (!PyArg_ParseTuple(mtime, "iii", &mtime_s, &mtime_ns,
114 &mtime_second_ambiguous)) {
114 &mtime_second_ambiguous)) {
115 return NULL;
115 return NULL;
116 }
116 }
117 } else {
117 } else {
118 has_meaningful_mtime = 0;
118 has_meaningful_mtime = 0;
119 }
119 }
120 } else {
120 } else {
121 has_meaningful_data = 0;
121 has_meaningful_data = 0;
122 has_meaningful_mtime = 0;
122 has_meaningful_mtime = 0;
123 }
123 }
124 if (has_meaningful_data) {
124 if (has_meaningful_data) {
125 t->flags |= dirstate_flag_has_meaningful_data;
125 t->flags |= dirstate_flag_has_meaningful_data;
126 t->mode = mode;
126 t->mode = mode;
127 t->size = size;
127 t->size = size;
128 if (mtime_second_ambiguous) {
128 if (mtime_second_ambiguous) {
129 t->flags |= dirstate_flag_mtime_second_ambiguous;
129 t->flags |= dirstate_flag_mtime_second_ambiguous;
130 }
130 }
131 } else {
131 } else {
132 t->mode = 0;
132 t->mode = 0;
133 t->size = 0;
133 t->size = 0;
134 }
134 }
135 if (has_meaningful_mtime) {
135 if (has_meaningful_mtime) {
136 t->flags |= dirstate_flag_has_mtime;
136 t->flags |= dirstate_flag_has_mtime;
137 t->mtime_s = mtime_s;
137 t->mtime_s = mtime_s;
138 t->mtime_ns = mtime_ns;
138 t->mtime_ns = mtime_ns;
139 } else {
139 } else {
140 t->mtime_s = 0;
140 t->mtime_s = 0;
141 t->mtime_ns = 0;
141 t->mtime_ns = 0;
142 }
142 }
143 return (PyObject *)t;
143 return (PyObject *)t;
144 }
144 }
145
145
146 static void dirstate_item_dealloc(PyObject *o)
146 static void dirstate_item_dealloc(PyObject *o)
147 {
147 {
148 PyObject_Del(o);
148 PyObject_Del(o);
149 }
149 }
150
150
151 static inline bool dirstate_item_c_tracked(dirstateItemObject *self)
151 static inline bool dirstate_item_c_tracked(dirstateItemObject *self)
152 {
152 {
153 return (self->flags & dirstate_flag_wc_tracked);
153 return (self->flags & dirstate_flag_wc_tracked);
154 }
154 }
155
155
156 static inline bool dirstate_item_c_any_tracked(dirstateItemObject *self)
156 static inline bool dirstate_item_c_any_tracked(dirstateItemObject *self)
157 {
157 {
158 const int mask = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
158 const int mask = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
159 dirstate_flag_p2_info;
159 dirstate_flag_p2_info;
160 return (self->flags & mask);
160 return (self->flags & mask);
161 }
161 }
162
162
163 static inline bool dirstate_item_c_added(dirstateItemObject *self)
163 static inline bool dirstate_item_c_added(dirstateItemObject *self)
164 {
164 {
165 const int mask = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
165 const int mask = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
166 dirstate_flag_p2_info);
166 dirstate_flag_p2_info);
167 const int target = dirstate_flag_wc_tracked;
167 const int target = dirstate_flag_wc_tracked;
168 return (self->flags & mask) == target;
168 return (self->flags & mask) == target;
169 }
169 }
170
170
171 static inline bool dirstate_item_c_removed(dirstateItemObject *self)
171 static inline bool dirstate_item_c_removed(dirstateItemObject *self)
172 {
172 {
173 if (self->flags & dirstate_flag_wc_tracked) {
173 if (self->flags & dirstate_flag_wc_tracked) {
174 return false;
174 return false;
175 }
175 }
176 return (self->flags &
176 return (self->flags &
177 (dirstate_flag_p1_tracked | dirstate_flag_p2_info));
177 (dirstate_flag_p1_tracked | dirstate_flag_p2_info));
178 }
178 }
179
179
180 static inline bool dirstate_item_c_merged(dirstateItemObject *self)
180 static inline bool dirstate_item_c_merged(dirstateItemObject *self)
181 {
181 {
182 return ((self->flags & dirstate_flag_wc_tracked) &&
182 return ((self->flags & dirstate_flag_wc_tracked) &&
183 (self->flags & dirstate_flag_p1_tracked) &&
183 (self->flags & dirstate_flag_p1_tracked) &&
184 (self->flags & dirstate_flag_p2_info));
184 (self->flags & dirstate_flag_p2_info));
185 }
185 }
186
186
187 static inline bool dirstate_item_c_from_p2(dirstateItemObject *self)
187 static inline bool dirstate_item_c_from_p2(dirstateItemObject *self)
188 {
188 {
189 return ((self->flags & dirstate_flag_wc_tracked) &&
189 return ((self->flags & dirstate_flag_wc_tracked) &&
190 !(self->flags & dirstate_flag_p1_tracked) &&
190 !(self->flags & dirstate_flag_p1_tracked) &&
191 (self->flags & dirstate_flag_p2_info));
191 (self->flags & dirstate_flag_p2_info));
192 }
192 }
193
193
194 static inline char dirstate_item_c_v1_state(dirstateItemObject *self)
194 static inline char dirstate_item_c_v1_state(dirstateItemObject *self)
195 {
195 {
196 if (dirstate_item_c_removed(self)) {
196 if (dirstate_item_c_removed(self)) {
197 return 'r';
197 return 'r';
198 } else if (dirstate_item_c_merged(self)) {
198 } else if (dirstate_item_c_merged(self)) {
199 return 'm';
199 return 'm';
200 } else if (dirstate_item_c_added(self)) {
200 } else if (dirstate_item_c_added(self)) {
201 return 'a';
201 return 'a';
202 } else {
202 } else {
203 return 'n';
203 return 'n';
204 }
204 }
205 }
205 }
206
206
207 static inline bool dirstate_item_c_has_fallback_exec(dirstateItemObject *self)
207 static inline bool dirstate_item_c_has_fallback_exec(dirstateItemObject *self)
208 {
208 {
209 return (bool)self->flags & dirstate_flag_has_fallback_exec;
209 return (bool)self->flags & dirstate_flag_has_fallback_exec;
210 }
210 }
211
211
212 static inline bool
212 static inline bool
213 dirstate_item_c_has_fallback_symlink(dirstateItemObject *self)
213 dirstate_item_c_has_fallback_symlink(dirstateItemObject *self)
214 {
214 {
215 return (bool)self->flags & dirstate_flag_has_fallback_symlink;
215 return (bool)self->flags & dirstate_flag_has_fallback_symlink;
216 }
216 }
217
217
218 static inline int dirstate_item_c_v1_mode(dirstateItemObject *self)
218 static inline int dirstate_item_c_v1_mode(dirstateItemObject *self)
219 {
219 {
220 if (self->flags & dirstate_flag_has_meaningful_data) {
220 if (self->flags & dirstate_flag_has_meaningful_data) {
221 return self->mode;
221 return self->mode;
222 } else {
222 } else {
223 return 0;
223 return 0;
224 }
224 }
225 }
225 }
226
226
227 static inline int dirstate_item_c_v1_size(dirstateItemObject *self)
227 static inline int dirstate_item_c_v1_size(dirstateItemObject *self)
228 {
228 {
229 if (!(self->flags & dirstate_flag_wc_tracked) &&
229 if (!(self->flags & dirstate_flag_wc_tracked) &&
230 (self->flags & dirstate_flag_p2_info)) {
230 (self->flags & dirstate_flag_p2_info)) {
231 if (self->flags & dirstate_flag_p1_tracked) {
231 if (self->flags & dirstate_flag_p1_tracked) {
232 return dirstate_v1_nonnormal;
232 return dirstate_v1_nonnormal;
233 } else {
233 } else {
234 return dirstate_v1_from_p2;
234 return dirstate_v1_from_p2;
235 }
235 }
236 } else if (dirstate_item_c_removed(self)) {
236 } else if (dirstate_item_c_removed(self)) {
237 return 0;
237 return 0;
238 } else if (self->flags & dirstate_flag_p2_info) {
238 } else if (self->flags & dirstate_flag_p2_info) {
239 return dirstate_v1_from_p2;
239 return dirstate_v1_from_p2;
240 } else if (dirstate_item_c_added(self)) {
240 } else if (dirstate_item_c_added(self)) {
241 return dirstate_v1_nonnormal;
241 return dirstate_v1_nonnormal;
242 } else if (self->flags & dirstate_flag_has_meaningful_data) {
242 } else if (self->flags & dirstate_flag_has_meaningful_data) {
243 return self->size;
243 return self->size;
244 } else {
244 } else {
245 return dirstate_v1_nonnormal;
245 return dirstate_v1_nonnormal;
246 }
246 }
247 }
247 }
248
248
249 static inline int dirstate_item_c_v1_mtime(dirstateItemObject *self)
249 static inline int dirstate_item_c_v1_mtime(dirstateItemObject *self)
250 {
250 {
251 if (dirstate_item_c_removed(self)) {
251 if (dirstate_item_c_removed(self)) {
252 return 0;
252 return 0;
253 } else if (!(self->flags & dirstate_flag_has_mtime) ||
253 } else if (!(self->flags & dirstate_flag_has_mtime) ||
254 !(self->flags & dirstate_flag_p1_tracked) ||
254 !(self->flags & dirstate_flag_p1_tracked) ||
255 !(self->flags & dirstate_flag_wc_tracked) ||
255 !(self->flags & dirstate_flag_wc_tracked) ||
256 (self->flags & dirstate_flag_p2_info) ||
256 (self->flags & dirstate_flag_p2_info) ||
257 (self->flags & dirstate_flag_mtime_second_ambiguous)) {
257 (self->flags & dirstate_flag_mtime_second_ambiguous)) {
258 return ambiguous_time;
258 return ambiguous_time;
259 } else {
259 } else {
260 return self->mtime_s;
260 return self->mtime_s;
261 }
261 }
262 }
262 }
263
263
264 static PyObject *dirstate_item_v2_data(dirstateItemObject *self)
264 static PyObject *dirstate_item_v2_data(dirstateItemObject *self)
265 {
265 {
266 int flags = self->flags;
266 int flags = self->flags;
267 int mode = dirstate_item_c_v1_mode(self);
267 int mode = dirstate_item_c_v1_mode(self);
268 #ifdef S_IXUSR
268 #ifdef S_IXUSR
269 /* This is for platforms with an exec bit */
269 /* This is for platforms with an exec bit */
270 if ((mode & S_IXUSR) != 0) {
270 if ((mode & S_IXUSR) != 0) {
271 flags |= dirstate_flag_mode_exec_perm;
271 flags |= dirstate_flag_mode_exec_perm;
272 } else {
272 } else {
273 flags &= ~dirstate_flag_mode_exec_perm;
273 flags &= ~dirstate_flag_mode_exec_perm;
274 }
274 }
275 #else
275 #else
276 flags &= ~dirstate_flag_mode_exec_perm;
276 flags &= ~dirstate_flag_mode_exec_perm;
277 #endif
277 #endif
278 #ifdef S_ISLNK
278 #ifdef S_ISLNK
279 /* This is for platforms with support for symlinks */
279 /* This is for platforms with support for symlinks */
280 if (S_ISLNK(mode)) {
280 if (S_ISLNK(mode)) {
281 flags |= dirstate_flag_mode_is_symlink;
281 flags |= dirstate_flag_mode_is_symlink;
282 } else {
282 } else {
283 flags &= ~dirstate_flag_mode_is_symlink;
283 flags &= ~dirstate_flag_mode_is_symlink;
284 }
284 }
285 #else
285 #else
286 flags &= ~dirstate_flag_mode_is_symlink;
286 flags &= ~dirstate_flag_mode_is_symlink;
287 #endif
287 #endif
288 return Py_BuildValue("iiii", flags, self->size, self->mtime_s,
288 return Py_BuildValue("iiii", flags, self->size, self->mtime_s,
289 self->mtime_ns);
289 self->mtime_ns);
290 };
290 };
291
291
292 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
292 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
293 {
293 {
294 char state = dirstate_item_c_v1_state(self);
294 char state = dirstate_item_c_v1_state(self);
295 return PyBytes_FromStringAndSize(&state, 1);
295 return PyBytes_FromStringAndSize(&state, 1);
296 };
296 };
297
297
298 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
298 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
299 {
299 {
300 return PyLong_FromLong(dirstate_item_c_v1_mode(self));
300 return PyLong_FromLong(dirstate_item_c_v1_mode(self));
301 };
301 };
302
302
303 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
303 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
304 {
304 {
305 return PyLong_FromLong(dirstate_item_c_v1_size(self));
305 return PyLong_FromLong(dirstate_item_c_v1_size(self));
306 };
306 };
307
307
308 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
308 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
309 {
309 {
310 return PyLong_FromLong(dirstate_item_c_v1_mtime(self));
310 return PyLong_FromLong(dirstate_item_c_v1_mtime(self));
311 };
311 };
312
312
313 static PyObject *dirstate_item_mtime_likely_equal_to(dirstateItemObject *self,
313 static PyObject *dirstate_item_mtime_likely_equal_to(dirstateItemObject *self,
314 PyObject *other)
314 PyObject *other)
315 {
315 {
316 int other_s;
316 int other_s;
317 int other_ns;
317 int other_ns;
318 int other_second_ambiguous;
318 int other_second_ambiguous;
319 if (!PyArg_ParseTuple(other, "iii", &other_s, &other_ns,
319 if (!PyArg_ParseTuple(other, "iii", &other_s, &other_ns,
320 &other_second_ambiguous)) {
320 &other_second_ambiguous)) {
321 return NULL;
321 return NULL;
322 }
322 }
323 if (!(self->flags & dirstate_flag_has_mtime)) {
323 if (!(self->flags & dirstate_flag_has_mtime)) {
324 Py_RETURN_FALSE;
324 Py_RETURN_FALSE;
325 }
325 }
326 if (self->mtime_s != other_s) {
326 if (self->mtime_s != other_s) {
327 Py_RETURN_FALSE;
327 Py_RETURN_FALSE;
328 }
328 }
329 if (self->mtime_ns == 0 || other_ns == 0) {
329 if (self->mtime_ns == 0 || other_ns == 0) {
330 if (self->flags & dirstate_flag_mtime_second_ambiguous) {
330 if (self->flags & dirstate_flag_mtime_second_ambiguous) {
331 Py_RETURN_FALSE;
331 Py_RETURN_FALSE;
332 } else {
332 } else {
333 Py_RETURN_TRUE;
333 Py_RETURN_TRUE;
334 }
334 }
335 }
335 }
336 if (self->mtime_ns == other_ns) {
336 if (self->mtime_ns == other_ns) {
337 Py_RETURN_TRUE;
337 Py_RETURN_TRUE;
338 } else {
338 } else {
339 Py_RETURN_FALSE;
339 Py_RETURN_FALSE;
340 }
340 }
341 };
341 };
342
342
343 /* This will never change since it's bound to V1
343 /* This will never change since it's bound to V1
344 */
344 */
345 static inline dirstateItemObject *
345 static inline dirstateItemObject *
346 dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
346 dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
347 {
347 {
348 dirstateItemObject *t =
348 dirstateItemObject *t =
349 PyObject_New(dirstateItemObject, &dirstateItemType);
349 PyObject_New(dirstateItemObject, &dirstateItemType);
350 if (!t) {
350 if (!t) {
351 return NULL;
351 return NULL;
352 }
352 }
353 t->flags = 0;
353 t->flags = 0;
354 t->mode = 0;
354 t->mode = 0;
355 t->size = 0;
355 t->size = 0;
356 t->mtime_s = 0;
356 t->mtime_s = 0;
357 t->mtime_ns = 0;
357 t->mtime_ns = 0;
358
358
359 if (state == 'm') {
359 if (state == 'm') {
360 t->flags = (dirstate_flag_wc_tracked |
360 t->flags = (dirstate_flag_wc_tracked |
361 dirstate_flag_p1_tracked | dirstate_flag_p2_info);
361 dirstate_flag_p1_tracked | dirstate_flag_p2_info);
362 } else if (state == 'a') {
362 } else if (state == 'a') {
363 t->flags = dirstate_flag_wc_tracked;
363 t->flags = dirstate_flag_wc_tracked;
364 } else if (state == 'r') {
364 } else if (state == 'r') {
365 if (size == dirstate_v1_nonnormal) {
365 if (size == dirstate_v1_nonnormal) {
366 t->flags =
366 t->flags =
367 dirstate_flag_p1_tracked | dirstate_flag_p2_info;
367 dirstate_flag_p1_tracked | dirstate_flag_p2_info;
368 } else if (size == dirstate_v1_from_p2) {
368 } else if (size == dirstate_v1_from_p2) {
369 t->flags = dirstate_flag_p2_info;
369 t->flags = dirstate_flag_p2_info;
370 } else {
370 } else {
371 t->flags = dirstate_flag_p1_tracked;
371 t->flags = dirstate_flag_p1_tracked;
372 }
372 }
373 } else if (state == 'n') {
373 } else if (state == 'n') {
374 if (size == dirstate_v1_from_p2) {
374 if (size == dirstate_v1_from_p2) {
375 t->flags =
375 t->flags =
376 dirstate_flag_wc_tracked | dirstate_flag_p2_info;
376 dirstate_flag_wc_tracked | dirstate_flag_p2_info;
377 } else if (size == dirstate_v1_nonnormal) {
377 } else if (size == dirstate_v1_nonnormal) {
378 t->flags =
378 t->flags =
379 dirstate_flag_wc_tracked | dirstate_flag_p1_tracked;
379 dirstate_flag_wc_tracked | dirstate_flag_p1_tracked;
380 } else if (mtime == ambiguous_time) {
380 } else if (mtime == ambiguous_time) {
381 t->flags = (dirstate_flag_wc_tracked |
381 t->flags = (dirstate_flag_wc_tracked |
382 dirstate_flag_p1_tracked |
382 dirstate_flag_p1_tracked |
383 dirstate_flag_has_meaningful_data);
383 dirstate_flag_has_meaningful_data);
384 t->mode = mode;
384 t->mode = mode;
385 t->size = size;
385 t->size = size;
386 } else {
386 } else {
387 t->flags = (dirstate_flag_wc_tracked |
387 t->flags = (dirstate_flag_wc_tracked |
388 dirstate_flag_p1_tracked |
388 dirstate_flag_p1_tracked |
389 dirstate_flag_has_meaningful_data |
389 dirstate_flag_has_meaningful_data |
390 dirstate_flag_has_mtime);
390 dirstate_flag_has_mtime);
391 t->mode = mode;
391 t->mode = mode;
392 t->size = size;
392 t->size = size;
393 t->mtime_s = mtime;
393 t->mtime_s = mtime;
394 }
394 }
395 } else {
395 } else {
396 PyErr_Format(PyExc_RuntimeError,
396 PyErr_Format(PyExc_RuntimeError,
397 "unknown state: `%c` (%d, %d, %d)", state, mode,
397 "unknown state: `%c` (%d, %d, %d)", state, mode,
398 size, mtime, NULL);
398 size, mtime, NULL);
399 Py_DECREF(t);
399 Py_DECREF(t);
400 return NULL;
400 return NULL;
401 }
401 }
402
402
403 return t;
403 return t;
404 }
404 }
405
405
406 /* This will never change since it's bound to V1, unlike `dirstate_item_new` */
406 /* This will never change since it's bound to V1, unlike `dirstate_item_new` */
407 static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
407 static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
408 PyObject *args)
408 PyObject *args)
409 {
409 {
410 /* We do all the initialization here and not a tp_init function because
410 /* We do all the initialization here and not a tp_init function because
411 * dirstate_item is immutable. */
411 * dirstate_item is immutable. */
412 char state;
412 char state;
413 int size, mode, mtime;
413 int size, mode, mtime;
414 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
414 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
415 return NULL;
415 return NULL;
416 }
416 }
417 return (PyObject *)dirstate_item_from_v1_data(state, mode, size, mtime);
417 return (PyObject *)dirstate_item_from_v1_data(state, mode, size, mtime);
418 };
418 };
419
419
420 static PyObject *dirstate_item_from_v2_meth(PyTypeObject *subtype,
420 static PyObject *dirstate_item_from_v2_meth(PyTypeObject *subtype,
421 PyObject *args)
421 PyObject *args)
422 {
422 {
423 dirstateItemObject *t =
423 dirstateItemObject *t =
424 PyObject_New(dirstateItemObject, &dirstateItemType);
424 PyObject_New(dirstateItemObject, &dirstateItemType);
425 if (!t) {
425 if (!t) {
426 return NULL;
426 return NULL;
427 }
427 }
428 if (!PyArg_ParseTuple(args, "iiii", &t->flags, &t->size, &t->mtime_s,
428 if (!PyArg_ParseTuple(args, "iiii", &t->flags, &t->size, &t->mtime_s,
429 &t->mtime_ns)) {
429 &t->mtime_ns)) {
430 return NULL;
430 return NULL;
431 }
431 }
432 if (t->flags & dirstate_flag_expected_state_is_modified) {
432 if (t->flags & dirstate_flag_expected_state_is_modified) {
433 t->flags &= ~(dirstate_flag_expected_state_is_modified |
433 t->flags &= ~(dirstate_flag_expected_state_is_modified |
434 dirstate_flag_has_meaningful_data |
434 dirstate_flag_has_meaningful_data |
435 dirstate_flag_has_mtime);
435 dirstate_flag_has_mtime);
436 }
436 }
437 t->mode = 0;
437 t->mode = 0;
438 if (t->flags & dirstate_flag_has_meaningful_data) {
438 if (t->flags & dirstate_flag_has_meaningful_data) {
439 if (t->flags & dirstate_flag_mode_exec_perm) {
439 if (t->flags & dirstate_flag_mode_exec_perm) {
440 t->mode = 0755;
440 t->mode = 0755;
441 } else {
441 } else {
442 t->mode = 0644;
442 t->mode = 0644;
443 }
443 }
444 if (t->flags & dirstate_flag_mode_is_symlink) {
444 if (t->flags & dirstate_flag_mode_is_symlink) {
445 t->mode |= S_IFLNK;
445 t->mode |= S_IFLNK;
446 } else {
446 } else {
447 t->mode |= S_IFREG;
447 t->mode |= S_IFREG;
448 }
448 }
449 }
449 }
450 return (PyObject *)t;
450 return (PyObject *)t;
451 };
451 };
452
452
453 /* This means the next status call will have to actually check its content
453 /* This means the next status call will have to actually check its content
454 to make sure it is correct. */
454 to make sure it is correct. */
455 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
455 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
456 {
456 {
457 self->flags &= ~dirstate_flag_has_mtime;
457 self->flags &= ~dirstate_flag_has_mtime;
458 Py_RETURN_NONE;
458 Py_RETURN_NONE;
459 }
459 }
460
460
461 /* See docstring of the python implementation for details */
461 /* See docstring of the python implementation for details */
462 static PyObject *dirstate_item_set_clean(dirstateItemObject *self,
462 static PyObject *dirstate_item_set_clean(dirstateItemObject *self,
463 PyObject *args)
463 PyObject *args)
464 {
464 {
465 int size, mode, mtime_s, mtime_ns, mtime_second_ambiguous;
465 int size, mode, mtime_s, mtime_ns, mtime_second_ambiguous;
466 PyObject *mtime;
466 PyObject *mtime;
467 mtime_s = 0;
467 mtime_s = 0;
468 mtime_ns = 0;
468 mtime_ns = 0;
469 mtime_second_ambiguous = 0;
469 mtime_second_ambiguous = 0;
470 if (!PyArg_ParseTuple(args, "iiO", &mode, &size, &mtime)) {
470 if (!PyArg_ParseTuple(args, "iiO", &mode, &size, &mtime)) {
471 return NULL;
471 return NULL;
472 }
472 }
473 if (mtime != Py_None) {
473 if (mtime != Py_None) {
474 if (!PyArg_ParseTuple(mtime, "iii", &mtime_s, &mtime_ns,
474 if (!PyArg_ParseTuple(mtime, "iii", &mtime_s, &mtime_ns,
475 &mtime_second_ambiguous)) {
475 &mtime_second_ambiguous)) {
476 return NULL;
476 return NULL;
477 }
477 }
478 } else {
478 } else {
479 self->flags &= ~dirstate_flag_has_mtime;
479 self->flags &= ~dirstate_flag_has_mtime;
480 }
480 }
481 self->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
481 self->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
482 dirstate_flag_has_meaningful_data |
482 dirstate_flag_has_meaningful_data |
483 dirstate_flag_has_mtime;
483 dirstate_flag_has_mtime;
484 if (mtime_second_ambiguous) {
484 if (mtime_second_ambiguous) {
485 self->flags |= dirstate_flag_mtime_second_ambiguous;
485 self->flags |= dirstate_flag_mtime_second_ambiguous;
486 }
486 }
487 self->mode = mode;
487 self->mode = mode;
488 self->size = size;
488 self->size = size;
489 self->mtime_s = mtime_s;
489 self->mtime_s = mtime_s;
490 self->mtime_ns = mtime_ns;
490 self->mtime_ns = mtime_ns;
491 Py_RETURN_NONE;
491 Py_RETURN_NONE;
492 }
492 }
493
493
494 static PyObject *dirstate_item_set_tracked(dirstateItemObject *self)
494 static PyObject *dirstate_item_set_tracked(dirstateItemObject *self)
495 {
495 {
496 self->flags |= dirstate_flag_wc_tracked;
496 self->flags |= dirstate_flag_wc_tracked;
497 self->flags &= ~dirstate_flag_has_mtime;
497 self->flags &= ~dirstate_flag_has_mtime;
498 Py_RETURN_NONE;
498 Py_RETURN_NONE;
499 }
499 }
500
500
501 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
501 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
502 {
502 {
503 self->flags &= ~dirstate_flag_wc_tracked;
503 self->flags &= ~dirstate_flag_wc_tracked;
504 self->mode = 0;
504 self->mode = 0;
505 self->size = 0;
505 self->size = 0;
506 self->mtime_s = 0;
506 self->mtime_s = 0;
507 self->mtime_ns = 0;
507 self->mtime_ns = 0;
508 Py_RETURN_NONE;
508 Py_RETURN_NONE;
509 }
509 }
510
510
511 static PyObject *dirstate_item_drop_merge_data(dirstateItemObject *self)
511 static PyObject *dirstate_item_drop_merge_data(dirstateItemObject *self)
512 {
512 {
513 if (self->flags & dirstate_flag_p2_info) {
513 if (self->flags & dirstate_flag_p2_info) {
514 self->flags &= ~(dirstate_flag_p2_info |
514 self->flags &= ~(dirstate_flag_p2_info |
515 dirstate_flag_has_meaningful_data |
515 dirstate_flag_has_meaningful_data |
516 dirstate_flag_has_mtime);
516 dirstate_flag_has_mtime);
517 self->mode = 0;
517 self->mode = 0;
518 self->size = 0;
518 self->size = 0;
519 self->mtime_s = 0;
519 self->mtime_s = 0;
520 self->mtime_ns = 0;
520 self->mtime_ns = 0;
521 }
521 }
522 Py_RETURN_NONE;
522 Py_RETURN_NONE;
523 }
523 }
524 static PyMethodDef dirstate_item_methods[] = {
524 static PyMethodDef dirstate_item_methods[] = {
525 {"v2_data", (PyCFunction)dirstate_item_v2_data, METH_NOARGS,
525 {"v2_data", (PyCFunction)dirstate_item_v2_data, METH_NOARGS,
526 "return data suitable for v2 serialization"},
526 "return data suitable for v2 serialization"},
527 {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
527 {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
528 "return a \"state\" suitable for v1 serialization"},
528 "return a \"state\" suitable for v1 serialization"},
529 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
529 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
530 "return a \"mode\" suitable for v1 serialization"},
530 "return a \"mode\" suitable for v1 serialization"},
531 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
531 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
532 "return a \"size\" suitable for v1 serialization"},
532 "return a \"size\" suitable for v1 serialization"},
533 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
533 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
534 "return a \"mtime\" suitable for v1 serialization"},
534 "return a \"mtime\" suitable for v1 serialization"},
535 {"mtime_likely_equal_to", (PyCFunction)dirstate_item_mtime_likely_equal_to,
535 {"mtime_likely_equal_to", (PyCFunction)dirstate_item_mtime_likely_equal_to,
536 METH_O, "True if the stored mtime is likely equal to the given mtime"},
536 METH_O, "True if the stored mtime is likely equal to the given mtime"},
537 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
537 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
538 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V1 data"},
538 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V1 data"},
539 {"from_v2_data", (PyCFunction)dirstate_item_from_v2_meth,
539 {"from_v2_data", (PyCFunction)dirstate_item_from_v2_meth,
540 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V2 data"},
540 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V2 data"},
541 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
541 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
542 METH_NOARGS, "mark a file as \"possibly dirty\""},
542 METH_NOARGS, "mark a file as \"possibly dirty\""},
543 {"set_clean", (PyCFunction)dirstate_item_set_clean, METH_VARARGS,
543 {"set_clean", (PyCFunction)dirstate_item_set_clean, METH_VARARGS,
544 "mark a file as \"clean\""},
544 "mark a file as \"clean\""},
545 {"set_tracked", (PyCFunction)dirstate_item_set_tracked, METH_NOARGS,
545 {"set_tracked", (PyCFunction)dirstate_item_set_tracked, METH_NOARGS,
546 "mark a file as \"tracked\""},
546 "mark a file as \"tracked\""},
547 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
547 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
548 "mark a file as \"untracked\""},
548 "mark a file as \"untracked\""},
549 {"drop_merge_data", (PyCFunction)dirstate_item_drop_merge_data, METH_NOARGS,
549 {"drop_merge_data", (PyCFunction)dirstate_item_drop_merge_data, METH_NOARGS,
550 "remove all \"merge-only\" from a DirstateItem"},
550 "remove all \"merge-only\" from a DirstateItem"},
551 {NULL} /* Sentinel */
551 {NULL} /* Sentinel */
552 };
552 };
553
553
554 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
554 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
555 {
555 {
556 return PyLong_FromLong(dirstate_item_c_v1_mode(self));
556 return PyLong_FromLong(dirstate_item_c_v1_mode(self));
557 };
557 };
558
558
559 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
559 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
560 {
560 {
561 return PyLong_FromLong(dirstate_item_c_v1_size(self));
561 return PyLong_FromLong(dirstate_item_c_v1_size(self));
562 };
562 };
563
563
564 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
564 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
565 {
565 {
566 return PyLong_FromLong(dirstate_item_c_v1_mtime(self));
566 return PyLong_FromLong(dirstate_item_c_v1_mtime(self));
567 };
567 };
568
568
569 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
569 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
570 {
570 {
571 char state = dirstate_item_c_v1_state(self);
571 char state = dirstate_item_c_v1_state(self);
572 return PyBytes_FromStringAndSize(&state, 1);
572 return PyBytes_FromStringAndSize(&state, 1);
573 };
573 };
574
574
575 static PyObject *dirstate_item_get_has_fallback_exec(dirstateItemObject *self)
575 static PyObject *dirstate_item_get_has_fallback_exec(dirstateItemObject *self)
576 {
576 {
577 if (dirstate_item_c_has_fallback_exec(self)) {
577 if (dirstate_item_c_has_fallback_exec(self)) {
578 Py_RETURN_TRUE;
578 Py_RETURN_TRUE;
579 } else {
579 } else {
580 Py_RETURN_FALSE;
580 Py_RETURN_FALSE;
581 }
581 }
582 };
582 };
583
583
584 static PyObject *dirstate_item_get_fallback_exec(dirstateItemObject *self)
584 static PyObject *dirstate_item_get_fallback_exec(dirstateItemObject *self)
585 {
585 {
586 if (dirstate_item_c_has_fallback_exec(self)) {
586 if (dirstate_item_c_has_fallback_exec(self)) {
587 if (self->flags & dirstate_flag_fallback_exec) {
587 if (self->flags & dirstate_flag_fallback_exec) {
588 Py_RETURN_TRUE;
588 Py_RETURN_TRUE;
589 } else {
589 } else {
590 Py_RETURN_FALSE;
590 Py_RETURN_FALSE;
591 }
591 }
592 } else {
592 } else {
593 Py_RETURN_NONE;
593 Py_RETURN_NONE;
594 }
594 }
595 };
595 };
596
596
597 static int dirstate_item_set_fallback_exec(dirstateItemObject *self,
597 static int dirstate_item_set_fallback_exec(dirstateItemObject *self,
598 PyObject *value)
598 PyObject *value)
599 {
599 {
600 if ((value == Py_None) || (value == NULL)) {
600 if ((value == Py_None) || (value == NULL)) {
601 self->flags &= ~dirstate_flag_has_fallback_exec;
601 self->flags &= ~dirstate_flag_has_fallback_exec;
602 } else {
602 } else {
603 self->flags |= dirstate_flag_has_fallback_exec;
603 self->flags |= dirstate_flag_has_fallback_exec;
604 if (PyObject_IsTrue(value)) {
604 if (PyObject_IsTrue(value)) {
605 self->flags |= dirstate_flag_fallback_exec;
605 self->flags |= dirstate_flag_fallback_exec;
606 } else {
606 } else {
607 self->flags &= ~dirstate_flag_fallback_exec;
607 self->flags &= ~dirstate_flag_fallback_exec;
608 }
608 }
609 }
609 }
610 return 0;
610 return 0;
611 };
611 };
612
612
613 static PyObject *
613 static PyObject *
614 dirstate_item_get_has_fallback_symlink(dirstateItemObject *self)
614 dirstate_item_get_has_fallback_symlink(dirstateItemObject *self)
615 {
615 {
616 if (dirstate_item_c_has_fallback_symlink(self)) {
616 if (dirstate_item_c_has_fallback_symlink(self)) {
617 Py_RETURN_TRUE;
617 Py_RETURN_TRUE;
618 } else {
618 } else {
619 Py_RETURN_FALSE;
619 Py_RETURN_FALSE;
620 }
620 }
621 };
621 };
622
622
623 static PyObject *dirstate_item_get_fallback_symlink(dirstateItemObject *self)
623 static PyObject *dirstate_item_get_fallback_symlink(dirstateItemObject *self)
624 {
624 {
625 if (dirstate_item_c_has_fallback_symlink(self)) {
625 if (dirstate_item_c_has_fallback_symlink(self)) {
626 if (self->flags & dirstate_flag_fallback_symlink) {
626 if (self->flags & dirstate_flag_fallback_symlink) {
627 Py_RETURN_TRUE;
627 Py_RETURN_TRUE;
628 } else {
628 } else {
629 Py_RETURN_FALSE;
629 Py_RETURN_FALSE;
630 }
630 }
631 } else {
631 } else {
632 Py_RETURN_NONE;
632 Py_RETURN_NONE;
633 }
633 }
634 };
634 };
635
635
636 static int dirstate_item_set_fallback_symlink(dirstateItemObject *self,
636 static int dirstate_item_set_fallback_symlink(dirstateItemObject *self,
637 PyObject *value)
637 PyObject *value)
638 {
638 {
639 if ((value == Py_None) || (value == NULL)) {
639 if ((value == Py_None) || (value == NULL)) {
640 self->flags &= ~dirstate_flag_has_fallback_symlink;
640 self->flags &= ~dirstate_flag_has_fallback_symlink;
641 } else {
641 } else {
642 self->flags |= dirstate_flag_has_fallback_symlink;
642 self->flags |= dirstate_flag_has_fallback_symlink;
643 if (PyObject_IsTrue(value)) {
643 if (PyObject_IsTrue(value)) {
644 self->flags |= dirstate_flag_fallback_symlink;
644 self->flags |= dirstate_flag_fallback_symlink;
645 } else {
645 } else {
646 self->flags &= ~dirstate_flag_fallback_symlink;
646 self->flags &= ~dirstate_flag_fallback_symlink;
647 }
647 }
648 }
648 }
649 return 0;
649 return 0;
650 };
650 };
651
651
652 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
652 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
653 {
653 {
654 if (dirstate_item_c_tracked(self)) {
654 if (dirstate_item_c_tracked(self)) {
655 Py_RETURN_TRUE;
655 Py_RETURN_TRUE;
656 } else {
656 } else {
657 Py_RETURN_FALSE;
657 Py_RETURN_FALSE;
658 }
658 }
659 };
659 };
660 static PyObject *dirstate_item_get_p1_tracked(dirstateItemObject *self)
660 static PyObject *dirstate_item_get_p1_tracked(dirstateItemObject *self)
661 {
661 {
662 if (self->flags & dirstate_flag_p1_tracked) {
662 if (self->flags & dirstate_flag_p1_tracked) {
663 Py_RETURN_TRUE;
663 Py_RETURN_TRUE;
664 } else {
664 } else {
665 Py_RETURN_FALSE;
665 Py_RETURN_FALSE;
666 }
666 }
667 };
667 };
668
668
669 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
669 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
670 {
670 {
671 if (dirstate_item_c_added(self)) {
671 if (dirstate_item_c_added(self)) {
672 Py_RETURN_TRUE;
672 Py_RETURN_TRUE;
673 } else {
673 } else {
674 Py_RETURN_FALSE;
674 Py_RETURN_FALSE;
675 }
675 }
676 };
676 };
677
677
678 static PyObject *dirstate_item_get_p2_info(dirstateItemObject *self)
678 static PyObject *dirstate_item_get_p2_info(dirstateItemObject *self)
679 {
679 {
680 if (self->flags & dirstate_flag_wc_tracked &&
680 if (self->flags & dirstate_flag_wc_tracked &&
681 self->flags & dirstate_flag_p2_info) {
681 self->flags & dirstate_flag_p2_info) {
682 Py_RETURN_TRUE;
682 Py_RETURN_TRUE;
683 } else {
683 } else {
684 Py_RETURN_FALSE;
684 Py_RETURN_FALSE;
685 }
685 }
686 };
686 };
687
687
688 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
688 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
689 {
689 {
690 if (dirstate_item_c_merged(self)) {
690 if (dirstate_item_c_merged(self)) {
691 Py_RETURN_TRUE;
691 Py_RETURN_TRUE;
692 } else {
692 } else {
693 Py_RETURN_FALSE;
693 Py_RETURN_FALSE;
694 }
694 }
695 };
695 };
696
696
697 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
697 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
698 {
698 {
699 if (dirstate_item_c_from_p2(self)) {
699 if (dirstate_item_c_from_p2(self)) {
700 Py_RETURN_TRUE;
700 Py_RETURN_TRUE;
701 } else {
701 } else {
702 Py_RETURN_FALSE;
702 Py_RETURN_FALSE;
703 }
703 }
704 };
704 };
705
705
706 static PyObject *dirstate_item_get_maybe_clean(dirstateItemObject *self)
706 static PyObject *dirstate_item_get_maybe_clean(dirstateItemObject *self)
707 {
707 {
708 if (!(self->flags & dirstate_flag_wc_tracked)) {
708 if (!(self->flags & dirstate_flag_wc_tracked)) {
709 Py_RETURN_FALSE;
709 Py_RETURN_FALSE;
710 } else if (!(self->flags & dirstate_flag_p1_tracked)) {
710 } else if (!(self->flags & dirstate_flag_p1_tracked)) {
711 Py_RETURN_FALSE;
711 Py_RETURN_FALSE;
712 } else if (self->flags & dirstate_flag_p2_info) {
712 } else if (self->flags & dirstate_flag_p2_info) {
713 Py_RETURN_FALSE;
713 Py_RETURN_FALSE;
714 } else {
714 } else {
715 Py_RETURN_TRUE;
715 Py_RETURN_TRUE;
716 }
716 }
717 };
717 };
718
718
719 static PyObject *dirstate_item_get_any_tracked(dirstateItemObject *self)
719 static PyObject *dirstate_item_get_any_tracked(dirstateItemObject *self)
720 {
720 {
721 if (dirstate_item_c_any_tracked(self)) {
721 if (dirstate_item_c_any_tracked(self)) {
722 Py_RETURN_TRUE;
722 Py_RETURN_TRUE;
723 } else {
723 } else {
724 Py_RETURN_FALSE;
724 Py_RETURN_FALSE;
725 }
725 }
726 };
726 };
727
727
728 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
728 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
729 {
729 {
730 if (dirstate_item_c_removed(self)) {
730 if (dirstate_item_c_removed(self)) {
731 Py_RETURN_TRUE;
731 Py_RETURN_TRUE;
732 } else {
732 } else {
733 Py_RETURN_FALSE;
733 Py_RETURN_FALSE;
734 }
734 }
735 };
735 };
736
736
737 static PyGetSetDef dirstate_item_getset[] = {
737 static PyGetSetDef dirstate_item_getset[] = {
738 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
738 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
739 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
739 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
740 {"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
740 {"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
741 {"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
741 {"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
742 {"has_fallback_exec", (getter)dirstate_item_get_has_fallback_exec, NULL,
742 {"has_fallback_exec", (getter)dirstate_item_get_has_fallback_exec, NULL,
743 "has_fallback_exec", NULL},
743 "has_fallback_exec", NULL},
744 {"fallback_exec", (getter)dirstate_item_get_fallback_exec,
744 {"fallback_exec", (getter)dirstate_item_get_fallback_exec,
745 (setter)dirstate_item_set_fallback_exec, "fallback_exec", NULL},
745 (setter)dirstate_item_set_fallback_exec, "fallback_exec", NULL},
746 {"has_fallback_symlink", (getter)dirstate_item_get_has_fallback_symlink,
746 {"has_fallback_symlink", (getter)dirstate_item_get_has_fallback_symlink,
747 NULL, "has_fallback_symlink", NULL},
747 NULL, "has_fallback_symlink", NULL},
748 {"fallback_symlink", (getter)dirstate_item_get_fallback_symlink,
748 {"fallback_symlink", (getter)dirstate_item_get_fallback_symlink,
749 (setter)dirstate_item_set_fallback_symlink, "fallback_symlink", NULL},
749 (setter)dirstate_item_set_fallback_symlink, "fallback_symlink", NULL},
750 {"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
750 {"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
751 {"p1_tracked", (getter)dirstate_item_get_p1_tracked, NULL, "p1_tracked",
751 {"p1_tracked", (getter)dirstate_item_get_p1_tracked, NULL, "p1_tracked",
752 NULL},
752 NULL},
753 {"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
753 {"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
754 {"p2_info", (getter)dirstate_item_get_p2_info, NULL, "p2_info", NULL},
754 {"p2_info", (getter)dirstate_item_get_p2_info, NULL, "p2_info", NULL},
755 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
755 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
756 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
756 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
757 {"maybe_clean", (getter)dirstate_item_get_maybe_clean, NULL, "maybe_clean",
757 {"maybe_clean", (getter)dirstate_item_get_maybe_clean, NULL, "maybe_clean",
758 NULL},
758 NULL},
759 {"any_tracked", (getter)dirstate_item_get_any_tracked, NULL, "any_tracked",
759 {"any_tracked", (getter)dirstate_item_get_any_tracked, NULL, "any_tracked",
760 NULL},
760 NULL},
761 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
761 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
762 {NULL} /* Sentinel */
762 {NULL} /* Sentinel */
763 };
763 };
764
764
765 PyTypeObject dirstateItemType = {
765 PyTypeObject dirstateItemType = {
766 PyVarObject_HEAD_INIT(NULL, 0) /* header */
766 PyVarObject_HEAD_INIT(NULL, 0) /* header */
767 "dirstate_tuple", /* tp_name */
767 "dirstate_tuple", /* tp_name */
768 sizeof(dirstateItemObject), /* tp_basicsize */
768 sizeof(dirstateItemObject), /* tp_basicsize */
769 0, /* tp_itemsize */
769 0, /* tp_itemsize */
770 (destructor)dirstate_item_dealloc, /* tp_dealloc */
770 (destructor)dirstate_item_dealloc, /* tp_dealloc */
771 0, /* tp_print */
771 0, /* tp_print */
772 0, /* tp_getattr */
772 0, /* tp_getattr */
773 0, /* tp_setattr */
773 0, /* tp_setattr */
774 0, /* tp_compare */
774 0, /* tp_compare */
775 0, /* tp_repr */
775 0, /* tp_repr */
776 0, /* tp_as_number */
776 0, /* tp_as_number */
777 0, /* tp_as_sequence */
777 0, /* tp_as_sequence */
778 0, /* tp_as_mapping */
778 0, /* tp_as_mapping */
779 0, /* tp_hash */
779 0, /* tp_hash */
780 0, /* tp_call */
780 0, /* tp_call */
781 0, /* tp_str */
781 0, /* tp_str */
782 0, /* tp_getattro */
782 0, /* tp_getattro */
783 0, /* tp_setattro */
783 0, /* tp_setattro */
784 0, /* tp_as_buffer */
784 0, /* tp_as_buffer */
785 Py_TPFLAGS_DEFAULT, /* tp_flags */
785 Py_TPFLAGS_DEFAULT, /* tp_flags */
786 "dirstate tuple", /* tp_doc */
786 "dirstate tuple", /* tp_doc */
787 0, /* tp_traverse */
787 0, /* tp_traverse */
788 0, /* tp_clear */
788 0, /* tp_clear */
789 0, /* tp_richcompare */
789 0, /* tp_richcompare */
790 0, /* tp_weaklistoffset */
790 0, /* tp_weaklistoffset */
791 0, /* tp_iter */
791 0, /* tp_iter */
792 0, /* tp_iternext */
792 0, /* tp_iternext */
793 dirstate_item_methods, /* tp_methods */
793 dirstate_item_methods, /* tp_methods */
794 0, /* tp_members */
794 0, /* tp_members */
795 dirstate_item_getset, /* tp_getset */
795 dirstate_item_getset, /* tp_getset */
796 0, /* tp_base */
796 0, /* tp_base */
797 0, /* tp_dict */
797 0, /* tp_dict */
798 0, /* tp_descr_get */
798 0, /* tp_descr_get */
799 0, /* tp_descr_set */
799 0, /* tp_descr_set */
800 0, /* tp_dictoffset */
800 0, /* tp_dictoffset */
801 0, /* tp_init */
801 0, /* tp_init */
802 0, /* tp_alloc */
802 0, /* tp_alloc */
803 dirstate_item_new, /* tp_new */
803 dirstate_item_new, /* tp_new */
804 };
804 };
805
805
806 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
806 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
807 {
807 {
808 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
808 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
809 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
809 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
810 char state, *cur, *str, *cpos;
810 char state, *cur, *str, *cpos;
811 int mode, size, mtime;
811 int mode, size, mtime;
812 unsigned int flen, pos = 40;
812 unsigned int flen, pos = 40;
813 Py_ssize_t len = 40;
813 Py_ssize_t len = 40;
814 Py_ssize_t readlen;
814 Py_ssize_t readlen;
815
815
816 if (!PyArg_ParseTuple(
816 if (!PyArg_ParseTuple(args, "O!O!y#:parse_dirstate", &PyDict_Type,
817 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
817 &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
818 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
819 goto quit;
818 goto quit;
820 }
819 }
821
820
822 len = readlen;
821 len = readlen;
823
822
824 /* read parents */
823 /* read parents */
825 if (len < 40) {
824 if (len < 40) {
826 PyErr_SetString(PyExc_ValueError,
825 PyErr_SetString(PyExc_ValueError,
827 "too little data for parents");
826 "too little data for parents");
828 goto quit;
827 goto quit;
829 }
828 }
830
829
831 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
830 parents = Py_BuildValue("y#y#", str, (Py_ssize_t)20, str + 20,
832 str + 20, (Py_ssize_t)20);
831 (Py_ssize_t)20);
833 if (!parents) {
832 if (!parents) {
834 goto quit;
833 goto quit;
835 }
834 }
836
835
837 /* read filenames */
836 /* read filenames */
838 while (pos >= 40 && pos < len) {
837 while (pos >= 40 && pos < len) {
839 if (pos + 17 > len) {
838 if (pos + 17 > len) {
840 PyErr_SetString(PyExc_ValueError,
839 PyErr_SetString(PyExc_ValueError,
841 "overflow in dirstate");
840 "overflow in dirstate");
842 goto quit;
841 goto quit;
843 }
842 }
844 cur = str + pos;
843 cur = str + pos;
845 /* unpack header */
844 /* unpack header */
846 state = *cur;
845 state = *cur;
847 mode = getbe32(cur + 1);
846 mode = getbe32(cur + 1);
848 size = getbe32(cur + 5);
847 size = getbe32(cur + 5);
849 mtime = getbe32(cur + 9);
848 mtime = getbe32(cur + 9);
850 flen = getbe32(cur + 13);
849 flen = getbe32(cur + 13);
851 pos += 17;
850 pos += 17;
852 cur += 17;
851 cur += 17;
853 if (flen > len - pos) {
852 if (flen > len - pos) {
854 PyErr_SetString(PyExc_ValueError,
853 PyErr_SetString(PyExc_ValueError,
855 "overflow in dirstate");
854 "overflow in dirstate");
856 goto quit;
855 goto quit;
857 }
856 }
858
857
859 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
858 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
860 size, mtime);
859 size, mtime);
861 if (!entry)
860 if (!entry)
862 goto quit;
861 goto quit;
863 cpos = memchr(cur, 0, flen);
862 cpos = memchr(cur, 0, flen);
864 if (cpos) {
863 if (cpos) {
865 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
864 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
866 cname = PyBytes_FromStringAndSize(
865 cname = PyBytes_FromStringAndSize(
867 cpos + 1, flen - (cpos - cur) - 1);
866 cpos + 1, flen - (cpos - cur) - 1);
868 if (!fname || !cname ||
867 if (!fname || !cname ||
869 PyDict_SetItem(cmap, fname, cname) == -1 ||
868 PyDict_SetItem(cmap, fname, cname) == -1 ||
870 PyDict_SetItem(dmap, fname, entry) == -1) {
869 PyDict_SetItem(dmap, fname, entry) == -1) {
871 goto quit;
870 goto quit;
872 }
871 }
873 Py_DECREF(cname);
872 Py_DECREF(cname);
874 } else {
873 } else {
875 fname = PyBytes_FromStringAndSize(cur, flen);
874 fname = PyBytes_FromStringAndSize(cur, flen);
876 if (!fname ||
875 if (!fname ||
877 PyDict_SetItem(dmap, fname, entry) == -1) {
876 PyDict_SetItem(dmap, fname, entry) == -1) {
878 goto quit;
877 goto quit;
879 }
878 }
880 }
879 }
881 Py_DECREF(fname);
880 Py_DECREF(fname);
882 Py_DECREF(entry);
881 Py_DECREF(entry);
883 fname = cname = entry = NULL;
882 fname = cname = entry = NULL;
884 pos += flen;
883 pos += flen;
885 }
884 }
886
885
887 ret = parents;
886 ret = parents;
888 Py_INCREF(ret);
887 Py_INCREF(ret);
889 quit:
888 quit:
890 Py_XDECREF(fname);
889 Py_XDECREF(fname);
891 Py_XDECREF(cname);
890 Py_XDECREF(cname);
892 Py_XDECREF(entry);
891 Py_XDECREF(entry);
893 Py_XDECREF(parents);
892 Py_XDECREF(parents);
894 return ret;
893 return ret;
895 }
894 }
896
895
897 /*
896 /*
898 * Efficiently pack a dirstate object into its on-disk format.
897 * Efficiently pack a dirstate object into its on-disk format.
899 */
898 */
900 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
899 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
901 {
900 {
902 PyObject *packobj = NULL;
901 PyObject *packobj = NULL;
903 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
902 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
904 Py_ssize_t nbytes, pos, l;
903 Py_ssize_t nbytes, pos, l;
905 PyObject *k, *v = NULL, *pn;
904 PyObject *k, *v = NULL, *pn;
906 char *p, *s;
905 char *p, *s;
907
906
908 if (!PyArg_ParseTuple(args, "O!O!O!:pack_dirstate", &PyDict_Type, &map,
907 if (!PyArg_ParseTuple(args, "O!O!O!:pack_dirstate", &PyDict_Type, &map,
909 &PyDict_Type, &copymap, &PyTuple_Type, &pl)) {
908 &PyDict_Type, &copymap, &PyTuple_Type, &pl)) {
910 return NULL;
909 return NULL;
911 }
910 }
912
911
913 if (PyTuple_Size(pl) != 2) {
912 if (PyTuple_Size(pl) != 2) {
914 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
913 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
915 return NULL;
914 return NULL;
916 }
915 }
917
916
918 /* Figure out how much we need to allocate. */
917 /* Figure out how much we need to allocate. */
919 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
918 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
920 PyObject *c;
919 PyObject *c;
921 if (!PyBytes_Check(k)) {
920 if (!PyBytes_Check(k)) {
922 PyErr_SetString(PyExc_TypeError, "expected string key");
921 PyErr_SetString(PyExc_TypeError, "expected string key");
923 goto bail;
922 goto bail;
924 }
923 }
925 nbytes += PyBytes_GET_SIZE(k) + 17;
924 nbytes += PyBytes_GET_SIZE(k) + 17;
926 c = PyDict_GetItem(copymap, k);
925 c = PyDict_GetItem(copymap, k);
927 if (c) {
926 if (c) {
928 if (!PyBytes_Check(c)) {
927 if (!PyBytes_Check(c)) {
929 PyErr_SetString(PyExc_TypeError,
928 PyErr_SetString(PyExc_TypeError,
930 "expected string key");
929 "expected string key");
931 goto bail;
930 goto bail;
932 }
931 }
933 nbytes += PyBytes_GET_SIZE(c) + 1;
932 nbytes += PyBytes_GET_SIZE(c) + 1;
934 }
933 }
935 }
934 }
936
935
937 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
936 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
938 if (packobj == NULL) {
937 if (packobj == NULL) {
939 goto bail;
938 goto bail;
940 }
939 }
941
940
942 p = PyBytes_AS_STRING(packobj);
941 p = PyBytes_AS_STRING(packobj);
943
942
944 pn = PyTuple_GET_ITEM(pl, 0);
943 pn = PyTuple_GET_ITEM(pl, 0);
945 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
944 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
946 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
945 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
947 goto bail;
946 goto bail;
948 }
947 }
949 memcpy(p, s, l);
948 memcpy(p, s, l);
950 p += 20;
949 p += 20;
951 pn = PyTuple_GET_ITEM(pl, 1);
950 pn = PyTuple_GET_ITEM(pl, 1);
952 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
951 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
953 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
952 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
954 goto bail;
953 goto bail;
955 }
954 }
956 memcpy(p, s, l);
955 memcpy(p, s, l);
957 p += 20;
956 p += 20;
958
957
959 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
958 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
960 dirstateItemObject *tuple;
959 dirstateItemObject *tuple;
961 char state;
960 char state;
962 int mode, size, mtime;
961 int mode, size, mtime;
963 Py_ssize_t len, l;
962 Py_ssize_t len, l;
964 PyObject *o;
963 PyObject *o;
965 char *t;
964 char *t;
966
965
967 if (!dirstate_tuple_check(v)) {
966 if (!dirstate_tuple_check(v)) {
968 PyErr_SetString(PyExc_TypeError,
967 PyErr_SetString(PyExc_TypeError,
969 "expected a dirstate tuple");
968 "expected a dirstate tuple");
970 goto bail;
969 goto bail;
971 }
970 }
972 tuple = (dirstateItemObject *)v;
971 tuple = (dirstateItemObject *)v;
973
972
974 state = dirstate_item_c_v1_state(tuple);
973 state = dirstate_item_c_v1_state(tuple);
975 mode = dirstate_item_c_v1_mode(tuple);
974 mode = dirstate_item_c_v1_mode(tuple);
976 size = dirstate_item_c_v1_size(tuple);
975 size = dirstate_item_c_v1_size(tuple);
977 mtime = dirstate_item_c_v1_mtime(tuple);
976 mtime = dirstate_item_c_v1_mtime(tuple);
978 *p++ = state;
977 *p++ = state;
979 putbe32((uint32_t)mode, p);
978 putbe32((uint32_t)mode, p);
980 putbe32((uint32_t)size, p + 4);
979 putbe32((uint32_t)size, p + 4);
981 putbe32((uint32_t)mtime, p + 8);
980 putbe32((uint32_t)mtime, p + 8);
982 t = p + 12;
981 t = p + 12;
983 p += 16;
982 p += 16;
984 len = PyBytes_GET_SIZE(k);
983 len = PyBytes_GET_SIZE(k);
985 memcpy(p, PyBytes_AS_STRING(k), len);
984 memcpy(p, PyBytes_AS_STRING(k), len);
986 p += len;
985 p += len;
987 o = PyDict_GetItem(copymap, k);
986 o = PyDict_GetItem(copymap, k);
988 if (o) {
987 if (o) {
989 *p++ = '\0';
988 *p++ = '\0';
990 l = PyBytes_GET_SIZE(o);
989 l = PyBytes_GET_SIZE(o);
991 memcpy(p, PyBytes_AS_STRING(o), l);
990 memcpy(p, PyBytes_AS_STRING(o), l);
992 p += l;
991 p += l;
993 len += l + 1;
992 len += l + 1;
994 }
993 }
995 putbe32((uint32_t)len, t);
994 putbe32((uint32_t)len, t);
996 }
995 }
997
996
998 pos = p - PyBytes_AS_STRING(packobj);
997 pos = p - PyBytes_AS_STRING(packobj);
999 if (pos != nbytes) {
998 if (pos != nbytes) {
1000 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
999 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
1001 (long)pos, (long)nbytes);
1000 (long)pos, (long)nbytes);
1002 goto bail;
1001 goto bail;
1003 }
1002 }
1004
1003
1005 return packobj;
1004 return packobj;
1006 bail:
1005 bail:
1007 Py_XDECREF(mtime_unset);
1006 Py_XDECREF(mtime_unset);
1008 Py_XDECREF(packobj);
1007 Py_XDECREF(packobj);
1009 Py_XDECREF(v);
1008 Py_XDECREF(v);
1010 return NULL;
1009 return NULL;
1011 }
1010 }
1012
1011
1013 #define BUMPED_FIX 1
1012 #define BUMPED_FIX 1
1014 #define USING_SHA_256 2
1013 #define USING_SHA_256 2
1015 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
1014 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
1016
1015
1017 static PyObject *readshas(const char *source, unsigned char num,
1016 static PyObject *readshas(const char *source, unsigned char num,
1018 Py_ssize_t hashwidth)
1017 Py_ssize_t hashwidth)
1019 {
1018 {
1020 int i;
1019 int i;
1021 PyObject *list = PyTuple_New(num);
1020 PyObject *list = PyTuple_New(num);
1022 if (list == NULL) {
1021 if (list == NULL) {
1023 return NULL;
1022 return NULL;
1024 }
1023 }
1025 for (i = 0; i < num; i++) {
1024 for (i = 0; i < num; i++) {
1026 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
1025 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
1027 if (hash == NULL) {
1026 if (hash == NULL) {
1028 Py_DECREF(list);
1027 Py_DECREF(list);
1029 return NULL;
1028 return NULL;
1030 }
1029 }
1031 PyTuple_SET_ITEM(list, i, hash);
1030 PyTuple_SET_ITEM(list, i, hash);
1032 source += hashwidth;
1031 source += hashwidth;
1033 }
1032 }
1034 return list;
1033 return list;
1035 }
1034 }
1036
1035
1037 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
1036 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
1038 uint32_t *msize)
1037 uint32_t *msize)
1039 {
1038 {
1040 const char *data = databegin;
1039 const char *data = databegin;
1041 const char *meta;
1040 const char *meta;
1042
1041
1043 double mtime;
1042 double mtime;
1044 int16_t tz;
1043 int16_t tz;
1045 uint16_t flags;
1044 uint16_t flags;
1046 unsigned char nsuccs, nparents, nmetadata;
1045 unsigned char nsuccs, nparents, nmetadata;
1047 Py_ssize_t hashwidth = 20;
1046 Py_ssize_t hashwidth = 20;
1048
1047
1049 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
1048 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
1050 PyObject *metadata = NULL, *ret = NULL;
1049 PyObject *metadata = NULL, *ret = NULL;
1051 int i;
1050 int i;
1052
1051
1053 if (data + FM1_HEADER_SIZE > dataend) {
1052 if (data + FM1_HEADER_SIZE > dataend) {
1054 goto overflow;
1053 goto overflow;
1055 }
1054 }
1056
1055
1057 *msize = getbe32(data);
1056 *msize = getbe32(data);
1058 data += 4;
1057 data += 4;
1059 mtime = getbefloat64(data);
1058 mtime = getbefloat64(data);
1060 data += 8;
1059 data += 8;
1061 tz = getbeint16(data);
1060 tz = getbeint16(data);
1062 data += 2;
1061 data += 2;
1063 flags = getbeuint16(data);
1062 flags = getbeuint16(data);
1064 data += 2;
1063 data += 2;
1065
1064
1066 if (flags & USING_SHA_256) {
1065 if (flags & USING_SHA_256) {
1067 hashwidth = 32;
1066 hashwidth = 32;
1068 }
1067 }
1069
1068
1070 nsuccs = (unsigned char)(*data++);
1069 nsuccs = (unsigned char)(*data++);
1071 nparents = (unsigned char)(*data++);
1070 nparents = (unsigned char)(*data++);
1072 nmetadata = (unsigned char)(*data++);
1071 nmetadata = (unsigned char)(*data++);
1073
1072
1074 if (databegin + *msize > dataend) {
1073 if (databegin + *msize > dataend) {
1075 goto overflow;
1074 goto overflow;
1076 }
1075 }
1077 dataend = databegin + *msize; /* narrow down to marker size */
1076 dataend = databegin + *msize; /* narrow down to marker size */
1078
1077
1079 if (data + hashwidth > dataend) {
1078 if (data + hashwidth > dataend) {
1080 goto overflow;
1079 goto overflow;
1081 }
1080 }
1082 prec = PyBytes_FromStringAndSize(data, hashwidth);
1081 prec = PyBytes_FromStringAndSize(data, hashwidth);
1083 data += hashwidth;
1082 data += hashwidth;
1084 if (prec == NULL) {
1083 if (prec == NULL) {
1085 goto bail;
1084 goto bail;
1086 }
1085 }
1087
1086
1088 if (data + nsuccs * hashwidth > dataend) {
1087 if (data + nsuccs * hashwidth > dataend) {
1089 goto overflow;
1088 goto overflow;
1090 }
1089 }
1091 succs = readshas(data, nsuccs, hashwidth);
1090 succs = readshas(data, nsuccs, hashwidth);
1092 if (succs == NULL) {
1091 if (succs == NULL) {
1093 goto bail;
1092 goto bail;
1094 }
1093 }
1095 data += nsuccs * hashwidth;
1094 data += nsuccs * hashwidth;
1096
1095
1097 if (nparents == 1 || nparents == 2) {
1096 if (nparents == 1 || nparents == 2) {
1098 if (data + nparents * hashwidth > dataend) {
1097 if (data + nparents * hashwidth > dataend) {
1099 goto overflow;
1098 goto overflow;
1100 }
1099 }
1101 parents = readshas(data, nparents, hashwidth);
1100 parents = readshas(data, nparents, hashwidth);
1102 if (parents == NULL) {
1101 if (parents == NULL) {
1103 goto bail;
1102 goto bail;
1104 }
1103 }
1105 data += nparents * hashwidth;
1104 data += nparents * hashwidth;
1106 } else {
1105 } else {
1107 parents = Py_None;
1106 parents = Py_None;
1108 Py_INCREF(parents);
1107 Py_INCREF(parents);
1109 }
1108 }
1110
1109
1111 if (data + 2 * nmetadata > dataend) {
1110 if (data + 2 * nmetadata > dataend) {
1112 goto overflow;
1111 goto overflow;
1113 }
1112 }
1114 meta = data + (2 * nmetadata);
1113 meta = data + (2 * nmetadata);
1115 metadata = PyTuple_New(nmetadata);
1114 metadata = PyTuple_New(nmetadata);
1116 if (metadata == NULL) {
1115 if (metadata == NULL) {
1117 goto bail;
1116 goto bail;
1118 }
1117 }
1119 for (i = 0; i < nmetadata; i++) {
1118 for (i = 0; i < nmetadata; i++) {
1120 PyObject *tmp, *left = NULL, *right = NULL;
1119 PyObject *tmp, *left = NULL, *right = NULL;
1121 Py_ssize_t leftsize = (unsigned char)(*data++);
1120 Py_ssize_t leftsize = (unsigned char)(*data++);
1122 Py_ssize_t rightsize = (unsigned char)(*data++);
1121 Py_ssize_t rightsize = (unsigned char)(*data++);
1123 if (meta + leftsize + rightsize > dataend) {
1122 if (meta + leftsize + rightsize > dataend) {
1124 goto overflow;
1123 goto overflow;
1125 }
1124 }
1126 left = PyBytes_FromStringAndSize(meta, leftsize);
1125 left = PyBytes_FromStringAndSize(meta, leftsize);
1127 meta += leftsize;
1126 meta += leftsize;
1128 right = PyBytes_FromStringAndSize(meta, rightsize);
1127 right = PyBytes_FromStringAndSize(meta, rightsize);
1129 meta += rightsize;
1128 meta += rightsize;
1130 tmp = PyTuple_New(2);
1129 tmp = PyTuple_New(2);
1131 if (!left || !right || !tmp) {
1130 if (!left || !right || !tmp) {
1132 Py_XDECREF(left);
1131 Py_XDECREF(left);
1133 Py_XDECREF(right);
1132 Py_XDECREF(right);
1134 Py_XDECREF(tmp);
1133 Py_XDECREF(tmp);
1135 goto bail;
1134 goto bail;
1136 }
1135 }
1137 PyTuple_SET_ITEM(tmp, 0, left);
1136 PyTuple_SET_ITEM(tmp, 0, left);
1138 PyTuple_SET_ITEM(tmp, 1, right);
1137 PyTuple_SET_ITEM(tmp, 1, right);
1139 PyTuple_SET_ITEM(metadata, i, tmp);
1138 PyTuple_SET_ITEM(metadata, i, tmp);
1140 }
1139 }
1141 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
1140 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
1142 (int)tz * 60, parents);
1141 (int)tz * 60, parents);
1143 goto bail; /* return successfully */
1142 goto bail; /* return successfully */
1144
1143
1145 overflow:
1144 overflow:
1146 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
1145 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
1147 bail:
1146 bail:
1148 Py_XDECREF(prec);
1147 Py_XDECREF(prec);
1149 Py_XDECREF(succs);
1148 Py_XDECREF(succs);
1150 Py_XDECREF(metadata);
1149 Py_XDECREF(metadata);
1151 Py_XDECREF(parents);
1150 Py_XDECREF(parents);
1152 return ret;
1151 return ret;
1153 }
1152 }
1154
1153
1155 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
1154 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
1156 {
1155 {
1157 const char *data, *dataend;
1156 const char *data, *dataend;
1158 Py_ssize_t datalen, offset, stop;
1157 Py_ssize_t datalen, offset, stop;
1159 PyObject *markers = NULL;
1158 PyObject *markers = NULL;
1160
1159
1161 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
1160 if (!PyArg_ParseTuple(args, "y#nn", &data, &datalen, &offset, &stop)) {
1162 &offset, &stop)) {
1163 return NULL;
1161 return NULL;
1164 }
1162 }
1165 if (offset < 0) {
1163 if (offset < 0) {
1166 PyErr_SetString(PyExc_ValueError,
1164 PyErr_SetString(PyExc_ValueError,
1167 "invalid negative offset in fm1readmarkers");
1165 "invalid negative offset in fm1readmarkers");
1168 return NULL;
1166 return NULL;
1169 }
1167 }
1170 if (stop > datalen) {
1168 if (stop > datalen) {
1171 PyErr_SetString(
1169 PyErr_SetString(
1172 PyExc_ValueError,
1170 PyExc_ValueError,
1173 "stop longer than data length in fm1readmarkers");
1171 "stop longer than data length in fm1readmarkers");
1174 return NULL;
1172 return NULL;
1175 }
1173 }
1176 dataend = data + datalen;
1174 dataend = data + datalen;
1177 data += offset;
1175 data += offset;
1178 markers = PyList_New(0);
1176 markers = PyList_New(0);
1179 if (!markers) {
1177 if (!markers) {
1180 return NULL;
1178 return NULL;
1181 }
1179 }
1182 while (offset < stop) {
1180 while (offset < stop) {
1183 uint32_t msize;
1181 uint32_t msize;
1184 int error;
1182 int error;
1185 PyObject *record = fm1readmarker(data, dataend, &msize);
1183 PyObject *record = fm1readmarker(data, dataend, &msize);
1186 if (!record) {
1184 if (!record) {
1187 goto bail;
1185 goto bail;
1188 }
1186 }
1189 error = PyList_Append(markers, record);
1187 error = PyList_Append(markers, record);
1190 Py_DECREF(record);
1188 Py_DECREF(record);
1191 if (error) {
1189 if (error) {
1192 goto bail;
1190 goto bail;
1193 }
1191 }
1194 data += msize;
1192 data += msize;
1195 offset += msize;
1193 offset += msize;
1196 }
1194 }
1197 return markers;
1195 return markers;
1198 bail:
1196 bail:
1199 Py_DECREF(markers);
1197 Py_DECREF(markers);
1200 return NULL;
1198 return NULL;
1201 }
1199 }
1202
1200
1203 static char parsers_doc[] = "Efficient content parsing.";
1201 static char parsers_doc[] = "Efficient content parsing.";
1204
1202
1205 PyObject *encodedir(PyObject *self, PyObject *args);
1203 PyObject *encodedir(PyObject *self, PyObject *args);
1206 PyObject *pathencode(PyObject *self, PyObject *args);
1204 PyObject *pathencode(PyObject *self, PyObject *args);
1207 PyObject *lowerencode(PyObject *self, PyObject *args);
1205 PyObject *lowerencode(PyObject *self, PyObject *args);
1208 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
1206 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
1209
1207
1210 static PyMethodDef methods[] = {
1208 static PyMethodDef methods[] = {
1211 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1209 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1212 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1210 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1213 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
1211 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
1214 "parse a revlog index\n"},
1212 "parse a revlog index\n"},
1215 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
1213 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
1216 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
1214 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
1217 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
1215 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
1218 {"dict_new_presized", dict_new_presized, METH_VARARGS,
1216 {"dict_new_presized", dict_new_presized, METH_VARARGS,
1219 "construct a dict with an expected size\n"},
1217 "construct a dict with an expected size\n"},
1220 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
1218 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
1221 "make file foldmap\n"},
1219 "make file foldmap\n"},
1222 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
1220 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
1223 "escape a UTF-8 byte string to JSON (fast path)\n"},
1221 "escape a UTF-8 byte string to JSON (fast path)\n"},
1224 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
1222 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
1225 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
1223 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
1226 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
1224 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
1227 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
1225 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
1228 "parse v1 obsolete markers\n"},
1226 "parse v1 obsolete markers\n"},
1229 {NULL, NULL}};
1227 {NULL, NULL}};
1230
1228
1231 void dirs_module_init(PyObject *mod);
1229 void dirs_module_init(PyObject *mod);
1232 void manifest_module_init(PyObject *mod);
1230 void manifest_module_init(PyObject *mod);
1233 void revlog_module_init(PyObject *mod);
1231 void revlog_module_init(PyObject *mod);
1234
1232
1235 static const int version = 20;
1233 static const int version = 20;
1236
1234
1237 static void module_init(PyObject *mod)
1235 static void module_init(PyObject *mod)
1238 {
1236 {
1239 PyModule_AddIntConstant(mod, "version", version);
1237 PyModule_AddIntConstant(mod, "version", version);
1240
1238
1241 /* This module constant has two purposes. First, it lets us unit test
1239 /* This module constant has two purposes. First, it lets us unit test
1242 * the ImportError raised without hard-coding any error text. This
1240 * the ImportError raised without hard-coding any error text. This
1243 * means we can change the text in the future without breaking tests,
1241 * means we can change the text in the future without breaking tests,
1244 * even across changesets without a recompile. Second, its presence
1242 * even across changesets without a recompile. Second, its presence
1245 * can be used to determine whether the version-checking logic is
1243 * can be used to determine whether the version-checking logic is
1246 * present, which also helps in testing across changesets without a
1244 * present, which also helps in testing across changesets without a
1247 * recompile. Note that this means the pure-Python version of parsers
1245 * recompile. Note that this means the pure-Python version of parsers
1248 * should not have this module constant. */
1246 * should not have this module constant. */
1249 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
1247 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
1250
1248
1251 dirs_module_init(mod);
1249 dirs_module_init(mod);
1252 manifest_module_init(mod);
1250 manifest_module_init(mod);
1253 revlog_module_init(mod);
1251 revlog_module_init(mod);
1254
1252
1255 if (PyType_Ready(&dirstateItemType) < 0) {
1253 if (PyType_Ready(&dirstateItemType) < 0) {
1256 return;
1254 return;
1257 }
1255 }
1258 Py_INCREF(&dirstateItemType);
1256 Py_INCREF(&dirstateItemType);
1259 PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
1257 PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
1260 }
1258 }
1261
1259
1262 static int check_python_version(void)
1260 static int check_python_version(void)
1263 {
1261 {
1264 PyObject *sys = PyImport_ImportModule("sys"), *ver;
1262 PyObject *sys = PyImport_ImportModule("sys"), *ver;
1265 long hexversion;
1263 long hexversion;
1266 if (!sys) {
1264 if (!sys) {
1267 return -1;
1265 return -1;
1268 }
1266 }
1269 ver = PyObject_GetAttrString(sys, "hexversion");
1267 ver = PyObject_GetAttrString(sys, "hexversion");
1270 Py_DECREF(sys);
1268 Py_DECREF(sys);
1271 if (!ver) {
1269 if (!ver) {
1272 return -1;
1270 return -1;
1273 }
1271 }
1274 hexversion = PyLong_AsLong(ver);
1272 hexversion = PyLong_AsLong(ver);
1275 Py_DECREF(ver);
1273 Py_DECREF(ver);
1276 /* sys.hexversion is a 32-bit number by default, so the -1 case
1274 /* sys.hexversion is a 32-bit number by default, so the -1 case
1277 * should only occur in unusual circumstances (e.g. if sys.hexversion
1275 * should only occur in unusual circumstances (e.g. if sys.hexversion
1278 * is manually set to an invalid value). */
1276 * is manually set to an invalid value). */
1279 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
1277 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
1280 PyErr_Format(PyExc_ImportError,
1278 PyErr_Format(PyExc_ImportError,
1281 "%s: The Mercurial extension "
1279 "%s: The Mercurial extension "
1282 "modules were compiled with Python " PY_VERSION
1280 "modules were compiled with Python " PY_VERSION
1283 ", but "
1281 ", but "
1284 "Mercurial is currently using Python with "
1282 "Mercurial is currently using Python with "
1285 "sys.hexversion=%ld: "
1283 "sys.hexversion=%ld: "
1286 "Python %s\n at: %s",
1284 "Python %s\n at: %s",
1287 versionerrortext, hexversion, Py_GetVersion(),
1285 versionerrortext, hexversion, Py_GetVersion(),
1288 Py_GetProgramFullPath());
1286 Py_GetProgramFullPath());
1289 return -1;
1287 return -1;
1290 }
1288 }
1291 return 0;
1289 return 0;
1292 }
1290 }
1293
1291
1294 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
1292 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
1295 parsers_doc, -1, methods};
1293 parsers_doc, -1, methods};
1296
1294
1297 PyMODINIT_FUNC PyInit_parsers(void)
1295 PyMODINIT_FUNC PyInit_parsers(void)
1298 {
1296 {
1299 PyObject *mod;
1297 PyObject *mod;
1300
1298
1301 if (check_python_version() == -1)
1299 if (check_python_version() == -1)
1302 return NULL;
1300 return NULL;
1303 mod = PyModule_Create(&parsers_module);
1301 mod = PyModule_Create(&parsers_module);
1304 module_init(mod);
1302 module_init(mod);
1305 return mod;
1303 return mod;
1306 }
1304 }
@@ -1,803 +1,802 b''
1 /*
1 /*
2 pathencode.c - efficient path name encoding
2 pathencode.c - efficient path name encoding
3
3
4 Copyright 2012 Facebook
4 Copyright 2012 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 /*
10 /*
11 * An implementation of the name encoding scheme used by the fncache
11 * An implementation of the name encoding scheme used by the fncache
12 * store. The common case is of a path < 120 bytes long, which is
12 * store. The common case is of a path < 120 bytes long, which is
13 * handled either in a single pass with no allocations or two passes
13 * handled either in a single pass with no allocations or two passes
14 * with a single allocation. For longer paths, multiple passes are
14 * with a single allocation. For longer paths, multiple passes are
15 * required.
15 * required.
16 */
16 */
17
17
18 #define PY_SSIZE_T_CLEAN
18 #define PY_SSIZE_T_CLEAN
19 #include <Python.h>
19 #include <Python.h>
20 #include <assert.h>
20 #include <assert.h>
21 #include <ctype.h>
21 #include <ctype.h>
22 #include <stdlib.h>
22 #include <stdlib.h>
23 #include <string.h>
23 #include <string.h>
24 #include "pythoncapi_compat.h"
24 #include "pythoncapi_compat.h"
25
25
26 #include "util.h"
26 #include "util.h"
27
27
28 /* state machine for the fast path */
28 /* state machine for the fast path */
29 enum path_state {
29 enum path_state {
30 START, /* first byte of a path component */
30 START, /* first byte of a path component */
31 A, /* "AUX" */
31 A, /* "AUX" */
32 AU,
32 AU,
33 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
33 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
34 C, /* "CON" or "COMn" */
34 C, /* "CON" or "COMn" */
35 CO,
35 CO,
36 COMLPT, /* "COM" or "LPT" */
36 COMLPT, /* "COM" or "LPT" */
37 COMLPTn,
37 COMLPTn,
38 L,
38 L,
39 LP,
39 LP,
40 N,
40 N,
41 NU,
41 NU,
42 P, /* "PRN" */
42 P, /* "PRN" */
43 PR,
43 PR,
44 LDOT, /* leading '.' */
44 LDOT, /* leading '.' */
45 DOT, /* '.' in a non-leading position */
45 DOT, /* '.' in a non-leading position */
46 H, /* ".h" */
46 H, /* ".h" */
47 HGDI, /* ".hg", ".d", or ".i" */
47 HGDI, /* ".hg", ".d", or ".i" */
48 SPACE,
48 SPACE,
49 DEFAULT, /* byte of a path component after the first */
49 DEFAULT, /* byte of a path component after the first */
50 };
50 };
51
51
52 /* state machine for dir-encoding */
52 /* state machine for dir-encoding */
53 enum dir_state {
53 enum dir_state {
54 DDOT,
54 DDOT,
55 DH,
55 DH,
56 DHGDI,
56 DHGDI,
57 DDEFAULT,
57 DDEFAULT,
58 };
58 };
59
59
60 static inline int inset(const uint32_t bitset[], char c)
60 static inline int inset(const uint32_t bitset[], char c)
61 {
61 {
62 return bitset[((uint8_t)c) >> 5] & (1 << (((uint8_t)c) & 31));
62 return bitset[((uint8_t)c) >> 5] & (1 << (((uint8_t)c) & 31));
63 }
63 }
64
64
65 static inline void charcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
65 static inline void charcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
66 char c)
66 char c)
67 {
67 {
68 if (dest) {
68 if (dest) {
69 assert(*destlen < destsize);
69 assert(*destlen < destsize);
70 dest[*destlen] = c;
70 dest[*destlen] = c;
71 }
71 }
72 (*destlen)++;
72 (*destlen)++;
73 }
73 }
74
74
75 static inline void memcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
75 static inline void memcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
76 const void *src, Py_ssize_t len)
76 const void *src, Py_ssize_t len)
77 {
77 {
78 if (dest) {
78 if (dest) {
79 assert(*destlen + len < destsize);
79 assert(*destlen + len < destsize);
80 memcpy((void *)&dest[*destlen], src, len);
80 memcpy((void *)&dest[*destlen], src, len);
81 }
81 }
82 *destlen += len;
82 *destlen += len;
83 }
83 }
84
84
85 static inline void hexencode(char *dest, Py_ssize_t *destlen, size_t destsize,
85 static inline void hexencode(char *dest, Py_ssize_t *destlen, size_t destsize,
86 uint8_t c)
86 uint8_t c)
87 {
87 {
88 static const char hexdigit[] = "0123456789abcdef";
88 static const char hexdigit[] = "0123456789abcdef";
89
89
90 charcopy(dest, destlen, destsize, hexdigit[c >> 4]);
90 charcopy(dest, destlen, destsize, hexdigit[c >> 4]);
91 charcopy(dest, destlen, destsize, hexdigit[c & 15]);
91 charcopy(dest, destlen, destsize, hexdigit[c & 15]);
92 }
92 }
93
93
94 /* 3-byte escape: tilde followed by two hex digits */
94 /* 3-byte escape: tilde followed by two hex digits */
95 static inline void escape3(char *dest, Py_ssize_t *destlen, size_t destsize,
95 static inline void escape3(char *dest, Py_ssize_t *destlen, size_t destsize,
96 char c)
96 char c)
97 {
97 {
98 charcopy(dest, destlen, destsize, '~');
98 charcopy(dest, destlen, destsize, '~');
99 hexencode(dest, destlen, destsize, c);
99 hexencode(dest, destlen, destsize, c);
100 }
100 }
101
101
102 static Py_ssize_t _encodedir(char *dest, size_t destsize, const char *src,
102 static Py_ssize_t _encodedir(char *dest, size_t destsize, const char *src,
103 Py_ssize_t len)
103 Py_ssize_t len)
104 {
104 {
105 enum dir_state state = DDEFAULT;
105 enum dir_state state = DDEFAULT;
106 Py_ssize_t i = 0, destlen = 0;
106 Py_ssize_t i = 0, destlen = 0;
107
107
108 while (i < len) {
108 while (i < len) {
109 switch (state) {
109 switch (state) {
110 case DDOT:
110 case DDOT:
111 switch (src[i]) {
111 switch (src[i]) {
112 case 'd':
112 case 'd':
113 case 'i':
113 case 'i':
114 state = DHGDI;
114 state = DHGDI;
115 charcopy(dest, &destlen, destsize, src[i++]);
115 charcopy(dest, &destlen, destsize, src[i++]);
116 break;
116 break;
117 case 'h':
117 case 'h':
118 state = DH;
118 state = DH;
119 charcopy(dest, &destlen, destsize, src[i++]);
119 charcopy(dest, &destlen, destsize, src[i++]);
120 break;
120 break;
121 default:
121 default:
122 state = DDEFAULT;
122 state = DDEFAULT;
123 break;
123 break;
124 }
124 }
125 break;
125 break;
126 case DH:
126 case DH:
127 if (src[i] == 'g') {
127 if (src[i] == 'g') {
128 state = DHGDI;
128 state = DHGDI;
129 charcopy(dest, &destlen, destsize, src[i++]);
129 charcopy(dest, &destlen, destsize, src[i++]);
130 } else {
130 } else {
131 state = DDEFAULT;
131 state = DDEFAULT;
132 }
132 }
133 break;
133 break;
134 case DHGDI:
134 case DHGDI:
135 if (src[i] == '/') {
135 if (src[i] == '/') {
136 memcopy(dest, &destlen, destsize, ".hg", 3);
136 memcopy(dest, &destlen, destsize, ".hg", 3);
137 charcopy(dest, &destlen, destsize, src[i++]);
137 charcopy(dest, &destlen, destsize, src[i++]);
138 }
138 }
139 state = DDEFAULT;
139 state = DDEFAULT;
140 break;
140 break;
141 case DDEFAULT:
141 case DDEFAULT:
142 if (src[i] == '.') {
142 if (src[i] == '.') {
143 state = DDOT;
143 state = DDOT;
144 }
144 }
145 charcopy(dest, &destlen, destsize, src[i++]);
145 charcopy(dest, &destlen, destsize, src[i++]);
146 break;
146 break;
147 }
147 }
148 }
148 }
149
149
150 return destlen;
150 return destlen;
151 }
151 }
152
152
153 PyObject *encodedir(PyObject *self, PyObject *args)
153 PyObject *encodedir(PyObject *self, PyObject *args)
154 {
154 {
155 Py_ssize_t len, newlen;
155 Py_ssize_t len, newlen;
156 PyObject *pathobj, *newobj;
156 PyObject *pathobj, *newobj;
157 char *path;
157 char *path;
158
158
159 if (!PyArg_ParseTuple(args, "O:encodedir", &pathobj)) {
159 if (!PyArg_ParseTuple(args, "O:encodedir", &pathobj)) {
160 return NULL;
160 return NULL;
161 }
161 }
162
162
163 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
163 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
164 PyErr_SetString(PyExc_TypeError, "expected a string");
164 PyErr_SetString(PyExc_TypeError, "expected a string");
165 return NULL;
165 return NULL;
166 }
166 }
167
167
168 newlen = len ? _encodedir(NULL, 0, path, len + 1) : 1;
168 newlen = len ? _encodedir(NULL, 0, path, len + 1) : 1;
169
169
170 if (newlen == len + 1) {
170 if (newlen == len + 1) {
171 Py_INCREF(pathobj);
171 Py_INCREF(pathobj);
172 return pathobj;
172 return pathobj;
173 }
173 }
174
174
175 newobj = PyBytes_FromStringAndSize(NULL, newlen);
175 newobj = PyBytes_FromStringAndSize(NULL, newlen);
176
176
177 if (newobj) {
177 if (newobj) {
178 assert(PyBytes_Check(newobj));
178 assert(PyBytes_Check(newobj));
179 Py_SET_SIZE(newobj, Py_SIZE(newobj) - 1);
179 Py_SET_SIZE(newobj, Py_SIZE(newobj) - 1);
180 _encodedir(PyBytes_AS_STRING(newobj), newlen, path, len + 1);
180 _encodedir(PyBytes_AS_STRING(newobj), newlen, path, len + 1);
181 }
181 }
182
182
183 return newobj;
183 return newobj;
184 }
184 }
185
185
186 static Py_ssize_t _encode(const uint32_t twobytes[8], const uint32_t onebyte[8],
186 static Py_ssize_t _encode(const uint32_t twobytes[8], const uint32_t onebyte[8],
187 char *dest, Py_ssize_t destlen, size_t destsize,
187 char *dest, Py_ssize_t destlen, size_t destsize,
188 const char *src, Py_ssize_t len, int encodedir)
188 const char *src, Py_ssize_t len, int encodedir)
189 {
189 {
190 enum path_state state = START;
190 enum path_state state = START;
191 Py_ssize_t i = 0;
191 Py_ssize_t i = 0;
192
192
193 /*
193 /*
194 * Python strings end with a zero byte, which we use as a
194 * Python strings end with a zero byte, which we use as a
195 * terminal token as they are not valid inside path names.
195 * terminal token as they are not valid inside path names.
196 */
196 */
197
197
198 while (i < len) {
198 while (i < len) {
199 switch (state) {
199 switch (state) {
200 case START:
200 case START:
201 switch (src[i]) {
201 switch (src[i]) {
202 case '/':
202 case '/':
203 charcopy(dest, &destlen, destsize, src[i++]);
203 charcopy(dest, &destlen, destsize, src[i++]);
204 break;
204 break;
205 case '.':
205 case '.':
206 state = LDOT;
206 state = LDOT;
207 escape3(dest, &destlen, destsize, src[i++]);
207 escape3(dest, &destlen, destsize, src[i++]);
208 break;
208 break;
209 case ' ':
209 case ' ':
210 state = DEFAULT;
210 state = DEFAULT;
211 escape3(dest, &destlen, destsize, src[i++]);
211 escape3(dest, &destlen, destsize, src[i++]);
212 break;
212 break;
213 case 'a':
213 case 'a':
214 state = A;
214 state = A;
215 charcopy(dest, &destlen, destsize, src[i++]);
215 charcopy(dest, &destlen, destsize, src[i++]);
216 break;
216 break;
217 case 'c':
217 case 'c':
218 state = C;
218 state = C;
219 charcopy(dest, &destlen, destsize, src[i++]);
219 charcopy(dest, &destlen, destsize, src[i++]);
220 break;
220 break;
221 case 'l':
221 case 'l':
222 state = L;
222 state = L;
223 charcopy(dest, &destlen, destsize, src[i++]);
223 charcopy(dest, &destlen, destsize, src[i++]);
224 break;
224 break;
225 case 'n':
225 case 'n':
226 state = N;
226 state = N;
227 charcopy(dest, &destlen, destsize, src[i++]);
227 charcopy(dest, &destlen, destsize, src[i++]);
228 break;
228 break;
229 case 'p':
229 case 'p':
230 state = P;
230 state = P;
231 charcopy(dest, &destlen, destsize, src[i++]);
231 charcopy(dest, &destlen, destsize, src[i++]);
232 break;
232 break;
233 default:
233 default:
234 state = DEFAULT;
234 state = DEFAULT;
235 break;
235 break;
236 }
236 }
237 break;
237 break;
238 case A:
238 case A:
239 if (src[i] == 'u') {
239 if (src[i] == 'u') {
240 state = AU;
240 state = AU;
241 charcopy(dest, &destlen, destsize, src[i++]);
241 charcopy(dest, &destlen, destsize, src[i++]);
242 } else {
242 } else {
243 state = DEFAULT;
243 state = DEFAULT;
244 }
244 }
245 break;
245 break;
246 case AU:
246 case AU:
247 if (src[i] == 'x') {
247 if (src[i] == 'x') {
248 state = THIRD;
248 state = THIRD;
249 i++;
249 i++;
250 } else {
250 } else {
251 state = DEFAULT;
251 state = DEFAULT;
252 }
252 }
253 break;
253 break;
254 case THIRD:
254 case THIRD:
255 state = DEFAULT;
255 state = DEFAULT;
256 switch (src[i]) {
256 switch (src[i]) {
257 case '.':
257 case '.':
258 case '/':
258 case '/':
259 case '\0':
259 case '\0':
260 escape3(dest, &destlen, destsize, src[i - 1]);
260 escape3(dest, &destlen, destsize, src[i - 1]);
261 break;
261 break;
262 default:
262 default:
263 i--;
263 i--;
264 break;
264 break;
265 }
265 }
266 break;
266 break;
267 case C:
267 case C:
268 if (src[i] == 'o') {
268 if (src[i] == 'o') {
269 state = CO;
269 state = CO;
270 charcopy(dest, &destlen, destsize, src[i++]);
270 charcopy(dest, &destlen, destsize, src[i++]);
271 } else {
271 } else {
272 state = DEFAULT;
272 state = DEFAULT;
273 }
273 }
274 break;
274 break;
275 case CO:
275 case CO:
276 if (src[i] == 'm') {
276 if (src[i] == 'm') {
277 state = COMLPT;
277 state = COMLPT;
278 i++;
278 i++;
279 } else if (src[i] == 'n') {
279 } else if (src[i] == 'n') {
280 state = THIRD;
280 state = THIRD;
281 i++;
281 i++;
282 } else {
282 } else {
283 state = DEFAULT;
283 state = DEFAULT;
284 }
284 }
285 break;
285 break;
286 case COMLPT:
286 case COMLPT:
287 switch (src[i]) {
287 switch (src[i]) {
288 case '1':
288 case '1':
289 case '2':
289 case '2':
290 case '3':
290 case '3':
291 case '4':
291 case '4':
292 case '5':
292 case '5':
293 case '6':
293 case '6':
294 case '7':
294 case '7':
295 case '8':
295 case '8':
296 case '9':
296 case '9':
297 state = COMLPTn;
297 state = COMLPTn;
298 i++;
298 i++;
299 break;
299 break;
300 default:
300 default:
301 state = DEFAULT;
301 state = DEFAULT;
302 charcopy(dest, &destlen, destsize, src[i - 1]);
302 charcopy(dest, &destlen, destsize, src[i - 1]);
303 break;
303 break;
304 }
304 }
305 break;
305 break;
306 case COMLPTn:
306 case COMLPTn:
307 state = DEFAULT;
307 state = DEFAULT;
308 switch (src[i]) {
308 switch (src[i]) {
309 case '.':
309 case '.':
310 case '/':
310 case '/':
311 case '\0':
311 case '\0':
312 escape3(dest, &destlen, destsize, src[i - 2]);
312 escape3(dest, &destlen, destsize, src[i - 2]);
313 charcopy(dest, &destlen, destsize, src[i - 1]);
313 charcopy(dest, &destlen, destsize, src[i - 1]);
314 break;
314 break;
315 default:
315 default:
316 memcopy(dest, &destlen, destsize, &src[i - 2],
316 memcopy(dest, &destlen, destsize, &src[i - 2],
317 2);
317 2);
318 break;
318 break;
319 }
319 }
320 break;
320 break;
321 case L:
321 case L:
322 if (src[i] == 'p') {
322 if (src[i] == 'p') {
323 state = LP;
323 state = LP;
324 charcopy(dest, &destlen, destsize, src[i++]);
324 charcopy(dest, &destlen, destsize, src[i++]);
325 } else {
325 } else {
326 state = DEFAULT;
326 state = DEFAULT;
327 }
327 }
328 break;
328 break;
329 case LP:
329 case LP:
330 if (src[i] == 't') {
330 if (src[i] == 't') {
331 state = COMLPT;
331 state = COMLPT;
332 i++;
332 i++;
333 } else {
333 } else {
334 state = DEFAULT;
334 state = DEFAULT;
335 }
335 }
336 break;
336 break;
337 case N:
337 case N:
338 if (src[i] == 'u') {
338 if (src[i] == 'u') {
339 state = NU;
339 state = NU;
340 charcopy(dest, &destlen, destsize, src[i++]);
340 charcopy(dest, &destlen, destsize, src[i++]);
341 } else {
341 } else {
342 state = DEFAULT;
342 state = DEFAULT;
343 }
343 }
344 break;
344 break;
345 case NU:
345 case NU:
346 if (src[i] == 'l') {
346 if (src[i] == 'l') {
347 state = THIRD;
347 state = THIRD;
348 i++;
348 i++;
349 } else {
349 } else {
350 state = DEFAULT;
350 state = DEFAULT;
351 }
351 }
352 break;
352 break;
353 case P:
353 case P:
354 if (src[i] == 'r') {
354 if (src[i] == 'r') {
355 state = PR;
355 state = PR;
356 charcopy(dest, &destlen, destsize, src[i++]);
356 charcopy(dest, &destlen, destsize, src[i++]);
357 } else {
357 } else {
358 state = DEFAULT;
358 state = DEFAULT;
359 }
359 }
360 break;
360 break;
361 case PR:
361 case PR:
362 if (src[i] == 'n') {
362 if (src[i] == 'n') {
363 state = THIRD;
363 state = THIRD;
364 i++;
364 i++;
365 } else {
365 } else {
366 state = DEFAULT;
366 state = DEFAULT;
367 }
367 }
368 break;
368 break;
369 case LDOT:
369 case LDOT:
370 switch (src[i]) {
370 switch (src[i]) {
371 case 'd':
371 case 'd':
372 case 'i':
372 case 'i':
373 state = HGDI;
373 state = HGDI;
374 charcopy(dest, &destlen, destsize, src[i++]);
374 charcopy(dest, &destlen, destsize, src[i++]);
375 break;
375 break;
376 case 'h':
376 case 'h':
377 state = H;
377 state = H;
378 charcopy(dest, &destlen, destsize, src[i++]);
378 charcopy(dest, &destlen, destsize, src[i++]);
379 break;
379 break;
380 default:
380 default:
381 state = DEFAULT;
381 state = DEFAULT;
382 break;
382 break;
383 }
383 }
384 break;
384 break;
385 case DOT:
385 case DOT:
386 switch (src[i]) {
386 switch (src[i]) {
387 case '/':
387 case '/':
388 case '\0':
388 case '\0':
389 state = START;
389 state = START;
390 memcopy(dest, &destlen, destsize, "~2e", 3);
390 memcopy(dest, &destlen, destsize, "~2e", 3);
391 charcopy(dest, &destlen, destsize, src[i++]);
391 charcopy(dest, &destlen, destsize, src[i++]);
392 break;
392 break;
393 case 'd':
393 case 'd':
394 case 'i':
394 case 'i':
395 state = HGDI;
395 state = HGDI;
396 charcopy(dest, &destlen, destsize, '.');
396 charcopy(dest, &destlen, destsize, '.');
397 charcopy(dest, &destlen, destsize, src[i++]);
397 charcopy(dest, &destlen, destsize, src[i++]);
398 break;
398 break;
399 case 'h':
399 case 'h':
400 state = H;
400 state = H;
401 memcopy(dest, &destlen, destsize, ".h", 2);
401 memcopy(dest, &destlen, destsize, ".h", 2);
402 i++;
402 i++;
403 break;
403 break;
404 default:
404 default:
405 state = DEFAULT;
405 state = DEFAULT;
406 charcopy(dest, &destlen, destsize, '.');
406 charcopy(dest, &destlen, destsize, '.');
407 break;
407 break;
408 }
408 }
409 break;
409 break;
410 case H:
410 case H:
411 if (src[i] == 'g') {
411 if (src[i] == 'g') {
412 state = HGDI;
412 state = HGDI;
413 charcopy(dest, &destlen, destsize, src[i++]);
413 charcopy(dest, &destlen, destsize, src[i++]);
414 } else {
414 } else {
415 state = DEFAULT;
415 state = DEFAULT;
416 }
416 }
417 break;
417 break;
418 case HGDI:
418 case HGDI:
419 if (src[i] == '/') {
419 if (src[i] == '/') {
420 state = START;
420 state = START;
421 if (encodedir) {
421 if (encodedir) {
422 memcopy(dest, &destlen, destsize, ".hg",
422 memcopy(dest, &destlen, destsize, ".hg",
423 3);
423 3);
424 }
424 }
425 charcopy(dest, &destlen, destsize, src[i++]);
425 charcopy(dest, &destlen, destsize, src[i++]);
426 } else {
426 } else {
427 state = DEFAULT;
427 state = DEFAULT;
428 }
428 }
429 break;
429 break;
430 case SPACE:
430 case SPACE:
431 switch (src[i]) {
431 switch (src[i]) {
432 case '/':
432 case '/':
433 case '\0':
433 case '\0':
434 state = START;
434 state = START;
435 memcopy(dest, &destlen, destsize, "~20", 3);
435 memcopy(dest, &destlen, destsize, "~20", 3);
436 charcopy(dest, &destlen, destsize, src[i++]);
436 charcopy(dest, &destlen, destsize, src[i++]);
437 break;
437 break;
438 default:
438 default:
439 state = DEFAULT;
439 state = DEFAULT;
440 charcopy(dest, &destlen, destsize, ' ');
440 charcopy(dest, &destlen, destsize, ' ');
441 break;
441 break;
442 }
442 }
443 break;
443 break;
444 case DEFAULT:
444 case DEFAULT:
445 while (inset(onebyte, src[i])) {
445 while (inset(onebyte, src[i])) {
446 charcopy(dest, &destlen, destsize, src[i++]);
446 charcopy(dest, &destlen, destsize, src[i++]);
447 if (i == len) {
447 if (i == len) {
448 goto done;
448 goto done;
449 }
449 }
450 }
450 }
451 switch (src[i]) {
451 switch (src[i]) {
452 case '.':
452 case '.':
453 state = DOT;
453 state = DOT;
454 i++;
454 i++;
455 break;
455 break;
456 case ' ':
456 case ' ':
457 state = SPACE;
457 state = SPACE;
458 i++;
458 i++;
459 break;
459 break;
460 case '/':
460 case '/':
461 state = START;
461 state = START;
462 charcopy(dest, &destlen, destsize, '/');
462 charcopy(dest, &destlen, destsize, '/');
463 i++;
463 i++;
464 break;
464 break;
465 default:
465 default:
466 if (inset(onebyte, src[i])) {
466 if (inset(onebyte, src[i])) {
467 do {
467 do {
468 charcopy(dest, &destlen,
468 charcopy(dest, &destlen,
469 destsize, src[i++]);
469 destsize, src[i++]);
470 } while (i < len &&
470 } while (i < len &&
471 inset(onebyte, src[i]));
471 inset(onebyte, src[i]));
472 } else if (inset(twobytes, src[i])) {
472 } else if (inset(twobytes, src[i])) {
473 char c = src[i++];
473 char c = src[i++];
474 charcopy(dest, &destlen, destsize, '_');
474 charcopy(dest, &destlen, destsize, '_');
475 charcopy(dest, &destlen, destsize,
475 charcopy(dest, &destlen, destsize,
476 c == '_' ? '_' : c + 32);
476 c == '_' ? '_' : c + 32);
477 } else {
477 } else {
478 escape3(dest, &destlen, destsize,
478 escape3(dest, &destlen, destsize,
479 src[i++]);
479 src[i++]);
480 }
480 }
481 break;
481 break;
482 }
482 }
483 break;
483 break;
484 }
484 }
485 }
485 }
486 done:
486 done:
487 return destlen;
487 return destlen;
488 }
488 }
489
489
490 static Py_ssize_t basicencode(char *dest, size_t destsize, const char *src,
490 static Py_ssize_t basicencode(char *dest, size_t destsize, const char *src,
491 Py_ssize_t len)
491 Py_ssize_t len)
492 {
492 {
493 static const uint32_t twobytes[8] = {0, 0, 0x87fffffe};
493 static const uint32_t twobytes[8] = {0, 0, 0x87fffffe};
494
494
495 static const uint32_t onebyte[8] = {
495 static const uint32_t onebyte[8] = {
496 1,
496 1,
497 0x2bff3bfa,
497 0x2bff3bfa,
498 0x68000001,
498 0x68000001,
499 0x2fffffff,
499 0x2fffffff,
500 };
500 };
501
501
502 Py_ssize_t destlen = 0;
502 Py_ssize_t destlen = 0;
503
503
504 return _encode(twobytes, onebyte, dest, destlen, destsize, src, len, 1);
504 return _encode(twobytes, onebyte, dest, destlen, destsize, src, len, 1);
505 }
505 }
506
506
507 static const Py_ssize_t maxstorepathlen = 120;
507 static const Py_ssize_t maxstorepathlen = 120;
508
508
509 static Py_ssize_t _lowerencode(char *dest, size_t destsize, const char *src,
509 static Py_ssize_t _lowerencode(char *dest, size_t destsize, const char *src,
510 Py_ssize_t len)
510 Py_ssize_t len)
511 {
511 {
512 static const uint32_t onebyte[8] = {1, 0x2bfffbfb, 0xe8000001,
512 static const uint32_t onebyte[8] = {1, 0x2bfffbfb, 0xe8000001,
513 0x2fffffff};
513 0x2fffffff};
514
514
515 static const uint32_t lower[8] = {0, 0, 0x7fffffe};
515 static const uint32_t lower[8] = {0, 0, 0x7fffffe};
516
516
517 Py_ssize_t i, destlen = 0;
517 Py_ssize_t i, destlen = 0;
518
518
519 for (i = 0; i < len; i++) {
519 for (i = 0; i < len; i++) {
520 if (inset(onebyte, src[i])) {
520 if (inset(onebyte, src[i])) {
521 charcopy(dest, &destlen, destsize, src[i]);
521 charcopy(dest, &destlen, destsize, src[i]);
522 } else if (inset(lower, src[i])) {
522 } else if (inset(lower, src[i])) {
523 charcopy(dest, &destlen, destsize, src[i] + 32);
523 charcopy(dest, &destlen, destsize, src[i] + 32);
524 } else {
524 } else {
525 escape3(dest, &destlen, destsize, src[i]);
525 escape3(dest, &destlen, destsize, src[i]);
526 }
526 }
527 }
527 }
528
528
529 return destlen;
529 return destlen;
530 }
530 }
531
531
532 PyObject *lowerencode(PyObject *self, PyObject *args)
532 PyObject *lowerencode(PyObject *self, PyObject *args)
533 {
533 {
534 char *path;
534 char *path;
535 Py_ssize_t len, newlen;
535 Py_ssize_t len, newlen;
536 PyObject *ret;
536 PyObject *ret;
537
537
538 if (!PyArg_ParseTuple(args, PY23("s#:lowerencode", "y#:lowerencode"),
538 if (!PyArg_ParseTuple(args, "y#:lowerencode", &path, &len)) {
539 &path, &len)) {
540 return NULL;
539 return NULL;
541 }
540 }
542
541
543 newlen = _lowerencode(NULL, 0, path, len);
542 newlen = _lowerencode(NULL, 0, path, len);
544 ret = PyBytes_FromStringAndSize(NULL, newlen);
543 ret = PyBytes_FromStringAndSize(NULL, newlen);
545 if (ret) {
544 if (ret) {
546 _lowerencode(PyBytes_AS_STRING(ret), newlen, path, len);
545 _lowerencode(PyBytes_AS_STRING(ret), newlen, path, len);
547 }
546 }
548
547
549 return ret;
548 return ret;
550 }
549 }
551
550
552 /* See store.py:_auxencode for a description. */
551 /* See store.py:_auxencode for a description. */
553 static Py_ssize_t auxencode(char *dest, size_t destsize, const char *src,
552 static Py_ssize_t auxencode(char *dest, size_t destsize, const char *src,
554 Py_ssize_t len)
553 Py_ssize_t len)
555 {
554 {
556 static const uint32_t twobytes[8];
555 static const uint32_t twobytes[8];
557
556
558 static const uint32_t onebyte[8] = {
557 static const uint32_t onebyte[8] = {
559 ~0U, 0xffff3ffe, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
558 ~0U, 0xffff3ffe, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
560 };
559 };
561
560
562 return _encode(twobytes, onebyte, dest, 0, destsize, src, len, 0);
561 return _encode(twobytes, onebyte, dest, 0, destsize, src, len, 0);
563 }
562 }
564
563
565 static PyObject *hashmangle(const char *src, Py_ssize_t len, const char sha[20])
564 static PyObject *hashmangle(const char *src, Py_ssize_t len, const char sha[20])
566 {
565 {
567 static const Py_ssize_t dirprefixlen = 8;
566 static const Py_ssize_t dirprefixlen = 8;
568 static const Py_ssize_t maxshortdirslen = 68;
567 static const Py_ssize_t maxshortdirslen = 68;
569 char *dest;
568 char *dest;
570 PyObject *ret;
569 PyObject *ret;
571
570
572 Py_ssize_t i, d, p, lastslash = len - 1, lastdot = -1;
571 Py_ssize_t i, d, p, lastslash = len - 1, lastdot = -1;
573 Py_ssize_t destsize, destlen = 0, slop, used;
572 Py_ssize_t destsize, destlen = 0, slop, used;
574
573
575 while (lastslash >= 0 && src[lastslash] != '/') {
574 while (lastslash >= 0 && src[lastslash] != '/') {
576 if (src[lastslash] == '.' && lastdot == -1) {
575 if (src[lastslash] == '.' && lastdot == -1) {
577 lastdot = lastslash;
576 lastdot = lastslash;
578 }
577 }
579 lastslash--;
578 lastslash--;
580 }
579 }
581
580
582 #if 0
581 #if 0
583 /* All paths should end in a suffix of ".i" or ".d".
582 /* All paths should end in a suffix of ".i" or ".d".
584 Unfortunately, the file names in test-hybridencode.py
583 Unfortunately, the file names in test-hybridencode.py
585 violate this rule. */
584 violate this rule. */
586 if (lastdot != len - 3) {
585 if (lastdot != len - 3) {
587 PyErr_SetString(PyExc_ValueError,
586 PyErr_SetString(PyExc_ValueError,
588 "suffix missing or wrong length");
587 "suffix missing or wrong length");
589 return NULL;
588 return NULL;
590 }
589 }
591 #endif
590 #endif
592
591
593 /* If src contains a suffix, we will append it to the end of
592 /* If src contains a suffix, we will append it to the end of
594 the new string, so make room. */
593 the new string, so make room. */
595 destsize = 120;
594 destsize = 120;
596 if (lastdot >= 0) {
595 if (lastdot >= 0) {
597 destsize += len - lastdot - 1;
596 destsize += len - lastdot - 1;
598 }
597 }
599
598
600 ret = PyBytes_FromStringAndSize(NULL, destsize);
599 ret = PyBytes_FromStringAndSize(NULL, destsize);
601 if (ret == NULL) {
600 if (ret == NULL) {
602 return NULL;
601 return NULL;
603 }
602 }
604
603
605 dest = PyBytes_AS_STRING(ret);
604 dest = PyBytes_AS_STRING(ret);
606 memcopy(dest, &destlen, destsize, "dh/", 3);
605 memcopy(dest, &destlen, destsize, "dh/", 3);
607
606
608 /* Copy up to dirprefixlen bytes of each path component, up to
607 /* Copy up to dirprefixlen bytes of each path component, up to
609 a limit of maxshortdirslen bytes. */
608 a limit of maxshortdirslen bytes. */
610 for (i = d = p = 0; i < lastslash; i++, p++) {
609 for (i = d = p = 0; i < lastslash; i++, p++) {
611 if (src[i] == '/') {
610 if (src[i] == '/') {
612 char d = dest[destlen - 1];
611 char d = dest[destlen - 1];
613 /* After truncation, a directory name may end
612 /* After truncation, a directory name may end
614 in a space or dot, which are unportable. */
613 in a space or dot, which are unportable. */
615 if (d == '.' || d == ' ') {
614 if (d == '.' || d == ' ') {
616 dest[destlen - 1] = '_';
615 dest[destlen - 1] = '_';
617 /* The + 3 is to account for "dh/" in the
616 /* The + 3 is to account for "dh/" in the
618 * beginning */
617 * beginning */
619 }
618 }
620 if (destlen > maxshortdirslen + 3) {
619 if (destlen > maxshortdirslen + 3) {
621 break;
620 break;
622 }
621 }
623 charcopy(dest, &destlen, destsize, src[i]);
622 charcopy(dest, &destlen, destsize, src[i]);
624 p = -1;
623 p = -1;
625 } else if (p < dirprefixlen) {
624 } else if (p < dirprefixlen) {
626 charcopy(dest, &destlen, destsize, src[i]);
625 charcopy(dest, &destlen, destsize, src[i]);
627 }
626 }
628 }
627 }
629
628
630 /* Rewind to just before the last slash copied. */
629 /* Rewind to just before the last slash copied. */
631 if (destlen > maxshortdirslen + 3) {
630 if (destlen > maxshortdirslen + 3) {
632 do {
631 do {
633 destlen--;
632 destlen--;
634 } while (destlen > 0 && dest[destlen] != '/');
633 } while (destlen > 0 && dest[destlen] != '/');
635 }
634 }
636
635
637 if (destlen > 3) {
636 if (destlen > 3) {
638 if (lastslash > 0) {
637 if (lastslash > 0) {
639 char d = dest[destlen - 1];
638 char d = dest[destlen - 1];
640 /* The last directory component may be
639 /* The last directory component may be
641 truncated, so make it safe. */
640 truncated, so make it safe. */
642 if (d == '.' || d == ' ') {
641 if (d == '.' || d == ' ') {
643 dest[destlen - 1] = '_';
642 dest[destlen - 1] = '_';
644 }
643 }
645 }
644 }
646
645
647 charcopy(dest, &destlen, destsize, '/');
646 charcopy(dest, &destlen, destsize, '/');
648 }
647 }
649
648
650 /* Add a prefix of the original file's name. Its length
649 /* Add a prefix of the original file's name. Its length
651 depends on the number of bytes left after accounting for
650 depends on the number of bytes left after accounting for
652 hash and suffix. */
651 hash and suffix. */
653 used = destlen + 40;
652 used = destlen + 40;
654 if (lastdot >= 0) {
653 if (lastdot >= 0) {
655 used += len - lastdot - 1;
654 used += len - lastdot - 1;
656 }
655 }
657 slop = maxstorepathlen - used;
656 slop = maxstorepathlen - used;
658 if (slop > 0) {
657 if (slop > 0) {
659 Py_ssize_t basenamelen =
658 Py_ssize_t basenamelen =
660 lastslash >= 0 ? len - lastslash - 2 : len - 1;
659 lastslash >= 0 ? len - lastslash - 2 : len - 1;
661
660
662 if (basenamelen > slop) {
661 if (basenamelen > slop) {
663 basenamelen = slop;
662 basenamelen = slop;
664 }
663 }
665 if (basenamelen > 0) {
664 if (basenamelen > 0) {
666 memcopy(dest, &destlen, destsize, &src[lastslash + 1],
665 memcopy(dest, &destlen, destsize, &src[lastslash + 1],
667 basenamelen);
666 basenamelen);
668 }
667 }
669 }
668 }
670
669
671 /* Add hash and suffix. */
670 /* Add hash and suffix. */
672 for (i = 0; i < 20; i++) {
671 for (i = 0; i < 20; i++) {
673 hexencode(dest, &destlen, destsize, sha[i]);
672 hexencode(dest, &destlen, destsize, sha[i]);
674 }
673 }
675
674
676 if (lastdot >= 0) {
675 if (lastdot >= 0) {
677 memcopy(dest, &destlen, destsize, &src[lastdot],
676 memcopy(dest, &destlen, destsize, &src[lastdot],
678 len - lastdot - 1);
677 len - lastdot - 1);
679 }
678 }
680
679
681 assert(PyBytes_Check(ret));
680 assert(PyBytes_Check(ret));
682 Py_SET_SIZE(ret, destlen);
681 Py_SET_SIZE(ret, destlen);
683
682
684 return ret;
683 return ret;
685 }
684 }
686
685
687 /*
686 /*
688 * Avoiding a trip through Python would improve performance by 50%,
687 * Avoiding a trip through Python would improve performance by 50%,
689 * but we don't encounter enough long names to be worth the code.
688 * but we don't encounter enough long names to be worth the code.
690 */
689 */
691 static int sha1hash(char hash[20], const char *str, Py_ssize_t len)
690 static int sha1hash(char hash[20], const char *str, Py_ssize_t len)
692 {
691 {
693 static PyObject *shafunc;
692 static PyObject *shafunc;
694 PyObject *shaobj, *hashobj;
693 PyObject *shaobj, *hashobj;
695
694
696 if (shafunc == NULL) {
695 if (shafunc == NULL) {
697 PyObject *hashlib = PyImport_ImportModule("hashlib");
696 PyObject *hashlib = PyImport_ImportModule("hashlib");
698 if (hashlib == NULL) {
697 if (hashlib == NULL) {
699 PyErr_SetString(PyExc_ImportError,
698 PyErr_SetString(PyExc_ImportError,
700 "pathencode failed to find hashlib");
699 "pathencode failed to find hashlib");
701 return -1;
700 return -1;
702 }
701 }
703 shafunc = PyObject_GetAttrString(hashlib, "sha1");
702 shafunc = PyObject_GetAttrString(hashlib, "sha1");
704 Py_DECREF(hashlib);
703 Py_DECREF(hashlib);
705
704
706 if (shafunc == NULL) {
705 if (shafunc == NULL) {
707 PyErr_SetString(PyExc_AttributeError,
706 PyErr_SetString(PyExc_AttributeError,
708 "module 'hashlib' has no "
707 "module 'hashlib' has no "
709 "attribute 'sha1' in pathencode");
708 "attribute 'sha1' in pathencode");
710 return -1;
709 return -1;
711 }
710 }
712 }
711 }
713
712
714 shaobj = PyObject_CallFunction(shafunc, PY23("s#", "y#"), str, len);
713 shaobj = PyObject_CallFunction(shafunc, "y#", str, len);
715
714
716 if (shaobj == NULL) {
715 if (shaobj == NULL) {
717 return -1;
716 return -1;
718 }
717 }
719
718
720 hashobj = PyObject_CallMethod(shaobj, "digest", "");
719 hashobj = PyObject_CallMethod(shaobj, "digest", "");
721 Py_DECREF(shaobj);
720 Py_DECREF(shaobj);
722 if (hashobj == NULL) {
721 if (hashobj == NULL) {
723 return -1;
722 return -1;
724 }
723 }
725
724
726 if (!PyBytes_Check(hashobj) || PyBytes_GET_SIZE(hashobj) != 20) {
725 if (!PyBytes_Check(hashobj) || PyBytes_GET_SIZE(hashobj) != 20) {
727 PyErr_SetString(PyExc_TypeError,
726 PyErr_SetString(PyExc_TypeError,
728 "result of digest is not a 20-byte hash");
727 "result of digest is not a 20-byte hash");
729 Py_DECREF(hashobj);
728 Py_DECREF(hashobj);
730 return -1;
729 return -1;
731 }
730 }
732
731
733 memcpy(hash, PyBytes_AS_STRING(hashobj), 20);
732 memcpy(hash, PyBytes_AS_STRING(hashobj), 20);
734 Py_DECREF(hashobj);
733 Py_DECREF(hashobj);
735 return 0;
734 return 0;
736 }
735 }
737
736
738 #define MAXENCODE 4096 * 4
737 #define MAXENCODE 4096 * 4
739
738
740 static PyObject *hashencode(const char *src, Py_ssize_t len)
739 static PyObject *hashencode(const char *src, Py_ssize_t len)
741 {
740 {
742 char dired[MAXENCODE];
741 char dired[MAXENCODE];
743 char lowered[MAXENCODE];
742 char lowered[MAXENCODE];
744 char auxed[MAXENCODE];
743 char auxed[MAXENCODE];
745 Py_ssize_t dirlen, lowerlen, auxlen, baselen;
744 Py_ssize_t dirlen, lowerlen, auxlen, baselen;
746 char sha[20];
745 char sha[20];
747
746
748 baselen = (len - 5) * 3;
747 baselen = (len - 5) * 3;
749 if (baselen >= MAXENCODE) {
748 if (baselen >= MAXENCODE) {
750 PyErr_SetString(PyExc_ValueError, "string too long");
749 PyErr_SetString(PyExc_ValueError, "string too long");
751 return NULL;
750 return NULL;
752 }
751 }
753
752
754 dirlen = _encodedir(dired, baselen, src, len);
753 dirlen = _encodedir(dired, baselen, src, len);
755 if (sha1hash(sha, dired, dirlen - 1) == -1) {
754 if (sha1hash(sha, dired, dirlen - 1) == -1) {
756 return NULL;
755 return NULL;
757 }
756 }
758 lowerlen = _lowerencode(lowered, baselen, dired + 5, dirlen - 5);
757 lowerlen = _lowerencode(lowered, baselen, dired + 5, dirlen - 5);
759 auxlen = auxencode(auxed, baselen, lowered, lowerlen);
758 auxlen = auxencode(auxed, baselen, lowered, lowerlen);
760 return hashmangle(auxed, auxlen, sha);
759 return hashmangle(auxed, auxlen, sha);
761 }
760 }
762
761
763 PyObject *pathencode(PyObject *self, PyObject *args)
762 PyObject *pathencode(PyObject *self, PyObject *args)
764 {
763 {
765 Py_ssize_t len, newlen;
764 Py_ssize_t len, newlen;
766 PyObject *pathobj, *newobj;
765 PyObject *pathobj, *newobj;
767 char *path;
766 char *path;
768
767
769 if (!PyArg_ParseTuple(args, "O:pathencode", &pathobj)) {
768 if (!PyArg_ParseTuple(args, "O:pathencode", &pathobj)) {
770 return NULL;
769 return NULL;
771 }
770 }
772
771
773 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
772 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
774 PyErr_SetString(PyExc_TypeError, "expected a string");
773 PyErr_SetString(PyExc_TypeError, "expected a string");
775 return NULL;
774 return NULL;
776 }
775 }
777
776
778 if (len > maxstorepathlen) {
777 if (len > maxstorepathlen) {
779 newlen = maxstorepathlen + 2;
778 newlen = maxstorepathlen + 2;
780 } else {
779 } else {
781 newlen = len ? basicencode(NULL, 0, path, len + 1) : 1;
780 newlen = len ? basicencode(NULL, 0, path, len + 1) : 1;
782 }
781 }
783
782
784 if (newlen <= maxstorepathlen + 1) {
783 if (newlen <= maxstorepathlen + 1) {
785 if (newlen == len + 1) {
784 if (newlen == len + 1) {
786 Py_INCREF(pathobj);
785 Py_INCREF(pathobj);
787 return pathobj;
786 return pathobj;
788 }
787 }
789
788
790 newobj = PyBytes_FromStringAndSize(NULL, newlen);
789 newobj = PyBytes_FromStringAndSize(NULL, newlen);
791
790
792 if (newobj) {
791 if (newobj) {
793 assert(PyBytes_Check(newobj));
792 assert(PyBytes_Check(newobj));
794 Py_SET_SIZE(newobj, Py_SIZE(newobj) - 1);
793 Py_SET_SIZE(newobj, Py_SIZE(newobj) - 1);
795 basicencode(PyBytes_AS_STRING(newobj), newlen, path,
794 basicencode(PyBytes_AS_STRING(newobj), newlen, path,
796 len + 1);
795 len + 1);
797 }
796 }
798 } else {
797 } else {
799 newobj = hashencode(path, len + 1);
798 newobj = hashencode(path, len + 1);
800 }
799 }
801
800
802 return newobj;
801 return newobj;
803 }
802 }
@@ -1,3278 +1,3275 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #define PY_SSIZE_T_CLEAN
10 #define PY_SSIZE_T_CLEAN
11 #include <Python.h>
11 #include <Python.h>
12 #include <assert.h>
12 #include <assert.h>
13 #include <ctype.h>
13 #include <ctype.h>
14 #include <limits.h>
14 #include <limits.h>
15 #include <stddef.h>
15 #include <stddef.h>
16 #include <stdlib.h>
16 #include <stdlib.h>
17 #include <string.h>
17 #include <string.h>
18 #include <structmember.h>
18 #include <structmember.h>
19
19
20 #include "bitmanipulation.h"
20 #include "bitmanipulation.h"
21 #include "charencode.h"
21 #include "charencode.h"
22 #include "compat.h"
22 #include "compat.h"
23 #include "revlog.h"
23 #include "revlog.h"
24 #include "util.h"
24 #include "util.h"
25
25
26 typedef struct indexObjectStruct indexObject;
26 typedef struct indexObjectStruct indexObject;
27
27
28 typedef struct {
28 typedef struct {
29 int children[16];
29 int children[16];
30 } nodetreenode;
30 } nodetreenode;
31
31
32 typedef struct {
32 typedef struct {
33 int abi_version;
33 int abi_version;
34 Py_ssize_t (*index_length)(const indexObject *);
34 Py_ssize_t (*index_length)(const indexObject *);
35 const char *(*index_node)(indexObject *, Py_ssize_t);
35 const char *(*index_node)(indexObject *, Py_ssize_t);
36 int (*index_parents)(PyObject *, int, int *);
36 int (*index_parents)(PyObject *, int, int *);
37 } Revlog_CAPI;
37 } Revlog_CAPI;
38
38
39 /*
39 /*
40 * A base-16 trie for fast node->rev mapping.
40 * A base-16 trie for fast node->rev mapping.
41 *
41 *
42 * Positive value is index of the next node in the trie
42 * Positive value is index of the next node in the trie
43 * Negative value is a leaf: -(rev + 2)
43 * Negative value is a leaf: -(rev + 2)
44 * Zero is empty
44 * Zero is empty
45 */
45 */
46 typedef struct {
46 typedef struct {
47 indexObject *index;
47 indexObject *index;
48 nodetreenode *nodes;
48 nodetreenode *nodes;
49 Py_ssize_t nodelen;
49 Py_ssize_t nodelen;
50 size_t length; /* # nodes in use */
50 size_t length; /* # nodes in use */
51 size_t capacity; /* # nodes allocated */
51 size_t capacity; /* # nodes allocated */
52 int depth; /* maximum depth of tree */
52 int depth; /* maximum depth of tree */
53 int splits; /* # splits performed */
53 int splits; /* # splits performed */
54 } nodetree;
54 } nodetree;
55
55
56 typedef struct {
56 typedef struct {
57 PyObject_HEAD /* ; */
57 PyObject_HEAD /* ; */
58 nodetree nt;
58 nodetree nt;
59 } nodetreeObject;
59 } nodetreeObject;
60
60
61 /*
61 /*
62 * This class has two behaviors.
62 * This class has two behaviors.
63 *
63 *
64 * When used in a list-like way (with integer keys), we decode an
64 * When used in a list-like way (with integer keys), we decode an
65 * entry in a RevlogNG index file on demand. We have limited support for
65 * entry in a RevlogNG index file on demand. We have limited support for
66 * integer-keyed insert and delete, only at elements right before the
66 * integer-keyed insert and delete, only at elements right before the
67 * end.
67 * end.
68 *
68 *
69 * With string keys, we lazily perform a reverse mapping from node to
69 * With string keys, we lazily perform a reverse mapping from node to
70 * rev, using a base-16 trie.
70 * rev, using a base-16 trie.
71 */
71 */
72 struct indexObjectStruct {
72 struct indexObjectStruct {
73 PyObject_HEAD
73 PyObject_HEAD
74 /* Type-specific fields go here. */
74 /* Type-specific fields go here. */
75 PyObject *data; /* raw bytes of index */
75 PyObject *data; /* raw bytes of index */
76 Py_ssize_t nodelen; /* digest size of the hash, 20 for SHA-1 */
76 Py_ssize_t nodelen; /* digest size of the hash, 20 for SHA-1 */
77 PyObject *nullentry; /* fast path for references to null */
77 PyObject *nullentry; /* fast path for references to null */
78 Py_buffer buf; /* buffer of data */
78 Py_buffer buf; /* buffer of data */
79 const char **offsets; /* populated on demand */
79 const char **offsets; /* populated on demand */
80 Py_ssize_t length; /* current on-disk number of elements */
80 Py_ssize_t length; /* current on-disk number of elements */
81 unsigned new_length; /* number of added elements */
81 unsigned new_length; /* number of added elements */
82 unsigned added_length; /* space reserved for added elements */
82 unsigned added_length; /* space reserved for added elements */
83 char *added; /* populated on demand */
83 char *added; /* populated on demand */
84 PyObject *headrevs; /* cache, invalidated on changes */
84 PyObject *headrevs; /* cache, invalidated on changes */
85 PyObject *filteredrevs; /* filtered revs set */
85 PyObject *filteredrevs; /* filtered revs set */
86 nodetree nt; /* base-16 trie */
86 nodetree nt; /* base-16 trie */
87 int ntinitialized; /* 0 or 1 */
87 int ntinitialized; /* 0 or 1 */
88 int ntrev; /* last rev scanned */
88 int ntrev; /* last rev scanned */
89 int ntlookups; /* # lookups */
89 int ntlookups; /* # lookups */
90 int ntmisses; /* # lookups that miss the cache */
90 int ntmisses; /* # lookups that miss the cache */
91 int inlined;
91 int inlined;
92 long entry_size; /* size of index headers. Differs in v1 v.s. v2 format
92 long entry_size; /* size of index headers. Differs in v1 v.s. v2 format
93 */
93 */
94 long rust_ext_compat; /* compatibility with being used in rust
94 long rust_ext_compat; /* compatibility with being used in rust
95 extensions */
95 extensions */
96 long format_version; /* format version selector (format_*) */
96 long format_version; /* format version selector (format_*) */
97 };
97 };
98
98
99 static Py_ssize_t index_length(const indexObject *self)
99 static Py_ssize_t index_length(const indexObject *self)
100 {
100 {
101 return self->length + self->new_length;
101 return self->length + self->new_length;
102 }
102 }
103
103
104 static const char nullid[32] = {0};
104 static const char nullid[32] = {0};
105 static const Py_ssize_t nullrev = -1;
105 static const Py_ssize_t nullrev = -1;
106
106
107 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
107 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
108
108
109 static int index_find_node(indexObject *self, const char *node);
109 static int index_find_node(indexObject *self, const char *node);
110
110
111 #if LONG_MAX == 0x7fffffffL
111 #if LONG_MAX == 0x7fffffffL
112 static const char *const tuple_format =
112 static const char *const tuple_format = "Kiiiiiiy#KiBBi";
113 PY23("Kiiiiiis#KiBBi", "Kiiiiiiy#KiBBi");
114 #else
113 #else
115 static const char *const tuple_format =
114 static const char *const tuple_format = "kiiiiiiy#kiBBi";
116 PY23("kiiiiiis#kiBBi", "kiiiiiiy#kiBBi");
117 #endif
115 #endif
118
116
119 /* A RevlogNG v1 index entry is 64 bytes long. */
117 /* A RevlogNG v1 index entry is 64 bytes long. */
120 static const long v1_entry_size = 64;
118 static const long v1_entry_size = 64;
121
119
122 /* A Revlogv2 index entry is 96 bytes long. */
120 /* A Revlogv2 index entry is 96 bytes long. */
123 static const long v2_entry_size = 96;
121 static const long v2_entry_size = 96;
124
122
125 /* A Changelogv2 index entry is 96 bytes long. */
123 /* A Changelogv2 index entry is 96 bytes long. */
126 static const long cl2_entry_size = 96;
124 static const long cl2_entry_size = 96;
127
125
128 /* Internal format version.
126 /* Internal format version.
129 * Must match their counterparts in revlogutils/constants.py */
127 * Must match their counterparts in revlogutils/constants.py */
130 static const long format_v1 = 1; /* constants.py: REVLOGV1 */
128 static const long format_v1 = 1; /* constants.py: REVLOGV1 */
131 static const long format_v2 = 0xDEAD; /* constants.py: REVLOGV2 */
129 static const long format_v2 = 0xDEAD; /* constants.py: REVLOGV2 */
132 static const long format_cl2 = 0xD34D; /* constants.py: CHANGELOGV2 */
130 static const long format_cl2 = 0xD34D; /* constants.py: CHANGELOGV2 */
133
131
134 static const long entry_v1_offset_high = 0;
132 static const long entry_v1_offset_high = 0;
135 static const long entry_v1_offset_offset_flags = 4;
133 static const long entry_v1_offset_offset_flags = 4;
136 static const long entry_v1_offset_comp_len = 8;
134 static const long entry_v1_offset_comp_len = 8;
137 static const long entry_v1_offset_uncomp_len = 12;
135 static const long entry_v1_offset_uncomp_len = 12;
138 static const long entry_v1_offset_base_rev = 16;
136 static const long entry_v1_offset_base_rev = 16;
139 static const long entry_v1_offset_link_rev = 20;
137 static const long entry_v1_offset_link_rev = 20;
140 static const long entry_v1_offset_parent_1 = 24;
138 static const long entry_v1_offset_parent_1 = 24;
141 static const long entry_v1_offset_parent_2 = 28;
139 static const long entry_v1_offset_parent_2 = 28;
142 static const long entry_v1_offset_node_id = 32;
140 static const long entry_v1_offset_node_id = 32;
143
141
144 static const long entry_v2_offset_high = 0;
142 static const long entry_v2_offset_high = 0;
145 static const long entry_v2_offset_offset_flags = 4;
143 static const long entry_v2_offset_offset_flags = 4;
146 static const long entry_v2_offset_comp_len = 8;
144 static const long entry_v2_offset_comp_len = 8;
147 static const long entry_v2_offset_uncomp_len = 12;
145 static const long entry_v2_offset_uncomp_len = 12;
148 static const long entry_v2_offset_base_rev = 16;
146 static const long entry_v2_offset_base_rev = 16;
149 static const long entry_v2_offset_link_rev = 20;
147 static const long entry_v2_offset_link_rev = 20;
150 static const long entry_v2_offset_parent_1 = 24;
148 static const long entry_v2_offset_parent_1 = 24;
151 static const long entry_v2_offset_parent_2 = 28;
149 static const long entry_v2_offset_parent_2 = 28;
152 static const long entry_v2_offset_node_id = 32;
150 static const long entry_v2_offset_node_id = 32;
153 static const long entry_v2_offset_sidedata_offset = 64;
151 static const long entry_v2_offset_sidedata_offset = 64;
154 static const long entry_v2_offset_sidedata_comp_len = 72;
152 static const long entry_v2_offset_sidedata_comp_len = 72;
155 static const long entry_v2_offset_all_comp_mode = 76;
153 static const long entry_v2_offset_all_comp_mode = 76;
156 /* next free offset: 77 */
154 /* next free offset: 77 */
157
155
158 static const long entry_cl2_offset_high = 0;
156 static const long entry_cl2_offset_high = 0;
159 static const long entry_cl2_offset_offset_flags = 4;
157 static const long entry_cl2_offset_offset_flags = 4;
160 static const long entry_cl2_offset_comp_len = 8;
158 static const long entry_cl2_offset_comp_len = 8;
161 static const long entry_cl2_offset_uncomp_len = 12;
159 static const long entry_cl2_offset_uncomp_len = 12;
162 static const long entry_cl2_offset_parent_1 = 16;
160 static const long entry_cl2_offset_parent_1 = 16;
163 static const long entry_cl2_offset_parent_2 = 20;
161 static const long entry_cl2_offset_parent_2 = 20;
164 static const long entry_cl2_offset_node_id = 24;
162 static const long entry_cl2_offset_node_id = 24;
165 static const long entry_cl2_offset_sidedata_offset = 56;
163 static const long entry_cl2_offset_sidedata_offset = 56;
166 static const long entry_cl2_offset_sidedata_comp_len = 64;
164 static const long entry_cl2_offset_sidedata_comp_len = 64;
167 static const long entry_cl2_offset_all_comp_mode = 68;
165 static const long entry_cl2_offset_all_comp_mode = 68;
168 static const long entry_cl2_offset_rank = 69;
166 static const long entry_cl2_offset_rank = 69;
169 /* next free offset: 73 */
167 /* next free offset: 73 */
170
168
171 static const char comp_mode_inline = 2;
169 static const char comp_mode_inline = 2;
172 static const char rank_unknown = -1;
170 static const char rank_unknown = -1;
173
171
174 static void raise_revlog_error(void)
172 static void raise_revlog_error(void)
175 {
173 {
176 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
174 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
177
175
178 mod = PyImport_ImportModule("mercurial.error");
176 mod = PyImport_ImportModule("mercurial.error");
179 if (mod == NULL) {
177 if (mod == NULL) {
180 goto cleanup;
178 goto cleanup;
181 }
179 }
182
180
183 dict = PyModule_GetDict(mod);
181 dict = PyModule_GetDict(mod);
184 if (dict == NULL) {
182 if (dict == NULL) {
185 goto cleanup;
183 goto cleanup;
186 }
184 }
187 Py_INCREF(dict);
185 Py_INCREF(dict);
188
186
189 errclass = PyDict_GetItemString(dict, "RevlogError");
187 errclass = PyDict_GetItemString(dict, "RevlogError");
190 if (errclass == NULL) {
188 if (errclass == NULL) {
191 PyErr_SetString(PyExc_SystemError,
189 PyErr_SetString(PyExc_SystemError,
192 "could not find RevlogError");
190 "could not find RevlogError");
193 goto cleanup;
191 goto cleanup;
194 }
192 }
195
193
196 /* value of exception is ignored by callers */
194 /* value of exception is ignored by callers */
197 PyErr_SetString(errclass, "RevlogError");
195 PyErr_SetString(errclass, "RevlogError");
198
196
199 cleanup:
197 cleanup:
200 Py_XDECREF(dict);
198 Py_XDECREF(dict);
201 Py_XDECREF(mod);
199 Py_XDECREF(mod);
202 }
200 }
203
201
204 /*
202 /*
205 * Return a pointer to the beginning of a RevlogNG record.
203 * Return a pointer to the beginning of a RevlogNG record.
206 */
204 */
207 static const char *index_deref(indexObject *self, Py_ssize_t pos)
205 static const char *index_deref(indexObject *self, Py_ssize_t pos)
208 {
206 {
209 if (pos >= self->length)
207 if (pos >= self->length)
210 return self->added + (pos - self->length) * self->entry_size;
208 return self->added + (pos - self->length) * self->entry_size;
211
209
212 if (self->inlined && pos > 0) {
210 if (self->inlined && pos > 0) {
213 if (self->offsets == NULL) {
211 if (self->offsets == NULL) {
214 Py_ssize_t ret;
212 Py_ssize_t ret;
215 self->offsets =
213 self->offsets =
216 PyMem_Malloc(self->length * sizeof(*self->offsets));
214 PyMem_Malloc(self->length * sizeof(*self->offsets));
217 if (self->offsets == NULL)
215 if (self->offsets == NULL)
218 return (const char *)PyErr_NoMemory();
216 return (const char *)PyErr_NoMemory();
219 ret = inline_scan(self, self->offsets);
217 ret = inline_scan(self, self->offsets);
220 if (ret == -1) {
218 if (ret == -1) {
221 return NULL;
219 return NULL;
222 };
220 };
223 }
221 }
224 return self->offsets[pos];
222 return self->offsets[pos];
225 }
223 }
226
224
227 return (const char *)(self->buf.buf) + pos * self->entry_size;
225 return (const char *)(self->buf.buf) + pos * self->entry_size;
228 }
226 }
229
227
230 /*
228 /*
231 * Get parents of the given rev.
229 * Get parents of the given rev.
232 *
230 *
233 * The specified rev must be valid and must not be nullrev. A returned
231 * The specified rev must be valid and must not be nullrev. A returned
234 * parent revision may be nullrev, but is guaranteed to be in valid range.
232 * parent revision may be nullrev, but is guaranteed to be in valid range.
235 */
233 */
236 static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
234 static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
237 int maxrev)
235 int maxrev)
238 {
236 {
239 const char *data = index_deref(self, rev);
237 const char *data = index_deref(self, rev);
240
238
241 if (self->format_version == format_v1) {
239 if (self->format_version == format_v1) {
242 ps[0] = getbe32(data + entry_v1_offset_parent_1);
240 ps[0] = getbe32(data + entry_v1_offset_parent_1);
243 ps[1] = getbe32(data + entry_v1_offset_parent_2);
241 ps[1] = getbe32(data + entry_v1_offset_parent_2);
244 } else if (self->format_version == format_v2) {
242 } else if (self->format_version == format_v2) {
245 ps[0] = getbe32(data + entry_v2_offset_parent_1);
243 ps[0] = getbe32(data + entry_v2_offset_parent_1);
246 ps[1] = getbe32(data + entry_v2_offset_parent_2);
244 ps[1] = getbe32(data + entry_v2_offset_parent_2);
247 } else if (self->format_version == format_cl2) {
245 } else if (self->format_version == format_cl2) {
248 ps[0] = getbe32(data + entry_cl2_offset_parent_1);
246 ps[0] = getbe32(data + entry_cl2_offset_parent_1);
249 ps[1] = getbe32(data + entry_cl2_offset_parent_2);
247 ps[1] = getbe32(data + entry_cl2_offset_parent_2);
250 } else {
248 } else {
251 raise_revlog_error();
249 raise_revlog_error();
252 return -1;
250 return -1;
253 }
251 }
254
252
255 /* If index file is corrupted, ps[] may point to invalid revisions. So
253 /* If index file is corrupted, ps[] may point to invalid revisions. So
256 * there is a risk of buffer overflow to trust them unconditionally. */
254 * there is a risk of buffer overflow to trust them unconditionally. */
257 if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
255 if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
258 PyErr_SetString(PyExc_ValueError, "parent out of range");
256 PyErr_SetString(PyExc_ValueError, "parent out of range");
259 return -1;
257 return -1;
260 }
258 }
261 return 0;
259 return 0;
262 }
260 }
263
261
264 /*
262 /*
265 * Get parents of the given rev.
263 * Get parents of the given rev.
266 *
264 *
267 * If the specified rev is out of range, IndexError will be raised. If the
265 * If the specified rev is out of range, IndexError will be raised. If the
268 * revlog entry is corrupted, ValueError may be raised.
266 * revlog entry is corrupted, ValueError may be raised.
269 *
267 *
270 * Returns 0 on success or -1 on failure.
268 * Returns 0 on success or -1 on failure.
271 */
269 */
272 static int HgRevlogIndex_GetParents(PyObject *op, int rev, int *ps)
270 static int HgRevlogIndex_GetParents(PyObject *op, int rev, int *ps)
273 {
271 {
274 int tiprev;
272 int tiprev;
275 if (!op || !HgRevlogIndex_Check(op) || !ps) {
273 if (!op || !HgRevlogIndex_Check(op) || !ps) {
276 PyErr_BadInternalCall();
274 PyErr_BadInternalCall();
277 return -1;
275 return -1;
278 }
276 }
279 tiprev = (int)index_length((indexObject *)op) - 1;
277 tiprev = (int)index_length((indexObject *)op) - 1;
280 if (rev < -1 || rev > tiprev) {
278 if (rev < -1 || rev > tiprev) {
281 PyErr_Format(PyExc_IndexError, "rev out of range: %d", rev);
279 PyErr_Format(PyExc_IndexError, "rev out of range: %d", rev);
282 return -1;
280 return -1;
283 } else if (rev == -1) {
281 } else if (rev == -1) {
284 ps[0] = ps[1] = -1;
282 ps[0] = ps[1] = -1;
285 return 0;
283 return 0;
286 } else {
284 } else {
287 return index_get_parents((indexObject *)op, rev, ps, tiprev);
285 return index_get_parents((indexObject *)op, rev, ps, tiprev);
288 }
286 }
289 }
287 }
290
288
291 static inline int64_t index_get_start(indexObject *self, Py_ssize_t rev)
289 static inline int64_t index_get_start(indexObject *self, Py_ssize_t rev)
292 {
290 {
293 const char *data;
291 const char *data;
294 uint64_t offset;
292 uint64_t offset;
295
293
296 if (rev == nullrev)
294 if (rev == nullrev)
297 return 0;
295 return 0;
298
296
299 data = index_deref(self, rev);
297 data = index_deref(self, rev);
300
298
301 if (self->format_version == format_v1) {
299 if (self->format_version == format_v1) {
302 offset = getbe32(data + entry_v1_offset_offset_flags);
300 offset = getbe32(data + entry_v1_offset_offset_flags);
303 if (rev == 0) {
301 if (rev == 0) {
304 /* mask out version number for the first entry */
302 /* mask out version number for the first entry */
305 offset &= 0xFFFF;
303 offset &= 0xFFFF;
306 } else {
304 } else {
307 uint32_t offset_high =
305 uint32_t offset_high =
308 getbe32(data + entry_v1_offset_high);
306 getbe32(data + entry_v1_offset_high);
309 offset |= ((uint64_t)offset_high) << 32;
307 offset |= ((uint64_t)offset_high) << 32;
310 }
308 }
311 } else if (self->format_version == format_v2) {
309 } else if (self->format_version == format_v2) {
312 offset = getbe32(data + entry_v2_offset_offset_flags);
310 offset = getbe32(data + entry_v2_offset_offset_flags);
313 if (rev == 0) {
311 if (rev == 0) {
314 /* mask out version number for the first entry */
312 /* mask out version number for the first entry */
315 offset &= 0xFFFF;
313 offset &= 0xFFFF;
316 } else {
314 } else {
317 uint32_t offset_high =
315 uint32_t offset_high =
318 getbe32(data + entry_v2_offset_high);
316 getbe32(data + entry_v2_offset_high);
319 offset |= ((uint64_t)offset_high) << 32;
317 offset |= ((uint64_t)offset_high) << 32;
320 }
318 }
321 } else if (self->format_version == format_cl2) {
319 } else if (self->format_version == format_cl2) {
322 uint32_t offset_high = getbe32(data + entry_cl2_offset_high);
320 uint32_t offset_high = getbe32(data + entry_cl2_offset_high);
323 offset = getbe32(data + entry_cl2_offset_offset_flags);
321 offset = getbe32(data + entry_cl2_offset_offset_flags);
324 offset |= ((uint64_t)offset_high) << 32;
322 offset |= ((uint64_t)offset_high) << 32;
325 } else {
323 } else {
326 raise_revlog_error();
324 raise_revlog_error();
327 return -1;
325 return -1;
328 }
326 }
329
327
330 return (int64_t)(offset >> 16);
328 return (int64_t)(offset >> 16);
331 }
329 }
332
330
333 static inline int index_get_length(indexObject *self, Py_ssize_t rev)
331 static inline int index_get_length(indexObject *self, Py_ssize_t rev)
334 {
332 {
335 const char *data;
333 const char *data;
336 int tmp;
334 int tmp;
337
335
338 if (rev == nullrev)
336 if (rev == nullrev)
339 return 0;
337 return 0;
340
338
341 data = index_deref(self, rev);
339 data = index_deref(self, rev);
342
340
343 if (self->format_version == format_v1) {
341 if (self->format_version == format_v1) {
344 tmp = (int)getbe32(data + entry_v1_offset_comp_len);
342 tmp = (int)getbe32(data + entry_v1_offset_comp_len);
345 } else if (self->format_version == format_v2) {
343 } else if (self->format_version == format_v2) {
346 tmp = (int)getbe32(data + entry_v2_offset_comp_len);
344 tmp = (int)getbe32(data + entry_v2_offset_comp_len);
347 } else if (self->format_version == format_cl2) {
345 } else if (self->format_version == format_cl2) {
348 tmp = (int)getbe32(data + entry_cl2_offset_comp_len);
346 tmp = (int)getbe32(data + entry_cl2_offset_comp_len);
349 } else {
347 } else {
350 raise_revlog_error();
348 raise_revlog_error();
351 return -1;
349 return -1;
352 }
350 }
353 if (tmp < 0) {
351 if (tmp < 0) {
354 PyErr_Format(PyExc_OverflowError,
352 PyErr_Format(PyExc_OverflowError,
355 "revlog entry size out of bound (%d)", tmp);
353 "revlog entry size out of bound (%d)", tmp);
356 return -1;
354 return -1;
357 }
355 }
358 return tmp;
356 return tmp;
359 }
357 }
360
358
361 /*
359 /*
362 * RevlogNG format (all in big endian, data may be inlined):
360 * RevlogNG format (all in big endian, data may be inlined):
363 * 6 bytes: offset
361 * 6 bytes: offset
364 * 2 bytes: flags
362 * 2 bytes: flags
365 * 4 bytes: compressed length
363 * 4 bytes: compressed length
366 * 4 bytes: uncompressed length
364 * 4 bytes: uncompressed length
367 * 4 bytes: base revision
365 * 4 bytes: base revision
368 * 4 bytes: link revision
366 * 4 bytes: link revision
369 * 4 bytes: parent 1 revision
367 * 4 bytes: parent 1 revision
370 * 4 bytes: parent 2 revision
368 * 4 bytes: parent 2 revision
371 * 32 bytes: nodeid (only 20 bytes used with SHA-1)
369 * 32 bytes: nodeid (only 20 bytes used with SHA-1)
372 */
370 */
373 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
371 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
374 {
372 {
375 uint64_t offset_flags, sidedata_offset;
373 uint64_t offset_flags, sidedata_offset;
376 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2,
374 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2,
377 sidedata_comp_len, rank = rank_unknown;
375 sidedata_comp_len, rank = rank_unknown;
378 char data_comp_mode, sidedata_comp_mode;
376 char data_comp_mode, sidedata_comp_mode;
379 const char *c_node_id;
377 const char *c_node_id;
380 const char *data;
378 const char *data;
381 Py_ssize_t length = index_length(self);
379 Py_ssize_t length = index_length(self);
382
380
383 if (pos == nullrev) {
381 if (pos == nullrev) {
384 Py_INCREF(self->nullentry);
382 Py_INCREF(self->nullentry);
385 return self->nullentry;
383 return self->nullentry;
386 }
384 }
387
385
388 if (pos < 0 || pos >= length) {
386 if (pos < 0 || pos >= length) {
389 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
387 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
390 return NULL;
388 return NULL;
391 }
389 }
392
390
393 data = index_deref(self, pos);
391 data = index_deref(self, pos);
394 if (data == NULL)
392 if (data == NULL)
395 return NULL;
393 return NULL;
396
394
397 if (self->format_version == format_v1) {
395 if (self->format_version == format_v1) {
398 offset_flags = getbe32(data + entry_v1_offset_offset_flags);
396 offset_flags = getbe32(data + entry_v1_offset_offset_flags);
399 /*
397 /*
400 * The first entry on-disk needs the version number masked out,
398 * The first entry on-disk needs the version number masked out,
401 * but this doesn't apply if entries are added to an empty
399 * but this doesn't apply if entries are added to an empty
402 * index.
400 * index.
403 */
401 */
404 if (self->length && pos == 0)
402 if (self->length && pos == 0)
405 offset_flags &= 0xFFFF;
403 offset_flags &= 0xFFFF;
406 else {
404 else {
407 uint32_t offset_high =
405 uint32_t offset_high =
408 getbe32(data + entry_v1_offset_high);
406 getbe32(data + entry_v1_offset_high);
409 offset_flags |= ((uint64_t)offset_high) << 32;
407 offset_flags |= ((uint64_t)offset_high) << 32;
410 }
408 }
411
409
412 comp_len = getbe32(data + entry_v1_offset_comp_len);
410 comp_len = getbe32(data + entry_v1_offset_comp_len);
413 uncomp_len = getbe32(data + entry_v1_offset_uncomp_len);
411 uncomp_len = getbe32(data + entry_v1_offset_uncomp_len);
414 base_rev = getbe32(data + entry_v1_offset_base_rev);
412 base_rev = getbe32(data + entry_v1_offset_base_rev);
415 link_rev = getbe32(data + entry_v1_offset_link_rev);
413 link_rev = getbe32(data + entry_v1_offset_link_rev);
416 parent_1 = getbe32(data + entry_v1_offset_parent_1);
414 parent_1 = getbe32(data + entry_v1_offset_parent_1);
417 parent_2 = getbe32(data + entry_v1_offset_parent_2);
415 parent_2 = getbe32(data + entry_v1_offset_parent_2);
418 c_node_id = data + entry_v1_offset_node_id;
416 c_node_id = data + entry_v1_offset_node_id;
419
417
420 sidedata_offset = 0;
418 sidedata_offset = 0;
421 sidedata_comp_len = 0;
419 sidedata_comp_len = 0;
422 data_comp_mode = comp_mode_inline;
420 data_comp_mode = comp_mode_inline;
423 sidedata_comp_mode = comp_mode_inline;
421 sidedata_comp_mode = comp_mode_inline;
424 } else if (self->format_version == format_v2) {
422 } else if (self->format_version == format_v2) {
425 offset_flags = getbe32(data + entry_v2_offset_offset_flags);
423 offset_flags = getbe32(data + entry_v2_offset_offset_flags);
426 /*
424 /*
427 * The first entry on-disk needs the version number masked out,
425 * The first entry on-disk needs the version number masked out,
428 * but this doesn't apply if entries are added to an empty
426 * but this doesn't apply if entries are added to an empty
429 * index.
427 * index.
430 */
428 */
431 if (self->length && pos == 0)
429 if (self->length && pos == 0)
432 offset_flags &= 0xFFFF;
430 offset_flags &= 0xFFFF;
433 else {
431 else {
434 uint32_t offset_high =
432 uint32_t offset_high =
435 getbe32(data + entry_v2_offset_high);
433 getbe32(data + entry_v2_offset_high);
436 offset_flags |= ((uint64_t)offset_high) << 32;
434 offset_flags |= ((uint64_t)offset_high) << 32;
437 }
435 }
438
436
439 comp_len = getbe32(data + entry_v2_offset_comp_len);
437 comp_len = getbe32(data + entry_v2_offset_comp_len);
440 uncomp_len = getbe32(data + entry_v2_offset_uncomp_len);
438 uncomp_len = getbe32(data + entry_v2_offset_uncomp_len);
441 base_rev = getbe32(data + entry_v2_offset_base_rev);
439 base_rev = getbe32(data + entry_v2_offset_base_rev);
442 link_rev = getbe32(data + entry_v2_offset_link_rev);
440 link_rev = getbe32(data + entry_v2_offset_link_rev);
443 parent_1 = getbe32(data + entry_v2_offset_parent_1);
441 parent_1 = getbe32(data + entry_v2_offset_parent_1);
444 parent_2 = getbe32(data + entry_v2_offset_parent_2);
442 parent_2 = getbe32(data + entry_v2_offset_parent_2);
445 c_node_id = data + entry_v2_offset_node_id;
443 c_node_id = data + entry_v2_offset_node_id;
446
444
447 sidedata_offset =
445 sidedata_offset =
448 getbe64(data + entry_v2_offset_sidedata_offset);
446 getbe64(data + entry_v2_offset_sidedata_offset);
449 sidedata_comp_len =
447 sidedata_comp_len =
450 getbe32(data + entry_v2_offset_sidedata_comp_len);
448 getbe32(data + entry_v2_offset_sidedata_comp_len);
451 data_comp_mode = data[entry_v2_offset_all_comp_mode] & 3;
449 data_comp_mode = data[entry_v2_offset_all_comp_mode] & 3;
452 sidedata_comp_mode =
450 sidedata_comp_mode =
453 ((data[entry_v2_offset_all_comp_mode] >> 2) & 3);
451 ((data[entry_v2_offset_all_comp_mode] >> 2) & 3);
454 } else if (self->format_version == format_cl2) {
452 } else if (self->format_version == format_cl2) {
455 uint32_t offset_high = getbe32(data + entry_cl2_offset_high);
453 uint32_t offset_high = getbe32(data + entry_cl2_offset_high);
456 offset_flags = getbe32(data + entry_cl2_offset_offset_flags);
454 offset_flags = getbe32(data + entry_cl2_offset_offset_flags);
457 offset_flags |= ((uint64_t)offset_high) << 32;
455 offset_flags |= ((uint64_t)offset_high) << 32;
458 comp_len = getbe32(data + entry_cl2_offset_comp_len);
456 comp_len = getbe32(data + entry_cl2_offset_comp_len);
459 uncomp_len = getbe32(data + entry_cl2_offset_uncomp_len);
457 uncomp_len = getbe32(data + entry_cl2_offset_uncomp_len);
460 /* base_rev and link_rev are not stored in changelogv2, but are
458 /* base_rev and link_rev are not stored in changelogv2, but are
461 still used by some functions shared with the other revlogs.
459 still used by some functions shared with the other revlogs.
462 They are supposed to contain links to other revisions,
460 They are supposed to contain links to other revisions,
463 but they always point to themselves in the case of a changelog.
461 but they always point to themselves in the case of a changelog.
464 */
462 */
465 base_rev = pos;
463 base_rev = pos;
466 link_rev = pos;
464 link_rev = pos;
467 parent_1 = getbe32(data + entry_cl2_offset_parent_1);
465 parent_1 = getbe32(data + entry_cl2_offset_parent_1);
468 parent_2 = getbe32(data + entry_cl2_offset_parent_2);
466 parent_2 = getbe32(data + entry_cl2_offset_parent_2);
469 c_node_id = data + entry_cl2_offset_node_id;
467 c_node_id = data + entry_cl2_offset_node_id;
470 sidedata_offset =
468 sidedata_offset =
471 getbe64(data + entry_cl2_offset_sidedata_offset);
469 getbe64(data + entry_cl2_offset_sidedata_offset);
472 sidedata_comp_len =
470 sidedata_comp_len =
473 getbe32(data + entry_cl2_offset_sidedata_comp_len);
471 getbe32(data + entry_cl2_offset_sidedata_comp_len);
474 data_comp_mode = data[entry_cl2_offset_all_comp_mode] & 3;
472 data_comp_mode = data[entry_cl2_offset_all_comp_mode] & 3;
475 sidedata_comp_mode =
473 sidedata_comp_mode =
476 ((data[entry_cl2_offset_all_comp_mode] >> 2) & 3);
474 ((data[entry_cl2_offset_all_comp_mode] >> 2) & 3);
477 rank = getbe32(data + entry_cl2_offset_rank);
475 rank = getbe32(data + entry_cl2_offset_rank);
478 } else {
476 } else {
479 raise_revlog_error();
477 raise_revlog_error();
480 return NULL;
478 return NULL;
481 }
479 }
482
480
483 return Py_BuildValue(tuple_format, offset_flags, comp_len, uncomp_len,
481 return Py_BuildValue(tuple_format, offset_flags, comp_len, uncomp_len,
484 base_rev, link_rev, parent_1, parent_2, c_node_id,
482 base_rev, link_rev, parent_1, parent_2, c_node_id,
485 self->nodelen, sidedata_offset, sidedata_comp_len,
483 self->nodelen, sidedata_offset, sidedata_comp_len,
486 data_comp_mode, sidedata_comp_mode, rank);
484 data_comp_mode, sidedata_comp_mode, rank);
487 }
485 }
488 /*
486 /*
489 * Pack header information in binary
487 * Pack header information in binary
490 */
488 */
491 static PyObject *index_pack_header(indexObject *self, PyObject *args)
489 static PyObject *index_pack_header(indexObject *self, PyObject *args)
492 {
490 {
493 int header;
491 int header;
494 char out[4];
492 char out[4];
495 if (!PyArg_ParseTuple(args, "I", &header)) {
493 if (!PyArg_ParseTuple(args, "I", &header)) {
496 return NULL;
494 return NULL;
497 }
495 }
498 if (self->format_version != format_v1) {
496 if (self->format_version != format_v1) {
499 PyErr_Format(PyExc_RuntimeError,
497 PyErr_Format(PyExc_RuntimeError,
500 "version header should go in the docket, not the "
498 "version header should go in the docket, not the "
501 "index: %lu",
499 "index: %lu",
502 header);
500 header);
503 return NULL;
501 return NULL;
504 }
502 }
505 putbe32(header, out);
503 putbe32(header, out);
506 return PyBytes_FromStringAndSize(out, 4);
504 return PyBytes_FromStringAndSize(out, 4);
507 }
505 }
508 /*
506 /*
509 * Return the raw binary string representing a revision
507 * Return the raw binary string representing a revision
510 */
508 */
511 static PyObject *index_entry_binary(indexObject *self, PyObject *value)
509 static PyObject *index_entry_binary(indexObject *self, PyObject *value)
512 {
510 {
513 long rev;
511 long rev;
514 const char *data;
512 const char *data;
515 Py_ssize_t length = index_length(self);
513 Py_ssize_t length = index_length(self);
516
514
517 if (!pylong_to_long(value, &rev)) {
515 if (!pylong_to_long(value, &rev)) {
518 return NULL;
516 return NULL;
519 }
517 }
520 if (rev < 0 || rev >= length) {
518 if (rev < 0 || rev >= length) {
521 PyErr_Format(PyExc_ValueError, "revlog index out of range: %ld",
519 PyErr_Format(PyExc_ValueError, "revlog index out of range: %ld",
522 rev);
520 rev);
523 return NULL;
521 return NULL;
524 };
522 };
525
523
526 data = index_deref(self, rev);
524 data = index_deref(self, rev);
527 if (data == NULL)
525 if (data == NULL)
528 return NULL;
526 return NULL;
529 if (rev == 0 && self->format_version == format_v1) {
527 if (rev == 0 && self->format_version == format_v1) {
530 /* the header is eating the start of the first entry */
528 /* the header is eating the start of the first entry */
531 return PyBytes_FromStringAndSize(data + 4,
529 return PyBytes_FromStringAndSize(data + 4,
532 self->entry_size - 4);
530 self->entry_size - 4);
533 }
531 }
534 return PyBytes_FromStringAndSize(data, self->entry_size);
532 return PyBytes_FromStringAndSize(data, self->entry_size);
535 }
533 }
536
534
537 /*
535 /*
538 * Return the hash of node corresponding to the given rev.
536 * Return the hash of node corresponding to the given rev.
539 */
537 */
540 static const char *index_node(indexObject *self, Py_ssize_t pos)
538 static const char *index_node(indexObject *self, Py_ssize_t pos)
541 {
539 {
542 Py_ssize_t length = index_length(self);
540 Py_ssize_t length = index_length(self);
543 const char *data;
541 const char *data;
544 const char *node_id;
542 const char *node_id;
545
543
546 if (pos == nullrev)
544 if (pos == nullrev)
547 return nullid;
545 return nullid;
548
546
549 if (pos >= length)
547 if (pos >= length)
550 return NULL;
548 return NULL;
551
549
552 data = index_deref(self, pos);
550 data = index_deref(self, pos);
553
551
554 if (self->format_version == format_v1) {
552 if (self->format_version == format_v1) {
555 node_id = data + entry_v1_offset_node_id;
553 node_id = data + entry_v1_offset_node_id;
556 } else if (self->format_version == format_v2) {
554 } else if (self->format_version == format_v2) {
557 node_id = data + entry_v2_offset_node_id;
555 node_id = data + entry_v2_offset_node_id;
558 } else if (self->format_version == format_cl2) {
556 } else if (self->format_version == format_cl2) {
559 node_id = data + entry_cl2_offset_node_id;
557 node_id = data + entry_cl2_offset_node_id;
560 } else {
558 } else {
561 raise_revlog_error();
559 raise_revlog_error();
562 return NULL;
560 return NULL;
563 }
561 }
564
562
565 return data ? node_id : NULL;
563 return data ? node_id : NULL;
566 }
564 }
567
565
568 /*
566 /*
569 * Return the hash of the node corresponding to the given rev. The
567 * Return the hash of the node corresponding to the given rev. The
570 * rev is assumed to be existing. If not, an exception is set.
568 * rev is assumed to be existing. If not, an exception is set.
571 */
569 */
572 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
570 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
573 {
571 {
574 const char *node = index_node(self, pos);
572 const char *node = index_node(self, pos);
575 if (node == NULL) {
573 if (node == NULL) {
576 PyErr_Format(PyExc_IndexError, "could not access rev %d",
574 PyErr_Format(PyExc_IndexError, "could not access rev %d",
577 (int)pos);
575 (int)pos);
578 }
576 }
579 return node;
577 return node;
580 }
578 }
581
579
582 static int nt_insert(nodetree *self, const char *node, int rev);
580 static int nt_insert(nodetree *self, const char *node, int rev);
583
581
584 static int node_check(Py_ssize_t nodelen, PyObject *obj, char **node)
582 static int node_check(Py_ssize_t nodelen, PyObject *obj, char **node)
585 {
583 {
586 Py_ssize_t thisnodelen;
584 Py_ssize_t thisnodelen;
587 if (PyBytes_AsStringAndSize(obj, node, &thisnodelen) == -1)
585 if (PyBytes_AsStringAndSize(obj, node, &thisnodelen) == -1)
588 return -1;
586 return -1;
589 if (nodelen == thisnodelen)
587 if (nodelen == thisnodelen)
590 return 0;
588 return 0;
591 PyErr_Format(PyExc_ValueError, "node len %zd != expected node len %zd",
589 PyErr_Format(PyExc_ValueError, "node len %zd != expected node len %zd",
592 thisnodelen, nodelen);
590 thisnodelen, nodelen);
593 return -1;
591 return -1;
594 }
592 }
595
593
596 static PyObject *index_append(indexObject *self, PyObject *obj)
594 static PyObject *index_append(indexObject *self, PyObject *obj)
597 {
595 {
598 uint64_t offset_flags, sidedata_offset;
596 uint64_t offset_flags, sidedata_offset;
599 int rev, comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2,
597 int rev, comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2,
600 sidedata_comp_len, rank;
598 sidedata_comp_len, rank;
601 char data_comp_mode, sidedata_comp_mode;
599 char data_comp_mode, sidedata_comp_mode;
602 Py_ssize_t c_node_id_len;
600 Py_ssize_t c_node_id_len;
603 const char *c_node_id;
601 const char *c_node_id;
604 char comp_field;
602 char comp_field;
605 char *data;
603 char *data;
606
604
607 if (!PyArg_ParseTuple(obj, tuple_format, &offset_flags, &comp_len,
605 if (!PyArg_ParseTuple(obj, tuple_format, &offset_flags, &comp_len,
608 &uncomp_len, &base_rev, &link_rev, &parent_1,
606 &uncomp_len, &base_rev, &link_rev, &parent_1,
609 &parent_2, &c_node_id, &c_node_id_len,
607 &parent_2, &c_node_id, &c_node_id_len,
610 &sidedata_offset, &sidedata_comp_len,
608 &sidedata_offset, &sidedata_comp_len,
611 &data_comp_mode, &sidedata_comp_mode, &rank)) {
609 &data_comp_mode, &sidedata_comp_mode, &rank)) {
612 PyErr_SetString(PyExc_TypeError, "12-tuple required");
610 PyErr_SetString(PyExc_TypeError, "12-tuple required");
613 return NULL;
611 return NULL;
614 }
612 }
615
613
616 if (c_node_id_len != self->nodelen) {
614 if (c_node_id_len != self->nodelen) {
617 PyErr_SetString(PyExc_TypeError, "invalid node");
615 PyErr_SetString(PyExc_TypeError, "invalid node");
618 return NULL;
616 return NULL;
619 }
617 }
620 if (self->format_version == format_v1) {
618 if (self->format_version == format_v1) {
621
619
622 if (data_comp_mode != comp_mode_inline) {
620 if (data_comp_mode != comp_mode_inline) {
623 PyErr_Format(PyExc_ValueError,
621 PyErr_Format(PyExc_ValueError,
624 "invalid data compression mode: %i",
622 "invalid data compression mode: %i",
625 data_comp_mode);
623 data_comp_mode);
626 return NULL;
624 return NULL;
627 }
625 }
628 if (sidedata_comp_mode != comp_mode_inline) {
626 if (sidedata_comp_mode != comp_mode_inline) {
629 PyErr_Format(PyExc_ValueError,
627 PyErr_Format(PyExc_ValueError,
630 "invalid sidedata compression mode: %i",
628 "invalid sidedata compression mode: %i",
631 sidedata_comp_mode);
629 sidedata_comp_mode);
632 return NULL;
630 return NULL;
633 }
631 }
634 }
632 }
635
633
636 if (self->new_length == self->added_length) {
634 if (self->new_length == self->added_length) {
637 size_t new_added_length =
635 size_t new_added_length =
638 self->added_length ? self->added_length * 2 : 4096;
636 self->added_length ? self->added_length * 2 : 4096;
639 void *new_added = PyMem_Realloc(
637 void *new_added = PyMem_Realloc(
640 self->added, new_added_length * self->entry_size);
638 self->added, new_added_length * self->entry_size);
641 if (!new_added)
639 if (!new_added)
642 return PyErr_NoMemory();
640 return PyErr_NoMemory();
643 self->added = new_added;
641 self->added = new_added;
644 self->added_length = new_added_length;
642 self->added_length = new_added_length;
645 }
643 }
646 rev = self->length + self->new_length;
644 rev = self->length + self->new_length;
647 data = self->added + self->entry_size * self->new_length++;
645 data = self->added + self->entry_size * self->new_length++;
648
646
649 memset(data, 0, self->entry_size);
647 memset(data, 0, self->entry_size);
650
648
651 if (self->format_version == format_v1) {
649 if (self->format_version == format_v1) {
652 putbe32(offset_flags >> 32, data + entry_v1_offset_high);
650 putbe32(offset_flags >> 32, data + entry_v1_offset_high);
653 putbe32(offset_flags & 0xffffffffU,
651 putbe32(offset_flags & 0xffffffffU,
654 data + entry_v1_offset_offset_flags);
652 data + entry_v1_offset_offset_flags);
655 putbe32(comp_len, data + entry_v1_offset_comp_len);
653 putbe32(comp_len, data + entry_v1_offset_comp_len);
656 putbe32(uncomp_len, data + entry_v1_offset_uncomp_len);
654 putbe32(uncomp_len, data + entry_v1_offset_uncomp_len);
657 putbe32(base_rev, data + entry_v1_offset_base_rev);
655 putbe32(base_rev, data + entry_v1_offset_base_rev);
658 putbe32(link_rev, data + entry_v1_offset_link_rev);
656 putbe32(link_rev, data + entry_v1_offset_link_rev);
659 putbe32(parent_1, data + entry_v1_offset_parent_1);
657 putbe32(parent_1, data + entry_v1_offset_parent_1);
660 putbe32(parent_2, data + entry_v1_offset_parent_2);
658 putbe32(parent_2, data + entry_v1_offset_parent_2);
661 memcpy(data + entry_v1_offset_node_id, c_node_id,
659 memcpy(data + entry_v1_offset_node_id, c_node_id,
662 c_node_id_len);
660 c_node_id_len);
663 } else if (self->format_version == format_v2) {
661 } else if (self->format_version == format_v2) {
664 putbe32(offset_flags >> 32, data + entry_v2_offset_high);
662 putbe32(offset_flags >> 32, data + entry_v2_offset_high);
665 putbe32(offset_flags & 0xffffffffU,
663 putbe32(offset_flags & 0xffffffffU,
666 data + entry_v2_offset_offset_flags);
664 data + entry_v2_offset_offset_flags);
667 putbe32(comp_len, data + entry_v2_offset_comp_len);
665 putbe32(comp_len, data + entry_v2_offset_comp_len);
668 putbe32(uncomp_len, data + entry_v2_offset_uncomp_len);
666 putbe32(uncomp_len, data + entry_v2_offset_uncomp_len);
669 putbe32(base_rev, data + entry_v2_offset_base_rev);
667 putbe32(base_rev, data + entry_v2_offset_base_rev);
670 putbe32(link_rev, data + entry_v2_offset_link_rev);
668 putbe32(link_rev, data + entry_v2_offset_link_rev);
671 putbe32(parent_1, data + entry_v2_offset_parent_1);
669 putbe32(parent_1, data + entry_v2_offset_parent_1);
672 putbe32(parent_2, data + entry_v2_offset_parent_2);
670 putbe32(parent_2, data + entry_v2_offset_parent_2);
673 memcpy(data + entry_v2_offset_node_id, c_node_id,
671 memcpy(data + entry_v2_offset_node_id, c_node_id,
674 c_node_id_len);
672 c_node_id_len);
675 putbe64(sidedata_offset,
673 putbe64(sidedata_offset,
676 data + entry_v2_offset_sidedata_offset);
674 data + entry_v2_offset_sidedata_offset);
677 putbe32(sidedata_comp_len,
675 putbe32(sidedata_comp_len,
678 data + entry_v2_offset_sidedata_comp_len);
676 data + entry_v2_offset_sidedata_comp_len);
679 comp_field = data_comp_mode & 3;
677 comp_field = data_comp_mode & 3;
680 comp_field = comp_field | (sidedata_comp_mode & 3) << 2;
678 comp_field = comp_field | (sidedata_comp_mode & 3) << 2;
681 data[entry_v2_offset_all_comp_mode] = comp_field;
679 data[entry_v2_offset_all_comp_mode] = comp_field;
682 } else if (self->format_version == format_cl2) {
680 } else if (self->format_version == format_cl2) {
683 putbe32(offset_flags >> 32, data + entry_cl2_offset_high);
681 putbe32(offset_flags >> 32, data + entry_cl2_offset_high);
684 putbe32(offset_flags & 0xffffffffU,
682 putbe32(offset_flags & 0xffffffffU,
685 data + entry_cl2_offset_offset_flags);
683 data + entry_cl2_offset_offset_flags);
686 putbe32(comp_len, data + entry_cl2_offset_comp_len);
684 putbe32(comp_len, data + entry_cl2_offset_comp_len);
687 putbe32(uncomp_len, data + entry_cl2_offset_uncomp_len);
685 putbe32(uncomp_len, data + entry_cl2_offset_uncomp_len);
688 putbe32(parent_1, data + entry_cl2_offset_parent_1);
686 putbe32(parent_1, data + entry_cl2_offset_parent_1);
689 putbe32(parent_2, data + entry_cl2_offset_parent_2);
687 putbe32(parent_2, data + entry_cl2_offset_parent_2);
690 memcpy(data + entry_cl2_offset_node_id, c_node_id,
688 memcpy(data + entry_cl2_offset_node_id, c_node_id,
691 c_node_id_len);
689 c_node_id_len);
692 putbe64(sidedata_offset,
690 putbe64(sidedata_offset,
693 data + entry_cl2_offset_sidedata_offset);
691 data + entry_cl2_offset_sidedata_offset);
694 putbe32(sidedata_comp_len,
692 putbe32(sidedata_comp_len,
695 data + entry_cl2_offset_sidedata_comp_len);
693 data + entry_cl2_offset_sidedata_comp_len);
696 comp_field = data_comp_mode & 3;
694 comp_field = data_comp_mode & 3;
697 comp_field = comp_field | (sidedata_comp_mode & 3) << 2;
695 comp_field = comp_field | (sidedata_comp_mode & 3) << 2;
698 data[entry_cl2_offset_all_comp_mode] = comp_field;
696 data[entry_cl2_offset_all_comp_mode] = comp_field;
699 putbe32(rank, data + entry_cl2_offset_rank);
697 putbe32(rank, data + entry_cl2_offset_rank);
700 } else {
698 } else {
701 raise_revlog_error();
699 raise_revlog_error();
702 return NULL;
700 return NULL;
703 }
701 }
704
702
705 if (self->ntinitialized)
703 if (self->ntinitialized)
706 nt_insert(&self->nt, c_node_id, rev);
704 nt_insert(&self->nt, c_node_id, rev);
707
705
708 Py_CLEAR(self->headrevs);
706 Py_CLEAR(self->headrevs);
709 Py_RETURN_NONE;
707 Py_RETURN_NONE;
710 }
708 }
711
709
712 /* Replace an existing index entry's sidedata offset and length with new ones.
710 /* Replace an existing index entry's sidedata offset and length with new ones.
713 This cannot be used outside of the context of sidedata rewriting,
711 This cannot be used outside of the context of sidedata rewriting,
714 inside the transaction that creates the given revision. */
712 inside the transaction that creates the given revision. */
715 static PyObject *index_replace_sidedata_info(indexObject *self, PyObject *args)
713 static PyObject *index_replace_sidedata_info(indexObject *self, PyObject *args)
716 {
714 {
717 uint64_t offset_flags, sidedata_offset;
715 uint64_t offset_flags, sidedata_offset;
718 Py_ssize_t rev;
716 Py_ssize_t rev;
719 int sidedata_comp_len;
717 int sidedata_comp_len;
720 char comp_mode;
718 char comp_mode;
721 char *data;
719 char *data;
722 #if LONG_MAX == 0x7fffffffL
720 #if LONG_MAX == 0x7fffffffL
723 const char *const sidedata_format = PY23("nKiKB", "nKiKB");
721 const char *const sidedata_format = "nKiKB";
724 #else
722 #else
725 const char *const sidedata_format = PY23("nkikB", "nkikB");
723 const char *const sidedata_format = "nkikB";
726 #endif
724 #endif
727
725
728 if (self->entry_size == v1_entry_size || self->inlined) {
726 if (self->entry_size == v1_entry_size || self->inlined) {
729 /*
727 /*
730 There is a bug in the transaction handling when going from an
728 There is a bug in the transaction handling when going from an
731 inline revlog to a separate index and data file. Turn it off until
729 inline revlog to a separate index and data file. Turn it off until
732 it's fixed, since v2 revlogs sometimes get rewritten on exchange.
730 it's fixed, since v2 revlogs sometimes get rewritten on exchange.
733 See issue6485.
731 See issue6485.
734 */
732 */
735 raise_revlog_error();
733 raise_revlog_error();
736 return NULL;
734 return NULL;
737 }
735 }
738
736
739 if (!PyArg_ParseTuple(args, sidedata_format, &rev, &sidedata_offset,
737 if (!PyArg_ParseTuple(args, sidedata_format, &rev, &sidedata_offset,
740 &sidedata_comp_len, &offset_flags, &comp_mode))
738 &sidedata_comp_len, &offset_flags, &comp_mode))
741 return NULL;
739 return NULL;
742
740
743 if (rev < 0 || rev >= index_length(self)) {
741 if (rev < 0 || rev >= index_length(self)) {
744 PyErr_SetString(PyExc_IndexError, "revision outside index");
742 PyErr_SetString(PyExc_IndexError, "revision outside index");
745 return NULL;
743 return NULL;
746 }
744 }
747 if (rev < self->length) {
745 if (rev < self->length) {
748 PyErr_SetString(
746 PyErr_SetString(
749 PyExc_IndexError,
747 PyExc_IndexError,
750 "cannot rewrite entries outside of this transaction");
748 "cannot rewrite entries outside of this transaction");
751 return NULL;
749 return NULL;
752 }
750 }
753
751
754 /* Find the newly added node, offset from the "already on-disk" length
752 /* Find the newly added node, offset from the "already on-disk" length
755 */
753 */
756 data = self->added + self->entry_size * (rev - self->length);
754 data = self->added + self->entry_size * (rev - self->length);
757 if (self->format_version == format_v2) {
755 if (self->format_version == format_v2) {
758 putbe64(offset_flags, data + entry_v2_offset_high);
756 putbe64(offset_flags, data + entry_v2_offset_high);
759 putbe64(sidedata_offset,
757 putbe64(sidedata_offset,
760 data + entry_v2_offset_sidedata_offset);
758 data + entry_v2_offset_sidedata_offset);
761 putbe32(sidedata_comp_len,
759 putbe32(sidedata_comp_len,
762 data + entry_v2_offset_sidedata_comp_len);
760 data + entry_v2_offset_sidedata_comp_len);
763 data[entry_v2_offset_all_comp_mode] =
761 data[entry_v2_offset_all_comp_mode] =
764 (data[entry_v2_offset_all_comp_mode] & ~(3 << 2)) |
762 (data[entry_v2_offset_all_comp_mode] & ~(3 << 2)) |
765 ((comp_mode & 3) << 2);
763 ((comp_mode & 3) << 2);
766 } else if (self->format_version == format_cl2) {
764 } else if (self->format_version == format_cl2) {
767 putbe64(offset_flags, data + entry_cl2_offset_high);
765 putbe64(offset_flags, data + entry_cl2_offset_high);
768 putbe64(sidedata_offset,
766 putbe64(sidedata_offset,
769 data + entry_cl2_offset_sidedata_offset);
767 data + entry_cl2_offset_sidedata_offset);
770 putbe32(sidedata_comp_len,
768 putbe32(sidedata_comp_len,
771 data + entry_cl2_offset_sidedata_comp_len);
769 data + entry_cl2_offset_sidedata_comp_len);
772 data[entry_cl2_offset_all_comp_mode] =
770 data[entry_cl2_offset_all_comp_mode] =
773 (data[entry_cl2_offset_all_comp_mode] & ~(3 << 2)) |
771 (data[entry_cl2_offset_all_comp_mode] & ~(3 << 2)) |
774 ((comp_mode & 3) << 2);
772 ((comp_mode & 3) << 2);
775 } else {
773 } else {
776 raise_revlog_error();
774 raise_revlog_error();
777 return NULL;
775 return NULL;
778 }
776 }
779
777
780 Py_RETURN_NONE;
778 Py_RETURN_NONE;
781 }
779 }
782
780
783 static PyObject *index_stats(indexObject *self)
781 static PyObject *index_stats(indexObject *self)
784 {
782 {
785 PyObject *obj = PyDict_New();
783 PyObject *obj = PyDict_New();
786 PyObject *s = NULL;
784 PyObject *s = NULL;
787 PyObject *t = NULL;
785 PyObject *t = NULL;
788
786
789 if (obj == NULL)
787 if (obj == NULL)
790 return NULL;
788 return NULL;
791
789
792 #define istat(__n, __d) \
790 #define istat(__n, __d) \
793 do { \
791 do { \
794 s = PyBytes_FromString(__d); \
792 s = PyBytes_FromString(__d); \
795 t = PyLong_FromSsize_t(self->__n); \
793 t = PyLong_FromSsize_t(self->__n); \
796 if (!s || !t) \
794 if (!s || !t) \
797 goto bail; \
795 goto bail; \
798 if (PyDict_SetItem(obj, s, t) == -1) \
796 if (PyDict_SetItem(obj, s, t) == -1) \
799 goto bail; \
797 goto bail; \
800 Py_CLEAR(s); \
798 Py_CLEAR(s); \
801 Py_CLEAR(t); \
799 Py_CLEAR(t); \
802 } while (0)
800 } while (0)
803
801
804 if (self->added_length)
802 if (self->added_length)
805 istat(new_length, "index entries added");
803 istat(new_length, "index entries added");
806 istat(length, "revs in memory");
804 istat(length, "revs in memory");
807 istat(ntlookups, "node trie lookups");
805 istat(ntlookups, "node trie lookups");
808 istat(ntmisses, "node trie misses");
806 istat(ntmisses, "node trie misses");
809 istat(ntrev, "node trie last rev scanned");
807 istat(ntrev, "node trie last rev scanned");
810 if (self->ntinitialized) {
808 if (self->ntinitialized) {
811 istat(nt.capacity, "node trie capacity");
809 istat(nt.capacity, "node trie capacity");
812 istat(nt.depth, "node trie depth");
810 istat(nt.depth, "node trie depth");
813 istat(nt.length, "node trie count");
811 istat(nt.length, "node trie count");
814 istat(nt.splits, "node trie splits");
812 istat(nt.splits, "node trie splits");
815 }
813 }
816
814
817 #undef istat
815 #undef istat
818
816
819 return obj;
817 return obj;
820
818
821 bail:
819 bail:
822 Py_XDECREF(obj);
820 Py_XDECREF(obj);
823 Py_XDECREF(s);
821 Py_XDECREF(s);
824 Py_XDECREF(t);
822 Py_XDECREF(t);
825 return NULL;
823 return NULL;
826 }
824 }
827
825
828 /*
826 /*
829 * When we cache a list, we want to be sure the caller can't mutate
827 * When we cache a list, we want to be sure the caller can't mutate
830 * the cached copy.
828 * the cached copy.
831 */
829 */
832 static PyObject *list_copy(PyObject *list)
830 static PyObject *list_copy(PyObject *list)
833 {
831 {
834 Py_ssize_t len = PyList_GET_SIZE(list);
832 Py_ssize_t len = PyList_GET_SIZE(list);
835 PyObject *newlist = PyList_New(len);
833 PyObject *newlist = PyList_New(len);
836 Py_ssize_t i;
834 Py_ssize_t i;
837
835
838 if (newlist == NULL)
836 if (newlist == NULL)
839 return NULL;
837 return NULL;
840
838
841 for (i = 0; i < len; i++) {
839 for (i = 0; i < len; i++) {
842 PyObject *obj = PyList_GET_ITEM(list, i);
840 PyObject *obj = PyList_GET_ITEM(list, i);
843 Py_INCREF(obj);
841 Py_INCREF(obj);
844 PyList_SET_ITEM(newlist, i, obj);
842 PyList_SET_ITEM(newlist, i, obj);
845 }
843 }
846
844
847 return newlist;
845 return newlist;
848 }
846 }
849
847
850 static int check_filter(PyObject *filter, Py_ssize_t arg)
848 static int check_filter(PyObject *filter, Py_ssize_t arg)
851 {
849 {
852 if (filter) {
850 if (filter) {
853 PyObject *arglist, *result;
851 PyObject *arglist, *result;
854 int isfiltered;
852 int isfiltered;
855
853
856 arglist = Py_BuildValue("(n)", arg);
854 arglist = Py_BuildValue("(n)", arg);
857 if (!arglist) {
855 if (!arglist) {
858 return -1;
856 return -1;
859 }
857 }
860
858
861 result = PyObject_Call(filter, arglist, NULL);
859 result = PyObject_Call(filter, arglist, NULL);
862 Py_DECREF(arglist);
860 Py_DECREF(arglist);
863 if (!result) {
861 if (!result) {
864 return -1;
862 return -1;
865 }
863 }
866
864
867 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
865 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
868 * same as this function, so we can just return it directly.*/
866 * same as this function, so we can just return it directly.*/
869 isfiltered = PyObject_IsTrue(result);
867 isfiltered = PyObject_IsTrue(result);
870 Py_DECREF(result);
868 Py_DECREF(result);
871 return isfiltered;
869 return isfiltered;
872 } else {
870 } else {
873 return 0;
871 return 0;
874 }
872 }
875 }
873 }
876
874
877 static inline void set_phase_from_parents(char *phases, int parent_1,
875 static inline void set_phase_from_parents(char *phases, int parent_1,
878 int parent_2, Py_ssize_t i)
876 int parent_2, Py_ssize_t i)
879 {
877 {
880 if (parent_1 >= 0 && phases[parent_1] > phases[i])
878 if (parent_1 >= 0 && phases[parent_1] > phases[i])
881 phases[i] = phases[parent_1];
879 phases[i] = phases[parent_1];
882 if (parent_2 >= 0 && phases[parent_2] > phases[i])
880 if (parent_2 >= 0 && phases[parent_2] > phases[i])
883 phases[i] = phases[parent_2];
881 phases[i] = phases[parent_2];
884 }
882 }
885
883
886 static PyObject *reachableroots2(indexObject *self, PyObject *args)
884 static PyObject *reachableroots2(indexObject *self, PyObject *args)
887 {
885 {
888
886
889 /* Input */
887 /* Input */
890 long minroot;
888 long minroot;
891 PyObject *includepatharg = NULL;
889 PyObject *includepatharg = NULL;
892 int includepath = 0;
890 int includepath = 0;
893 /* heads and roots are lists */
891 /* heads and roots are lists */
894 PyObject *heads = NULL;
892 PyObject *heads = NULL;
895 PyObject *roots = NULL;
893 PyObject *roots = NULL;
896 PyObject *reachable = NULL;
894 PyObject *reachable = NULL;
897
895
898 PyObject *val;
896 PyObject *val;
899 Py_ssize_t len = index_length(self);
897 Py_ssize_t len = index_length(self);
900 long revnum;
898 long revnum;
901 Py_ssize_t k;
899 Py_ssize_t k;
902 Py_ssize_t i;
900 Py_ssize_t i;
903 Py_ssize_t l;
901 Py_ssize_t l;
904 int r;
902 int r;
905 int parents[2];
903 int parents[2];
906
904
907 /* Internal data structure:
905 /* Internal data structure:
908 * tovisit: array of length len+1 (all revs + nullrev), filled upto
906 * tovisit: array of length len+1 (all revs + nullrev), filled upto
909 * lentovisit
907 * lentovisit
910 *
908 *
911 * revstates: array of length len+1 (all revs + nullrev) */
909 * revstates: array of length len+1 (all revs + nullrev) */
912 int *tovisit = NULL;
910 int *tovisit = NULL;
913 long lentovisit = 0;
911 long lentovisit = 0;
914 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
912 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
915 char *revstates = NULL;
913 char *revstates = NULL;
916
914
917 /* Get arguments */
915 /* Get arguments */
918 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
916 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
919 &PyList_Type, &roots, &PyBool_Type,
917 &PyList_Type, &roots, &PyBool_Type,
920 &includepatharg))
918 &includepatharg))
921 goto bail;
919 goto bail;
922
920
923 if (includepatharg == Py_True)
921 if (includepatharg == Py_True)
924 includepath = 1;
922 includepath = 1;
925
923
926 /* Initialize return set */
924 /* Initialize return set */
927 reachable = PyList_New(0);
925 reachable = PyList_New(0);
928 if (reachable == NULL)
926 if (reachable == NULL)
929 goto bail;
927 goto bail;
930
928
931 /* Initialize internal datastructures */
929 /* Initialize internal datastructures */
932 tovisit = (int *)malloc((len + 1) * sizeof(int));
930 tovisit = (int *)malloc((len + 1) * sizeof(int));
933 if (tovisit == NULL) {
931 if (tovisit == NULL) {
934 PyErr_NoMemory();
932 PyErr_NoMemory();
935 goto bail;
933 goto bail;
936 }
934 }
937
935
938 revstates = (char *)calloc(len + 1, 1);
936 revstates = (char *)calloc(len + 1, 1);
939 if (revstates == NULL) {
937 if (revstates == NULL) {
940 PyErr_NoMemory();
938 PyErr_NoMemory();
941 goto bail;
939 goto bail;
942 }
940 }
943
941
944 l = PyList_GET_SIZE(roots);
942 l = PyList_GET_SIZE(roots);
945 for (i = 0; i < l; i++) {
943 for (i = 0; i < l; i++) {
946 revnum = PyLong_AsLong(PyList_GET_ITEM(roots, i));
944 revnum = PyLong_AsLong(PyList_GET_ITEM(roots, i));
947 if (revnum == -1 && PyErr_Occurred())
945 if (revnum == -1 && PyErr_Occurred())
948 goto bail;
946 goto bail;
949 /* If root is out of range, e.g. wdir(), it must be unreachable
947 /* If root is out of range, e.g. wdir(), it must be unreachable
950 * from heads. So we can just ignore it. */
948 * from heads. So we can just ignore it. */
951 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
949 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
952 continue;
950 continue;
953 revstates[revnum + 1] |= RS_ROOT;
951 revstates[revnum + 1] |= RS_ROOT;
954 }
952 }
955
953
956 /* Populate tovisit with all the heads */
954 /* Populate tovisit with all the heads */
957 l = PyList_GET_SIZE(heads);
955 l = PyList_GET_SIZE(heads);
958 for (i = 0; i < l; i++) {
956 for (i = 0; i < l; i++) {
959 revnum = PyLong_AsLong(PyList_GET_ITEM(heads, i));
957 revnum = PyLong_AsLong(PyList_GET_ITEM(heads, i));
960 if (revnum == -1 && PyErr_Occurred())
958 if (revnum == -1 && PyErr_Occurred())
961 goto bail;
959 goto bail;
962 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
960 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
963 PyErr_SetString(PyExc_IndexError, "head out of range");
961 PyErr_SetString(PyExc_IndexError, "head out of range");
964 goto bail;
962 goto bail;
965 }
963 }
966 if (!(revstates[revnum + 1] & RS_SEEN)) {
964 if (!(revstates[revnum + 1] & RS_SEEN)) {
967 tovisit[lentovisit++] = (int)revnum;
965 tovisit[lentovisit++] = (int)revnum;
968 revstates[revnum + 1] |= RS_SEEN;
966 revstates[revnum + 1] |= RS_SEEN;
969 }
967 }
970 }
968 }
971
969
972 /* Visit the tovisit list and find the reachable roots */
970 /* Visit the tovisit list and find the reachable roots */
973 k = 0;
971 k = 0;
974 while (k < lentovisit) {
972 while (k < lentovisit) {
975 /* Add the node to reachable if it is a root*/
973 /* Add the node to reachable if it is a root*/
976 revnum = tovisit[k++];
974 revnum = tovisit[k++];
977 if (revstates[revnum + 1] & RS_ROOT) {
975 if (revstates[revnum + 1] & RS_ROOT) {
978 revstates[revnum + 1] |= RS_REACHABLE;
976 revstates[revnum + 1] |= RS_REACHABLE;
979 val = PyLong_FromLong(revnum);
977 val = PyLong_FromLong(revnum);
980 if (val == NULL)
978 if (val == NULL)
981 goto bail;
979 goto bail;
982 r = PyList_Append(reachable, val);
980 r = PyList_Append(reachable, val);
983 Py_DECREF(val);
981 Py_DECREF(val);
984 if (r < 0)
982 if (r < 0)
985 goto bail;
983 goto bail;
986 if (includepath == 0)
984 if (includepath == 0)
987 continue;
985 continue;
988 }
986 }
989
987
990 /* Add its parents to the list of nodes to visit */
988 /* Add its parents to the list of nodes to visit */
991 if (revnum == nullrev)
989 if (revnum == nullrev)
992 continue;
990 continue;
993 r = index_get_parents(self, revnum, parents, (int)len - 1);
991 r = index_get_parents(self, revnum, parents, (int)len - 1);
994 if (r < 0)
992 if (r < 0)
995 goto bail;
993 goto bail;
996 for (i = 0; i < 2; i++) {
994 for (i = 0; i < 2; i++) {
997 if (!(revstates[parents[i] + 1] & RS_SEEN) &&
995 if (!(revstates[parents[i] + 1] & RS_SEEN) &&
998 parents[i] >= minroot) {
996 parents[i] >= minroot) {
999 tovisit[lentovisit++] = parents[i];
997 tovisit[lentovisit++] = parents[i];
1000 revstates[parents[i] + 1] |= RS_SEEN;
998 revstates[parents[i] + 1] |= RS_SEEN;
1001 }
999 }
1002 }
1000 }
1003 }
1001 }
1004
1002
1005 /* Find all the nodes in between the roots we found and the heads
1003 /* Find all the nodes in between the roots we found and the heads
1006 * and add them to the reachable set */
1004 * and add them to the reachable set */
1007 if (includepath == 1) {
1005 if (includepath == 1) {
1008 long minidx = minroot;
1006 long minidx = minroot;
1009 if (minidx < 0)
1007 if (minidx < 0)
1010 minidx = 0;
1008 minidx = 0;
1011 for (i = minidx; i < len; i++) {
1009 for (i = minidx; i < len; i++) {
1012 if (!(revstates[i + 1] & RS_SEEN))
1010 if (!(revstates[i + 1] & RS_SEEN))
1013 continue;
1011 continue;
1014 r = index_get_parents(self, i, parents, (int)len - 1);
1012 r = index_get_parents(self, i, parents, (int)len - 1);
1015 /* Corrupted index file, error is set from
1013 /* Corrupted index file, error is set from
1016 * index_get_parents */
1014 * index_get_parents */
1017 if (r < 0)
1015 if (r < 0)
1018 goto bail;
1016 goto bail;
1019 if (((revstates[parents[0] + 1] |
1017 if (((revstates[parents[0] + 1] |
1020 revstates[parents[1] + 1]) &
1018 revstates[parents[1] + 1]) &
1021 RS_REACHABLE) &&
1019 RS_REACHABLE) &&
1022 !(revstates[i + 1] & RS_REACHABLE)) {
1020 !(revstates[i + 1] & RS_REACHABLE)) {
1023 revstates[i + 1] |= RS_REACHABLE;
1021 revstates[i + 1] |= RS_REACHABLE;
1024 val = PyLong_FromSsize_t(i);
1022 val = PyLong_FromSsize_t(i);
1025 if (val == NULL)
1023 if (val == NULL)
1026 goto bail;
1024 goto bail;
1027 r = PyList_Append(reachable, val);
1025 r = PyList_Append(reachable, val);
1028 Py_DECREF(val);
1026 Py_DECREF(val);
1029 if (r < 0)
1027 if (r < 0)
1030 goto bail;
1028 goto bail;
1031 }
1029 }
1032 }
1030 }
1033 }
1031 }
1034
1032
1035 free(revstates);
1033 free(revstates);
1036 free(tovisit);
1034 free(tovisit);
1037 return reachable;
1035 return reachable;
1038 bail:
1036 bail:
1039 Py_XDECREF(reachable);
1037 Py_XDECREF(reachable);
1040 free(revstates);
1038 free(revstates);
1041 free(tovisit);
1039 free(tovisit);
1042 return NULL;
1040 return NULL;
1043 }
1041 }
1044
1042
1045 static int add_roots_get_min(indexObject *self, PyObject *roots, char *phases,
1043 static int add_roots_get_min(indexObject *self, PyObject *roots, char *phases,
1046 char phase)
1044 char phase)
1047 {
1045 {
1048 Py_ssize_t len = index_length(self);
1046 Py_ssize_t len = index_length(self);
1049 PyObject *item;
1047 PyObject *item;
1050 PyObject *iterator;
1048 PyObject *iterator;
1051 int rev, minrev = -1;
1049 int rev, minrev = -1;
1052 char *node;
1050 char *node;
1053
1051
1054 if (!PySet_Check(roots)) {
1052 if (!PySet_Check(roots)) {
1055 PyErr_SetString(PyExc_TypeError,
1053 PyErr_SetString(PyExc_TypeError,
1056 "roots must be a set of nodes");
1054 "roots must be a set of nodes");
1057 return -2;
1055 return -2;
1058 }
1056 }
1059 iterator = PyObject_GetIter(roots);
1057 iterator = PyObject_GetIter(roots);
1060 if (iterator == NULL)
1058 if (iterator == NULL)
1061 return -2;
1059 return -2;
1062 while ((item = PyIter_Next(iterator))) {
1060 while ((item = PyIter_Next(iterator))) {
1063 if (node_check(self->nodelen, item, &node) == -1)
1061 if (node_check(self->nodelen, item, &node) == -1)
1064 goto failed;
1062 goto failed;
1065 rev = index_find_node(self, node);
1063 rev = index_find_node(self, node);
1066 /* null is implicitly public, so negative is invalid */
1064 /* null is implicitly public, so negative is invalid */
1067 if (rev < 0 || rev >= len)
1065 if (rev < 0 || rev >= len)
1068 goto failed;
1066 goto failed;
1069 phases[rev] = phase;
1067 phases[rev] = phase;
1070 if (minrev == -1 || minrev > rev)
1068 if (minrev == -1 || minrev > rev)
1071 minrev = rev;
1069 minrev = rev;
1072 Py_DECREF(item);
1070 Py_DECREF(item);
1073 }
1071 }
1074 Py_DECREF(iterator);
1072 Py_DECREF(iterator);
1075 return minrev;
1073 return minrev;
1076 failed:
1074 failed:
1077 Py_DECREF(iterator);
1075 Py_DECREF(iterator);
1078 Py_DECREF(item);
1076 Py_DECREF(item);
1079 return -2;
1077 return -2;
1080 }
1078 }
1081
1079
1082 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
1080 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
1083 {
1081 {
1084 /* 0: public (untracked), 1: draft, 2: secret, 32: archive,
1082 /* 0: public (untracked), 1: draft, 2: secret, 32: archive,
1085 96: internal */
1083 96: internal */
1086 static const char trackedphases[] = {1, 2, 32, 96};
1084 static const char trackedphases[] = {1, 2, 32, 96};
1087 PyObject *roots = Py_None;
1085 PyObject *roots = Py_None;
1088 PyObject *phasesetsdict = NULL;
1086 PyObject *phasesetsdict = NULL;
1089 PyObject *phasesets[4] = {NULL, NULL, NULL, NULL};
1087 PyObject *phasesets[4] = {NULL, NULL, NULL, NULL};
1090 Py_ssize_t len = index_length(self);
1088 Py_ssize_t len = index_length(self);
1091 char *phases = NULL;
1089 char *phases = NULL;
1092 int minphaserev = -1, rev, i;
1090 int minphaserev = -1, rev, i;
1093 const int numphases = (int)(sizeof(phasesets) / sizeof(phasesets[0]));
1091 const int numphases = (int)(sizeof(phasesets) / sizeof(phasesets[0]));
1094
1092
1095 if (!PyArg_ParseTuple(args, "O", &roots))
1093 if (!PyArg_ParseTuple(args, "O", &roots))
1096 return NULL;
1094 return NULL;
1097 if (roots == NULL || !PyDict_Check(roots)) {
1095 if (roots == NULL || !PyDict_Check(roots)) {
1098 PyErr_SetString(PyExc_TypeError, "roots must be a dictionary");
1096 PyErr_SetString(PyExc_TypeError, "roots must be a dictionary");
1099 return NULL;
1097 return NULL;
1100 }
1098 }
1101
1099
1102 phases = calloc(len, 1);
1100 phases = calloc(len, 1);
1103 if (phases == NULL) {
1101 if (phases == NULL) {
1104 PyErr_NoMemory();
1102 PyErr_NoMemory();
1105 return NULL;
1103 return NULL;
1106 }
1104 }
1107
1105
1108 for (i = 0; i < numphases; ++i) {
1106 for (i = 0; i < numphases; ++i) {
1109 PyObject *pyphase = PyLong_FromLong(trackedphases[i]);
1107 PyObject *pyphase = PyLong_FromLong(trackedphases[i]);
1110 PyObject *phaseroots = NULL;
1108 PyObject *phaseroots = NULL;
1111 if (pyphase == NULL)
1109 if (pyphase == NULL)
1112 goto release;
1110 goto release;
1113 phaseroots = PyDict_GetItem(roots, pyphase);
1111 phaseroots = PyDict_GetItem(roots, pyphase);
1114 Py_DECREF(pyphase);
1112 Py_DECREF(pyphase);
1115 if (phaseroots == NULL)
1113 if (phaseroots == NULL)
1116 continue;
1114 continue;
1117 rev = add_roots_get_min(self, phaseroots, phases,
1115 rev = add_roots_get_min(self, phaseroots, phases,
1118 trackedphases[i]);
1116 trackedphases[i]);
1119 if (rev == -2)
1117 if (rev == -2)
1120 goto release;
1118 goto release;
1121 if (rev != -1 && (minphaserev == -1 || rev < minphaserev))
1119 if (rev != -1 && (minphaserev == -1 || rev < minphaserev))
1122 minphaserev = rev;
1120 minphaserev = rev;
1123 }
1121 }
1124
1122
1125 for (i = 0; i < numphases; ++i) {
1123 for (i = 0; i < numphases; ++i) {
1126 phasesets[i] = PySet_New(NULL);
1124 phasesets[i] = PySet_New(NULL);
1127 if (phasesets[i] == NULL)
1125 if (phasesets[i] == NULL)
1128 goto release;
1126 goto release;
1129 }
1127 }
1130
1128
1131 if (minphaserev == -1)
1129 if (minphaserev == -1)
1132 minphaserev = len;
1130 minphaserev = len;
1133 for (rev = minphaserev; rev < len; ++rev) {
1131 for (rev = minphaserev; rev < len; ++rev) {
1134 PyObject *pyphase = NULL;
1132 PyObject *pyphase = NULL;
1135 PyObject *pyrev = NULL;
1133 PyObject *pyrev = NULL;
1136 int parents[2];
1134 int parents[2];
1137 /*
1135 /*
1138 * The parent lookup could be skipped for phaseroots, but
1136 * The parent lookup could be skipped for phaseroots, but
1139 * phase --force would historically not recompute them
1137 * phase --force would historically not recompute them
1140 * correctly, leaving descendents with a lower phase around.
1138 * correctly, leaving descendents with a lower phase around.
1141 * As such, unconditionally recompute the phase.
1139 * As such, unconditionally recompute the phase.
1142 */
1140 */
1143 if (index_get_parents(self, rev, parents, (int)len - 1) < 0)
1141 if (index_get_parents(self, rev, parents, (int)len - 1) < 0)
1144 goto release;
1142 goto release;
1145 set_phase_from_parents(phases, parents[0], parents[1], rev);
1143 set_phase_from_parents(phases, parents[0], parents[1], rev);
1146 switch (phases[rev]) {
1144 switch (phases[rev]) {
1147 case 0:
1145 case 0:
1148 continue;
1146 continue;
1149 case 1:
1147 case 1:
1150 pyphase = phasesets[0];
1148 pyphase = phasesets[0];
1151 break;
1149 break;
1152 case 2:
1150 case 2:
1153 pyphase = phasesets[1];
1151 pyphase = phasesets[1];
1154 break;
1152 break;
1155 case 32:
1153 case 32:
1156 pyphase = phasesets[2];
1154 pyphase = phasesets[2];
1157 break;
1155 break;
1158 case 96:
1156 case 96:
1159 pyphase = phasesets[3];
1157 pyphase = phasesets[3];
1160 break;
1158 break;
1161 default:
1159 default:
1162 /* this should never happen since the phase number is
1160 /* this should never happen since the phase number is
1163 * specified by this function. */
1161 * specified by this function. */
1164 PyErr_SetString(PyExc_SystemError,
1162 PyErr_SetString(PyExc_SystemError,
1165 "bad phase number in internal list");
1163 "bad phase number in internal list");
1166 goto release;
1164 goto release;
1167 }
1165 }
1168 pyrev = PyLong_FromLong(rev);
1166 pyrev = PyLong_FromLong(rev);
1169 if (pyrev == NULL)
1167 if (pyrev == NULL)
1170 goto release;
1168 goto release;
1171 if (PySet_Add(pyphase, pyrev) == -1) {
1169 if (PySet_Add(pyphase, pyrev) == -1) {
1172 Py_DECREF(pyrev);
1170 Py_DECREF(pyrev);
1173 goto release;
1171 goto release;
1174 }
1172 }
1175 Py_DECREF(pyrev);
1173 Py_DECREF(pyrev);
1176 }
1174 }
1177
1175
1178 phasesetsdict = _dict_new_presized(numphases);
1176 phasesetsdict = _dict_new_presized(numphases);
1179 if (phasesetsdict == NULL)
1177 if (phasesetsdict == NULL)
1180 goto release;
1178 goto release;
1181 for (i = 0; i < numphases; ++i) {
1179 for (i = 0; i < numphases; ++i) {
1182 PyObject *pyphase = PyLong_FromLong(trackedphases[i]);
1180 PyObject *pyphase = PyLong_FromLong(trackedphases[i]);
1183 if (pyphase == NULL)
1181 if (pyphase == NULL)
1184 goto release;
1182 goto release;
1185 if (PyDict_SetItem(phasesetsdict, pyphase, phasesets[i]) ==
1183 if (PyDict_SetItem(phasesetsdict, pyphase, phasesets[i]) ==
1186 -1) {
1184 -1) {
1187 Py_DECREF(pyphase);
1185 Py_DECREF(pyphase);
1188 goto release;
1186 goto release;
1189 }
1187 }
1190 Py_DECREF(phasesets[i]);
1188 Py_DECREF(phasesets[i]);
1191 phasesets[i] = NULL;
1189 phasesets[i] = NULL;
1192 }
1190 }
1193
1191
1194 free(phases);
1192 free(phases);
1195 return Py_BuildValue("nN", len, phasesetsdict);
1193 return Py_BuildValue("nN", len, phasesetsdict);
1196
1194
1197 release:
1195 release:
1198 for (i = 0; i < numphases; ++i)
1196 for (i = 0; i < numphases; ++i)
1199 Py_XDECREF(phasesets[i]);
1197 Py_XDECREF(phasesets[i]);
1200 Py_XDECREF(phasesetsdict);
1198 Py_XDECREF(phasesetsdict);
1201
1199
1202 free(phases);
1200 free(phases);
1203 return NULL;
1201 return NULL;
1204 }
1202 }
1205
1203
1206 static PyObject *index_headrevs(indexObject *self, PyObject *args)
1204 static PyObject *index_headrevs(indexObject *self, PyObject *args)
1207 {
1205 {
1208 Py_ssize_t i, j, len;
1206 Py_ssize_t i, j, len;
1209 char *nothead = NULL;
1207 char *nothead = NULL;
1210 PyObject *heads = NULL;
1208 PyObject *heads = NULL;
1211 PyObject *filter = NULL;
1209 PyObject *filter = NULL;
1212 PyObject *filteredrevs = Py_None;
1210 PyObject *filteredrevs = Py_None;
1213
1211
1214 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
1212 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
1215 return NULL;
1213 return NULL;
1216 }
1214 }
1217
1215
1218 if (self->headrevs && filteredrevs == self->filteredrevs)
1216 if (self->headrevs && filteredrevs == self->filteredrevs)
1219 return list_copy(self->headrevs);
1217 return list_copy(self->headrevs);
1220
1218
1221 Py_DECREF(self->filteredrevs);
1219 Py_DECREF(self->filteredrevs);
1222 self->filteredrevs = filteredrevs;
1220 self->filteredrevs = filteredrevs;
1223 Py_INCREF(filteredrevs);
1221 Py_INCREF(filteredrevs);
1224
1222
1225 if (filteredrevs != Py_None) {
1223 if (filteredrevs != Py_None) {
1226 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
1224 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
1227 if (!filter) {
1225 if (!filter) {
1228 PyErr_SetString(
1226 PyErr_SetString(
1229 PyExc_TypeError,
1227 PyExc_TypeError,
1230 "filteredrevs has no attribute __contains__");
1228 "filteredrevs has no attribute __contains__");
1231 goto bail;
1229 goto bail;
1232 }
1230 }
1233 }
1231 }
1234
1232
1235 len = index_length(self);
1233 len = index_length(self);
1236 heads = PyList_New(0);
1234 heads = PyList_New(0);
1237 if (heads == NULL)
1235 if (heads == NULL)
1238 goto bail;
1236 goto bail;
1239 if (len == 0) {
1237 if (len == 0) {
1240 PyObject *nullid = PyLong_FromLong(-1);
1238 PyObject *nullid = PyLong_FromLong(-1);
1241 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
1239 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
1242 Py_XDECREF(nullid);
1240 Py_XDECREF(nullid);
1243 goto bail;
1241 goto bail;
1244 }
1242 }
1245 goto done;
1243 goto done;
1246 }
1244 }
1247
1245
1248 nothead = calloc(len, 1);
1246 nothead = calloc(len, 1);
1249 if (nothead == NULL) {
1247 if (nothead == NULL) {
1250 PyErr_NoMemory();
1248 PyErr_NoMemory();
1251 goto bail;
1249 goto bail;
1252 }
1250 }
1253
1251
1254 for (i = len - 1; i >= 0; i--) {
1252 for (i = len - 1; i >= 0; i--) {
1255 int isfiltered;
1253 int isfiltered;
1256 int parents[2];
1254 int parents[2];
1257
1255
1258 /* If nothead[i] == 1, it means we've seen an unfiltered child
1256 /* If nothead[i] == 1, it means we've seen an unfiltered child
1259 * of this node already, and therefore this node is not
1257 * of this node already, and therefore this node is not
1260 * filtered. So we can skip the expensive check_filter step.
1258 * filtered. So we can skip the expensive check_filter step.
1261 */
1259 */
1262 if (nothead[i] != 1) {
1260 if (nothead[i] != 1) {
1263 isfiltered = check_filter(filter, i);
1261 isfiltered = check_filter(filter, i);
1264 if (isfiltered == -1) {
1262 if (isfiltered == -1) {
1265 PyErr_SetString(PyExc_TypeError,
1263 PyErr_SetString(PyExc_TypeError,
1266 "unable to check filter");
1264 "unable to check filter");
1267 goto bail;
1265 goto bail;
1268 }
1266 }
1269
1267
1270 if (isfiltered) {
1268 if (isfiltered) {
1271 nothead[i] = 1;
1269 nothead[i] = 1;
1272 continue;
1270 continue;
1273 }
1271 }
1274 }
1272 }
1275
1273
1276 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
1274 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
1277 goto bail;
1275 goto bail;
1278 for (j = 0; j < 2; j++) {
1276 for (j = 0; j < 2; j++) {
1279 if (parents[j] >= 0)
1277 if (parents[j] >= 0)
1280 nothead[parents[j]] = 1;
1278 nothead[parents[j]] = 1;
1281 }
1279 }
1282 }
1280 }
1283
1281
1284 for (i = 0; i < len; i++) {
1282 for (i = 0; i < len; i++) {
1285 PyObject *head;
1283 PyObject *head;
1286
1284
1287 if (nothead[i])
1285 if (nothead[i])
1288 continue;
1286 continue;
1289 head = PyLong_FromSsize_t(i);
1287 head = PyLong_FromSsize_t(i);
1290 if (head == NULL || PyList_Append(heads, head) == -1) {
1288 if (head == NULL || PyList_Append(heads, head) == -1) {
1291 Py_XDECREF(head);
1289 Py_XDECREF(head);
1292 goto bail;
1290 goto bail;
1293 }
1291 }
1294 }
1292 }
1295
1293
1296 done:
1294 done:
1297 self->headrevs = heads;
1295 self->headrevs = heads;
1298 Py_XDECREF(filter);
1296 Py_XDECREF(filter);
1299 free(nothead);
1297 free(nothead);
1300 return list_copy(self->headrevs);
1298 return list_copy(self->headrevs);
1301 bail:
1299 bail:
1302 Py_XDECREF(filter);
1300 Py_XDECREF(filter);
1303 Py_XDECREF(heads);
1301 Py_XDECREF(heads);
1304 free(nothead);
1302 free(nothead);
1305 return NULL;
1303 return NULL;
1306 }
1304 }
1307
1305
1308 /**
1306 /**
1309 * Obtain the base revision index entry.
1307 * Obtain the base revision index entry.
1310 *
1308 *
1311 * Callers must ensure that rev >= 0 or illegal memory access may occur.
1309 * Callers must ensure that rev >= 0 or illegal memory access may occur.
1312 */
1310 */
1313 static inline int index_baserev(indexObject *self, int rev)
1311 static inline int index_baserev(indexObject *self, int rev)
1314 {
1312 {
1315 const char *data;
1313 const char *data;
1316 int result;
1314 int result;
1317
1315
1318 data = index_deref(self, rev);
1316 data = index_deref(self, rev);
1319 if (data == NULL)
1317 if (data == NULL)
1320 return -2;
1318 return -2;
1321
1319
1322 if (self->format_version == format_v1) {
1320 if (self->format_version == format_v1) {
1323 result = getbe32(data + entry_v1_offset_base_rev);
1321 result = getbe32(data + entry_v1_offset_base_rev);
1324 } else if (self->format_version == format_v2) {
1322 } else if (self->format_version == format_v2) {
1325 result = getbe32(data + entry_v2_offset_base_rev);
1323 result = getbe32(data + entry_v2_offset_base_rev);
1326 } else if (self->format_version == format_cl2) {
1324 } else if (self->format_version == format_cl2) {
1327 return rev;
1325 return rev;
1328 } else {
1326 } else {
1329 raise_revlog_error();
1327 raise_revlog_error();
1330 return -1;
1328 return -1;
1331 }
1329 }
1332
1330
1333 if (result > rev) {
1331 if (result > rev) {
1334 PyErr_Format(
1332 PyErr_Format(
1335 PyExc_ValueError,
1333 PyExc_ValueError,
1336 "corrupted revlog, revision base above revision: %d, %d",
1334 "corrupted revlog, revision base above revision: %d, %d",
1337 rev, result);
1335 rev, result);
1338 return -2;
1336 return -2;
1339 }
1337 }
1340 if (result < -1) {
1338 if (result < -1) {
1341 PyErr_Format(
1339 PyErr_Format(
1342 PyExc_ValueError,
1340 PyExc_ValueError,
1343 "corrupted revlog, revision base out of range: %d, %d", rev,
1341 "corrupted revlog, revision base out of range: %d, %d", rev,
1344 result);
1342 result);
1345 return -2;
1343 return -2;
1346 }
1344 }
1347 return result;
1345 return result;
1348 }
1346 }
1349
1347
1350 /**
1348 /**
1351 * Find if a revision is a snapshot or not
1349 * Find if a revision is a snapshot or not
1352 *
1350 *
1353 * Only relevant for sparse-revlog case.
1351 * Only relevant for sparse-revlog case.
1354 * Callers must ensure that rev is in a valid range.
1352 * Callers must ensure that rev is in a valid range.
1355 */
1353 */
1356 static int index_issnapshotrev(indexObject *self, Py_ssize_t rev)
1354 static int index_issnapshotrev(indexObject *self, Py_ssize_t rev)
1357 {
1355 {
1358 int ps[2];
1356 int ps[2];
1359 Py_ssize_t base;
1357 Py_ssize_t base;
1360 while (rev >= 0) {
1358 while (rev >= 0) {
1361 base = (Py_ssize_t)index_baserev(self, rev);
1359 base = (Py_ssize_t)index_baserev(self, rev);
1362 if (base == rev) {
1360 if (base == rev) {
1363 base = -1;
1361 base = -1;
1364 }
1362 }
1365 if (base == -2) {
1363 if (base == -2) {
1366 assert(PyErr_Occurred());
1364 assert(PyErr_Occurred());
1367 return -1;
1365 return -1;
1368 }
1366 }
1369 if (base == -1) {
1367 if (base == -1) {
1370 return 1;
1368 return 1;
1371 }
1369 }
1372 if (index_get_parents(self, rev, ps, (int)rev) < 0) {
1370 if (index_get_parents(self, rev, ps, (int)rev) < 0) {
1373 assert(PyErr_Occurred());
1371 assert(PyErr_Occurred());
1374 return -1;
1372 return -1;
1375 };
1373 };
1376 if (base == ps[0] || base == ps[1]) {
1374 if (base == ps[0] || base == ps[1]) {
1377 return 0;
1375 return 0;
1378 }
1376 }
1379 rev = base;
1377 rev = base;
1380 }
1378 }
1381 return rev == -1;
1379 return rev == -1;
1382 }
1380 }
1383
1381
1384 static PyObject *index_issnapshot(indexObject *self, PyObject *value)
1382 static PyObject *index_issnapshot(indexObject *self, PyObject *value)
1385 {
1383 {
1386 long rev;
1384 long rev;
1387 int issnap;
1385 int issnap;
1388 Py_ssize_t length = index_length(self);
1386 Py_ssize_t length = index_length(self);
1389
1387
1390 if (!pylong_to_long(value, &rev)) {
1388 if (!pylong_to_long(value, &rev)) {
1391 return NULL;
1389 return NULL;
1392 }
1390 }
1393 if (rev < -1 || rev >= length) {
1391 if (rev < -1 || rev >= length) {
1394 PyErr_Format(PyExc_ValueError, "revlog index out of range: %ld",
1392 PyErr_Format(PyExc_ValueError, "revlog index out of range: %ld",
1395 rev);
1393 rev);
1396 return NULL;
1394 return NULL;
1397 };
1395 };
1398 issnap = index_issnapshotrev(self, (Py_ssize_t)rev);
1396 issnap = index_issnapshotrev(self, (Py_ssize_t)rev);
1399 if (issnap < 0) {
1397 if (issnap < 0) {
1400 return NULL;
1398 return NULL;
1401 };
1399 };
1402 return PyBool_FromLong((long)issnap);
1400 return PyBool_FromLong((long)issnap);
1403 }
1401 }
1404
1402
1405 static PyObject *index_findsnapshots(indexObject *self, PyObject *args)
1403 static PyObject *index_findsnapshots(indexObject *self, PyObject *args)
1406 {
1404 {
1407 Py_ssize_t start_rev;
1405 Py_ssize_t start_rev;
1408 PyObject *cache;
1406 PyObject *cache;
1409 Py_ssize_t base;
1407 Py_ssize_t base;
1410 Py_ssize_t rev;
1408 Py_ssize_t rev;
1411 PyObject *key = NULL;
1409 PyObject *key = NULL;
1412 PyObject *value = NULL;
1410 PyObject *value = NULL;
1413 const Py_ssize_t length = index_length(self);
1411 const Py_ssize_t length = index_length(self);
1414 if (!PyArg_ParseTuple(args, "O!n", &PyDict_Type, &cache, &start_rev)) {
1412 if (!PyArg_ParseTuple(args, "O!n", &PyDict_Type, &cache, &start_rev)) {
1415 return NULL;
1413 return NULL;
1416 }
1414 }
1417 for (rev = start_rev; rev < length; rev++) {
1415 for (rev = start_rev; rev < length; rev++) {
1418 int issnap;
1416 int issnap;
1419 PyObject *allvalues = NULL;
1417 PyObject *allvalues = NULL;
1420 issnap = index_issnapshotrev(self, rev);
1418 issnap = index_issnapshotrev(self, rev);
1421 if (issnap < 0) {
1419 if (issnap < 0) {
1422 goto bail;
1420 goto bail;
1423 }
1421 }
1424 if (issnap == 0) {
1422 if (issnap == 0) {
1425 continue;
1423 continue;
1426 }
1424 }
1427 base = (Py_ssize_t)index_baserev(self, rev);
1425 base = (Py_ssize_t)index_baserev(self, rev);
1428 if (base == rev) {
1426 if (base == rev) {
1429 base = -1;
1427 base = -1;
1430 }
1428 }
1431 if (base == -2) {
1429 if (base == -2) {
1432 assert(PyErr_Occurred());
1430 assert(PyErr_Occurred());
1433 goto bail;
1431 goto bail;
1434 }
1432 }
1435 key = PyLong_FromSsize_t(base);
1433 key = PyLong_FromSsize_t(base);
1436 allvalues = PyDict_GetItem(cache, key);
1434 allvalues = PyDict_GetItem(cache, key);
1437 if (allvalues == NULL && PyErr_Occurred()) {
1435 if (allvalues == NULL && PyErr_Occurred()) {
1438 goto bail;
1436 goto bail;
1439 }
1437 }
1440 if (allvalues == NULL) {
1438 if (allvalues == NULL) {
1441 int r;
1439 int r;
1442 allvalues = PyList_New(0);
1440 allvalues = PyList_New(0);
1443 if (!allvalues) {
1441 if (!allvalues) {
1444 goto bail;
1442 goto bail;
1445 }
1443 }
1446 r = PyDict_SetItem(cache, key, allvalues);
1444 r = PyDict_SetItem(cache, key, allvalues);
1447 Py_DECREF(allvalues);
1445 Py_DECREF(allvalues);
1448 if (r < 0) {
1446 if (r < 0) {
1449 goto bail;
1447 goto bail;
1450 }
1448 }
1451 }
1449 }
1452 value = PyLong_FromSsize_t(rev);
1450 value = PyLong_FromSsize_t(rev);
1453 if (PyList_Append(allvalues, value)) {
1451 if (PyList_Append(allvalues, value)) {
1454 goto bail;
1452 goto bail;
1455 }
1453 }
1456 Py_CLEAR(key);
1454 Py_CLEAR(key);
1457 Py_CLEAR(value);
1455 Py_CLEAR(value);
1458 }
1456 }
1459 Py_RETURN_NONE;
1457 Py_RETURN_NONE;
1460 bail:
1458 bail:
1461 Py_XDECREF(key);
1459 Py_XDECREF(key);
1462 Py_XDECREF(value);
1460 Py_XDECREF(value);
1463 return NULL;
1461 return NULL;
1464 }
1462 }
1465
1463
1466 static PyObject *index_deltachain(indexObject *self, PyObject *args)
1464 static PyObject *index_deltachain(indexObject *self, PyObject *args)
1467 {
1465 {
1468 int rev, generaldelta;
1466 int rev, generaldelta;
1469 PyObject *stoparg;
1467 PyObject *stoparg;
1470 int stoprev, iterrev, baserev = -1;
1468 int stoprev, iterrev, baserev = -1;
1471 int stopped;
1469 int stopped;
1472 PyObject *chain = NULL, *result = NULL;
1470 PyObject *chain = NULL, *result = NULL;
1473 const Py_ssize_t length = index_length(self);
1471 const Py_ssize_t length = index_length(self);
1474
1472
1475 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
1473 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
1476 return NULL;
1474 return NULL;
1477 }
1475 }
1478
1476
1479 if (PyLong_Check(stoparg)) {
1477 if (PyLong_Check(stoparg)) {
1480 stoprev = (int)PyLong_AsLong(stoparg);
1478 stoprev = (int)PyLong_AsLong(stoparg);
1481 if (stoprev == -1 && PyErr_Occurred()) {
1479 if (stoprev == -1 && PyErr_Occurred()) {
1482 return NULL;
1480 return NULL;
1483 }
1481 }
1484 } else if (stoparg == Py_None) {
1482 } else if (stoparg == Py_None) {
1485 stoprev = -2;
1483 stoprev = -2;
1486 } else {
1484 } else {
1487 PyErr_SetString(PyExc_ValueError,
1485 PyErr_SetString(PyExc_ValueError,
1488 "stoprev must be integer or None");
1486 "stoprev must be integer or None");
1489 return NULL;
1487 return NULL;
1490 }
1488 }
1491
1489
1492 if (rev < 0 || rev >= length) {
1490 if (rev < 0 || rev >= length) {
1493 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1491 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1494 return NULL;
1492 return NULL;
1495 }
1493 }
1496
1494
1497 chain = PyList_New(0);
1495 chain = PyList_New(0);
1498 if (chain == NULL) {
1496 if (chain == NULL) {
1499 return NULL;
1497 return NULL;
1500 }
1498 }
1501
1499
1502 baserev = index_baserev(self, rev);
1500 baserev = index_baserev(self, rev);
1503
1501
1504 /* This should never happen. */
1502 /* This should never happen. */
1505 if (baserev <= -2) {
1503 if (baserev <= -2) {
1506 /* Error should be set by index_deref() */
1504 /* Error should be set by index_deref() */
1507 assert(PyErr_Occurred());
1505 assert(PyErr_Occurred());
1508 goto bail;
1506 goto bail;
1509 }
1507 }
1510
1508
1511 iterrev = rev;
1509 iterrev = rev;
1512
1510
1513 while (iterrev != baserev && iterrev != stoprev) {
1511 while (iterrev != baserev && iterrev != stoprev) {
1514 PyObject *value = PyLong_FromLong(iterrev);
1512 PyObject *value = PyLong_FromLong(iterrev);
1515 if (value == NULL) {
1513 if (value == NULL) {
1516 goto bail;
1514 goto bail;
1517 }
1515 }
1518 if (PyList_Append(chain, value)) {
1516 if (PyList_Append(chain, value)) {
1519 Py_DECREF(value);
1517 Py_DECREF(value);
1520 goto bail;
1518 goto bail;
1521 }
1519 }
1522 Py_DECREF(value);
1520 Py_DECREF(value);
1523
1521
1524 if (generaldelta) {
1522 if (generaldelta) {
1525 iterrev = baserev;
1523 iterrev = baserev;
1526 } else {
1524 } else {
1527 iterrev--;
1525 iterrev--;
1528 }
1526 }
1529
1527
1530 if (iterrev < 0) {
1528 if (iterrev < 0) {
1531 break;
1529 break;
1532 }
1530 }
1533
1531
1534 if (iterrev >= length) {
1532 if (iterrev >= length) {
1535 PyErr_SetString(PyExc_IndexError,
1533 PyErr_SetString(PyExc_IndexError,
1536 "revision outside index");
1534 "revision outside index");
1537 return NULL;
1535 return NULL;
1538 }
1536 }
1539
1537
1540 baserev = index_baserev(self, iterrev);
1538 baserev = index_baserev(self, iterrev);
1541
1539
1542 /* This should never happen. */
1540 /* This should never happen. */
1543 if (baserev <= -2) {
1541 if (baserev <= -2) {
1544 /* Error should be set by index_deref() */
1542 /* Error should be set by index_deref() */
1545 assert(PyErr_Occurred());
1543 assert(PyErr_Occurred());
1546 goto bail;
1544 goto bail;
1547 }
1545 }
1548 }
1546 }
1549
1547
1550 if (iterrev == stoprev) {
1548 if (iterrev == stoprev) {
1551 stopped = 1;
1549 stopped = 1;
1552 } else {
1550 } else {
1553 PyObject *value = PyLong_FromLong(iterrev);
1551 PyObject *value = PyLong_FromLong(iterrev);
1554 if (value == NULL) {
1552 if (value == NULL) {
1555 goto bail;
1553 goto bail;
1556 }
1554 }
1557 if (PyList_Append(chain, value)) {
1555 if (PyList_Append(chain, value)) {
1558 Py_DECREF(value);
1556 Py_DECREF(value);
1559 goto bail;
1557 goto bail;
1560 }
1558 }
1561 Py_DECREF(value);
1559 Py_DECREF(value);
1562
1560
1563 stopped = 0;
1561 stopped = 0;
1564 }
1562 }
1565
1563
1566 if (PyList_Reverse(chain)) {
1564 if (PyList_Reverse(chain)) {
1567 goto bail;
1565 goto bail;
1568 }
1566 }
1569
1567
1570 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
1568 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
1571 Py_DECREF(chain);
1569 Py_DECREF(chain);
1572 return result;
1570 return result;
1573
1571
1574 bail:
1572 bail:
1575 Py_DECREF(chain);
1573 Py_DECREF(chain);
1576 return NULL;
1574 return NULL;
1577 }
1575 }
1578
1576
1579 static inline int64_t
1577 static inline int64_t
1580 index_segment_span(indexObject *self, Py_ssize_t start_rev, Py_ssize_t end_rev)
1578 index_segment_span(indexObject *self, Py_ssize_t start_rev, Py_ssize_t end_rev)
1581 {
1579 {
1582 int64_t start_offset;
1580 int64_t start_offset;
1583 int64_t end_offset;
1581 int64_t end_offset;
1584 int end_size;
1582 int end_size;
1585 start_offset = index_get_start(self, start_rev);
1583 start_offset = index_get_start(self, start_rev);
1586 if (start_offset < 0) {
1584 if (start_offset < 0) {
1587 return -1;
1585 return -1;
1588 }
1586 }
1589 end_offset = index_get_start(self, end_rev);
1587 end_offset = index_get_start(self, end_rev);
1590 if (end_offset < 0) {
1588 if (end_offset < 0) {
1591 return -1;
1589 return -1;
1592 }
1590 }
1593 end_size = index_get_length(self, end_rev);
1591 end_size = index_get_length(self, end_rev);
1594 if (end_size < 0) {
1592 if (end_size < 0) {
1595 return -1;
1593 return -1;
1596 }
1594 }
1597 if (end_offset < start_offset) {
1595 if (end_offset < start_offset) {
1598 PyErr_Format(PyExc_ValueError,
1596 PyErr_Format(PyExc_ValueError,
1599 "corrupted revlog index: inconsistent offset "
1597 "corrupted revlog index: inconsistent offset "
1600 "between revisions (%zd) and (%zd)",
1598 "between revisions (%zd) and (%zd)",
1601 start_rev, end_rev);
1599 start_rev, end_rev);
1602 return -1;
1600 return -1;
1603 }
1601 }
1604 return (end_offset - start_offset) + (int64_t)end_size;
1602 return (end_offset - start_offset) + (int64_t)end_size;
1605 }
1603 }
1606
1604
1607 /* returns endidx so that revs[startidx:endidx] has no empty trailing revs */
1605 /* returns endidx so that revs[startidx:endidx] has no empty trailing revs */
1608 static Py_ssize_t trim_endidx(indexObject *self, const Py_ssize_t *revs,
1606 static Py_ssize_t trim_endidx(indexObject *self, const Py_ssize_t *revs,
1609 Py_ssize_t startidx, Py_ssize_t endidx)
1607 Py_ssize_t startidx, Py_ssize_t endidx)
1610 {
1608 {
1611 int length;
1609 int length;
1612 while (endidx > 1 && endidx > startidx) {
1610 while (endidx > 1 && endidx > startidx) {
1613 length = index_get_length(self, revs[endidx - 1]);
1611 length = index_get_length(self, revs[endidx - 1]);
1614 if (length < 0) {
1612 if (length < 0) {
1615 return -1;
1613 return -1;
1616 }
1614 }
1617 if (length != 0) {
1615 if (length != 0) {
1618 break;
1616 break;
1619 }
1617 }
1620 endidx -= 1;
1618 endidx -= 1;
1621 }
1619 }
1622 return endidx;
1620 return endidx;
1623 }
1621 }
1624
1622
1625 struct Gap {
1623 struct Gap {
1626 int64_t size;
1624 int64_t size;
1627 Py_ssize_t idx;
1625 Py_ssize_t idx;
1628 };
1626 };
1629
1627
1630 static int gap_compare(const void *left, const void *right)
1628 static int gap_compare(const void *left, const void *right)
1631 {
1629 {
1632 const struct Gap *l_left = ((const struct Gap *)left);
1630 const struct Gap *l_left = ((const struct Gap *)left);
1633 const struct Gap *l_right = ((const struct Gap *)right);
1631 const struct Gap *l_right = ((const struct Gap *)right);
1634 if (l_left->size < l_right->size) {
1632 if (l_left->size < l_right->size) {
1635 return -1;
1633 return -1;
1636 } else if (l_left->size > l_right->size) {
1634 } else if (l_left->size > l_right->size) {
1637 return 1;
1635 return 1;
1638 }
1636 }
1639 return 0;
1637 return 0;
1640 }
1638 }
1641 static int Py_ssize_t_compare(const void *left, const void *right)
1639 static int Py_ssize_t_compare(const void *left, const void *right)
1642 {
1640 {
1643 const Py_ssize_t l_left = *(const Py_ssize_t *)left;
1641 const Py_ssize_t l_left = *(const Py_ssize_t *)left;
1644 const Py_ssize_t l_right = *(const Py_ssize_t *)right;
1642 const Py_ssize_t l_right = *(const Py_ssize_t *)right;
1645 if (l_left < l_right) {
1643 if (l_left < l_right) {
1646 return -1;
1644 return -1;
1647 } else if (l_left > l_right) {
1645 } else if (l_left > l_right) {
1648 return 1;
1646 return 1;
1649 }
1647 }
1650 return 0;
1648 return 0;
1651 }
1649 }
1652
1650
1653 static PyObject *index_slicechunktodensity(indexObject *self, PyObject *args)
1651 static PyObject *index_slicechunktodensity(indexObject *self, PyObject *args)
1654 {
1652 {
1655 /* method arguments */
1653 /* method arguments */
1656 PyObject *list_revs = NULL; /* revisions in the chain */
1654 PyObject *list_revs = NULL; /* revisions in the chain */
1657 double targetdensity = 0; /* min density to achieve */
1655 double targetdensity = 0; /* min density to achieve */
1658 Py_ssize_t mingapsize = 0; /* threshold to ignore gaps */
1656 Py_ssize_t mingapsize = 0; /* threshold to ignore gaps */
1659
1657
1660 /* other core variables */
1658 /* other core variables */
1661 Py_ssize_t idxlen = index_length(self);
1659 Py_ssize_t idxlen = index_length(self);
1662 Py_ssize_t i; /* used for various iteration */
1660 Py_ssize_t i; /* used for various iteration */
1663 PyObject *result = NULL; /* the final return of the function */
1661 PyObject *result = NULL; /* the final return of the function */
1664
1662
1665 /* generic information about the delta chain being slice */
1663 /* generic information about the delta chain being slice */
1666 Py_ssize_t num_revs = 0; /* size of the full delta chain */
1664 Py_ssize_t num_revs = 0; /* size of the full delta chain */
1667 Py_ssize_t *revs = NULL; /* native array of revision in the chain */
1665 Py_ssize_t *revs = NULL; /* native array of revision in the chain */
1668 int64_t chainpayload = 0; /* sum of all delta in the chain */
1666 int64_t chainpayload = 0; /* sum of all delta in the chain */
1669 int64_t deltachainspan = 0; /* distance from first byte to last byte */
1667 int64_t deltachainspan = 0; /* distance from first byte to last byte */
1670
1668
1671 /* variable used for slicing the delta chain */
1669 /* variable used for slicing the delta chain */
1672 int64_t readdata = 0; /* amount of data currently planned to be read */
1670 int64_t readdata = 0; /* amount of data currently planned to be read */
1673 double density = 0; /* ration of payload data compared to read ones */
1671 double density = 0; /* ration of payload data compared to read ones */
1674 int64_t previous_end;
1672 int64_t previous_end;
1675 struct Gap *gaps = NULL; /* array of notable gap in the chain */
1673 struct Gap *gaps = NULL; /* array of notable gap in the chain */
1676 Py_ssize_t num_gaps =
1674 Py_ssize_t num_gaps =
1677 0; /* total number of notable gap recorded so far */
1675 0; /* total number of notable gap recorded so far */
1678 Py_ssize_t *selected_indices = NULL; /* indices of gap skipped over */
1676 Py_ssize_t *selected_indices = NULL; /* indices of gap skipped over */
1679 Py_ssize_t num_selected = 0; /* number of gaps skipped */
1677 Py_ssize_t num_selected = 0; /* number of gaps skipped */
1680 PyObject *chunk = NULL; /* individual slice */
1678 PyObject *chunk = NULL; /* individual slice */
1681 PyObject *allchunks = NULL; /* all slices */
1679 PyObject *allchunks = NULL; /* all slices */
1682 Py_ssize_t previdx;
1680 Py_ssize_t previdx;
1683
1681
1684 /* parsing argument */
1682 /* parsing argument */
1685 if (!PyArg_ParseTuple(args, "O!dn", &PyList_Type, &list_revs,
1683 if (!PyArg_ParseTuple(args, "O!dn", &PyList_Type, &list_revs,
1686 &targetdensity, &mingapsize)) {
1684 &targetdensity, &mingapsize)) {
1687 goto bail;
1685 goto bail;
1688 }
1686 }
1689
1687
1690 /* If the delta chain contains a single element, we do not need slicing
1688 /* If the delta chain contains a single element, we do not need slicing
1691 */
1689 */
1692 num_revs = PyList_GET_SIZE(list_revs);
1690 num_revs = PyList_GET_SIZE(list_revs);
1693 if (num_revs <= 1) {
1691 if (num_revs <= 1) {
1694 result = PyTuple_Pack(1, list_revs);
1692 result = PyTuple_Pack(1, list_revs);
1695 goto done;
1693 goto done;
1696 }
1694 }
1697
1695
1698 /* Turn the python list into a native integer array (for efficiency) */
1696 /* Turn the python list into a native integer array (for efficiency) */
1699 revs = (Py_ssize_t *)calloc(num_revs, sizeof(Py_ssize_t));
1697 revs = (Py_ssize_t *)calloc(num_revs, sizeof(Py_ssize_t));
1700 if (revs == NULL) {
1698 if (revs == NULL) {
1701 PyErr_NoMemory();
1699 PyErr_NoMemory();
1702 goto bail;
1700 goto bail;
1703 }
1701 }
1704 for (i = 0; i < num_revs; i++) {
1702 for (i = 0; i < num_revs; i++) {
1705 Py_ssize_t revnum =
1703 Py_ssize_t revnum =
1706 PyLong_AsLong(PyList_GET_ITEM(list_revs, i));
1704 PyLong_AsLong(PyList_GET_ITEM(list_revs, i));
1707 if (revnum == -1 && PyErr_Occurred()) {
1705 if (revnum == -1 && PyErr_Occurred()) {
1708 goto bail;
1706 goto bail;
1709 }
1707 }
1710 if (revnum < nullrev || revnum >= idxlen) {
1708 if (revnum < nullrev || revnum >= idxlen) {
1711 PyErr_Format(PyExc_IndexError,
1709 PyErr_Format(PyExc_IndexError,
1712 "index out of range: %zd", revnum);
1710 "index out of range: %zd", revnum);
1713 goto bail;
1711 goto bail;
1714 }
1712 }
1715 revs[i] = revnum;
1713 revs[i] = revnum;
1716 }
1714 }
1717
1715
1718 /* Compute and check various property of the unsliced delta chain */
1716 /* Compute and check various property of the unsliced delta chain */
1719 deltachainspan = index_segment_span(self, revs[0], revs[num_revs - 1]);
1717 deltachainspan = index_segment_span(self, revs[0], revs[num_revs - 1]);
1720 if (deltachainspan < 0) {
1718 if (deltachainspan < 0) {
1721 goto bail;
1719 goto bail;
1722 }
1720 }
1723
1721
1724 if (deltachainspan <= mingapsize) {
1722 if (deltachainspan <= mingapsize) {
1725 result = PyTuple_Pack(1, list_revs);
1723 result = PyTuple_Pack(1, list_revs);
1726 goto done;
1724 goto done;
1727 }
1725 }
1728 chainpayload = 0;
1726 chainpayload = 0;
1729 for (i = 0; i < num_revs; i++) {
1727 for (i = 0; i < num_revs; i++) {
1730 int tmp = index_get_length(self, revs[i]);
1728 int tmp = index_get_length(self, revs[i]);
1731 if (tmp < 0) {
1729 if (tmp < 0) {
1732 goto bail;
1730 goto bail;
1733 }
1731 }
1734 chainpayload += tmp;
1732 chainpayload += tmp;
1735 }
1733 }
1736
1734
1737 readdata = deltachainspan;
1735 readdata = deltachainspan;
1738 density = 1.0;
1736 density = 1.0;
1739
1737
1740 if (0 < deltachainspan) {
1738 if (0 < deltachainspan) {
1741 density = (double)chainpayload / (double)deltachainspan;
1739 density = (double)chainpayload / (double)deltachainspan;
1742 }
1740 }
1743
1741
1744 if (density >= targetdensity) {
1742 if (density >= targetdensity) {
1745 result = PyTuple_Pack(1, list_revs);
1743 result = PyTuple_Pack(1, list_revs);
1746 goto done;
1744 goto done;
1747 }
1745 }
1748
1746
1749 /* if chain is too sparse, look for relevant gaps */
1747 /* if chain is too sparse, look for relevant gaps */
1750 gaps = (struct Gap *)calloc(num_revs, sizeof(struct Gap));
1748 gaps = (struct Gap *)calloc(num_revs, sizeof(struct Gap));
1751 if (gaps == NULL) {
1749 if (gaps == NULL) {
1752 PyErr_NoMemory();
1750 PyErr_NoMemory();
1753 goto bail;
1751 goto bail;
1754 }
1752 }
1755
1753
1756 previous_end = -1;
1754 previous_end = -1;
1757 for (i = 0; i < num_revs; i++) {
1755 for (i = 0; i < num_revs; i++) {
1758 int64_t revstart;
1756 int64_t revstart;
1759 int revsize;
1757 int revsize;
1760 revstart = index_get_start(self, revs[i]);
1758 revstart = index_get_start(self, revs[i]);
1761 if (revstart < 0) {
1759 if (revstart < 0) {
1762 goto bail;
1760 goto bail;
1763 };
1761 };
1764 revsize = index_get_length(self, revs[i]);
1762 revsize = index_get_length(self, revs[i]);
1765 if (revsize < 0) {
1763 if (revsize < 0) {
1766 goto bail;
1764 goto bail;
1767 };
1765 };
1768 if (revsize == 0) {
1766 if (revsize == 0) {
1769 continue;
1767 continue;
1770 }
1768 }
1771 if (previous_end >= 0) {
1769 if (previous_end >= 0) {
1772 int64_t gapsize = revstart - previous_end;
1770 int64_t gapsize = revstart - previous_end;
1773 if (gapsize > mingapsize) {
1771 if (gapsize > mingapsize) {
1774 gaps[num_gaps].size = gapsize;
1772 gaps[num_gaps].size = gapsize;
1775 gaps[num_gaps].idx = i;
1773 gaps[num_gaps].idx = i;
1776 num_gaps += 1;
1774 num_gaps += 1;
1777 }
1775 }
1778 }
1776 }
1779 previous_end = revstart + revsize;
1777 previous_end = revstart + revsize;
1780 }
1778 }
1781 if (num_gaps == 0) {
1779 if (num_gaps == 0) {
1782 result = PyTuple_Pack(1, list_revs);
1780 result = PyTuple_Pack(1, list_revs);
1783 goto done;
1781 goto done;
1784 }
1782 }
1785 qsort(gaps, num_gaps, sizeof(struct Gap), &gap_compare);
1783 qsort(gaps, num_gaps, sizeof(struct Gap), &gap_compare);
1786
1784
1787 /* Slice the largest gap first, they improve the density the most */
1785 /* Slice the largest gap first, they improve the density the most */
1788 selected_indices =
1786 selected_indices =
1789 (Py_ssize_t *)malloc((num_gaps + 1) * sizeof(Py_ssize_t));
1787 (Py_ssize_t *)malloc((num_gaps + 1) * sizeof(Py_ssize_t));
1790 if (selected_indices == NULL) {
1788 if (selected_indices == NULL) {
1791 PyErr_NoMemory();
1789 PyErr_NoMemory();
1792 goto bail;
1790 goto bail;
1793 }
1791 }
1794
1792
1795 for (i = num_gaps - 1; i >= 0; i--) {
1793 for (i = num_gaps - 1; i >= 0; i--) {
1796 selected_indices[num_selected] = gaps[i].idx;
1794 selected_indices[num_selected] = gaps[i].idx;
1797 readdata -= gaps[i].size;
1795 readdata -= gaps[i].size;
1798 num_selected += 1;
1796 num_selected += 1;
1799 if (readdata <= 0) {
1797 if (readdata <= 0) {
1800 density = 1.0;
1798 density = 1.0;
1801 } else {
1799 } else {
1802 density = (double)chainpayload / (double)readdata;
1800 density = (double)chainpayload / (double)readdata;
1803 }
1801 }
1804 if (density >= targetdensity) {
1802 if (density >= targetdensity) {
1805 break;
1803 break;
1806 }
1804 }
1807 }
1805 }
1808 qsort(selected_indices, num_selected, sizeof(Py_ssize_t),
1806 qsort(selected_indices, num_selected, sizeof(Py_ssize_t),
1809 &Py_ssize_t_compare);
1807 &Py_ssize_t_compare);
1810
1808
1811 /* create the resulting slice */
1809 /* create the resulting slice */
1812 allchunks = PyList_New(0);
1810 allchunks = PyList_New(0);
1813 if (allchunks == NULL) {
1811 if (allchunks == NULL) {
1814 goto bail;
1812 goto bail;
1815 }
1813 }
1816 previdx = 0;
1814 previdx = 0;
1817 selected_indices[num_selected] = num_revs;
1815 selected_indices[num_selected] = num_revs;
1818 for (i = 0; i <= num_selected; i++) {
1816 for (i = 0; i <= num_selected; i++) {
1819 Py_ssize_t idx = selected_indices[i];
1817 Py_ssize_t idx = selected_indices[i];
1820 Py_ssize_t endidx = trim_endidx(self, revs, previdx, idx);
1818 Py_ssize_t endidx = trim_endidx(self, revs, previdx, idx);
1821 if (endidx < 0) {
1819 if (endidx < 0) {
1822 goto bail;
1820 goto bail;
1823 }
1821 }
1824 if (previdx < endidx) {
1822 if (previdx < endidx) {
1825 chunk = PyList_GetSlice(list_revs, previdx, endidx);
1823 chunk = PyList_GetSlice(list_revs, previdx, endidx);
1826 if (chunk == NULL) {
1824 if (chunk == NULL) {
1827 goto bail;
1825 goto bail;
1828 }
1826 }
1829 if (PyList_Append(allchunks, chunk) == -1) {
1827 if (PyList_Append(allchunks, chunk) == -1) {
1830 goto bail;
1828 goto bail;
1831 }
1829 }
1832 Py_DECREF(chunk);
1830 Py_DECREF(chunk);
1833 chunk = NULL;
1831 chunk = NULL;
1834 }
1832 }
1835 previdx = idx;
1833 previdx = idx;
1836 }
1834 }
1837 result = allchunks;
1835 result = allchunks;
1838 goto done;
1836 goto done;
1839
1837
1840 bail:
1838 bail:
1841 Py_XDECREF(allchunks);
1839 Py_XDECREF(allchunks);
1842 Py_XDECREF(chunk);
1840 Py_XDECREF(chunk);
1843 done:
1841 done:
1844 free(revs);
1842 free(revs);
1845 free(gaps);
1843 free(gaps);
1846 free(selected_indices);
1844 free(selected_indices);
1847 return result;
1845 return result;
1848 }
1846 }
1849
1847
1850 static inline int nt_level(const char *node, Py_ssize_t level)
1848 static inline int nt_level(const char *node, Py_ssize_t level)
1851 {
1849 {
1852 int v = node[level >> 1];
1850 int v = node[level >> 1];
1853 if (!(level & 1))
1851 if (!(level & 1))
1854 v >>= 4;
1852 v >>= 4;
1855 return v & 0xf;
1853 return v & 0xf;
1856 }
1854 }
1857
1855
1858 /*
1856 /*
1859 * Return values:
1857 * Return values:
1860 *
1858 *
1861 * -4: match is ambiguous (multiple candidates)
1859 * -4: match is ambiguous (multiple candidates)
1862 * -2: not found
1860 * -2: not found
1863 * rest: valid rev
1861 * rest: valid rev
1864 */
1862 */
1865 static int nt_find(nodetree *self, const char *node, Py_ssize_t nodelen,
1863 static int nt_find(nodetree *self, const char *node, Py_ssize_t nodelen,
1866 int hex)
1864 int hex)
1867 {
1865 {
1868 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1866 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1869 int level, maxlevel, off;
1867 int level, maxlevel, off;
1870
1868
1871 /* If the input is binary, do a fast check for the nullid first. */
1869 /* If the input is binary, do a fast check for the nullid first. */
1872 if (!hex && nodelen == self->nodelen && node[0] == '\0' &&
1870 if (!hex && nodelen == self->nodelen && node[0] == '\0' &&
1873 node[1] == '\0' && memcmp(node, nullid, self->nodelen) == 0)
1871 node[1] == '\0' && memcmp(node, nullid, self->nodelen) == 0)
1874 return -1;
1872 return -1;
1875
1873
1876 if (hex)
1874 if (hex)
1877 maxlevel = nodelen;
1875 maxlevel = nodelen;
1878 else
1876 else
1879 maxlevel = 2 * nodelen;
1877 maxlevel = 2 * nodelen;
1880 if (maxlevel > 2 * self->nodelen)
1878 if (maxlevel > 2 * self->nodelen)
1881 maxlevel = 2 * self->nodelen;
1879 maxlevel = 2 * self->nodelen;
1882
1880
1883 for (level = off = 0; level < maxlevel; level++) {
1881 for (level = off = 0; level < maxlevel; level++) {
1884 int k = getnybble(node, level);
1882 int k = getnybble(node, level);
1885 nodetreenode *n = &self->nodes[off];
1883 nodetreenode *n = &self->nodes[off];
1886 int v = n->children[k];
1884 int v = n->children[k];
1887
1885
1888 if (v < 0) {
1886 if (v < 0) {
1889 const char *n;
1887 const char *n;
1890 Py_ssize_t i;
1888 Py_ssize_t i;
1891
1889
1892 v = -(v + 2);
1890 v = -(v + 2);
1893 n = index_node(self->index, v);
1891 n = index_node(self->index, v);
1894 if (n == NULL)
1892 if (n == NULL)
1895 return -2;
1893 return -2;
1896 for (i = level; i < maxlevel; i++)
1894 for (i = level; i < maxlevel; i++)
1897 if (getnybble(node, i) != nt_level(n, i))
1895 if (getnybble(node, i) != nt_level(n, i))
1898 return -2;
1896 return -2;
1899 return v;
1897 return v;
1900 }
1898 }
1901 if (v == 0)
1899 if (v == 0)
1902 return -2;
1900 return -2;
1903 off = v;
1901 off = v;
1904 }
1902 }
1905 /* multiple matches against an ambiguous prefix */
1903 /* multiple matches against an ambiguous prefix */
1906 return -4;
1904 return -4;
1907 }
1905 }
1908
1906
1909 static int nt_new(nodetree *self)
1907 static int nt_new(nodetree *self)
1910 {
1908 {
1911 if (self->length == self->capacity) {
1909 if (self->length == self->capacity) {
1912 size_t newcapacity;
1910 size_t newcapacity;
1913 nodetreenode *newnodes;
1911 nodetreenode *newnodes;
1914 newcapacity = self->capacity * 2;
1912 newcapacity = self->capacity * 2;
1915 if (newcapacity >= SIZE_MAX / sizeof(nodetreenode)) {
1913 if (newcapacity >= SIZE_MAX / sizeof(nodetreenode)) {
1916 PyErr_SetString(PyExc_MemoryError,
1914 PyErr_SetString(PyExc_MemoryError,
1917 "overflow in nt_new");
1915 "overflow in nt_new");
1918 return -1;
1916 return -1;
1919 }
1917 }
1920 newnodes =
1918 newnodes =
1921 realloc(self->nodes, newcapacity * sizeof(nodetreenode));
1919 realloc(self->nodes, newcapacity * sizeof(nodetreenode));
1922 if (newnodes == NULL) {
1920 if (newnodes == NULL) {
1923 PyErr_SetString(PyExc_MemoryError, "out of memory");
1921 PyErr_SetString(PyExc_MemoryError, "out of memory");
1924 return -1;
1922 return -1;
1925 }
1923 }
1926 self->capacity = newcapacity;
1924 self->capacity = newcapacity;
1927 self->nodes = newnodes;
1925 self->nodes = newnodes;
1928 memset(&self->nodes[self->length], 0,
1926 memset(&self->nodes[self->length], 0,
1929 sizeof(nodetreenode) * (self->capacity - self->length));
1927 sizeof(nodetreenode) * (self->capacity - self->length));
1930 }
1928 }
1931 return self->length++;
1929 return self->length++;
1932 }
1930 }
1933
1931
1934 static int nt_insert(nodetree *self, const char *node, int rev)
1932 static int nt_insert(nodetree *self, const char *node, int rev)
1935 {
1933 {
1936 int level = 0;
1934 int level = 0;
1937 int off = 0;
1935 int off = 0;
1938
1936
1939 while (level < 2 * self->nodelen) {
1937 while (level < 2 * self->nodelen) {
1940 int k = nt_level(node, level);
1938 int k = nt_level(node, level);
1941 nodetreenode *n;
1939 nodetreenode *n;
1942 int v;
1940 int v;
1943
1941
1944 n = &self->nodes[off];
1942 n = &self->nodes[off];
1945 v = n->children[k];
1943 v = n->children[k];
1946
1944
1947 if (v == 0) {
1945 if (v == 0) {
1948 n->children[k] = -rev - 2;
1946 n->children[k] = -rev - 2;
1949 return 0;
1947 return 0;
1950 }
1948 }
1951 if (v < 0) {
1949 if (v < 0) {
1952 const char *oldnode =
1950 const char *oldnode =
1953 index_node_existing(self->index, -(v + 2));
1951 index_node_existing(self->index, -(v + 2));
1954 int noff;
1952 int noff;
1955
1953
1956 if (oldnode == NULL)
1954 if (oldnode == NULL)
1957 return -1;
1955 return -1;
1958 if (!memcmp(oldnode, node, self->nodelen)) {
1956 if (!memcmp(oldnode, node, self->nodelen)) {
1959 n->children[k] = -rev - 2;
1957 n->children[k] = -rev - 2;
1960 return 0;
1958 return 0;
1961 }
1959 }
1962 noff = nt_new(self);
1960 noff = nt_new(self);
1963 if (noff == -1)
1961 if (noff == -1)
1964 return -1;
1962 return -1;
1965 /* self->nodes may have been changed by realloc */
1963 /* self->nodes may have been changed by realloc */
1966 self->nodes[off].children[k] = noff;
1964 self->nodes[off].children[k] = noff;
1967 off = noff;
1965 off = noff;
1968 n = &self->nodes[off];
1966 n = &self->nodes[off];
1969 n->children[nt_level(oldnode, ++level)] = v;
1967 n->children[nt_level(oldnode, ++level)] = v;
1970 if (level > self->depth)
1968 if (level > self->depth)
1971 self->depth = level;
1969 self->depth = level;
1972 self->splits += 1;
1970 self->splits += 1;
1973 } else {
1971 } else {
1974 level += 1;
1972 level += 1;
1975 off = v;
1973 off = v;
1976 }
1974 }
1977 }
1975 }
1978
1976
1979 return -1;
1977 return -1;
1980 }
1978 }
1981
1979
1982 static PyObject *ntobj_insert(nodetreeObject *self, PyObject *args)
1980 static PyObject *ntobj_insert(nodetreeObject *self, PyObject *args)
1983 {
1981 {
1984 Py_ssize_t rev;
1982 Py_ssize_t rev;
1985 const char *node;
1983 const char *node;
1986 Py_ssize_t length;
1984 Py_ssize_t length;
1987 if (!PyArg_ParseTuple(args, "n", &rev))
1985 if (!PyArg_ParseTuple(args, "n", &rev))
1988 return NULL;
1986 return NULL;
1989 length = index_length(self->nt.index);
1987 length = index_length(self->nt.index);
1990 if (rev < 0 || rev >= length) {
1988 if (rev < 0 || rev >= length) {
1991 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1989 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1992 return NULL;
1990 return NULL;
1993 }
1991 }
1994 node = index_node_existing(self->nt.index, rev);
1992 node = index_node_existing(self->nt.index, rev);
1995 if (nt_insert(&self->nt, node, (int)rev) == -1)
1993 if (nt_insert(&self->nt, node, (int)rev) == -1)
1996 return NULL;
1994 return NULL;
1997 Py_RETURN_NONE;
1995 Py_RETURN_NONE;
1998 }
1996 }
1999
1997
2000 static int nt_delete_node(nodetree *self, const char *node)
1998 static int nt_delete_node(nodetree *self, const char *node)
2001 {
1999 {
2002 /* rev==-2 happens to get encoded as 0, which is interpreted as not set
2000 /* rev==-2 happens to get encoded as 0, which is interpreted as not set
2003 */
2001 */
2004 return nt_insert(self, node, -2);
2002 return nt_insert(self, node, -2);
2005 }
2003 }
2006
2004
2007 static int nt_init(nodetree *self, indexObject *index, unsigned capacity)
2005 static int nt_init(nodetree *self, indexObject *index, unsigned capacity)
2008 {
2006 {
2009 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */
2007 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */
2010 self->nodes = NULL;
2008 self->nodes = NULL;
2011
2009
2012 self->index = index;
2010 self->index = index;
2013 /* The input capacity is in terms of revisions, while the field is in
2011 /* The input capacity is in terms of revisions, while the field is in
2014 * terms of nodetree nodes. */
2012 * terms of nodetree nodes. */
2015 self->capacity = (capacity < 4 ? 4 : capacity / 2);
2013 self->capacity = (capacity < 4 ? 4 : capacity / 2);
2016 self->nodelen = index->nodelen;
2014 self->nodelen = index->nodelen;
2017 self->depth = 0;
2015 self->depth = 0;
2018 self->splits = 0;
2016 self->splits = 0;
2019 if (self->capacity > SIZE_MAX / sizeof(nodetreenode)) {
2017 if (self->capacity > SIZE_MAX / sizeof(nodetreenode)) {
2020 PyErr_SetString(PyExc_ValueError, "overflow in init_nt");
2018 PyErr_SetString(PyExc_ValueError, "overflow in init_nt");
2021 return -1;
2019 return -1;
2022 }
2020 }
2023 self->nodes = calloc(self->capacity, sizeof(nodetreenode));
2021 self->nodes = calloc(self->capacity, sizeof(nodetreenode));
2024 if (self->nodes == NULL) {
2022 if (self->nodes == NULL) {
2025 PyErr_NoMemory();
2023 PyErr_NoMemory();
2026 return -1;
2024 return -1;
2027 }
2025 }
2028 self->length = 1;
2026 self->length = 1;
2029 return 0;
2027 return 0;
2030 }
2028 }
2031
2029
2032 static int ntobj_init(nodetreeObject *self, PyObject *args)
2030 static int ntobj_init(nodetreeObject *self, PyObject *args)
2033 {
2031 {
2034 PyObject *index;
2032 PyObject *index;
2035 unsigned capacity;
2033 unsigned capacity;
2036 if (!PyArg_ParseTuple(args, "O!I", &HgRevlogIndex_Type, &index,
2034 if (!PyArg_ParseTuple(args, "O!I", &HgRevlogIndex_Type, &index,
2037 &capacity))
2035 &capacity))
2038 return -1;
2036 return -1;
2039 Py_INCREF(index);
2037 Py_INCREF(index);
2040 return nt_init(&self->nt, (indexObject *)index, capacity);
2038 return nt_init(&self->nt, (indexObject *)index, capacity);
2041 }
2039 }
2042
2040
2043 static int nt_partialmatch(nodetree *self, const char *node, Py_ssize_t nodelen)
2041 static int nt_partialmatch(nodetree *self, const char *node, Py_ssize_t nodelen)
2044 {
2042 {
2045 return nt_find(self, node, nodelen, 1);
2043 return nt_find(self, node, nodelen, 1);
2046 }
2044 }
2047
2045
2048 /*
2046 /*
2049 * Find the length of the shortest unique prefix of node.
2047 * Find the length of the shortest unique prefix of node.
2050 *
2048 *
2051 * Return values:
2049 * Return values:
2052 *
2050 *
2053 * -3: error (exception set)
2051 * -3: error (exception set)
2054 * -2: not found (no exception set)
2052 * -2: not found (no exception set)
2055 * rest: length of shortest prefix
2053 * rest: length of shortest prefix
2056 */
2054 */
2057 static int nt_shortest(nodetree *self, const char *node)
2055 static int nt_shortest(nodetree *self, const char *node)
2058 {
2056 {
2059 int level, off;
2057 int level, off;
2060
2058
2061 for (level = off = 0; level < 2 * self->nodelen; level++) {
2059 for (level = off = 0; level < 2 * self->nodelen; level++) {
2062 int k, v;
2060 int k, v;
2063 nodetreenode *n = &self->nodes[off];
2061 nodetreenode *n = &self->nodes[off];
2064 k = nt_level(node, level);
2062 k = nt_level(node, level);
2065 v = n->children[k];
2063 v = n->children[k];
2066 if (v < 0) {
2064 if (v < 0) {
2067 const char *n;
2065 const char *n;
2068 v = -(v + 2);
2066 v = -(v + 2);
2069 n = index_node_existing(self->index, v);
2067 n = index_node_existing(self->index, v);
2070 if (n == NULL)
2068 if (n == NULL)
2071 return -3;
2069 return -3;
2072 if (memcmp(node, n, self->nodelen) != 0)
2070 if (memcmp(node, n, self->nodelen) != 0)
2073 /*
2071 /*
2074 * Found a unique prefix, but it wasn't for the
2072 * Found a unique prefix, but it wasn't for the
2075 * requested node (i.e the requested node does
2073 * requested node (i.e the requested node does
2076 * not exist).
2074 * not exist).
2077 */
2075 */
2078 return -2;
2076 return -2;
2079 return level + 1;
2077 return level + 1;
2080 }
2078 }
2081 if (v == 0)
2079 if (v == 0)
2082 return -2;
2080 return -2;
2083 off = v;
2081 off = v;
2084 }
2082 }
2085 /*
2083 /*
2086 * The node was still not unique after 40 hex digits, so this won't
2084 * The node was still not unique after 40 hex digits, so this won't
2087 * happen. Also, if we get here, then there's a programming error in
2085 * happen. Also, if we get here, then there's a programming error in
2088 * this file that made us insert a node longer than 40 hex digits.
2086 * this file that made us insert a node longer than 40 hex digits.
2089 */
2087 */
2090 PyErr_SetString(PyExc_Exception, "broken node tree");
2088 PyErr_SetString(PyExc_Exception, "broken node tree");
2091 return -3;
2089 return -3;
2092 }
2090 }
2093
2091
2094 static PyObject *ntobj_shortest(nodetreeObject *self, PyObject *args)
2092 static PyObject *ntobj_shortest(nodetreeObject *self, PyObject *args)
2095 {
2093 {
2096 PyObject *val;
2094 PyObject *val;
2097 char *node;
2095 char *node;
2098 int length;
2096 int length;
2099
2097
2100 if (!PyArg_ParseTuple(args, "O", &val))
2098 if (!PyArg_ParseTuple(args, "O", &val))
2101 return NULL;
2099 return NULL;
2102 if (node_check(self->nt.nodelen, val, &node) == -1)
2100 if (node_check(self->nt.nodelen, val, &node) == -1)
2103 return NULL;
2101 return NULL;
2104
2102
2105 length = nt_shortest(&self->nt, node);
2103 length = nt_shortest(&self->nt, node);
2106 if (length == -3)
2104 if (length == -3)
2107 return NULL;
2105 return NULL;
2108 if (length == -2) {
2106 if (length == -2) {
2109 raise_revlog_error();
2107 raise_revlog_error();
2110 return NULL;
2108 return NULL;
2111 }
2109 }
2112 return PyLong_FromLong(length);
2110 return PyLong_FromLong(length);
2113 }
2111 }
2114
2112
2115 static void nt_dealloc(nodetree *self)
2113 static void nt_dealloc(nodetree *self)
2116 {
2114 {
2117 free(self->nodes);
2115 free(self->nodes);
2118 self->nodes = NULL;
2116 self->nodes = NULL;
2119 }
2117 }
2120
2118
2121 static void ntobj_dealloc(nodetreeObject *self)
2119 static void ntobj_dealloc(nodetreeObject *self)
2122 {
2120 {
2123 Py_XDECREF(self->nt.index);
2121 Py_XDECREF(self->nt.index);
2124 nt_dealloc(&self->nt);
2122 nt_dealloc(&self->nt);
2125 PyObject_Del(self);
2123 PyObject_Del(self);
2126 }
2124 }
2127
2125
2128 static PyMethodDef ntobj_methods[] = {
2126 static PyMethodDef ntobj_methods[] = {
2129 {"insert", (PyCFunction)ntobj_insert, METH_VARARGS,
2127 {"insert", (PyCFunction)ntobj_insert, METH_VARARGS,
2130 "insert an index entry"},
2128 "insert an index entry"},
2131 {"shortest", (PyCFunction)ntobj_shortest, METH_VARARGS,
2129 {"shortest", (PyCFunction)ntobj_shortest, METH_VARARGS,
2132 "find length of shortest hex nodeid of a binary ID"},
2130 "find length of shortest hex nodeid of a binary ID"},
2133 {NULL} /* Sentinel */
2131 {NULL} /* Sentinel */
2134 };
2132 };
2135
2133
2136 static PyTypeObject nodetreeType = {
2134 static PyTypeObject nodetreeType = {
2137 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2135 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2138 "parsers.nodetree", /* tp_name */
2136 "parsers.nodetree", /* tp_name */
2139 sizeof(nodetreeObject), /* tp_basicsize */
2137 sizeof(nodetreeObject), /* tp_basicsize */
2140 0, /* tp_itemsize */
2138 0, /* tp_itemsize */
2141 (destructor)ntobj_dealloc, /* tp_dealloc */
2139 (destructor)ntobj_dealloc, /* tp_dealloc */
2142 0, /* tp_print */
2140 0, /* tp_print */
2143 0, /* tp_getattr */
2141 0, /* tp_getattr */
2144 0, /* tp_setattr */
2142 0, /* tp_setattr */
2145 0, /* tp_compare */
2143 0, /* tp_compare */
2146 0, /* tp_repr */
2144 0, /* tp_repr */
2147 0, /* tp_as_number */
2145 0, /* tp_as_number */
2148 0, /* tp_as_sequence */
2146 0, /* tp_as_sequence */
2149 0, /* tp_as_mapping */
2147 0, /* tp_as_mapping */
2150 0, /* tp_hash */
2148 0, /* tp_hash */
2151 0, /* tp_call */
2149 0, /* tp_call */
2152 0, /* tp_str */
2150 0, /* tp_str */
2153 0, /* tp_getattro */
2151 0, /* tp_getattro */
2154 0, /* tp_setattro */
2152 0, /* tp_setattro */
2155 0, /* tp_as_buffer */
2153 0, /* tp_as_buffer */
2156 Py_TPFLAGS_DEFAULT, /* tp_flags */
2154 Py_TPFLAGS_DEFAULT, /* tp_flags */
2157 "nodetree", /* tp_doc */
2155 "nodetree", /* tp_doc */
2158 0, /* tp_traverse */
2156 0, /* tp_traverse */
2159 0, /* tp_clear */
2157 0, /* tp_clear */
2160 0, /* tp_richcompare */
2158 0, /* tp_richcompare */
2161 0, /* tp_weaklistoffset */
2159 0, /* tp_weaklistoffset */
2162 0, /* tp_iter */
2160 0, /* tp_iter */
2163 0, /* tp_iternext */
2161 0, /* tp_iternext */
2164 ntobj_methods, /* tp_methods */
2162 ntobj_methods, /* tp_methods */
2165 0, /* tp_members */
2163 0, /* tp_members */
2166 0, /* tp_getset */
2164 0, /* tp_getset */
2167 0, /* tp_base */
2165 0, /* tp_base */
2168 0, /* tp_dict */
2166 0, /* tp_dict */
2169 0, /* tp_descr_get */
2167 0, /* tp_descr_get */
2170 0, /* tp_descr_set */
2168 0, /* tp_descr_set */
2171 0, /* tp_dictoffset */
2169 0, /* tp_dictoffset */
2172 (initproc)ntobj_init, /* tp_init */
2170 (initproc)ntobj_init, /* tp_init */
2173 0, /* tp_alloc */
2171 0, /* tp_alloc */
2174 };
2172 };
2175
2173
2176 static int index_init_nt(indexObject *self)
2174 static int index_init_nt(indexObject *self)
2177 {
2175 {
2178 if (!self->ntinitialized) {
2176 if (!self->ntinitialized) {
2179 if (nt_init(&self->nt, self, (int)self->length) == -1) {
2177 if (nt_init(&self->nt, self, (int)self->length) == -1) {
2180 nt_dealloc(&self->nt);
2178 nt_dealloc(&self->nt);
2181 return -1;
2179 return -1;
2182 }
2180 }
2183 if (nt_insert(&self->nt, nullid, -1) == -1) {
2181 if (nt_insert(&self->nt, nullid, -1) == -1) {
2184 nt_dealloc(&self->nt);
2182 nt_dealloc(&self->nt);
2185 return -1;
2183 return -1;
2186 }
2184 }
2187 self->ntinitialized = 1;
2185 self->ntinitialized = 1;
2188 self->ntrev = (int)index_length(self);
2186 self->ntrev = (int)index_length(self);
2189 self->ntlookups = 1;
2187 self->ntlookups = 1;
2190 self->ntmisses = 0;
2188 self->ntmisses = 0;
2191 }
2189 }
2192 return 0;
2190 return 0;
2193 }
2191 }
2194
2192
2195 /*
2193 /*
2196 * Return values:
2194 * Return values:
2197 *
2195 *
2198 * -3: error (exception set)
2196 * -3: error (exception set)
2199 * -2: not found (no exception set)
2197 * -2: not found (no exception set)
2200 * rest: valid rev
2198 * rest: valid rev
2201 */
2199 */
2202 static int index_find_node(indexObject *self, const char *node)
2200 static int index_find_node(indexObject *self, const char *node)
2203 {
2201 {
2204 int rev;
2202 int rev;
2205
2203
2206 if (index_init_nt(self) == -1)
2204 if (index_init_nt(self) == -1)
2207 return -3;
2205 return -3;
2208
2206
2209 self->ntlookups++;
2207 self->ntlookups++;
2210 rev = nt_find(&self->nt, node, self->nodelen, 0);
2208 rev = nt_find(&self->nt, node, self->nodelen, 0);
2211 if (rev >= -1)
2209 if (rev >= -1)
2212 return rev;
2210 return rev;
2213
2211
2214 /*
2212 /*
2215 * For the first handful of lookups, we scan the entire index,
2213 * For the first handful of lookups, we scan the entire index,
2216 * and cache only the matching nodes. This optimizes for cases
2214 * and cache only the matching nodes. This optimizes for cases
2217 * like "hg tip", where only a few nodes are accessed.
2215 * like "hg tip", where only a few nodes are accessed.
2218 *
2216 *
2219 * After that, we cache every node we visit, using a single
2217 * After that, we cache every node we visit, using a single
2220 * scan amortized over multiple lookups. This gives the best
2218 * scan amortized over multiple lookups. This gives the best
2221 * bulk performance, e.g. for "hg log".
2219 * bulk performance, e.g. for "hg log".
2222 */
2220 */
2223 if (self->ntmisses++ < 4) {
2221 if (self->ntmisses++ < 4) {
2224 for (rev = self->ntrev - 1; rev >= 0; rev--) {
2222 for (rev = self->ntrev - 1; rev >= 0; rev--) {
2225 const char *n = index_node_existing(self, rev);
2223 const char *n = index_node_existing(self, rev);
2226 if (n == NULL)
2224 if (n == NULL)
2227 return -3;
2225 return -3;
2228 if (memcmp(node, n, self->nodelen) == 0) {
2226 if (memcmp(node, n, self->nodelen) == 0) {
2229 if (nt_insert(&self->nt, n, rev) == -1)
2227 if (nt_insert(&self->nt, n, rev) == -1)
2230 return -3;
2228 return -3;
2231 break;
2229 break;
2232 }
2230 }
2233 }
2231 }
2234 } else {
2232 } else {
2235 for (rev = self->ntrev - 1; rev >= 0; rev--) {
2233 for (rev = self->ntrev - 1; rev >= 0; rev--) {
2236 const char *n = index_node_existing(self, rev);
2234 const char *n = index_node_existing(self, rev);
2237 if (n == NULL)
2235 if (n == NULL)
2238 return -3;
2236 return -3;
2239 if (nt_insert(&self->nt, n, rev) == -1) {
2237 if (nt_insert(&self->nt, n, rev) == -1) {
2240 self->ntrev = rev + 1;
2238 self->ntrev = rev + 1;
2241 return -3;
2239 return -3;
2242 }
2240 }
2243 if (memcmp(node, n, self->nodelen) == 0) {
2241 if (memcmp(node, n, self->nodelen) == 0) {
2244 break;
2242 break;
2245 }
2243 }
2246 }
2244 }
2247 self->ntrev = rev;
2245 self->ntrev = rev;
2248 }
2246 }
2249
2247
2250 if (rev >= 0)
2248 if (rev >= 0)
2251 return rev;
2249 return rev;
2252 return -2;
2250 return -2;
2253 }
2251 }
2254
2252
2255 static PyObject *index_getitem(indexObject *self, PyObject *value)
2253 static PyObject *index_getitem(indexObject *self, PyObject *value)
2256 {
2254 {
2257 char *node;
2255 char *node;
2258 int rev;
2256 int rev;
2259
2257
2260 if (PyLong_Check(value)) {
2258 if (PyLong_Check(value)) {
2261 long idx;
2259 long idx;
2262 if (!pylong_to_long(value, &idx)) {
2260 if (!pylong_to_long(value, &idx)) {
2263 return NULL;
2261 return NULL;
2264 }
2262 }
2265 return index_get(self, idx);
2263 return index_get(self, idx);
2266 }
2264 }
2267
2265
2268 if (node_check(self->nodelen, value, &node) == -1)
2266 if (node_check(self->nodelen, value, &node) == -1)
2269 return NULL;
2267 return NULL;
2270 rev = index_find_node(self, node);
2268 rev = index_find_node(self, node);
2271 if (rev >= -1)
2269 if (rev >= -1)
2272 return PyLong_FromLong(rev);
2270 return PyLong_FromLong(rev);
2273 if (rev == -2)
2271 if (rev == -2)
2274 raise_revlog_error();
2272 raise_revlog_error();
2275 return NULL;
2273 return NULL;
2276 }
2274 }
2277
2275
2278 /*
2276 /*
2279 * Fully populate the radix tree.
2277 * Fully populate the radix tree.
2280 */
2278 */
2281 static int index_populate_nt(indexObject *self)
2279 static int index_populate_nt(indexObject *self)
2282 {
2280 {
2283 int rev;
2281 int rev;
2284 if (self->ntrev > 0) {
2282 if (self->ntrev > 0) {
2285 for (rev = self->ntrev - 1; rev >= 0; rev--) {
2283 for (rev = self->ntrev - 1; rev >= 0; rev--) {
2286 const char *n = index_node_existing(self, rev);
2284 const char *n = index_node_existing(self, rev);
2287 if (n == NULL)
2285 if (n == NULL)
2288 return -1;
2286 return -1;
2289 if (nt_insert(&self->nt, n, rev) == -1)
2287 if (nt_insert(&self->nt, n, rev) == -1)
2290 return -1;
2288 return -1;
2291 }
2289 }
2292 self->ntrev = -1;
2290 self->ntrev = -1;
2293 }
2291 }
2294 return 0;
2292 return 0;
2295 }
2293 }
2296
2294
2297 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
2295 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
2298 {
2296 {
2299 const char *fullnode;
2297 const char *fullnode;
2300 Py_ssize_t nodelen;
2298 Py_ssize_t nodelen;
2301 char *node;
2299 char *node;
2302 int rev, i;
2300 int rev, i;
2303
2301
2304 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &node, &nodelen))
2302 if (!PyArg_ParseTuple(args, "y#", &node, &nodelen))
2305 return NULL;
2303 return NULL;
2306
2304
2307 if (nodelen < 1) {
2305 if (nodelen < 1) {
2308 PyErr_SetString(PyExc_ValueError, "key too short");
2306 PyErr_SetString(PyExc_ValueError, "key too short");
2309 return NULL;
2307 return NULL;
2310 }
2308 }
2311
2309
2312 if (nodelen > 2 * self->nodelen) {
2310 if (nodelen > 2 * self->nodelen) {
2313 PyErr_SetString(PyExc_ValueError, "key too long");
2311 PyErr_SetString(PyExc_ValueError, "key too long");
2314 return NULL;
2312 return NULL;
2315 }
2313 }
2316
2314
2317 for (i = 0; i < nodelen; i++)
2315 for (i = 0; i < nodelen; i++)
2318 hexdigit(node, i);
2316 hexdigit(node, i);
2319 if (PyErr_Occurred()) {
2317 if (PyErr_Occurred()) {
2320 /* input contains non-hex characters */
2318 /* input contains non-hex characters */
2321 PyErr_Clear();
2319 PyErr_Clear();
2322 Py_RETURN_NONE;
2320 Py_RETURN_NONE;
2323 }
2321 }
2324
2322
2325 if (index_init_nt(self) == -1)
2323 if (index_init_nt(self) == -1)
2326 return NULL;
2324 return NULL;
2327 if (index_populate_nt(self) == -1)
2325 if (index_populate_nt(self) == -1)
2328 return NULL;
2326 return NULL;
2329 rev = nt_partialmatch(&self->nt, node, nodelen);
2327 rev = nt_partialmatch(&self->nt, node, nodelen);
2330
2328
2331 switch (rev) {
2329 switch (rev) {
2332 case -4:
2330 case -4:
2333 raise_revlog_error();
2331 raise_revlog_error();
2334 return NULL;
2332 return NULL;
2335 case -2:
2333 case -2:
2336 Py_RETURN_NONE;
2334 Py_RETURN_NONE;
2337 case -1:
2335 case -1:
2338 return PyBytes_FromStringAndSize(nullid, self->nodelen);
2336 return PyBytes_FromStringAndSize(nullid, self->nodelen);
2339 }
2337 }
2340
2338
2341 fullnode = index_node_existing(self, rev);
2339 fullnode = index_node_existing(self, rev);
2342 if (fullnode == NULL) {
2340 if (fullnode == NULL) {
2343 return NULL;
2341 return NULL;
2344 }
2342 }
2345 return PyBytes_FromStringAndSize(fullnode, self->nodelen);
2343 return PyBytes_FromStringAndSize(fullnode, self->nodelen);
2346 }
2344 }
2347
2345
2348 static PyObject *index_shortest(indexObject *self, PyObject *args)
2346 static PyObject *index_shortest(indexObject *self, PyObject *args)
2349 {
2347 {
2350 PyObject *val;
2348 PyObject *val;
2351 char *node;
2349 char *node;
2352 int length;
2350 int length;
2353
2351
2354 if (!PyArg_ParseTuple(args, "O", &val))
2352 if (!PyArg_ParseTuple(args, "O", &val))
2355 return NULL;
2353 return NULL;
2356 if (node_check(self->nodelen, val, &node) == -1)
2354 if (node_check(self->nodelen, val, &node) == -1)
2357 return NULL;
2355 return NULL;
2358
2356
2359 self->ntlookups++;
2357 self->ntlookups++;
2360 if (index_init_nt(self) == -1)
2358 if (index_init_nt(self) == -1)
2361 return NULL;
2359 return NULL;
2362 if (index_populate_nt(self) == -1)
2360 if (index_populate_nt(self) == -1)
2363 return NULL;
2361 return NULL;
2364 length = nt_shortest(&self->nt, node);
2362 length = nt_shortest(&self->nt, node);
2365 if (length == -3)
2363 if (length == -3)
2366 return NULL;
2364 return NULL;
2367 if (length == -2) {
2365 if (length == -2) {
2368 raise_revlog_error();
2366 raise_revlog_error();
2369 return NULL;
2367 return NULL;
2370 }
2368 }
2371 return PyLong_FromLong(length);
2369 return PyLong_FromLong(length);
2372 }
2370 }
2373
2371
2374 static PyObject *index_m_get(indexObject *self, PyObject *args)
2372 static PyObject *index_m_get(indexObject *self, PyObject *args)
2375 {
2373 {
2376 PyObject *val;
2374 PyObject *val;
2377 char *node;
2375 char *node;
2378 int rev;
2376 int rev;
2379
2377
2380 if (!PyArg_ParseTuple(args, "O", &val))
2378 if (!PyArg_ParseTuple(args, "O", &val))
2381 return NULL;
2379 return NULL;
2382 if (node_check(self->nodelen, val, &node) == -1)
2380 if (node_check(self->nodelen, val, &node) == -1)
2383 return NULL;
2381 return NULL;
2384 rev = index_find_node(self, node);
2382 rev = index_find_node(self, node);
2385 if (rev == -3)
2383 if (rev == -3)
2386 return NULL;
2384 return NULL;
2387 if (rev == -2)
2385 if (rev == -2)
2388 Py_RETURN_NONE;
2386 Py_RETURN_NONE;
2389 return PyLong_FromLong(rev);
2387 return PyLong_FromLong(rev);
2390 }
2388 }
2391
2389
2392 static int index_contains(indexObject *self, PyObject *value)
2390 static int index_contains(indexObject *self, PyObject *value)
2393 {
2391 {
2394 char *node;
2392 char *node;
2395
2393
2396 if (PyLong_Check(value)) {
2394 if (PyLong_Check(value)) {
2397 long rev;
2395 long rev;
2398 if (!pylong_to_long(value, &rev)) {
2396 if (!pylong_to_long(value, &rev)) {
2399 return -1;
2397 return -1;
2400 }
2398 }
2401 return rev >= -1 && rev < index_length(self);
2399 return rev >= -1 && rev < index_length(self);
2402 }
2400 }
2403
2401
2404 if (node_check(self->nodelen, value, &node) == -1)
2402 if (node_check(self->nodelen, value, &node) == -1)
2405 return -1;
2403 return -1;
2406
2404
2407 switch (index_find_node(self, node)) {
2405 switch (index_find_node(self, node)) {
2408 case -3:
2406 case -3:
2409 return -1;
2407 return -1;
2410 case -2:
2408 case -2:
2411 return 0;
2409 return 0;
2412 default:
2410 default:
2413 return 1;
2411 return 1;
2414 }
2412 }
2415 }
2413 }
2416
2414
2417 static PyObject *index_m_has_node(indexObject *self, PyObject *args)
2415 static PyObject *index_m_has_node(indexObject *self, PyObject *args)
2418 {
2416 {
2419 int ret = index_contains(self, args);
2417 int ret = index_contains(self, args);
2420 if (ret < 0)
2418 if (ret < 0)
2421 return NULL;
2419 return NULL;
2422 return PyBool_FromLong((long)ret);
2420 return PyBool_FromLong((long)ret);
2423 }
2421 }
2424
2422
2425 static PyObject *index_m_rev(indexObject *self, PyObject *val)
2423 static PyObject *index_m_rev(indexObject *self, PyObject *val)
2426 {
2424 {
2427 char *node;
2425 char *node;
2428 int rev;
2426 int rev;
2429
2427
2430 if (node_check(self->nodelen, val, &node) == -1)
2428 if (node_check(self->nodelen, val, &node) == -1)
2431 return NULL;
2429 return NULL;
2432 rev = index_find_node(self, node);
2430 rev = index_find_node(self, node);
2433 if (rev >= -1)
2431 if (rev >= -1)
2434 return PyLong_FromLong(rev);
2432 return PyLong_FromLong(rev);
2435 if (rev == -2)
2433 if (rev == -2)
2436 raise_revlog_error();
2434 raise_revlog_error();
2437 return NULL;
2435 return NULL;
2438 }
2436 }
2439
2437
2440 typedef uint64_t bitmask;
2438 typedef uint64_t bitmask;
2441
2439
2442 /*
2440 /*
2443 * Given a disjoint set of revs, return all candidates for the
2441 * Given a disjoint set of revs, return all candidates for the
2444 * greatest common ancestor. In revset notation, this is the set
2442 * greatest common ancestor. In revset notation, this is the set
2445 * "heads(::a and ::b and ...)"
2443 * "heads(::a and ::b and ...)"
2446 */
2444 */
2447 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
2445 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
2448 int revcount)
2446 int revcount)
2449 {
2447 {
2450 const bitmask allseen = (1ull << revcount) - 1;
2448 const bitmask allseen = (1ull << revcount) - 1;
2451 const bitmask poison = 1ull << revcount;
2449 const bitmask poison = 1ull << revcount;
2452 PyObject *gca = PyList_New(0);
2450 PyObject *gca = PyList_New(0);
2453 int i, v, interesting;
2451 int i, v, interesting;
2454 int maxrev = -1;
2452 int maxrev = -1;
2455 bitmask sp;
2453 bitmask sp;
2456 bitmask *seen;
2454 bitmask *seen;
2457
2455
2458 if (gca == NULL)
2456 if (gca == NULL)
2459 return PyErr_NoMemory();
2457 return PyErr_NoMemory();
2460
2458
2461 for (i = 0; i < revcount; i++) {
2459 for (i = 0; i < revcount; i++) {
2462 if (revs[i] > maxrev)
2460 if (revs[i] > maxrev)
2463 maxrev = revs[i];
2461 maxrev = revs[i];
2464 }
2462 }
2465
2463
2466 seen = calloc(sizeof(*seen), maxrev + 1);
2464 seen = calloc(sizeof(*seen), maxrev + 1);
2467 if (seen == NULL) {
2465 if (seen == NULL) {
2468 Py_DECREF(gca);
2466 Py_DECREF(gca);
2469 return PyErr_NoMemory();
2467 return PyErr_NoMemory();
2470 }
2468 }
2471
2469
2472 for (i = 0; i < revcount; i++)
2470 for (i = 0; i < revcount; i++)
2473 seen[revs[i]] = 1ull << i;
2471 seen[revs[i]] = 1ull << i;
2474
2472
2475 interesting = revcount;
2473 interesting = revcount;
2476
2474
2477 for (v = maxrev; v >= 0 && interesting; v--) {
2475 for (v = maxrev; v >= 0 && interesting; v--) {
2478 bitmask sv = seen[v];
2476 bitmask sv = seen[v];
2479 int parents[2];
2477 int parents[2];
2480
2478
2481 if (!sv)
2479 if (!sv)
2482 continue;
2480 continue;
2483
2481
2484 if (sv < poison) {
2482 if (sv < poison) {
2485 interesting -= 1;
2483 interesting -= 1;
2486 if (sv == allseen) {
2484 if (sv == allseen) {
2487 PyObject *obj = PyLong_FromLong(v);
2485 PyObject *obj = PyLong_FromLong(v);
2488 if (obj == NULL)
2486 if (obj == NULL)
2489 goto bail;
2487 goto bail;
2490 if (PyList_Append(gca, obj) == -1) {
2488 if (PyList_Append(gca, obj) == -1) {
2491 Py_DECREF(obj);
2489 Py_DECREF(obj);
2492 goto bail;
2490 goto bail;
2493 }
2491 }
2494 sv |= poison;
2492 sv |= poison;
2495 for (i = 0; i < revcount; i++) {
2493 for (i = 0; i < revcount; i++) {
2496 if (revs[i] == v)
2494 if (revs[i] == v)
2497 goto done;
2495 goto done;
2498 }
2496 }
2499 }
2497 }
2500 }
2498 }
2501 if (index_get_parents(self, v, parents, maxrev) < 0)
2499 if (index_get_parents(self, v, parents, maxrev) < 0)
2502 goto bail;
2500 goto bail;
2503
2501
2504 for (i = 0; i < 2; i++) {
2502 for (i = 0; i < 2; i++) {
2505 int p = parents[i];
2503 int p = parents[i];
2506 if (p == -1)
2504 if (p == -1)
2507 continue;
2505 continue;
2508 sp = seen[p];
2506 sp = seen[p];
2509 if (sv < poison) {
2507 if (sv < poison) {
2510 if (sp == 0) {
2508 if (sp == 0) {
2511 seen[p] = sv;
2509 seen[p] = sv;
2512 interesting++;
2510 interesting++;
2513 } else if (sp != sv)
2511 } else if (sp != sv)
2514 seen[p] |= sv;
2512 seen[p] |= sv;
2515 } else {
2513 } else {
2516 if (sp && sp < poison)
2514 if (sp && sp < poison)
2517 interesting--;
2515 interesting--;
2518 seen[p] = sv;
2516 seen[p] = sv;
2519 }
2517 }
2520 }
2518 }
2521 }
2519 }
2522
2520
2523 done:
2521 done:
2524 free(seen);
2522 free(seen);
2525 return gca;
2523 return gca;
2526 bail:
2524 bail:
2527 free(seen);
2525 free(seen);
2528 Py_XDECREF(gca);
2526 Py_XDECREF(gca);
2529 return NULL;
2527 return NULL;
2530 }
2528 }
2531
2529
2532 /*
2530 /*
2533 * Given a disjoint set of revs, return the subset with the longest
2531 * Given a disjoint set of revs, return the subset with the longest
2534 * path to the root.
2532 * path to the root.
2535 */
2533 */
2536 static PyObject *find_deepest(indexObject *self, PyObject *revs)
2534 static PyObject *find_deepest(indexObject *self, PyObject *revs)
2537 {
2535 {
2538 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
2536 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
2539 static const Py_ssize_t capacity = 24;
2537 static const Py_ssize_t capacity = 24;
2540 int *depth, *interesting = NULL;
2538 int *depth, *interesting = NULL;
2541 int i, j, v, ninteresting;
2539 int i, j, v, ninteresting;
2542 PyObject *dict = NULL, *keys = NULL;
2540 PyObject *dict = NULL, *keys = NULL;
2543 long *seen = NULL;
2541 long *seen = NULL;
2544 int maxrev = -1;
2542 int maxrev = -1;
2545 long final;
2543 long final;
2546
2544
2547 if (revcount > capacity) {
2545 if (revcount > capacity) {
2548 PyErr_Format(PyExc_OverflowError,
2546 PyErr_Format(PyExc_OverflowError,
2549 "bitset size (%ld) > capacity (%ld)",
2547 "bitset size (%ld) > capacity (%ld)",
2550 (long)revcount, (long)capacity);
2548 (long)revcount, (long)capacity);
2551 return NULL;
2549 return NULL;
2552 }
2550 }
2553
2551
2554 for (i = 0; i < revcount; i++) {
2552 for (i = 0; i < revcount; i++) {
2555 int n = (int)PyLong_AsLong(PyList_GET_ITEM(revs, i));
2553 int n = (int)PyLong_AsLong(PyList_GET_ITEM(revs, i));
2556 if (n > maxrev)
2554 if (n > maxrev)
2557 maxrev = n;
2555 maxrev = n;
2558 }
2556 }
2559
2557
2560 depth = calloc(sizeof(*depth), maxrev + 1);
2558 depth = calloc(sizeof(*depth), maxrev + 1);
2561 if (depth == NULL)
2559 if (depth == NULL)
2562 return PyErr_NoMemory();
2560 return PyErr_NoMemory();
2563
2561
2564 seen = calloc(sizeof(*seen), maxrev + 1);
2562 seen = calloc(sizeof(*seen), maxrev + 1);
2565 if (seen == NULL) {
2563 if (seen == NULL) {
2566 PyErr_NoMemory();
2564 PyErr_NoMemory();
2567 goto bail;
2565 goto bail;
2568 }
2566 }
2569
2567
2570 interesting = calloc(sizeof(*interesting), ((size_t)1) << revcount);
2568 interesting = calloc(sizeof(*interesting), ((size_t)1) << revcount);
2571 if (interesting == NULL) {
2569 if (interesting == NULL) {
2572 PyErr_NoMemory();
2570 PyErr_NoMemory();
2573 goto bail;
2571 goto bail;
2574 }
2572 }
2575
2573
2576 if (PyList_Sort(revs) == -1)
2574 if (PyList_Sort(revs) == -1)
2577 goto bail;
2575 goto bail;
2578
2576
2579 for (i = 0; i < revcount; i++) {
2577 for (i = 0; i < revcount; i++) {
2580 int n = (int)PyLong_AsLong(PyList_GET_ITEM(revs, i));
2578 int n = (int)PyLong_AsLong(PyList_GET_ITEM(revs, i));
2581 long b = 1l << i;
2579 long b = 1l << i;
2582 depth[n] = 1;
2580 depth[n] = 1;
2583 seen[n] = b;
2581 seen[n] = b;
2584 interesting[b] = 1;
2582 interesting[b] = 1;
2585 }
2583 }
2586
2584
2587 /* invariant: ninteresting is the number of non-zero entries in
2585 /* invariant: ninteresting is the number of non-zero entries in
2588 * interesting. */
2586 * interesting. */
2589 ninteresting = (int)revcount;
2587 ninteresting = (int)revcount;
2590
2588
2591 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
2589 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
2592 int dv = depth[v];
2590 int dv = depth[v];
2593 int parents[2];
2591 int parents[2];
2594 long sv;
2592 long sv;
2595
2593
2596 if (dv == 0)
2594 if (dv == 0)
2597 continue;
2595 continue;
2598
2596
2599 sv = seen[v];
2597 sv = seen[v];
2600 if (index_get_parents(self, v, parents, maxrev) < 0)
2598 if (index_get_parents(self, v, parents, maxrev) < 0)
2601 goto bail;
2599 goto bail;
2602
2600
2603 for (i = 0; i < 2; i++) {
2601 for (i = 0; i < 2; i++) {
2604 int p = parents[i];
2602 int p = parents[i];
2605 long sp;
2603 long sp;
2606 int dp;
2604 int dp;
2607
2605
2608 if (p == -1)
2606 if (p == -1)
2609 continue;
2607 continue;
2610
2608
2611 dp = depth[p];
2609 dp = depth[p];
2612 sp = seen[p];
2610 sp = seen[p];
2613 if (dp <= dv) {
2611 if (dp <= dv) {
2614 depth[p] = dv + 1;
2612 depth[p] = dv + 1;
2615 if (sp != sv) {
2613 if (sp != sv) {
2616 interesting[sv] += 1;
2614 interesting[sv] += 1;
2617 seen[p] = sv;
2615 seen[p] = sv;
2618 if (sp) {
2616 if (sp) {
2619 interesting[sp] -= 1;
2617 interesting[sp] -= 1;
2620 if (interesting[sp] == 0)
2618 if (interesting[sp] == 0)
2621 ninteresting -= 1;
2619 ninteresting -= 1;
2622 }
2620 }
2623 }
2621 }
2624 } else if (dv == dp - 1) {
2622 } else if (dv == dp - 1) {
2625 long nsp = sp | sv;
2623 long nsp = sp | sv;
2626 if (nsp == sp)
2624 if (nsp == sp)
2627 continue;
2625 continue;
2628 seen[p] = nsp;
2626 seen[p] = nsp;
2629 interesting[sp] -= 1;
2627 interesting[sp] -= 1;
2630 if (interesting[sp] == 0)
2628 if (interesting[sp] == 0)
2631 ninteresting -= 1;
2629 ninteresting -= 1;
2632 if (interesting[nsp] == 0)
2630 if (interesting[nsp] == 0)
2633 ninteresting += 1;
2631 ninteresting += 1;
2634 interesting[nsp] += 1;
2632 interesting[nsp] += 1;
2635 }
2633 }
2636 }
2634 }
2637 interesting[sv] -= 1;
2635 interesting[sv] -= 1;
2638 if (interesting[sv] == 0)
2636 if (interesting[sv] == 0)
2639 ninteresting -= 1;
2637 ninteresting -= 1;
2640 }
2638 }
2641
2639
2642 final = 0;
2640 final = 0;
2643 j = ninteresting;
2641 j = ninteresting;
2644 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
2642 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
2645 if (interesting[i] == 0)
2643 if (interesting[i] == 0)
2646 continue;
2644 continue;
2647 final |= i;
2645 final |= i;
2648 j -= 1;
2646 j -= 1;
2649 }
2647 }
2650 if (final == 0) {
2648 if (final == 0) {
2651 keys = PyList_New(0);
2649 keys = PyList_New(0);
2652 goto bail;
2650 goto bail;
2653 }
2651 }
2654
2652
2655 dict = PyDict_New();
2653 dict = PyDict_New();
2656 if (dict == NULL)
2654 if (dict == NULL)
2657 goto bail;
2655 goto bail;
2658
2656
2659 for (i = 0; i < revcount; i++) {
2657 for (i = 0; i < revcount; i++) {
2660 PyObject *key;
2658 PyObject *key;
2661
2659
2662 if ((final & (1 << i)) == 0)
2660 if ((final & (1 << i)) == 0)
2663 continue;
2661 continue;
2664
2662
2665 key = PyList_GET_ITEM(revs, i);
2663 key = PyList_GET_ITEM(revs, i);
2666 Py_INCREF(key);
2664 Py_INCREF(key);
2667 Py_INCREF(Py_None);
2665 Py_INCREF(Py_None);
2668 if (PyDict_SetItem(dict, key, Py_None) == -1) {
2666 if (PyDict_SetItem(dict, key, Py_None) == -1) {
2669 Py_DECREF(key);
2667 Py_DECREF(key);
2670 Py_DECREF(Py_None);
2668 Py_DECREF(Py_None);
2671 goto bail;
2669 goto bail;
2672 }
2670 }
2673 }
2671 }
2674
2672
2675 keys = PyDict_Keys(dict);
2673 keys = PyDict_Keys(dict);
2676
2674
2677 bail:
2675 bail:
2678 free(depth);
2676 free(depth);
2679 free(seen);
2677 free(seen);
2680 free(interesting);
2678 free(interesting);
2681 Py_XDECREF(dict);
2679 Py_XDECREF(dict);
2682
2680
2683 return keys;
2681 return keys;
2684 }
2682 }
2685
2683
2686 /*
2684 /*
2687 * Given a (possibly overlapping) set of revs, return all the
2685 * Given a (possibly overlapping) set of revs, return all the
2688 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
2686 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
2689 */
2687 */
2690 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
2688 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
2691 {
2689 {
2692 PyObject *ret = NULL;
2690 PyObject *ret = NULL;
2693 Py_ssize_t argcount, i, len;
2691 Py_ssize_t argcount, i, len;
2694 bitmask repeat = 0;
2692 bitmask repeat = 0;
2695 int revcount = 0;
2693 int revcount = 0;
2696 int *revs;
2694 int *revs;
2697
2695
2698 argcount = PySequence_Length(args);
2696 argcount = PySequence_Length(args);
2699 revs = PyMem_Malloc(argcount * sizeof(*revs));
2697 revs = PyMem_Malloc(argcount * sizeof(*revs));
2700 if (argcount > 0 && revs == NULL)
2698 if (argcount > 0 && revs == NULL)
2701 return PyErr_NoMemory();
2699 return PyErr_NoMemory();
2702 len = index_length(self);
2700 len = index_length(self);
2703
2701
2704 for (i = 0; i < argcount; i++) {
2702 for (i = 0; i < argcount; i++) {
2705 static const int capacity = 24;
2703 static const int capacity = 24;
2706 PyObject *obj = PySequence_GetItem(args, i);
2704 PyObject *obj = PySequence_GetItem(args, i);
2707 bitmask x;
2705 bitmask x;
2708 long val;
2706 long val;
2709
2707
2710 if (!PyLong_Check(obj)) {
2708 if (!PyLong_Check(obj)) {
2711 PyErr_SetString(PyExc_TypeError,
2709 PyErr_SetString(PyExc_TypeError,
2712 "arguments must all be ints");
2710 "arguments must all be ints");
2713 Py_DECREF(obj);
2711 Py_DECREF(obj);
2714 goto bail;
2712 goto bail;
2715 }
2713 }
2716 val = PyLong_AsLong(obj);
2714 val = PyLong_AsLong(obj);
2717 Py_DECREF(obj);
2715 Py_DECREF(obj);
2718 if (val == -1) {
2716 if (val == -1) {
2719 ret = PyList_New(0);
2717 ret = PyList_New(0);
2720 goto done;
2718 goto done;
2721 }
2719 }
2722 if (val < 0 || val >= len) {
2720 if (val < 0 || val >= len) {
2723 PyErr_SetString(PyExc_IndexError, "index out of range");
2721 PyErr_SetString(PyExc_IndexError, "index out of range");
2724 goto bail;
2722 goto bail;
2725 }
2723 }
2726 /* this cheesy bloom filter lets us avoid some more
2724 /* this cheesy bloom filter lets us avoid some more
2727 * expensive duplicate checks in the common set-is-disjoint
2725 * expensive duplicate checks in the common set-is-disjoint
2728 * case */
2726 * case */
2729 x = 1ull << (val & 0x3f);
2727 x = 1ull << (val & 0x3f);
2730 if (repeat & x) {
2728 if (repeat & x) {
2731 int k;
2729 int k;
2732 for (k = 0; k < revcount; k++) {
2730 for (k = 0; k < revcount; k++) {
2733 if (val == revs[k])
2731 if (val == revs[k])
2734 goto duplicate;
2732 goto duplicate;
2735 }
2733 }
2736 } else
2734 } else
2737 repeat |= x;
2735 repeat |= x;
2738 if (revcount >= capacity) {
2736 if (revcount >= capacity) {
2739 PyErr_Format(PyExc_OverflowError,
2737 PyErr_Format(PyExc_OverflowError,
2740 "bitset size (%d) > capacity (%d)",
2738 "bitset size (%d) > capacity (%d)",
2741 revcount, capacity);
2739 revcount, capacity);
2742 goto bail;
2740 goto bail;
2743 }
2741 }
2744 revs[revcount++] = (int)val;
2742 revs[revcount++] = (int)val;
2745 duplicate:;
2743 duplicate:;
2746 }
2744 }
2747
2745
2748 if (revcount == 0) {
2746 if (revcount == 0) {
2749 ret = PyList_New(0);
2747 ret = PyList_New(0);
2750 goto done;
2748 goto done;
2751 }
2749 }
2752 if (revcount == 1) {
2750 if (revcount == 1) {
2753 PyObject *obj;
2751 PyObject *obj;
2754 ret = PyList_New(1);
2752 ret = PyList_New(1);
2755 if (ret == NULL)
2753 if (ret == NULL)
2756 goto bail;
2754 goto bail;
2757 obj = PyLong_FromLong(revs[0]);
2755 obj = PyLong_FromLong(revs[0]);
2758 if (obj == NULL)
2756 if (obj == NULL)
2759 goto bail;
2757 goto bail;
2760 PyList_SET_ITEM(ret, 0, obj);
2758 PyList_SET_ITEM(ret, 0, obj);
2761 goto done;
2759 goto done;
2762 }
2760 }
2763
2761
2764 ret = find_gca_candidates(self, revs, revcount);
2762 ret = find_gca_candidates(self, revs, revcount);
2765 if (ret == NULL)
2763 if (ret == NULL)
2766 goto bail;
2764 goto bail;
2767
2765
2768 done:
2766 done:
2769 PyMem_Free(revs);
2767 PyMem_Free(revs);
2770 return ret;
2768 return ret;
2771
2769
2772 bail:
2770 bail:
2773 PyMem_Free(revs);
2771 PyMem_Free(revs);
2774 Py_XDECREF(ret);
2772 Py_XDECREF(ret);
2775 return NULL;
2773 return NULL;
2776 }
2774 }
2777
2775
2778 /*
2776 /*
2779 * Given a (possibly overlapping) set of revs, return the greatest
2777 * Given a (possibly overlapping) set of revs, return the greatest
2780 * common ancestors: those with the longest path to the root.
2778 * common ancestors: those with the longest path to the root.
2781 */
2779 */
2782 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2780 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2783 {
2781 {
2784 PyObject *ret;
2782 PyObject *ret;
2785 PyObject *gca = index_commonancestorsheads(self, args);
2783 PyObject *gca = index_commonancestorsheads(self, args);
2786 if (gca == NULL)
2784 if (gca == NULL)
2787 return NULL;
2785 return NULL;
2788
2786
2789 if (PyList_GET_SIZE(gca) <= 1) {
2787 if (PyList_GET_SIZE(gca) <= 1) {
2790 return gca;
2788 return gca;
2791 }
2789 }
2792
2790
2793 ret = find_deepest(self, gca);
2791 ret = find_deepest(self, gca);
2794 Py_DECREF(gca);
2792 Py_DECREF(gca);
2795 return ret;
2793 return ret;
2796 }
2794 }
2797
2795
2798 /*
2796 /*
2799 * Invalidate any trie entries introduced by added revs.
2797 * Invalidate any trie entries introduced by added revs.
2800 */
2798 */
2801 static void index_invalidate_added(indexObject *self, Py_ssize_t start)
2799 static void index_invalidate_added(indexObject *self, Py_ssize_t start)
2802 {
2800 {
2803 Py_ssize_t i, len;
2801 Py_ssize_t i, len;
2804
2802
2805 len = self->length + self->new_length;
2803 len = self->length + self->new_length;
2806 i = start - self->length;
2804 i = start - self->length;
2807 if (i < 0)
2805 if (i < 0)
2808 return;
2806 return;
2809
2807
2810 for (i = start; i < len; i++) {
2808 for (i = start; i < len; i++) {
2811 const char *node = index_node(self, i);
2809 const char *node = index_node(self, i);
2812 nt_delete_node(&self->nt, node);
2810 nt_delete_node(&self->nt, node);
2813 }
2811 }
2814
2812
2815 self->new_length = start - self->length;
2813 self->new_length = start - self->length;
2816 }
2814 }
2817
2815
2818 /*
2816 /*
2819 * Delete a numeric range of revs, which must be at the end of the
2817 * Delete a numeric range of revs, which must be at the end of the
2820 * range.
2818 * range.
2821 */
2819 */
2822 static int index_slice_del(indexObject *self, PyObject *item)
2820 static int index_slice_del(indexObject *self, PyObject *item)
2823 {
2821 {
2824 Py_ssize_t start, stop, step, slicelength;
2822 Py_ssize_t start, stop, step, slicelength;
2825 Py_ssize_t length = index_length(self) + 1;
2823 Py_ssize_t length = index_length(self) + 1;
2826 int ret = 0;
2824 int ret = 0;
2827
2825
2828 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step,
2826 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step,
2829 &slicelength) < 0)
2827 &slicelength) < 0)
2830 return -1;
2828 return -1;
2831
2829
2832 if (slicelength <= 0)
2830 if (slicelength <= 0)
2833 return 0;
2831 return 0;
2834
2832
2835 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2833 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2836 stop = start;
2834 stop = start;
2837
2835
2838 if (step < 0) {
2836 if (step < 0) {
2839 stop = start + 1;
2837 stop = start + 1;
2840 start = stop + step * (slicelength - 1) - 1;
2838 start = stop + step * (slicelength - 1) - 1;
2841 step = -step;
2839 step = -step;
2842 }
2840 }
2843
2841
2844 if (step != 1) {
2842 if (step != 1) {
2845 PyErr_SetString(PyExc_ValueError,
2843 PyErr_SetString(PyExc_ValueError,
2846 "revlog index delete requires step size of 1");
2844 "revlog index delete requires step size of 1");
2847 return -1;
2845 return -1;
2848 }
2846 }
2849
2847
2850 if (stop != length - 1) {
2848 if (stop != length - 1) {
2851 PyErr_SetString(PyExc_IndexError,
2849 PyErr_SetString(PyExc_IndexError,
2852 "revlog index deletion indices are invalid");
2850 "revlog index deletion indices are invalid");
2853 return -1;
2851 return -1;
2854 }
2852 }
2855
2853
2856 if (start < self->length) {
2854 if (start < self->length) {
2857 if (self->ntinitialized) {
2855 if (self->ntinitialized) {
2858 Py_ssize_t i;
2856 Py_ssize_t i;
2859
2857
2860 for (i = start; i < self->length; i++) {
2858 for (i = start; i < self->length; i++) {
2861 const char *node = index_node_existing(self, i);
2859 const char *node = index_node_existing(self, i);
2862 if (node == NULL)
2860 if (node == NULL)
2863 return -1;
2861 return -1;
2864
2862
2865 nt_delete_node(&self->nt, node);
2863 nt_delete_node(&self->nt, node);
2866 }
2864 }
2867 if (self->new_length)
2865 if (self->new_length)
2868 index_invalidate_added(self, self->length);
2866 index_invalidate_added(self, self->length);
2869 if (self->ntrev > start)
2867 if (self->ntrev > start)
2870 self->ntrev = (int)start;
2868 self->ntrev = (int)start;
2871 } else if (self->new_length) {
2869 } else if (self->new_length) {
2872 self->new_length = 0;
2870 self->new_length = 0;
2873 }
2871 }
2874
2872
2875 self->length = start;
2873 self->length = start;
2876 goto done;
2874 goto done;
2877 }
2875 }
2878
2876
2879 if (self->ntinitialized) {
2877 if (self->ntinitialized) {
2880 index_invalidate_added(self, start);
2878 index_invalidate_added(self, start);
2881 if (self->ntrev > start)
2879 if (self->ntrev > start)
2882 self->ntrev = (int)start;
2880 self->ntrev = (int)start;
2883 } else {
2881 } else {
2884 self->new_length = start - self->length;
2882 self->new_length = start - self->length;
2885 }
2883 }
2886 done:
2884 done:
2887 Py_CLEAR(self->headrevs);
2885 Py_CLEAR(self->headrevs);
2888 return ret;
2886 return ret;
2889 }
2887 }
2890
2888
2891 /*
2889 /*
2892 * Supported ops:
2890 * Supported ops:
2893 *
2891 *
2894 * slice deletion
2892 * slice deletion
2895 * string assignment (extend node->rev mapping)
2893 * string assignment (extend node->rev mapping)
2896 * string deletion (shrink node->rev mapping)
2894 * string deletion (shrink node->rev mapping)
2897 */
2895 */
2898 static int index_assign_subscript(indexObject *self, PyObject *item,
2896 static int index_assign_subscript(indexObject *self, PyObject *item,
2899 PyObject *value)
2897 PyObject *value)
2900 {
2898 {
2901 char *node;
2899 char *node;
2902 long rev;
2900 long rev;
2903
2901
2904 if (PySlice_Check(item) && value == NULL)
2902 if (PySlice_Check(item) && value == NULL)
2905 return index_slice_del(self, item);
2903 return index_slice_del(self, item);
2906
2904
2907 if (node_check(self->nodelen, item, &node) == -1)
2905 if (node_check(self->nodelen, item, &node) == -1)
2908 return -1;
2906 return -1;
2909
2907
2910 if (value == NULL)
2908 if (value == NULL)
2911 return self->ntinitialized ? nt_delete_node(&self->nt, node)
2909 return self->ntinitialized ? nt_delete_node(&self->nt, node)
2912 : 0;
2910 : 0;
2913 rev = PyLong_AsLong(value);
2911 rev = PyLong_AsLong(value);
2914 if (rev > INT_MAX || rev < 0) {
2912 if (rev > INT_MAX || rev < 0) {
2915 if (!PyErr_Occurred())
2913 if (!PyErr_Occurred())
2916 PyErr_SetString(PyExc_ValueError, "rev out of range");
2914 PyErr_SetString(PyExc_ValueError, "rev out of range");
2917 return -1;
2915 return -1;
2918 }
2916 }
2919
2917
2920 if (index_init_nt(self) == -1)
2918 if (index_init_nt(self) == -1)
2921 return -1;
2919 return -1;
2922 return nt_insert(&self->nt, node, (int)rev);
2920 return nt_insert(&self->nt, node, (int)rev);
2923 }
2921 }
2924
2922
2925 /*
2923 /*
2926 * Find all RevlogNG entries in an index that has inline data. Update
2924 * Find all RevlogNG entries in an index that has inline data. Update
2927 * the optional "offsets" table with those entries.
2925 * the optional "offsets" table with those entries.
2928 */
2926 */
2929 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2927 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2930 {
2928 {
2931 const char *data = (const char *)self->buf.buf;
2929 const char *data = (const char *)self->buf.buf;
2932 Py_ssize_t pos = 0;
2930 Py_ssize_t pos = 0;
2933 Py_ssize_t end = self->buf.len;
2931 Py_ssize_t end = self->buf.len;
2934 long incr = self->entry_size;
2932 long incr = self->entry_size;
2935 Py_ssize_t len = 0;
2933 Py_ssize_t len = 0;
2936
2934
2937 while (pos + self->entry_size <= end && pos >= 0) {
2935 while (pos + self->entry_size <= end && pos >= 0) {
2938 uint32_t comp_len, sidedata_comp_len = 0;
2936 uint32_t comp_len, sidedata_comp_len = 0;
2939 /* 3rd element of header is length of compressed inline data */
2937 /* 3rd element of header is length of compressed inline data */
2940 if (self->format_version == format_v1) {
2938 if (self->format_version == format_v1) {
2941 comp_len =
2939 comp_len =
2942 getbe32(data + pos + entry_v1_offset_comp_len);
2940 getbe32(data + pos + entry_v1_offset_comp_len);
2943 sidedata_comp_len = 0;
2941 sidedata_comp_len = 0;
2944 } else if (self->format_version == format_v2) {
2942 } else if (self->format_version == format_v2) {
2945 comp_len =
2943 comp_len =
2946 getbe32(data + pos + entry_v2_offset_comp_len);
2944 getbe32(data + pos + entry_v2_offset_comp_len);
2947 sidedata_comp_len = getbe32(
2945 sidedata_comp_len = getbe32(
2948 data + pos + entry_v2_offset_sidedata_comp_len);
2946 data + pos + entry_v2_offset_sidedata_comp_len);
2949 } else {
2947 } else {
2950 raise_revlog_error();
2948 raise_revlog_error();
2951 return -1;
2949 return -1;
2952 }
2950 }
2953 incr = self->entry_size + comp_len + sidedata_comp_len;
2951 incr = self->entry_size + comp_len + sidedata_comp_len;
2954 if (offsets)
2952 if (offsets)
2955 offsets[len] = data + pos;
2953 offsets[len] = data + pos;
2956 len++;
2954 len++;
2957 pos += incr;
2955 pos += incr;
2958 }
2956 }
2959
2957
2960 if (pos != end) {
2958 if (pos != end) {
2961 if (!PyErr_Occurred())
2959 if (!PyErr_Occurred())
2962 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2960 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2963 return -1;
2961 return -1;
2964 }
2962 }
2965
2963
2966 return len;
2964 return len;
2967 }
2965 }
2968
2966
2969 static int index_init(indexObject *self, PyObject *args, PyObject *kwargs)
2967 static int index_init(indexObject *self, PyObject *args, PyObject *kwargs)
2970 {
2968 {
2971 PyObject *data_obj, *inlined_obj;
2969 PyObject *data_obj, *inlined_obj;
2972 Py_ssize_t size;
2970 Py_ssize_t size;
2973
2971
2974 static char *kwlist[] = {"data", "inlined", "format", NULL};
2972 static char *kwlist[] = {"data", "inlined", "format", NULL};
2975
2973
2976 /* Initialize before argument-checking to avoid index_dealloc() crash.
2974 /* Initialize before argument-checking to avoid index_dealloc() crash.
2977 */
2975 */
2978 self->added = NULL;
2976 self->added = NULL;
2979 self->new_length = 0;
2977 self->new_length = 0;
2980 self->added_length = 0;
2978 self->added_length = 0;
2981 self->data = NULL;
2979 self->data = NULL;
2982 memset(&self->buf, 0, sizeof(self->buf));
2980 memset(&self->buf, 0, sizeof(self->buf));
2983 self->headrevs = NULL;
2981 self->headrevs = NULL;
2984 self->filteredrevs = Py_None;
2982 self->filteredrevs = Py_None;
2985 Py_INCREF(Py_None);
2983 Py_INCREF(Py_None);
2986 self->ntinitialized = 0;
2984 self->ntinitialized = 0;
2987 self->offsets = NULL;
2985 self->offsets = NULL;
2988 self->nodelen = 20;
2986 self->nodelen = 20;
2989 self->nullentry = NULL;
2987 self->nullentry = NULL;
2990 self->rust_ext_compat = 1;
2988 self->rust_ext_compat = 1;
2991 self->format_version = format_v1;
2989 self->format_version = format_v1;
2992
2990
2993 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|l", kwlist,
2991 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|l", kwlist,
2994 &data_obj, &inlined_obj,
2992 &data_obj, &inlined_obj,
2995 &(self->format_version)))
2993 &(self->format_version)))
2996 return -1;
2994 return -1;
2997 if (!PyObject_CheckBuffer(data_obj)) {
2995 if (!PyObject_CheckBuffer(data_obj)) {
2998 PyErr_SetString(PyExc_TypeError,
2996 PyErr_SetString(PyExc_TypeError,
2999 "data does not support buffer interface");
2997 "data does not support buffer interface");
3000 return -1;
2998 return -1;
3001 }
2999 }
3002 if (self->nodelen < 20 || self->nodelen > (Py_ssize_t)sizeof(nullid)) {
3000 if (self->nodelen < 20 || self->nodelen > (Py_ssize_t)sizeof(nullid)) {
3003 PyErr_SetString(PyExc_RuntimeError, "unsupported node size");
3001 PyErr_SetString(PyExc_RuntimeError, "unsupported node size");
3004 return -1;
3002 return -1;
3005 }
3003 }
3006
3004
3007 if (self->format_version == format_v1) {
3005 if (self->format_version == format_v1) {
3008 self->entry_size = v1_entry_size;
3006 self->entry_size = v1_entry_size;
3009 } else if (self->format_version == format_v2) {
3007 } else if (self->format_version == format_v2) {
3010 self->entry_size = v2_entry_size;
3008 self->entry_size = v2_entry_size;
3011 } else if (self->format_version == format_cl2) {
3009 } else if (self->format_version == format_cl2) {
3012 self->entry_size = cl2_entry_size;
3010 self->entry_size = cl2_entry_size;
3013 }
3011 }
3014
3012
3015 self->nullentry =
3013 self->nullentry = Py_BuildValue(
3016 Py_BuildValue(PY23("iiiiiiis#iiBBi", "iiiiiiiy#iiBBi"), 0, 0, 0, -1,
3014 "iiiiiiiy#iiBBi", 0, 0, 0, -1, -1, -1, -1, nullid, self->nodelen, 0,
3017 -1, -1, -1, nullid, self->nodelen, 0, 0,
3015 0, comp_mode_inline, comp_mode_inline, rank_unknown);
3018 comp_mode_inline, comp_mode_inline, rank_unknown);
3019
3016
3020 if (!self->nullentry)
3017 if (!self->nullentry)
3021 return -1;
3018 return -1;
3022 PyObject_GC_UnTrack(self->nullentry);
3019 PyObject_GC_UnTrack(self->nullentry);
3023
3020
3024 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
3021 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
3025 return -1;
3022 return -1;
3026 size = self->buf.len;
3023 size = self->buf.len;
3027
3024
3028 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
3025 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
3029 self->data = data_obj;
3026 self->data = data_obj;
3030
3027
3031 self->ntlookups = self->ntmisses = 0;
3028 self->ntlookups = self->ntmisses = 0;
3032 self->ntrev = -1;
3029 self->ntrev = -1;
3033 Py_INCREF(self->data);
3030 Py_INCREF(self->data);
3034
3031
3035 if (self->inlined) {
3032 if (self->inlined) {
3036 Py_ssize_t len = inline_scan(self, NULL);
3033 Py_ssize_t len = inline_scan(self, NULL);
3037 if (len == -1)
3034 if (len == -1)
3038 goto bail;
3035 goto bail;
3039 self->length = len;
3036 self->length = len;
3040 } else {
3037 } else {
3041 if (size % self->entry_size) {
3038 if (size % self->entry_size) {
3042 PyErr_SetString(PyExc_ValueError, "corrupt index file");
3039 PyErr_SetString(PyExc_ValueError, "corrupt index file");
3043 goto bail;
3040 goto bail;
3044 }
3041 }
3045 self->length = size / self->entry_size;
3042 self->length = size / self->entry_size;
3046 }
3043 }
3047
3044
3048 return 0;
3045 return 0;
3049 bail:
3046 bail:
3050 return -1;
3047 return -1;
3051 }
3048 }
3052
3049
3053 static PyObject *index_nodemap(indexObject *self)
3050 static PyObject *index_nodemap(indexObject *self)
3054 {
3051 {
3055 Py_INCREF(self);
3052 Py_INCREF(self);
3056 return (PyObject *)self;
3053 return (PyObject *)self;
3057 }
3054 }
3058
3055
3059 static void _index_clearcaches(indexObject *self)
3056 static void _index_clearcaches(indexObject *self)
3060 {
3057 {
3061 if (self->offsets) {
3058 if (self->offsets) {
3062 PyMem_Free((void *)self->offsets);
3059 PyMem_Free((void *)self->offsets);
3063 self->offsets = NULL;
3060 self->offsets = NULL;
3064 }
3061 }
3065 if (self->ntinitialized) {
3062 if (self->ntinitialized) {
3066 nt_dealloc(&self->nt);
3063 nt_dealloc(&self->nt);
3067 }
3064 }
3068 self->ntinitialized = 0;
3065 self->ntinitialized = 0;
3069 Py_CLEAR(self->headrevs);
3066 Py_CLEAR(self->headrevs);
3070 }
3067 }
3071
3068
3072 static PyObject *index_clearcaches(indexObject *self)
3069 static PyObject *index_clearcaches(indexObject *self)
3073 {
3070 {
3074 _index_clearcaches(self);
3071 _index_clearcaches(self);
3075 self->ntrev = -1;
3072 self->ntrev = -1;
3076 self->ntlookups = self->ntmisses = 0;
3073 self->ntlookups = self->ntmisses = 0;
3077 Py_RETURN_NONE;
3074 Py_RETURN_NONE;
3078 }
3075 }
3079
3076
3080 static void index_dealloc(indexObject *self)
3077 static void index_dealloc(indexObject *self)
3081 {
3078 {
3082 _index_clearcaches(self);
3079 _index_clearcaches(self);
3083 Py_XDECREF(self->filteredrevs);
3080 Py_XDECREF(self->filteredrevs);
3084 if (self->buf.buf) {
3081 if (self->buf.buf) {
3085 PyBuffer_Release(&self->buf);
3082 PyBuffer_Release(&self->buf);
3086 memset(&self->buf, 0, sizeof(self->buf));
3083 memset(&self->buf, 0, sizeof(self->buf));
3087 }
3084 }
3088 Py_XDECREF(self->data);
3085 Py_XDECREF(self->data);
3089 PyMem_Free(self->added);
3086 PyMem_Free(self->added);
3090 Py_XDECREF(self->nullentry);
3087 Py_XDECREF(self->nullentry);
3091 PyObject_Del(self);
3088 PyObject_Del(self);
3092 }
3089 }
3093
3090
3094 static PySequenceMethods index_sequence_methods = {
3091 static PySequenceMethods index_sequence_methods = {
3095 (lenfunc)index_length, /* sq_length */
3092 (lenfunc)index_length, /* sq_length */
3096 0, /* sq_concat */
3093 0, /* sq_concat */
3097 0, /* sq_repeat */
3094 0, /* sq_repeat */
3098 (ssizeargfunc)index_get, /* sq_item */
3095 (ssizeargfunc)index_get, /* sq_item */
3099 0, /* sq_slice */
3096 0, /* sq_slice */
3100 0, /* sq_ass_item */
3097 0, /* sq_ass_item */
3101 0, /* sq_ass_slice */
3098 0, /* sq_ass_slice */
3102 (objobjproc)index_contains, /* sq_contains */
3099 (objobjproc)index_contains, /* sq_contains */
3103 };
3100 };
3104
3101
3105 static PyMappingMethods index_mapping_methods = {
3102 static PyMappingMethods index_mapping_methods = {
3106 (lenfunc)index_length, /* mp_length */
3103 (lenfunc)index_length, /* mp_length */
3107 (binaryfunc)index_getitem, /* mp_subscript */
3104 (binaryfunc)index_getitem, /* mp_subscript */
3108 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
3105 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
3109 };
3106 };
3110
3107
3111 static PyMethodDef index_methods[] = {
3108 static PyMethodDef index_methods[] = {
3112 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
3109 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
3113 "return the gca set of the given revs"},
3110 "return the gca set of the given revs"},
3114 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
3111 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
3115 METH_VARARGS,
3112 METH_VARARGS,
3116 "return the heads of the common ancestors of the given revs"},
3113 "return the heads of the common ancestors of the given revs"},
3117 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
3114 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
3118 "clear the index caches"},
3115 "clear the index caches"},
3119 {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"},
3116 {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"},
3120 {"get_rev", (PyCFunction)index_m_get, METH_VARARGS,
3117 {"get_rev", (PyCFunction)index_m_get, METH_VARARGS,
3121 "return `rev` associated with a node or None"},
3118 "return `rev` associated with a node or None"},
3122 {"has_node", (PyCFunction)index_m_has_node, METH_O,
3119 {"has_node", (PyCFunction)index_m_has_node, METH_O,
3123 "return True if the node exist in the index"},
3120 "return True if the node exist in the index"},
3124 {"rev", (PyCFunction)index_m_rev, METH_O,
3121 {"rev", (PyCFunction)index_m_rev, METH_O,
3125 "return `rev` associated with a node or raise RevlogError"},
3122 "return `rev` associated with a node or raise RevlogError"},
3126 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, METH_VARARGS,
3123 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, METH_VARARGS,
3127 "compute phases"},
3124 "compute phases"},
3128 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
3125 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
3129 "reachableroots"},
3126 "reachableroots"},
3130 {"replace_sidedata_info", (PyCFunction)index_replace_sidedata_info,
3127 {"replace_sidedata_info", (PyCFunction)index_replace_sidedata_info,
3131 METH_VARARGS, "replace an existing index entry with a new value"},
3128 METH_VARARGS, "replace an existing index entry with a new value"},
3132 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
3129 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
3133 "get head revisions"}, /* Can do filtering since 3.2 */
3130 "get head revisions"}, /* Can do filtering since 3.2 */
3134 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
3131 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
3135 "get filtered head revisions"}, /* Can always do filtering */
3132 "get filtered head revisions"}, /* Can always do filtering */
3136 {"issnapshot", (PyCFunction)index_issnapshot, METH_O,
3133 {"issnapshot", (PyCFunction)index_issnapshot, METH_O,
3137 "True if the object is a snapshot"},
3134 "True if the object is a snapshot"},
3138 {"findsnapshots", (PyCFunction)index_findsnapshots, METH_VARARGS,
3135 {"findsnapshots", (PyCFunction)index_findsnapshots, METH_VARARGS,
3139 "Gather snapshot data in a cache dict"},
3136 "Gather snapshot data in a cache dict"},
3140 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
3137 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
3141 "determine revisions with deltas to reconstruct fulltext"},
3138 "determine revisions with deltas to reconstruct fulltext"},
3142 {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
3139 {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
3143 METH_VARARGS, "determine revisions with deltas to reconstruct fulltext"},
3140 METH_VARARGS, "determine revisions with deltas to reconstruct fulltext"},
3144 {"append", (PyCFunction)index_append, METH_O, "append an index entry"},
3141 {"append", (PyCFunction)index_append, METH_O, "append an index entry"},
3145 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
3142 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
3146 "match a potentially ambiguous node ID"},
3143 "match a potentially ambiguous node ID"},
3147 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
3144 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
3148 "find length of shortest hex nodeid of a binary ID"},
3145 "find length of shortest hex nodeid of a binary ID"},
3149 {"stats", (PyCFunction)index_stats, METH_NOARGS, "stats for the index"},
3146 {"stats", (PyCFunction)index_stats, METH_NOARGS, "stats for the index"},
3150 {"entry_binary", (PyCFunction)index_entry_binary, METH_O,
3147 {"entry_binary", (PyCFunction)index_entry_binary, METH_O,
3151 "return an entry in binary form"},
3148 "return an entry in binary form"},
3152 {"pack_header", (PyCFunction)index_pack_header, METH_VARARGS,
3149 {"pack_header", (PyCFunction)index_pack_header, METH_VARARGS,
3153 "pack the revlog header information into binary"},
3150 "pack the revlog header information into binary"},
3154 {NULL} /* Sentinel */
3151 {NULL} /* Sentinel */
3155 };
3152 };
3156
3153
3157 static PyGetSetDef index_getset[] = {
3154 static PyGetSetDef index_getset[] = {
3158 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
3155 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
3159 {NULL} /* Sentinel */
3156 {NULL} /* Sentinel */
3160 };
3157 };
3161
3158
3162 static PyMemberDef index_members[] = {
3159 static PyMemberDef index_members[] = {
3163 {"entry_size", T_LONG, offsetof(indexObject, entry_size), 0,
3160 {"entry_size", T_LONG, offsetof(indexObject, entry_size), 0,
3164 "size of an index entry"},
3161 "size of an index entry"},
3165 {"rust_ext_compat", T_LONG, offsetof(indexObject, rust_ext_compat), 0,
3162 {"rust_ext_compat", T_LONG, offsetof(indexObject, rust_ext_compat), 0,
3166 "size of an index entry"},
3163 "size of an index entry"},
3167 {NULL} /* Sentinel */
3164 {NULL} /* Sentinel */
3168 };
3165 };
3169
3166
3170 PyTypeObject HgRevlogIndex_Type = {
3167 PyTypeObject HgRevlogIndex_Type = {
3171 PyVarObject_HEAD_INIT(NULL, 0) /* header */
3168 PyVarObject_HEAD_INIT(NULL, 0) /* header */
3172 "parsers.index", /* tp_name */
3169 "parsers.index", /* tp_name */
3173 sizeof(indexObject), /* tp_basicsize */
3170 sizeof(indexObject), /* tp_basicsize */
3174 0, /* tp_itemsize */
3171 0, /* tp_itemsize */
3175 (destructor)index_dealloc, /* tp_dealloc */
3172 (destructor)index_dealloc, /* tp_dealloc */
3176 0, /* tp_print */
3173 0, /* tp_print */
3177 0, /* tp_getattr */
3174 0, /* tp_getattr */
3178 0, /* tp_setattr */
3175 0, /* tp_setattr */
3179 0, /* tp_compare */
3176 0, /* tp_compare */
3180 0, /* tp_repr */
3177 0, /* tp_repr */
3181 0, /* tp_as_number */
3178 0, /* tp_as_number */
3182 &index_sequence_methods, /* tp_as_sequence */
3179 &index_sequence_methods, /* tp_as_sequence */
3183 &index_mapping_methods, /* tp_as_mapping */
3180 &index_mapping_methods, /* tp_as_mapping */
3184 0, /* tp_hash */
3181 0, /* tp_hash */
3185 0, /* tp_call */
3182 0, /* tp_call */
3186 0, /* tp_str */
3183 0, /* tp_str */
3187 0, /* tp_getattro */
3184 0, /* tp_getattro */
3188 0, /* tp_setattro */
3185 0, /* tp_setattro */
3189 0, /* tp_as_buffer */
3186 0, /* tp_as_buffer */
3190 Py_TPFLAGS_DEFAULT, /* tp_flags */
3187 Py_TPFLAGS_DEFAULT, /* tp_flags */
3191 "revlog index", /* tp_doc */
3188 "revlog index", /* tp_doc */
3192 0, /* tp_traverse */
3189 0, /* tp_traverse */
3193 0, /* tp_clear */
3190 0, /* tp_clear */
3194 0, /* tp_richcompare */
3191 0, /* tp_richcompare */
3195 0, /* tp_weaklistoffset */
3192 0, /* tp_weaklistoffset */
3196 0, /* tp_iter */
3193 0, /* tp_iter */
3197 0, /* tp_iternext */
3194 0, /* tp_iternext */
3198 index_methods, /* tp_methods */
3195 index_methods, /* tp_methods */
3199 index_members, /* tp_members */
3196 index_members, /* tp_members */
3200 index_getset, /* tp_getset */
3197 index_getset, /* tp_getset */
3201 0, /* tp_base */
3198 0, /* tp_base */
3202 0, /* tp_dict */
3199 0, /* tp_dict */
3203 0, /* tp_descr_get */
3200 0, /* tp_descr_get */
3204 0, /* tp_descr_set */
3201 0, /* tp_descr_set */
3205 0, /* tp_dictoffset */
3202 0, /* tp_dictoffset */
3206 (initproc)index_init, /* tp_init */
3203 (initproc)index_init, /* tp_init */
3207 0, /* tp_alloc */
3204 0, /* tp_alloc */
3208 };
3205 };
3209
3206
3210 /*
3207 /*
3211 * returns a tuple of the form (index, cache) with elements as
3208 * returns a tuple of the form (index, cache) with elements as
3212 * follows:
3209 * follows:
3213 *
3210 *
3214 * index: an index object that lazily parses Revlog (v1 or v2) records
3211 * index: an index object that lazily parses Revlog (v1 or v2) records
3215 * cache: if data is inlined, a tuple (0, index_file_content), else None
3212 * cache: if data is inlined, a tuple (0, index_file_content), else None
3216 * index_file_content could be a string, or a buffer
3213 * index_file_content could be a string, or a buffer
3217 *
3214 *
3218 * added complications are for backwards compatibility
3215 * added complications are for backwards compatibility
3219 */
3216 */
3220 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs)
3217 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs)
3221 {
3218 {
3222 PyObject *cache = NULL;
3219 PyObject *cache = NULL;
3223 indexObject *idx;
3220 indexObject *idx;
3224 int ret;
3221 int ret;
3225
3222
3226 idx = PyObject_New(indexObject, &HgRevlogIndex_Type);
3223 idx = PyObject_New(indexObject, &HgRevlogIndex_Type);
3227 if (idx == NULL)
3224 if (idx == NULL)
3228 goto bail;
3225 goto bail;
3229
3226
3230 ret = index_init(idx, args, kwargs);
3227 ret = index_init(idx, args, kwargs);
3231 if (ret == -1)
3228 if (ret == -1)
3232 goto bail;
3229 goto bail;
3233
3230
3234 if (idx->inlined) {
3231 if (idx->inlined) {
3235 cache = Py_BuildValue("iO", 0, idx->data);
3232 cache = Py_BuildValue("iO", 0, idx->data);
3236 if (cache == NULL)
3233 if (cache == NULL)
3237 goto bail;
3234 goto bail;
3238 } else {
3235 } else {
3239 cache = Py_None;
3236 cache = Py_None;
3240 Py_INCREF(cache);
3237 Py_INCREF(cache);
3241 }
3238 }
3242
3239
3243 return Py_BuildValue("NN", idx, cache);
3240 return Py_BuildValue("NN", idx, cache);
3244
3241
3245 bail:
3242 bail:
3246 Py_XDECREF(idx);
3243 Py_XDECREF(idx);
3247 Py_XDECREF(cache);
3244 Py_XDECREF(cache);
3248 return NULL;
3245 return NULL;
3249 }
3246 }
3250
3247
3251 static Revlog_CAPI CAPI = {
3248 static Revlog_CAPI CAPI = {
3252 /* increment the abi_version field upon each change in the Revlog_CAPI
3249 /* increment the abi_version field upon each change in the Revlog_CAPI
3253 struct or in the ABI of the listed functions */
3250 struct or in the ABI of the listed functions */
3254 2,
3251 2,
3255 index_length,
3252 index_length,
3256 index_node,
3253 index_node,
3257 HgRevlogIndex_GetParents,
3254 HgRevlogIndex_GetParents,
3258 };
3255 };
3259
3256
3260 void revlog_module_init(PyObject *mod)
3257 void revlog_module_init(PyObject *mod)
3261 {
3258 {
3262 PyObject *caps = NULL;
3259 PyObject *caps = NULL;
3263 HgRevlogIndex_Type.tp_new = PyType_GenericNew;
3260 HgRevlogIndex_Type.tp_new = PyType_GenericNew;
3264 if (PyType_Ready(&HgRevlogIndex_Type) < 0)
3261 if (PyType_Ready(&HgRevlogIndex_Type) < 0)
3265 return;
3262 return;
3266 Py_INCREF(&HgRevlogIndex_Type);
3263 Py_INCREF(&HgRevlogIndex_Type);
3267 PyModule_AddObject(mod, "index", (PyObject *)&HgRevlogIndex_Type);
3264 PyModule_AddObject(mod, "index", (PyObject *)&HgRevlogIndex_Type);
3268
3265
3269 nodetreeType.tp_new = PyType_GenericNew;
3266 nodetreeType.tp_new = PyType_GenericNew;
3270 if (PyType_Ready(&nodetreeType) < 0)
3267 if (PyType_Ready(&nodetreeType) < 0)
3271 return;
3268 return;
3272 Py_INCREF(&nodetreeType);
3269 Py_INCREF(&nodetreeType);
3273 PyModule_AddObject(mod, "nodetree", (PyObject *)&nodetreeType);
3270 PyModule_AddObject(mod, "nodetree", (PyObject *)&nodetreeType);
3274
3271
3275 caps = PyCapsule_New(&CAPI, "mercurial.cext.parsers.revlog_CAPI", NULL);
3272 caps = PyCapsule_New(&CAPI, "mercurial.cext.parsers.revlog_CAPI", NULL);
3276 if (caps != NULL)
3273 if (caps != NULL)
3277 PyModule_AddObject(mod, "revlog_CAPI", caps);
3274 PyModule_AddObject(mod, "revlog_CAPI", caps);
3278 }
3275 }
@@ -1,92 +1,85 b''
1 /*
1 /*
2 util.h - utility functions for interfacing with the various python APIs.
2 util.h - utility functions for interfacing with the various python APIs.
3
3
4 This software may be used and distributed according to the terms of
4 This software may be used and distributed according to the terms of
5 the GNU General Public License, incorporated herein by reference.
5 the GNU General Public License, incorporated herein by reference.
6 */
6 */
7
7
8 #ifndef _HG_UTIL_H_
8 #ifndef _HG_UTIL_H_
9 #define _HG_UTIL_H_
9 #define _HG_UTIL_H_
10
10
11 #include "compat.h"
11 #include "compat.h"
12
12
13 #if PY_MAJOR_VERSION >= 3
13 #if PY_MAJOR_VERSION >= 3
14 #define IS_PY3K
14 #define IS_PY3K
15 #endif
15 #endif
16
16
17 /* helper to switch things like string literal depending on Python version */
18 #ifdef IS_PY3K
19 #define PY23(py2, py3) py3
20 #else
21 #define PY23(py2, py3) py2
22 #endif
23
24 /* clang-format off */
17 /* clang-format off */
25 typedef struct {
18 typedef struct {
26 PyObject_HEAD
19 PyObject_HEAD
27 int flags;
20 int flags;
28 int mode;
21 int mode;
29 int size;
22 int size;
30 int mtime_s;
23 int mtime_s;
31 int mtime_ns;
24 int mtime_ns;
32 } dirstateItemObject;
25 } dirstateItemObject;
33 /* clang-format on */
26 /* clang-format on */
34
27
35 static const int dirstate_flag_wc_tracked = 1 << 0;
28 static const int dirstate_flag_wc_tracked = 1 << 0;
36 static const int dirstate_flag_p1_tracked = 1 << 1;
29 static const int dirstate_flag_p1_tracked = 1 << 1;
37 static const int dirstate_flag_p2_info = 1 << 2;
30 static const int dirstate_flag_p2_info = 1 << 2;
38 static const int dirstate_flag_mode_exec_perm = 1 << 3;
31 static const int dirstate_flag_mode_exec_perm = 1 << 3;
39 static const int dirstate_flag_mode_is_symlink = 1 << 4;
32 static const int dirstate_flag_mode_is_symlink = 1 << 4;
40 static const int dirstate_flag_has_fallback_exec = 1 << 5;
33 static const int dirstate_flag_has_fallback_exec = 1 << 5;
41 static const int dirstate_flag_fallback_exec = 1 << 6;
34 static const int dirstate_flag_fallback_exec = 1 << 6;
42 static const int dirstate_flag_has_fallback_symlink = 1 << 7;
35 static const int dirstate_flag_has_fallback_symlink = 1 << 7;
43 static const int dirstate_flag_fallback_symlink = 1 << 8;
36 static const int dirstate_flag_fallback_symlink = 1 << 8;
44 static const int dirstate_flag_expected_state_is_modified = 1 << 9;
37 static const int dirstate_flag_expected_state_is_modified = 1 << 9;
45 static const int dirstate_flag_has_meaningful_data = 1 << 10;
38 static const int dirstate_flag_has_meaningful_data = 1 << 10;
46 static const int dirstate_flag_has_mtime = 1 << 11;
39 static const int dirstate_flag_has_mtime = 1 << 11;
47 static const int dirstate_flag_mtime_second_ambiguous = 1 << 12;
40 static const int dirstate_flag_mtime_second_ambiguous = 1 << 12;
48 static const int dirstate_flag_directory = 1 << 13;
41 static const int dirstate_flag_directory = 1 << 13;
49 static const int dirstate_flag_all_unknown_recorded = 1 << 14;
42 static const int dirstate_flag_all_unknown_recorded = 1 << 14;
50 static const int dirstate_flag_all_ignored_recorded = 1 << 15;
43 static const int dirstate_flag_all_ignored_recorded = 1 << 15;
51
44
52 extern PyTypeObject dirstateItemType;
45 extern PyTypeObject dirstateItemType;
53 #define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateItemType)
46 #define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateItemType)
54
47
55 #ifndef MIN
48 #ifndef MIN
56 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
49 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
57 #endif
50 #endif
58 /* VC9 doesn't include bool and lacks stdbool.h based on my searching */
51 /* VC9 doesn't include bool and lacks stdbool.h based on my searching */
59 #if defined(_MSC_VER) || __STDC_VERSION__ < 199901L
52 #if defined(_MSC_VER) || __STDC_VERSION__ < 199901L
60 #define true 1
53 #define true 1
61 #define false 0
54 #define false 0
62 typedef unsigned char bool;
55 typedef unsigned char bool;
63 #else
56 #else
64 #include <stdbool.h>
57 #include <stdbool.h>
65 #endif
58 #endif
66
59
67 static inline PyObject *_dict_new_presized(Py_ssize_t expected_size)
60 static inline PyObject *_dict_new_presized(Py_ssize_t expected_size)
68 {
61 {
69 /* _PyDict_NewPresized expects a minused parameter, but it actually
62 /* _PyDict_NewPresized expects a minused parameter, but it actually
70 creates a dictionary that's the nearest power of two bigger than the
63 creates a dictionary that's the nearest power of two bigger than the
71 parameter. For example, with the initial minused = 1000, the
64 parameter. For example, with the initial minused = 1000, the
72 dictionary created has size 1024. Of course in a lot of cases that
65 dictionary created has size 1024. Of course in a lot of cases that
73 can be greater than the maximum load factor Python's dict object
66 can be greater than the maximum load factor Python's dict object
74 expects (= 2/3), so as soon as we cross the threshold we'll resize
67 expects (= 2/3), so as soon as we cross the threshold we'll resize
75 anyway. So create a dictionary that's at least 3/2 the size. */
68 anyway. So create a dictionary that's at least 3/2 the size. */
76 return _PyDict_NewPresized(((1 + expected_size) / 2) * 3);
69 return _PyDict_NewPresized(((1 + expected_size) / 2) * 3);
77 }
70 }
78
71
79 /* Convert a PyInt or PyLong to a long. Returns false if there is an
72 /* Convert a PyInt or PyLong to a long. Returns false if there is an
80 error, in which case an exception will already have been set. */
73 error, in which case an exception will already have been set. */
81 static inline bool pylong_to_long(PyObject *pylong, long *out)
74 static inline bool pylong_to_long(PyObject *pylong, long *out)
82 {
75 {
83 *out = PyLong_AsLong(pylong);
76 *out = PyLong_AsLong(pylong);
84 /* Fast path to avoid hitting PyErr_Occurred if the value was obviously
77 /* Fast path to avoid hitting PyErr_Occurred if the value was obviously
85 * not an error. */
78 * not an error. */
86 if (*out != -1) {
79 if (*out != -1) {
87 return true;
80 return true;
88 }
81 }
89 return PyErr_Occurred() == NULL;
82 return PyErr_Occurred() == NULL;
90 }
83 }
91
84
92 #endif /* _HG_UTIL_H_ */
85 #endif /* _HG_UTIL_H_ */
General Comments 0
You need to be logged in to leave comments. Login now