##// END OF EJS Templates
cffi: pass C type and attribute names as str instead of bytes
Manuel Jacob -
r52683:ecc3a893 stable
parent child Browse files
Show More
@@ -1,88 +1,88
1 # bdiff.py - CFFI implementation of bdiff.c
1 # bdiff.py - CFFI implementation of bdiff.c
2 #
2 #
3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
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
8
9 import struct
9 import struct
10
10
11 from typing import (
11 from typing import (
12 List,
12 List,
13 Tuple,
13 Tuple,
14 )
14 )
15
15
16 from ..pure.bdiff import *
16 from ..pure.bdiff import *
17 from . import _bdiff # pytype: disable=import-error
17 from . import _bdiff # pytype: disable=import-error
18
18
19 ffi = _bdiff.ffi
19 ffi = _bdiff.ffi
20 lib = _bdiff.lib
20 lib = _bdiff.lib
21
21
22
22
23 def blocks(sa: bytes, sb: bytes) -> List[Tuple[int, int, int, int]]:
23 def blocks(sa: bytes, sb: bytes) -> List[Tuple[int, int, int, int]]:
24 a = ffi.new(b"struct bdiff_line**")
24 a = ffi.new("struct bdiff_line**")
25 b = ffi.new(b"struct bdiff_line**")
25 b = ffi.new("struct bdiff_line**")
26 ac = ffi.new(b"char[]", str(sa))
26 ac = ffi.new("char[]", str(sa))
27 bc = ffi.new(b"char[]", str(sb))
27 bc = ffi.new("char[]", str(sb))
28 l = ffi.new(b"struct bdiff_hunk*")
28 l = ffi.new("struct bdiff_hunk*")
29 try:
29 try:
30 an = lib.bdiff_splitlines(ac, len(sa), a)
30 an = lib.bdiff_splitlines(ac, len(sa), a)
31 bn = lib.bdiff_splitlines(bc, len(sb), b)
31 bn = lib.bdiff_splitlines(bc, len(sb), b)
32 if not a[0] or not b[0]:
32 if not a[0] or not b[0]:
33 raise MemoryError
33 raise MemoryError
34 count = lib.bdiff_diff(a[0], an, b[0], bn, l)
34 count = lib.bdiff_diff(a[0], an, b[0], bn, l)
35 if count < 0:
35 if count < 0:
36 raise MemoryError
36 raise MemoryError
37 rl = [(0, 0, 0, 0)] * count
37 rl = [(0, 0, 0, 0)] * count
38 h = l.next
38 h = l.next
39 i = 0
39 i = 0
40 while h:
40 while h:
41 rl[i] = (h.a1, h.a2, h.b1, h.b2)
41 rl[i] = (h.a1, h.a2, h.b1, h.b2)
42 h = h.next
42 h = h.next
43 i += 1
43 i += 1
44 finally:
44 finally:
45 lib.free(a[0])
45 lib.free(a[0])
46 lib.free(b[0])
46 lib.free(b[0])
47 lib.bdiff_freehunks(l.next)
47 lib.bdiff_freehunks(l.next)
48 return rl
48 return rl
49
49
50
50
51 def bdiff(sa: bytes, sb: bytes) -> bytes:
51 def bdiff(sa: bytes, sb: bytes) -> bytes:
52 a = ffi.new(b"struct bdiff_line**")
52 a = ffi.new("struct bdiff_line**")
53 b = ffi.new(b"struct bdiff_line**")
53 b = ffi.new("struct bdiff_line**")
54 ac = ffi.new(b"char[]", str(sa))
54 ac = ffi.new("char[]", str(sa))
55 bc = ffi.new(b"char[]", str(sb))
55 bc = ffi.new("char[]", str(sb))
56 l = ffi.new(b"struct bdiff_hunk*")
56 l = ffi.new("struct bdiff_hunk*")
57 try:
57 try:
58 an = lib.bdiff_splitlines(ac, len(sa), a)
58 an = lib.bdiff_splitlines(ac, len(sa), a)
59 bn = lib.bdiff_splitlines(bc, len(sb), b)
59 bn = lib.bdiff_splitlines(bc, len(sb), b)
60 if not a[0] or not b[0]:
60 if not a[0] or not b[0]:
61 raise MemoryError
61 raise MemoryError
62 count = lib.bdiff_diff(a[0], an, b[0], bn, l)
62 count = lib.bdiff_diff(a[0], an, b[0], bn, l)
63 if count < 0:
63 if count < 0:
64 raise MemoryError
64 raise MemoryError
65 rl = []
65 rl = []
66 h = l.next
66 h = l.next
67 la = lb = 0
67 la = lb = 0
68 while h:
68 while h:
69 if h.a1 != la or h.b1 != lb:
69 if h.a1 != la or h.b1 != lb:
70 lgt = (b[0] + h.b1).l - (b[0] + lb).l
70 lgt = (b[0] + h.b1).l - (b[0] + lb).l
71 rl.append(
71 rl.append(
72 struct.pack(
72 struct.pack(
73 b">lll",
73 b">lll",
74 (a[0] + la).l - a[0].l,
74 (a[0] + la).l - a[0].l,
75 (a[0] + h.a1).l - a[0].l,
75 (a[0] + h.a1).l - a[0].l,
76 lgt,
76 lgt,
77 )
77 )
78 )
78 )
79 rl.append(str(ffi.buffer((b[0] + lb).l, lgt)))
79 rl.append(str(ffi.buffer((b[0] + lb).l, lgt)))
80 la = h.a2
80 la = h.a2
81 lb = h.b2
81 lb = h.b2
82 h = h.next
82 h = h.next
83
83
84 finally:
84 finally:
85 lib.free(a[0])
85 lib.free(a[0])
86 lib.free(b[0])
86 lib.free(b[0])
87 lib.bdiff_freehunks(l.next)
87 lib.bdiff_freehunks(l.next)
88 return b"".join(rl)
88 return b"".join(rl)
@@ -1,50 +1,50
1 # mpatch.py - CFFI implementation of mpatch.c
1 # mpatch.py - CFFI implementation of mpatch.c
2 #
2 #
3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
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
8
9 from typing import List
9 from typing import List
10
10
11 from ..pure.mpatch import *
11 from ..pure.mpatch import *
12 from ..pure.mpatch import mpatchError # silence pyflakes
12 from ..pure.mpatch import mpatchError # silence pyflakes
13 from . import _mpatch # pytype: disable=import-error
13 from . import _mpatch # pytype: disable=import-error
14
14
15 ffi = _mpatch.ffi
15 ffi = _mpatch.ffi
16 lib = _mpatch.lib
16 lib = _mpatch.lib
17
17
18
18
19 @ffi.def_extern()
19 @ffi.def_extern()
20 def cffi_get_next_item(arg, pos):
20 def cffi_get_next_item(arg, pos):
21 all, bins = ffi.from_handle(arg)
21 all, bins = ffi.from_handle(arg)
22 container = ffi.new(b"struct mpatch_flist*[1]")
22 container = ffi.new("struct mpatch_flist*[1]")
23 to_pass = ffi.new(b"char[]", str(bins[pos]))
23 to_pass = ffi.new("char[]", str(bins[pos]))
24 all.append(to_pass)
24 all.append(to_pass)
25 r = lib.mpatch_decode(to_pass, len(to_pass) - 1, container)
25 r = lib.mpatch_decode(to_pass, len(to_pass) - 1, container)
26 if r < 0:
26 if r < 0:
27 return ffi.NULL
27 return ffi.NULL
28 return container[0]
28 return container[0]
29
29
30
30
31 def patches(text: bytes, bins: List[bytes]) -> bytes:
31 def patches(text: bytes, bins: List[bytes]) -> bytes:
32 lgt = len(bins)
32 lgt = len(bins)
33 all = []
33 all = []
34 if not lgt:
34 if not lgt:
35 return text
35 return text
36 arg = (all, bins)
36 arg = (all, bins)
37 patch = lib.mpatch_fold(ffi.new_handle(arg), lib.cffi_get_next_item, 0, lgt)
37 patch = lib.mpatch_fold(ffi.new_handle(arg), lib.cffi_get_next_item, 0, lgt)
38 if not patch:
38 if not patch:
39 raise mpatchError(b"cannot decode chunk")
39 raise mpatchError(b"cannot decode chunk")
40 outlen = lib.mpatch_calcsize(len(text), patch)
40 outlen = lib.mpatch_calcsize(len(text), patch)
41 if outlen < 0:
41 if outlen < 0:
42 lib.mpatch_lfree(patch)
42 lib.mpatch_lfree(patch)
43 raise mpatchError(b"inconsistency detected")
43 raise mpatchError(b"inconsistency detected")
44 buf = ffi.new(b"char[]", outlen)
44 buf = ffi.new("char[]", outlen)
45 if lib.mpatch_apply(buf, text, len(text), patch) < 0:
45 if lib.mpatch_apply(buf, text, len(text), patch) < 0:
46 lib.mpatch_lfree(patch)
46 lib.mpatch_lfree(patch)
47 raise mpatchError(b"error applying patches")
47 raise mpatchError(b"error applying patches")
48 res = ffi.buffer(buf, outlen)[:]
48 res = ffi.buffer(buf, outlen)[:]
49 lib.mpatch_lfree(patch)
49 lib.mpatch_lfree(patch)
50 return res
50 return res
@@ -1,114 +1,114
1 # osutil.py - CFFI version of osutil.c
1 # osutil.py - CFFI version of osutil.c
2 #
2 #
3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
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
8
9 import os
9 import os
10 import stat as statmod
10 import stat as statmod
11
11
12 from ..pure.osutil import *
12 from ..pure.osutil import *
13
13
14 from .. import pycompat
14 from .. import pycompat
15
15
16 if pycompat.isdarwin:
16 if pycompat.isdarwin:
17 from . import _osutil # pytype: disable=import-error
17 from . import _osutil # pytype: disable=import-error
18
18
19 ffi = _osutil.ffi
19 ffi = _osutil.ffi
20 lib = _osutil.lib
20 lib = _osutil.lib
21
21
22 listdir_batch_size = 4096
22 listdir_batch_size = 4096
23 # tweakable number, only affects performance, which chunks
23 # tweakable number, only affects performance, which chunks
24 # of bytes do we get back from getattrlistbulk
24 # of bytes do we get back from getattrlistbulk
25
25
26 attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty
26 attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty
27
27
28 attrkinds[lib.VREG] = statmod.S_IFREG
28 attrkinds[lib.VREG] = statmod.S_IFREG
29 attrkinds[lib.VDIR] = statmod.S_IFDIR
29 attrkinds[lib.VDIR] = statmod.S_IFDIR
30 attrkinds[lib.VLNK] = statmod.S_IFLNK
30 attrkinds[lib.VLNK] = statmod.S_IFLNK
31 attrkinds[lib.VBLK] = statmod.S_IFBLK
31 attrkinds[lib.VBLK] = statmod.S_IFBLK
32 attrkinds[lib.VCHR] = statmod.S_IFCHR
32 attrkinds[lib.VCHR] = statmod.S_IFCHR
33 attrkinds[lib.VFIFO] = statmod.S_IFIFO
33 attrkinds[lib.VFIFO] = statmod.S_IFIFO
34 attrkinds[lib.VSOCK] = statmod.S_IFSOCK
34 attrkinds[lib.VSOCK] = statmod.S_IFSOCK
35
35
36 class stat_res:
36 class stat_res:
37 def __init__(self, st_mode, st_mtime, st_size):
37 def __init__(self, st_mode, st_mtime, st_size):
38 self.st_mode = st_mode
38 self.st_mode = st_mode
39 self.st_mtime = st_mtime
39 self.st_mtime = st_mtime
40 self.st_size = st_size
40 self.st_size = st_size
41
41
42 tv_sec_ofs = ffi.offsetof(b"struct timespec", b"tv_sec")
42 tv_sec_ofs = ffi.offsetof("struct timespec", "tv_sec")
43 buf = ffi.new(b"char[]", listdir_batch_size)
43 buf = ffi.new("char[]", listdir_batch_size)
44
44
45 def listdirinternal(dfd, req, stat, skip):
45 def listdirinternal(dfd, req, stat, skip):
46 ret = []
46 ret = []
47 while True:
47 while True:
48 r = lib.getattrlistbulk(dfd, req, buf, listdir_batch_size, 0)
48 r = lib.getattrlistbulk(dfd, req, buf, listdir_batch_size, 0)
49 if r == 0:
49 if r == 0:
50 break
50 break
51 if r == -1:
51 if r == -1:
52 raise OSError(ffi.errno, os.strerror(ffi.errno))
52 raise OSError(ffi.errno, os.strerror(ffi.errno))
53 cur = ffi.cast(b"val_attrs_t*", buf)
53 cur = ffi.cast("val_attrs_t*", buf)
54 for i in range(r):
54 for i in range(r):
55 lgt = cur.length
55 lgt = cur.length
56 assert lgt == ffi.cast(b'uint32_t*', cur)[0]
56 assert lgt == ffi.cast('uint32_t*', cur)[0]
57 ofs = cur.name_info.attr_dataoffset
57 ofs = cur.name_info.attr_dataoffset
58 str_lgt = cur.name_info.attr_length
58 str_lgt = cur.name_info.attr_length
59 base_ofs = ffi.offsetof(b'val_attrs_t', b'name_info')
59 base_ofs = ffi.offsetof('val_attrs_t', 'name_info')
60 name = bytes(
60 name = bytes(
61 ffi.buffer(
61 ffi.buffer(
62 ffi.cast(b"char*", cur) + base_ofs + ofs, str_lgt - 1
62 ffi.cast("char*", cur) + base_ofs + ofs, str_lgt - 1
63 )
63 )
64 )
64 )
65 tp = attrkinds[cur.obj_type]
65 tp = attrkinds[cur.obj_type]
66 if name == b"." or name == b"..":
66 if name == b"." or name == b"..":
67 continue
67 continue
68 if skip == name and tp == statmod.S_ISDIR:
68 if skip == name and tp == statmod.S_ISDIR:
69 return []
69 return []
70 if stat:
70 if stat:
71 mtime = cur.mtime.tv_sec
71 mtime = cur.mtime.tv_sec
72 mode = (cur.accessmask & ~lib.S_IFMT) | tp
72 mode = (cur.accessmask & ~lib.S_IFMT) | tp
73 ret.append(
73 ret.append(
74 (
74 (
75 name,
75 name,
76 tp,
76 tp,
77 stat_res(
77 stat_res(
78 st_mode=mode,
78 st_mode=mode,
79 st_mtime=mtime,
79 st_mtime=mtime,
80 st_size=cur.datalength,
80 st_size=cur.datalength,
81 ),
81 ),
82 )
82 )
83 )
83 )
84 else:
84 else:
85 ret.append((name, tp))
85 ret.append((name, tp))
86 cur = ffi.cast(
86 cur = ffi.cast(
87 b"val_attrs_t*", int(ffi.cast(b"intptr_t", cur)) + lgt
87 "val_attrs_t*", int(ffi.cast("intptr_t", cur)) + lgt
88 )
88 )
89 return ret
89 return ret
90
90
91 def listdir(path, stat=False, skip=None):
91 def listdir(path, stat=False, skip=None):
92 req = ffi.new(b"struct attrlist*")
92 req = ffi.new("struct attrlist*")
93 req.bitmapcount = lib.ATTR_BIT_MAP_COUNT
93 req.bitmapcount = lib.ATTR_BIT_MAP_COUNT
94 req.commonattr = (
94 req.commonattr = (
95 lib.ATTR_CMN_RETURNED_ATTRS
95 lib.ATTR_CMN_RETURNED_ATTRS
96 | lib.ATTR_CMN_NAME
96 | lib.ATTR_CMN_NAME
97 | lib.ATTR_CMN_OBJTYPE
97 | lib.ATTR_CMN_OBJTYPE
98 | lib.ATTR_CMN_ACCESSMASK
98 | lib.ATTR_CMN_ACCESSMASK
99 | lib.ATTR_CMN_MODTIME
99 | lib.ATTR_CMN_MODTIME
100 )
100 )
101 req.fileattr = lib.ATTR_FILE_DATALENGTH
101 req.fileattr = lib.ATTR_FILE_DATALENGTH
102 dfd = lib.open(path, lib.O_RDONLY, 0)
102 dfd = lib.open(path, lib.O_RDONLY, 0)
103 if dfd == -1:
103 if dfd == -1:
104 raise OSError(ffi.errno, os.strerror(ffi.errno))
104 raise OSError(ffi.errno, os.strerror(ffi.errno))
105
105
106 try:
106 try:
107 ret = listdirinternal(dfd, req, stat, skip)
107 ret = listdirinternal(dfd, req, stat, skip)
108 finally:
108 finally:
109 try:
109 try:
110 lib.close(dfd)
110 lib.close(dfd)
111 except BaseException:
111 except BaseException:
112 pass # we ignore all the errors from closing, not
112 pass # we ignore all the errors from closing, not
113 # much we can do about that
113 # much we can do about that
114 return ret
114 return ret
General Comments 0
You need to be logged in to leave comments. Login now