##// END OF EJS Templates
cffi: split modules from pure...
Yuya Nishihara -
r32512:0e8b0b9a default
parent child Browse files
Show More
@@ -0,0 +1,10 b''
1 # base85.py: pure python base85 codec
2 #
3 # Copyright (C) 2009 Brendan Cully <brendan@kublai.com>
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
7
8 from __future__ import absolute_import
9
10 from ..pure.base85 import *
@@ -0,0 +1,10 b''
1 # diffhelpers.py - pure Python implementation of diffhelpers.c
2 #
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
7
8 from __future__ import absolute_import
9
10 from ..pure.diffhelpers import *
@@ -0,0 +1,10 b''
1 # parsers.py - Python implementation of parsers.c
2 #
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
7
8 from __future__ import absolute_import
9
10 from ..pure.parsers import *
@@ -1,106 +1,22 b''
1 # bdiff.py - Python implementation of bdiff.c
1 # bdiff.py - CFFI implementation of bdiff.c
2 #
2 #
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
11 import re
12 import struct
10 import struct
13
11
14 from .. import policy
12 from ..pure.bdiff import *
15 policynocffi = policy.policynocffi
13 from . import _bdiff
16 modulepolicy = policy.policy
17
18 def splitnewlines(text):
19 '''like str.splitlines, but only split on newlines.'''
20 lines = [l + '\n' for l in text.split('\n')]
21 if lines:
22 if lines[-1] == '\n':
23 lines.pop()
24 else:
25 lines[-1] = lines[-1][:-1]
26 return lines
27
28 def _normalizeblocks(a, b, blocks):
29 prev = None
30 r = []
31 for curr in blocks:
32 if prev is None:
33 prev = curr
34 continue
35 shift = 0
36
37 a1, b1, l1 = prev
38 a1end = a1 + l1
39 b1end = b1 + l1
40
41 a2, b2, l2 = curr
42 a2end = a2 + l2
43 b2end = b2 + l2
44 if a1end == a2:
45 while (a1end + shift < a2end and
46 a[a1end + shift] == b[b1end + shift]):
47 shift += 1
48 elif b1end == b2:
49 while (b1end + shift < b2end and
50 a[a1end + shift] == b[b1end + shift]):
51 shift += 1
52 r.append((a1, b1, l1 + shift))
53 prev = a2 + shift, b2 + shift, l2 - shift
54 r.append(prev)
55 return r
56
14
57 def bdiff(a, b):
15 ffi = _bdiff.ffi
58 a = bytes(a).splitlines(True)
16 lib = _bdiff.lib
59 b = bytes(b).splitlines(True)
60
61 if not a:
62 s = "".join(b)
63 return s and (struct.pack(">lll", 0, 0, len(s)) + s)
64
65 bin = []
66 p = [0]
67 for i in a: p.append(p[-1] + len(i))
68
69 d = difflib.SequenceMatcher(None, a, b).get_matching_blocks()
70 d = _normalizeblocks(a, b, d)
71 la = 0
72 lb = 0
73 for am, bm, size in d:
74 s = "".join(b[lb:bm])
75 if am > la or s:
76 bin.append(struct.pack(">lll", p[la], p[am], len(s)) + s)
77 la = am + size
78 lb = bm + size
79
17
80 return "".join(bin)
18 if True:
81
19 if True:
82 def blocks(a, b):
83 an = splitnewlines(a)
84 bn = splitnewlines(b)
85 d = difflib.SequenceMatcher(None, an, bn).get_matching_blocks()
86 d = _normalizeblocks(an, bn, d)
87 return [(i, i + n, j, j + n) for (i, j, n) in d]
88
89 def fixws(text, allws):
90 if allws:
91 text = re.sub('[ \t\r]+', '', text)
92 else:
93 text = re.sub('[ \t\r]+', ' ', text)
94 text = text.replace(' \n', '\n')
95 return text
96
97 if modulepolicy not in policynocffi:
98 try:
99 from ..cffi._bdiff import ffi, lib
100 except ImportError:
101 if modulepolicy == 'cffi': # strict cffi import
102 raise
103 else:
104 def blocks(sa, sb):
20 def blocks(sa, sb):
105 a = ffi.new("struct bdiff_line**")
21 a = ffi.new("struct bdiff_line**")
106 b = ffi.new("struct bdiff_line**")
22 b = ffi.new("struct bdiff_line**")
@@ -1,140 +1,21 b''
1 # mpatch.py - Python implementation of mpatch.c
1 # mpatch.py - CFFI implementation of mpatch.c
2 #
2 #
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import struct
10 from ..pure.mpatch import *
11
11 from ..pure.mpatch import mpatchError # silence pyflakes
12 from .. import policy, pycompat
12 from . import _mpatch
13 stringio = pycompat.stringio
14 modulepolicy = policy.policy
15 policynocffi = policy.policynocffi
16
17 class mpatchError(Exception):
18 """error raised when a delta cannot be decoded
19 """
20
21 # This attempts to apply a series of patches in time proportional to
22 # the total size of the patches, rather than patches * len(text). This
23 # means rather than shuffling strings around, we shuffle around
24 # pointers to fragments with fragment lists.
25 #
26 # When the fragment lists get too long, we collapse them. To do this
27 # efficiently, we do all our operations inside a buffer created by
28 # mmap and simply use memmove. This avoids creating a bunch of large
29 # temporary string buffers.
30
31 def _pull(dst, src, l): # pull l bytes from src
32 while l:
33 f = src.pop()
34 if f[0] > l: # do we need to split?
35 src.append((f[0] - l, f[1] + l))
36 dst.append((l, f[1]))
37 return
38 dst.append(f)
39 l -= f[0]
40
41 def _move(m, dest, src, count):
42 """move count bytes from src to dest
43
44 The file pointer is left at the end of dest.
45 """
46 m.seek(src)
47 buf = m.read(count)
48 m.seek(dest)
49 m.write(buf)
50
51 def _collect(m, buf, list):
52 start = buf
53 for l, p in reversed(list):
54 _move(m, buf, p, l)
55 buf += l
56 return (buf - start, start)
57
58 def patches(a, bins):
59 if not bins:
60 return a
61
62 plens = [len(x) for x in bins]
63 pl = sum(plens)
64 bl = len(a) + pl
65 tl = bl + bl + pl # enough for the patches and two working texts
66 b1, b2 = 0, bl
67
68 if not tl:
69 return a
70
71 m = stringio()
72
13
73 # load our original text
14 ffi = _mpatch.ffi
74 m.write(a)
15 lib = _mpatch.lib
75 frags = [(len(a), b1)]
76
77 # copy all the patches into our segment so we can memmove from them
78 pos = b2 + bl
79 m.seek(pos)
80 for p in bins: m.write(p)
81
82 for plen in plens:
83 # if our list gets too long, execute it
84 if len(frags) > 128:
85 b2, b1 = b1, b2
86 frags = [_collect(m, b1, frags)]
87
88 new = []
89 end = pos + plen
90 last = 0
91 while pos < end:
92 m.seek(pos)
93 try:
94 p1, p2, l = struct.unpack(">lll", m.read(12))
95 except struct.error:
96 raise mpatchError("patch cannot be decoded")
97 _pull(new, frags, p1 - last) # what didn't change
98 _pull([], frags, p2 - p1) # what got deleted
99 new.append((l, pos + 12)) # what got added
100 pos += l + 12
101 last = p2
102 frags.extend(reversed(new)) # what was left at the end
103
104 t = _collect(m, b2, frags)
105
16
106 m.seek(t[1])
17 if True:
107 return m.read(t[0])
18 if True:
108
109 def patchedsize(orig, delta):
110 outlen, last, bin = 0, 0, 0
111 binend = len(delta)
112 data = 12
113
114 while data <= binend:
115 decode = delta[bin:bin + 12]
116 start, end, length = struct.unpack(">lll", decode)
117 if start > end:
118 break
119 bin = data + length
120 data = bin + 12
121 outlen += start - last
122 last = end
123 outlen += length
124
125 if bin != binend:
126 raise mpatchError("patch cannot be decoded")
127
128 outlen += orig - last
129 return outlen
130
131 if modulepolicy not in policynocffi:
132 try:
133 from ..cffi._mpatch import ffi, lib
134 except ImportError:
135 if modulepolicy == 'cffi': # strict cffi import
136 raise
137 else:
138 @ffi.def_extern()
19 @ffi.def_extern()
139 def cffi_get_next_item(arg, pos):
20 def cffi_get_next_item(arg, pos):
140 all, bins = ffi.from_handle(arg)
21 all, bins = ffi.from_handle(arg)
@@ -1,82 +1,27 b''
1 # osutil.py - pure Python version of osutil.c
1 # osutil.py - CFFI version of osutil.c
2 #
2 #
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import ctypes
11 import ctypes.util
12 import os
10 import os
13 import socket
14 import stat as statmod
11 import stat as statmod
15
12
13 from ..pure.osutil import *
14
16 from .. import (
15 from .. import (
17 policy,
18 pycompat,
16 pycompat,
19 )
17 )
20
18
21 modulepolicy = policy.policy
19 if pycompat.sysplatform == 'darwin':
22 policynocffi = policy.policynocffi
20 from . import _osutil
23
24 def _mode_to_kind(mode):
25 if statmod.S_ISREG(mode):
26 return statmod.S_IFREG
27 if statmod.S_ISDIR(mode):
28 return statmod.S_IFDIR
29 if statmod.S_ISLNK(mode):
30 return statmod.S_IFLNK
31 if statmod.S_ISBLK(mode):
32 return statmod.S_IFBLK
33 if statmod.S_ISCHR(mode):
34 return statmod.S_IFCHR
35 if statmod.S_ISFIFO(mode):
36 return statmod.S_IFIFO
37 if statmod.S_ISSOCK(mode):
38 return statmod.S_IFSOCK
39 return mode
40
41 def listdirpure(path, stat=False, skip=None):
42 '''listdir(path, stat=False) -> list_of_tuples
43
44 Return a sorted list containing information about the entries
45 in the directory.
46
47 If stat is True, each element is a 3-tuple:
48
49 (name, type, stat object)
50
21
51 Otherwise, each element is a 2-tuple:
22 ffi = _osutil.ffi
23 lib = _osutil.lib
52
24
53 (name, type)
54 '''
55 result = []
56 prefix = path
57 if not prefix.endswith(pycompat.ossep):
58 prefix += pycompat.ossep
59 names = os.listdir(path)
60 names.sort()
61 for fn in names:
62 st = os.lstat(prefix + fn)
63 if fn == skip and statmod.S_ISDIR(st.st_mode):
64 return []
65 if stat:
66 result.append((fn, _mode_to_kind(st.st_mode), st))
67 else:
68 result.append((fn, _mode_to_kind(st.st_mode)))
69 return result
70
71 ffi = None
72 if modulepolicy not in policynocffi and pycompat.sysplatform == 'darwin':
73 try:
74 from ..cffi._osutil import ffi, lib
75 except ImportError:
76 if modulepolicy == 'cffi': # strict cffi import
77 raise
78
79 if pycompat.sysplatform == 'darwin' and ffi is not None:
80 listdir_batch_size = 4096
25 listdir_batch_size = 4096
81 # tweakable number, only affects performance, which chunks
26 # tweakable number, only affects performance, which chunks
82 # of bytes do we get back from getattrlistbulk
27 # of bytes do we get back from getattrlistbulk
@@ -155,211 +100,3 b" if pycompat.sysplatform == 'darwin' and "
155 pass # we ignore all the errors from closing, not
100 pass # we ignore all the errors from closing, not
156 # much we can do about that
101 # much we can do about that
157 return ret
102 return ret
158 else:
159 listdir = listdirpure
160
161 if pycompat.osname != 'nt':
162 posixfile = open
163
164 _SCM_RIGHTS = 0x01
165 _socklen_t = ctypes.c_uint
166
167 if pycompat.sysplatform.startswith('linux'):
168 # socket.h says "the type should be socklen_t but the definition of
169 # the kernel is incompatible with this."
170 _cmsg_len_t = ctypes.c_size_t
171 _msg_controllen_t = ctypes.c_size_t
172 _msg_iovlen_t = ctypes.c_size_t
173 else:
174 _cmsg_len_t = _socklen_t
175 _msg_controllen_t = _socklen_t
176 _msg_iovlen_t = ctypes.c_int
177
178 class _iovec(ctypes.Structure):
179 _fields_ = [
180 (u'iov_base', ctypes.c_void_p),
181 (u'iov_len', ctypes.c_size_t),
182 ]
183
184 class _msghdr(ctypes.Structure):
185 _fields_ = [
186 (u'msg_name', ctypes.c_void_p),
187 (u'msg_namelen', _socklen_t),
188 (u'msg_iov', ctypes.POINTER(_iovec)),
189 (u'msg_iovlen', _msg_iovlen_t),
190 (u'msg_control', ctypes.c_void_p),
191 (u'msg_controllen', _msg_controllen_t),
192 (u'msg_flags', ctypes.c_int),
193 ]
194
195 class _cmsghdr(ctypes.Structure):
196 _fields_ = [
197 (u'cmsg_len', _cmsg_len_t),
198 (u'cmsg_level', ctypes.c_int),
199 (u'cmsg_type', ctypes.c_int),
200 (u'cmsg_data', ctypes.c_ubyte * 0),
201 ]
202
203 _libc = ctypes.CDLL(ctypes.util.find_library(u'c'), use_errno=True)
204 _recvmsg = getattr(_libc, 'recvmsg', None)
205 if _recvmsg:
206 _recvmsg.restype = getattr(ctypes, 'c_ssize_t', ctypes.c_long)
207 _recvmsg.argtypes = (ctypes.c_int, ctypes.POINTER(_msghdr),
208 ctypes.c_int)
209 else:
210 # recvmsg isn't always provided by libc; such systems are unsupported
211 def _recvmsg(sockfd, msg, flags):
212 raise NotImplementedError('unsupported platform')
213
214 def _CMSG_FIRSTHDR(msgh):
215 if msgh.msg_controllen < ctypes.sizeof(_cmsghdr):
216 return
217 cmsgptr = ctypes.cast(msgh.msg_control, ctypes.POINTER(_cmsghdr))
218 return cmsgptr.contents
219
220 # The pure version is less portable than the native version because the
221 # handling of socket ancillary data heavily depends on C preprocessor.
222 # Also, some length fields are wrongly typed in Linux kernel.
223 def recvfds(sockfd):
224 """receive list of file descriptors via socket"""
225 dummy = (ctypes.c_ubyte * 1)()
226 iov = _iovec(ctypes.cast(dummy, ctypes.c_void_p), ctypes.sizeof(dummy))
227 cbuf = ctypes.create_string_buffer(256)
228 msgh = _msghdr(None, 0,
229 ctypes.pointer(iov), 1,
230 ctypes.cast(cbuf, ctypes.c_void_p), ctypes.sizeof(cbuf),
231 0)
232 r = _recvmsg(sockfd, ctypes.byref(msgh), 0)
233 if r < 0:
234 e = ctypes.get_errno()
235 raise OSError(e, os.strerror(e))
236 # assumes that the first cmsg has fds because it isn't easy to write
237 # portable CMSG_NXTHDR() with ctypes.
238 cmsg = _CMSG_FIRSTHDR(msgh)
239 if not cmsg:
240 return []
241 if (cmsg.cmsg_level != socket.SOL_SOCKET or
242 cmsg.cmsg_type != _SCM_RIGHTS):
243 return []
244 rfds = ctypes.cast(cmsg.cmsg_data, ctypes.POINTER(ctypes.c_int))
245 rfdscount = ((cmsg.cmsg_len - _cmsghdr.cmsg_data.offset) /
246 ctypes.sizeof(ctypes.c_int))
247 return [rfds[i] for i in xrange(rfdscount)]
248
249 else:
250 import msvcrt
251
252 _kernel32 = ctypes.windll.kernel32
253
254 _DWORD = ctypes.c_ulong
255 _LPCSTR = _LPSTR = ctypes.c_char_p
256 _HANDLE = ctypes.c_void_p
257
258 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
259
260 # CreateFile
261 _FILE_SHARE_READ = 0x00000001
262 _FILE_SHARE_WRITE = 0x00000002
263 _FILE_SHARE_DELETE = 0x00000004
264
265 _CREATE_ALWAYS = 2
266 _OPEN_EXISTING = 3
267 _OPEN_ALWAYS = 4
268
269 _GENERIC_READ = 0x80000000
270 _GENERIC_WRITE = 0x40000000
271
272 _FILE_ATTRIBUTE_NORMAL = 0x80
273
274 # open_osfhandle flags
275 _O_RDONLY = 0x0000
276 _O_RDWR = 0x0002
277 _O_APPEND = 0x0008
278
279 _O_TEXT = 0x4000
280 _O_BINARY = 0x8000
281
282 # types of parameters of C functions used (required by pypy)
283
284 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
285 _DWORD, _DWORD, _HANDLE]
286 _kernel32.CreateFileA.restype = _HANDLE
287
288 def _raiseioerror(name):
289 err = ctypes.WinError()
290 raise IOError(err.errno, '%s: %s' % (name, err.strerror))
291
292 class posixfile(object):
293 '''a file object aiming for POSIX-like semantics
294
295 CPython's open() returns a file that was opened *without* setting the
296 _FILE_SHARE_DELETE flag, which causes rename and unlink to abort.
297 This even happens if any hardlinked copy of the file is in open state.
298 We set _FILE_SHARE_DELETE here, so files opened with posixfile can be
299 renamed and deleted while they are held open.
300 Note that if a file opened with posixfile is unlinked, the file
301 remains but cannot be opened again or be recreated under the same name,
302 until all reading processes have closed the file.'''
303
304 def __init__(self, name, mode='r', bufsize=-1):
305 if 'b' in mode:
306 flags = _O_BINARY
307 else:
308 flags = _O_TEXT
309
310 m0 = mode[0]
311 if m0 == 'r' and '+' not in mode:
312 flags |= _O_RDONLY
313 access = _GENERIC_READ
314 else:
315 # work around http://support.microsoft.com/kb/899149 and
316 # set _O_RDWR for 'w' and 'a', even if mode has no '+'
317 flags |= _O_RDWR
318 access = _GENERIC_READ | _GENERIC_WRITE
319
320 if m0 == 'r':
321 creation = _OPEN_EXISTING
322 elif m0 == 'w':
323 creation = _CREATE_ALWAYS
324 elif m0 == 'a':
325 creation = _OPEN_ALWAYS
326 flags |= _O_APPEND
327 else:
328 raise ValueError("invalid mode: %s" % mode)
329
330 fh = _kernel32.CreateFileA(name, access,
331 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
332 None, creation, _FILE_ATTRIBUTE_NORMAL, None)
333 if fh == _INVALID_HANDLE_VALUE:
334 _raiseioerror(name)
335
336 fd = msvcrt.open_osfhandle(fh, flags)
337 if fd == -1:
338 _kernel32.CloseHandle(fh)
339 _raiseioerror(name)
340
341 f = os.fdopen(fd, pycompat.sysstr(mode), bufsize)
342 # unfortunately, f.name is '<fdopen>' at this point -- so we store
343 # the name on this wrapper. We cannot just assign to f.name,
344 # because that attribute is read-only.
345 object.__setattr__(self, r'name', name)
346 object.__setattr__(self, r'_file', f)
347
348 def __iter__(self):
349 return self._file
350
351 def __getattr__(self, name):
352 return getattr(self._file, name)
353
354 def __setattr__(self, name, value):
355 '''mimics the read-only attributes of Python file objects
356 by raising 'TypeError: readonly attribute' if someone tries:
357 f = posixfile('foo.txt')
358 f.name = 'bla' '''
359 return self._file.__setattr__(name, value)
360
361 def __enter__(self):
362 return self._file.__enter__()
363
364 def __exit__(self, exc_type, exc_value, exc_tb):
365 return self._file.__exit__(exc_type, exc_value, exc_tb)
@@ -28,8 +28,8 b" policynocffi = (b'c', b'py')"
28 # policy: (versioned package, pure package)
28 # policy: (versioned package, pure package)
29 b'c': (r'cext', None),
29 b'c': (r'cext', None),
30 b'allow': (r'cext', r'pure'),
30 b'allow': (r'cext', r'pure'),
31 b'cffi': (None, r'pure'), # TODO: (r'cffi', None)
31 b'cffi': (r'cffi', None),
32 b'cffi-allow': (None, r'pure'), # TODO: (r'cffi', r'pure')
32 b'cffi-allow': (r'cffi', r'pure'),
33 b'py': (None, r'pure'),
33 b'py': (None, r'pure'),
34 }
34 }
35
35
@@ -11,10 +11,6 b' import difflib'
11 import re
11 import re
12 import struct
12 import struct
13
13
14 from .. import policy
15 policynocffi = policy.policynocffi
16 modulepolicy = policy.policy
17
18 def splitnewlines(text):
14 def splitnewlines(text):
19 '''like str.splitlines, but only split on newlines.'''
15 '''like str.splitlines, but only split on newlines.'''
20 lines = [l + '\n' for l in text.split('\n')]
16 lines = [l + '\n' for l in text.split('\n')]
@@ -93,70 +89,3 b' def fixws(text, allws):'
93 text = re.sub('[ \t\r]+', ' ', text)
89 text = re.sub('[ \t\r]+', ' ', text)
94 text = text.replace(' \n', '\n')
90 text = text.replace(' \n', '\n')
95 return text
91 return text
96
97 if modulepolicy not in policynocffi:
98 try:
99 from ..cffi._bdiff import ffi, lib
100 except ImportError:
101 if modulepolicy == 'cffi': # strict cffi import
102 raise
103 else:
104 def blocks(sa, sb):
105 a = ffi.new("struct bdiff_line**")
106 b = ffi.new("struct bdiff_line**")
107 ac = ffi.new("char[]", str(sa))
108 bc = ffi.new("char[]", str(sb))
109 l = ffi.new("struct bdiff_hunk*")
110 try:
111 an = lib.bdiff_splitlines(ac, len(sa), a)
112 bn = lib.bdiff_splitlines(bc, len(sb), b)
113 if not a[0] or not b[0]:
114 raise MemoryError
115 count = lib.bdiff_diff(a[0], an, b[0], bn, l)
116 if count < 0:
117 raise MemoryError
118 rl = [None] * count
119 h = l.next
120 i = 0
121 while h:
122 rl[i] = (h.a1, h.a2, h.b1, h.b2)
123 h = h.next
124 i += 1
125 finally:
126 lib.free(a[0])
127 lib.free(b[0])
128 lib.bdiff_freehunks(l.next)
129 return rl
130
131 def bdiff(sa, sb):
132 a = ffi.new("struct bdiff_line**")
133 b = ffi.new("struct bdiff_line**")
134 ac = ffi.new("char[]", str(sa))
135 bc = ffi.new("char[]", str(sb))
136 l = ffi.new("struct bdiff_hunk*")
137 try:
138 an = lib.bdiff_splitlines(ac, len(sa), a)
139 bn = lib.bdiff_splitlines(bc, len(sb), b)
140 if not a[0] or not b[0]:
141 raise MemoryError
142 count = lib.bdiff_diff(a[0], an, b[0], bn, l)
143 if count < 0:
144 raise MemoryError
145 rl = []
146 h = l.next
147 la = lb = 0
148 while h:
149 if h.a1 != la or h.b1 != lb:
150 lgt = (b[0] + h.b1).l - (b[0] + lb).l
151 rl.append(struct.pack(">lll", (a[0] + la).l - a[0].l,
152 (a[0] + h.a1).l - a[0].l, lgt))
153 rl.append(str(ffi.buffer((b[0] + lb).l, lgt)))
154 la = h.a2
155 lb = h.b2
156 h = h.next
157
158 finally:
159 lib.free(a[0])
160 lib.free(b[0])
161 lib.bdiff_freehunks(l.next)
162 return "".join(rl)
@@ -9,10 +9,8 b' from __future__ import absolute_import'
9
9
10 import struct
10 import struct
11
11
12 from .. import policy, pycompat
12 from .. import pycompat
13 stringio = pycompat.stringio
13 stringio = pycompat.stringio
14 modulepolicy = policy.policy
15 policynocffi = policy.policynocffi
16
14
17 class mpatchError(Exception):
15 class mpatchError(Exception):
18 """error raised when a delta cannot be decoded
16 """error raised when a delta cannot be decoded
@@ -127,43 +125,3 b' def patchedsize(orig, delta):'
127
125
128 outlen += orig - last
126 outlen += orig - last
129 return outlen
127 return outlen
130
131 if modulepolicy not in policynocffi:
132 try:
133 from ..cffi._mpatch import ffi, lib
134 except ImportError:
135 if modulepolicy == 'cffi': # strict cffi import
136 raise
137 else:
138 @ffi.def_extern()
139 def cffi_get_next_item(arg, pos):
140 all, bins = ffi.from_handle(arg)
141 container = ffi.new("struct mpatch_flist*[1]")
142 to_pass = ffi.new("char[]", str(bins[pos]))
143 all.append(to_pass)
144 r = lib.mpatch_decode(to_pass, len(to_pass) - 1, container)
145 if r < 0:
146 return ffi.NULL
147 return container[0]
148
149 def patches(text, bins):
150 lgt = len(bins)
151 all = []
152 if not lgt:
153 return text
154 arg = (all, bins)
155 patch = lib.mpatch_fold(ffi.new_handle(arg),
156 lib.cffi_get_next_item, 0, lgt)
157 if not patch:
158 raise mpatchError("cannot decode chunk")
159 outlen = lib.mpatch_calcsize(len(text), patch)
160 if outlen < 0:
161 lib.mpatch_lfree(patch)
162 raise mpatchError("inconsistency detected")
163 buf = ffi.new("char[]", outlen)
164 if lib.mpatch_apply(buf, text, len(text), patch) < 0:
165 lib.mpatch_lfree(patch)
166 raise mpatchError("error applying patches")
167 res = ffi.buffer(buf, outlen)[:]
168 lib.mpatch_lfree(patch)
169 return res
@@ -14,13 +14,9 b' import socket'
14 import stat as statmod
14 import stat as statmod
15
15
16 from .. import (
16 from .. import (
17 policy,
18 pycompat,
17 pycompat,
19 )
18 )
20
19
21 modulepolicy = policy.policy
22 policynocffi = policy.policynocffi
23
24 def _mode_to_kind(mode):
20 def _mode_to_kind(mode):
25 if statmod.S_ISREG(mode):
21 if statmod.S_ISREG(mode):
26 return statmod.S_IFREG
22 return statmod.S_IFREG
@@ -38,7 +34,7 b' def _mode_to_kind(mode):'
38 return statmod.S_IFSOCK
34 return statmod.S_IFSOCK
39 return mode
35 return mode
40
36
41 def listdirpure(path, stat=False, skip=None):
37 def listdir(path, stat=False, skip=None):
42 '''listdir(path, stat=False) -> list_of_tuples
38 '''listdir(path, stat=False) -> list_of_tuples
43
39
44 Return a sorted list containing information about the entries
40 Return a sorted list containing information about the entries
@@ -68,96 +64,6 b' def listdirpure(path, stat=False, skip=N'
68 result.append((fn, _mode_to_kind(st.st_mode)))
64 result.append((fn, _mode_to_kind(st.st_mode)))
69 return result
65 return result
70
66
71 ffi = None
72 if modulepolicy not in policynocffi and pycompat.sysplatform == 'darwin':
73 try:
74 from ..cffi._osutil import ffi, lib
75 except ImportError:
76 if modulepolicy == 'cffi': # strict cffi import
77 raise
78
79 if pycompat.sysplatform == 'darwin' and ffi is not None:
80 listdir_batch_size = 4096
81 # tweakable number, only affects performance, which chunks
82 # of bytes do we get back from getattrlistbulk
83
84 attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty
85
86 attrkinds[lib.VREG] = statmod.S_IFREG
87 attrkinds[lib.VDIR] = statmod.S_IFDIR
88 attrkinds[lib.VLNK] = statmod.S_IFLNK
89 attrkinds[lib.VBLK] = statmod.S_IFBLK
90 attrkinds[lib.VCHR] = statmod.S_IFCHR
91 attrkinds[lib.VFIFO] = statmod.S_IFIFO
92 attrkinds[lib.VSOCK] = statmod.S_IFSOCK
93
94 class stat_res(object):
95 def __init__(self, st_mode, st_mtime, st_size):
96 self.st_mode = st_mode
97 self.st_mtime = st_mtime
98 self.st_size = st_size
99
100 tv_sec_ofs = ffi.offsetof("struct timespec", "tv_sec")
101 buf = ffi.new("char[]", listdir_batch_size)
102
103 def listdirinternal(dfd, req, stat, skip):
104 ret = []
105 while True:
106 r = lib.getattrlistbulk(dfd, req, buf, listdir_batch_size, 0)
107 if r == 0:
108 break
109 if r == -1:
110 raise OSError(ffi.errno, os.strerror(ffi.errno))
111 cur = ffi.cast("val_attrs_t*", buf)
112 for i in range(r):
113 lgt = cur.length
114 assert lgt == ffi.cast('uint32_t*', cur)[0]
115 ofs = cur.name_info.attr_dataoffset
116 str_lgt = cur.name_info.attr_length
117 base_ofs = ffi.offsetof('val_attrs_t', 'name_info')
118 name = str(ffi.buffer(ffi.cast("char*", cur) + base_ofs + ofs,
119 str_lgt - 1))
120 tp = attrkinds[cur.obj_type]
121 if name == "." or name == "..":
122 continue
123 if skip == name and tp == statmod.S_ISDIR:
124 return []
125 if stat:
126 mtime = cur.mtime.tv_sec
127 mode = (cur.accessmask & ~lib.S_IFMT)| tp
128 ret.append((name, tp, stat_res(st_mode=mode, st_mtime=mtime,
129 st_size=cur.datalength)))
130 else:
131 ret.append((name, tp))
132 cur = ffi.cast("val_attrs_t*", int(ffi.cast("intptr_t", cur))
133 + lgt)
134 return ret
135
136 def listdir(path, stat=False, skip=None):
137 req = ffi.new("struct attrlist*")
138 req.bitmapcount = lib.ATTR_BIT_MAP_COUNT
139 req.commonattr = (lib.ATTR_CMN_RETURNED_ATTRS |
140 lib.ATTR_CMN_NAME |
141 lib.ATTR_CMN_OBJTYPE |
142 lib.ATTR_CMN_ACCESSMASK |
143 lib.ATTR_CMN_MODTIME)
144 req.fileattr = lib.ATTR_FILE_DATALENGTH
145 dfd = lib.open(path, lib.O_RDONLY, 0)
146 if dfd == -1:
147 raise OSError(ffi.errno, os.strerror(ffi.errno))
148
149 try:
150 ret = listdirinternal(dfd, req, stat, skip)
151 finally:
152 try:
153 lib.close(dfd)
154 except BaseException:
155 pass # we ignore all the errors from closing, not
156 # much we can do about that
157 return ret
158 else:
159 listdir = listdirpure
160
161 if pycompat.osname != 'nt':
67 if pycompat.osname != 'nt':
162 posixfile = open
68 posixfile = open
163
69
General Comments 0
You need to be logged in to leave comments. Login now