##// END OF EJS Templates
dirstate: C parsing extension
Matt Mackall -
r7093:16bafceb default
parent child Browse files
Show More
@@ -10,7 +10,7 b' of the GNU General Public License, incor'
10 10 from node import nullid
11 11 from i18n import _
12 12 import struct, os, stat, util, errno, ignore
13 import cStringIO, osutil, sys
13 import cStringIO, osutil, sys, parsers
14 14
15 15 _unknown = ('?', 0, 0, 0)
16 16 _format = ">cllll"
@@ -190,8 +190,6 b' class dirstate(object):'
190 190 def _read(self):
191 191 self._map = {}
192 192 self._copymap = {}
193 if not self._dirtypl:
194 self._pl = [nullid, nullid]
195 193 try:
196 194 st = self._opener("dirstate").read()
197 195 except IOError, err:
@@ -200,27 +198,9 b' class dirstate(object):'
200 198 if not st:
201 199 return
202 200
201 p = parsers.parse_dirstate(self._map, self._copymap, st);
203 202 if not self._dirtypl:
204 self._pl = [st[:20], st[20: 40]]
205
206 # deref fields so they will be local in loop
207 dmap = self._map
208 copymap = self._copymap
209 unpack = struct.unpack
210 e_size = struct.calcsize(_format)
211 pos1 = 40
212 l = len(st)
213
214 # the inner loop
215 while pos1 < l:
216 pos2 = pos1 + e_size
217 e = unpack(">cllll", st[pos1:pos2]) # a literal here is faster
218 pos1 = pos2 + e[4]
219 f = st[pos2:pos1]
220 if '\0' in f:
221 f, c = f.split('\0')
222 copymap[f] = c
223 dmap[f] = e # we hold onto e[4] because making a subtuple is slow
203 self._pl = p
224 204
225 205 def invalidate(self):
226 206 for a in "_map _copymap _foldmap _branch _pl _dirs _ignore".split():
@@ -274,7 +254,7 b' class dirstate(object):'
274 254 self._dirty = True
275 255 self._addpath(f)
276 256 s = os.lstat(self._join(f))
277 self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0)
257 self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime)
278 258 if f in self._copymap:
279 259 del self._copymap[f]
280 260
@@ -297,7 +277,7 b' class dirstate(object):'
297 277 return
298 278 self._dirty = True
299 279 self._addpath(f)
300 self._map[f] = ('n', 0, -1, -1, 0)
280 self._map[f] = ('n', 0, -1, -1)
301 281 if f in self._copymap:
302 282 del self._copymap[f]
303 283
@@ -305,7 +285,7 b' class dirstate(object):'
305 285 'mark a file normal, but dirty'
306 286 self._dirty = True
307 287 self._addpath(f)
308 self._map[f] = ('n', 0, -2, -1, 0)
288 self._map[f] = ('n', 0, -2, -1)
309 289 if f in self._copymap:
310 290 del self._copymap[f]
311 291
@@ -313,7 +293,7 b' class dirstate(object):'
313 293 'mark a file added'
314 294 self._dirty = True
315 295 self._addpath(f, True)
316 self._map[f] = ('a', 0, -1, -1, 0)
296 self._map[f] = ('a', 0, -1, -1)
317 297 if f in self._copymap:
318 298 del self._copymap[f]
319 299
@@ -328,7 +308,7 b' class dirstate(object):'
328 308 size = -1
329 309 elif entry[0] == 'n' and entry[2] == -2:
330 310 size = -2
331 self._map[f] = ('r', 0, size, 0, 0)
311 self._map[f] = ('r', 0, size, 0)
332 312 if size == 0 and f in self._copymap:
333 313 del self._copymap[f]
334 314
@@ -337,7 +317,7 b' class dirstate(object):'
337 317 self._dirty = True
338 318 s = os.lstat(self._join(f))
339 319 self._addpath(f)
340 self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0)
320 self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime)
341 321 if f in self._copymap:
342 322 del self._copymap[f]
343 323
@@ -373,9 +353,9 b' class dirstate(object):'
373 353 self.clear()
374 354 for f in files:
375 355 if 'x' in files.flags(f):
376 self._map[f] = ('n', 0777, -1, 0, 0)
356 self._map[f] = ('n', 0777, -1, 0)
377 357 else:
378 self._map[f] = ('n', 0666, -1, 0, 0)
358 self._map[f] = ('n', 0666, -1, 0)
379 359 self._pl = (parent, nullid)
380 360 self._dirty = True
381 361
@@ -401,7 +381,7 b' class dirstate(object):'
401 381 if f in copymap:
402 382 f = "%s\0%s" % (f, copymap[f])
403 383 if e[3] > limit and e[0] == 'n':
404 e = (e[0], 0, -1, -1, 0)
384 e = (e[0], 0, -1, -1)
405 385 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
406 386 write(e)
407 387 write(f)
@@ -577,7 +557,7 b' class dirstate(object):'
577 557 uadd(fn)
578 558 continue
579 559
580 state, mode, size, time, foo = dmap[fn]
560 state, mode, size, time = dmap[fn]
581 561
582 562 if not st and state in "nma":
583 563 dadd(fn)
@@ -128,15 +128,117 b' static PyObject *parse_manifest(PyObject'
128 128
129 129 Py_INCREF(Py_None);
130 130 return Py_None;
131
132 131 quit:
133 132 return NULL;
134 133 }
135 134
135 #ifdef _WIN32
136 # ifdef _MSC_VER
137 /* msvc 6.0 has problems */
138 # define inline __inline
139 typedef unsigned long uint32_t;
140 # else
141 # include <stdint.h>
142 # endif
143 static uint32_t ntohl(uint32_t x)
144 {
145 return ((x & 0x000000ffUL) << 24) |
146 ((x & 0x0000ff00UL) << 8) |
147 ((x & 0x00ff0000UL) >> 8) |
148 ((x & 0xff000000UL) >> 24);
149 }
150 #else
151 /* not windows */
152 # include <sys/types.h>
153 # if defined __BEOS__ && !defined __HAIKU__
154 # include <ByteOrder.h>
155 # else
156 # include <arpa/inet.h>
157 # endif
158 # include <inttypes.h>
159 #endif
160
161 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
162 {
163 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
164 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
165 char *str, *cur, *end, *cpos;
166 int state, mode, size, mtime, flen;
167 int len;
168 char decode[16]; /* for alignment */
169
170 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
171 &PyDict_Type, &dmap,
172 &PyDict_Type, &cmap,
173 &str, &len))
174 goto quit;
175
176 /* read parents */
177 if (len < 40)
178 goto quit;
179
180 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
181 if (!parents)
182 goto quit;
183
184 /* read filenames */
185 cur = str + 40;
186 end = str + len;
187
188 while (cur < end - 17) {
189 /* unpack header */
190 state = *cur;
191 memcpy(decode, cur + 1, 16);
192 mode = ntohl(*(uint32_t *)(decode));
193 size = ntohl(*(uint32_t *)(decode + 4));
194 mtime = ntohl(*(uint32_t *)(decode + 8));
195 flen = ntohl(*(uint32_t *)(decode + 12));
196 cur += 17;
197 if (cur + flen > end)
198 goto quit;
199
200 entry = Py_BuildValue("ciii", state, mode, size, mtime);
201 PyObject_GC_UnTrack(entry); /* don't waste time with this */
202 if (!entry)
203 goto quit;
204
205 cpos = memchr(cur, 0, flen);
206 if (cpos) {
207 fname = PyString_FromStringAndSize(cur, cpos - cur);
208 cname = PyString_FromStringAndSize(cpos + 1,
209 flen - (cpos - cur) - 1);
210 if (!fname || !cname ||
211 PyDict_SetItem(cmap, fname, cname) == -1 ||
212 PyDict_SetItem(dmap, fname, entry) == -1)
213 goto quit;
214 Py_DECREF(cname);
215 } else {
216 fname = PyString_FromStringAndSize(cur, flen);
217 if (!fname ||
218 PyDict_SetItem(dmap, fname, entry) == -1)
219 goto quit;
220 }
221 cur += flen;
222 Py_DECREF(fname);
223 Py_DECREF(entry);
224 fname = cname = entry = NULL;
225 }
226
227 ret = parents;
228 Py_INCREF(ret);
229 quit:
230 Py_XDECREF(fname);
231 Py_XDECREF(cname);
232 Py_XDECREF(entry);
233 Py_XDECREF(parents);
234 return ret;
235 }
236
136 237 static char parsers_doc[] = "Efficient content parsing.";
137 238
138 239 static PyMethodDef methods[] = {
139 240 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
241 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
140 242 {NULL, NULL}
141 243 };
142 244
General Comments 0
You need to be logged in to leave comments. Login now