Show More
@@ -0,0 +1,101 b'' | |||
|
1 | from __future__ import absolute_import | |
|
2 | ||
|
3 | import cffi | |
|
4 | ||
|
5 | ffi = cffi.FFI() | |
|
6 | ffi.set_source("_osutil_cffi", """ | |
|
7 | #include <sys/attr.h> | |
|
8 | #include <sys/vnode.h> | |
|
9 | #include <unistd.h> | |
|
10 | #include <fcntl.h> | |
|
11 | #include <time.h> | |
|
12 | ||
|
13 | typedef struct val_attrs { | |
|
14 | uint32_t length; | |
|
15 | attribute_set_t returned; | |
|
16 | attrreference_t name_info; | |
|
17 | fsobj_type_t obj_type; | |
|
18 | struct timespec mtime; | |
|
19 | uint32_t accessmask; | |
|
20 | off_t datalength; | |
|
21 | } __attribute__((aligned(4), packed)) val_attrs_t; | |
|
22 | """, include_dirs=['mercurial']) | |
|
23 | ffi.cdef(''' | |
|
24 | ||
|
25 | typedef uint32_t attrgroup_t; | |
|
26 | ||
|
27 | typedef struct attrlist { | |
|
28 | uint16_t bitmapcount; /* number of attr. bit sets in list */ | |
|
29 | uint16_t reserved; /* (to maintain 4-byte alignment) */ | |
|
30 | attrgroup_t commonattr; /* common attribute group */ | |
|
31 | attrgroup_t volattr; /* volume attribute group */ | |
|
32 | attrgroup_t dirattr; /* directory attribute group */ | |
|
33 | attrgroup_t fileattr; /* file attribute group */ | |
|
34 | attrgroup_t forkattr; /* fork attribute group */ | |
|
35 | ...; | |
|
36 | }; | |
|
37 | ||
|
38 | typedef struct attribute_set { | |
|
39 | ...; | |
|
40 | } attribute_set_t; | |
|
41 | ||
|
42 | typedef struct attrreference { | |
|
43 | int attr_dataoffset; | |
|
44 | int attr_length; | |
|
45 | ...; | |
|
46 | } attrreference_t; | |
|
47 | ||
|
48 | typedef struct val_attrs { | |
|
49 | uint32_t length; | |
|
50 | attribute_set_t returned; | |
|
51 | attrreference_t name_info; | |
|
52 | uint32_t obj_type; | |
|
53 | struct timespec mtime; | |
|
54 | uint32_t accessmask; | |
|
55 | int datalength; | |
|
56 | ...; | |
|
57 | } val_attrs_t; | |
|
58 | ||
|
59 | /* the exact layout of the above struct will be figured out during build time */ | |
|
60 | ||
|
61 | typedef int ... time_t; | |
|
62 | typedef int ... off_t; | |
|
63 | ||
|
64 | typedef struct timespec { | |
|
65 | time_t tv_sec; | |
|
66 | ...; | |
|
67 | }; | |
|
68 | ||
|
69 | int getattrlist(const char* path, struct attrlist * attrList, void * attrBuf, | |
|
70 | size_t attrBufSize, unsigned int options); | |
|
71 | ||
|
72 | int getattrlistbulk(int dirfd, struct attrlist * attrList, void * attrBuf, | |
|
73 | size_t attrBufSize, uint64_t options); | |
|
74 | ||
|
75 | #define ATTR_BIT_MAP_COUNT ... | |
|
76 | #define ATTR_CMN_NAME ... | |
|
77 | #define ATTR_CMN_OBJTYPE ... | |
|
78 | #define ATTR_CMN_MODTIME ... | |
|
79 | #define ATTR_CMN_ACCESSMASK ... | |
|
80 | #define ATTR_CMN_ERROR ... | |
|
81 | #define ATTR_CMN_RETURNED_ATTRS ... | |
|
82 | #define ATTR_FILE_DATALENGTH ... | |
|
83 | ||
|
84 | #define VREG ... | |
|
85 | #define VDIR ... | |
|
86 | #define VLNK ... | |
|
87 | #define VBLK ... | |
|
88 | #define VCHR ... | |
|
89 | #define VFIFO ... | |
|
90 | #define VSOCK ... | |
|
91 | ||
|
92 | #define S_IFMT ... | |
|
93 | ||
|
94 | int open(const char *path, int oflag, int perm); | |
|
95 | int close(int); | |
|
96 | ||
|
97 | #define O_RDONLY ... | |
|
98 | ''') | |
|
99 | ||
|
100 | if __name__ == '__main__': | |
|
101 | ffi.compile() |
@@ -14,6 +14,10 b' import socket' | |||
|
14 | 14 | import stat as statmod |
|
15 | 15 | import sys |
|
16 | 16 | |
|
17 | from . import policy | |
|
18 | modulepolicy = policy.policy | |
|
19 | policynocffi = policy.policynocffi | |
|
20 | ||
|
17 | 21 | def _mode_to_kind(mode): |
|
18 | 22 | if statmod.S_ISREG(mode): |
|
19 | 23 | return statmod.S_IFREG |
@@ -31,7 +35,7 b' def _mode_to_kind(mode):' | |||
|
31 | 35 | return statmod.S_IFSOCK |
|
32 | 36 | return mode |
|
33 | 37 | |
|
34 | def listdir(path, stat=False, skip=None): | |
|
38 | def listdirpure(path, stat=False, skip=None): | |
|
35 | 39 | '''listdir(path, stat=False) -> list_of_tuples |
|
36 | 40 | |
|
37 | 41 | Return a sorted list containing information about the entries |
@@ -61,6 +65,95 b' def listdir(path, stat=False, skip=None)' | |||
|
61 | 65 | result.append((fn, _mode_to_kind(st.st_mode))) |
|
62 | 66 | return result |
|
63 | 67 | |
|
68 | ffi = None | |
|
69 | if modulepolicy not in policynocffi and sys.platform == 'darwin': | |
|
70 | try: | |
|
71 | from _osutil_cffi import ffi, lib | |
|
72 | except ImportError: | |
|
73 | if modulepolicy == 'cffi': # strict cffi import | |
|
74 | raise | |
|
75 | ||
|
76 | if sys.platform == 'darwin' and ffi is not None: | |
|
77 | listdir_batch_size = 4096 | |
|
78 | # tweakable number, only affects performance, which chunks | |
|
79 | # of bytes do we get back from getattrlistbulk | |
|
80 | ||
|
81 | attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty | |
|
82 | ||
|
83 | attrkinds[lib.VREG] = statmod.S_IFREG | |
|
84 | attrkinds[lib.VDIR] = statmod.S_IFDIR | |
|
85 | attrkinds[lib.VLNK] = statmod.S_IFLNK | |
|
86 | attrkinds[lib.VBLK] = statmod.S_IFBLK | |
|
87 | attrkinds[lib.VCHR] = statmod.S_IFCHR | |
|
88 | attrkinds[lib.VFIFO] = statmod.S_IFIFO | |
|
89 | attrkinds[lib.VSOCK] = statmod.S_IFSOCK | |
|
90 | ||
|
91 | class stat_res(object): | |
|
92 | def __init__(self, st_mode, st_mtime, st_size): | |
|
93 | self.st_mode = st_mode | |
|
94 | self.st_mtime = st_mtime | |
|
95 | self.st_size = st_size | |
|
96 | ||
|
97 | tv_sec_ofs = ffi.offsetof("struct timespec", "tv_sec") | |
|
98 | buf = ffi.new("char[]", listdir_batch_size) | |
|
99 | ||
|
100 | def listdirinternal(dfd, req, stat, skip): | |
|
101 | ret = [] | |
|
102 | while True: | |
|
103 | r = lib.getattrlistbulk(dfd, req, buf, listdir_batch_size, 0) | |
|
104 | if r == 0: | |
|
105 | break | |
|
106 | if r == -1: | |
|
107 | raise OSError(ffi.errno, os.strerror(ffi.errno)) | |
|
108 | cur = ffi.cast("val_attrs_t*", buf) | |
|
109 | for i in range(r): | |
|
110 | lgt = cur.length | |
|
111 | assert lgt == ffi.cast('uint32_t*', cur)[0] | |
|
112 | ofs = cur.name_info.attr_dataoffset | |
|
113 | str_lgt = cur.name_info.attr_length | |
|
114 | base_ofs = ffi.offsetof('val_attrs_t', 'name_info') | |
|
115 | name = str(ffi.buffer(ffi.cast("char*", cur) + base_ofs + ofs, | |
|
116 | str_lgt - 1)) | |
|
117 | tp = attrkinds[cur.obj_type] | |
|
118 | if name == "." or name == "..": | |
|
119 | continue | |
|
120 | if skip == name and tp == statmod.S_ISDIR: | |
|
121 | return [] | |
|
122 | if stat: | |
|
123 | mtime = cur.time.tv_sec | |
|
124 | mode = (cur.accessmask & ~lib.S_IFMT)| tp | |
|
125 | ret.append((name, tp, stat_res(st_mode=mode, st_mtime=mtime, | |
|
126 | st_size=cur.datalength))) | |
|
127 | else: | |
|
128 | ret.append((name, tp)) | |
|
129 | cur += lgt | |
|
130 | return ret | |
|
131 | ||
|
132 | def listdir(path, stat=False, skip=None): | |
|
133 | req = ffi.new("struct attrlist*") | |
|
134 | req.bitmapcount = lib.ATTR_BIT_MAP_COUNT | |
|
135 | req.commonattr = (lib.ATTR_CMN_RETURNED_ATTRS | | |
|
136 | lib.ATTR_CMN_NAME | | |
|
137 | lib.ATTR_CMN_OBJTYPE | | |
|
138 | lib.ATTR_CMN_ACCESSMASK | | |
|
139 | lib.ATTR_CMN_MODTIME) | |
|
140 | req.fileattr = lib.ATTR_FILE_DATALENGTH | |
|
141 | dfd = lib.open(path, lib.O_RDONLY, 0) | |
|
142 | if dfd == -1: | |
|
143 | raise OSError(ffi.errno, os.strerror(ffi.errno)) | |
|
144 | ||
|
145 | try: | |
|
146 | ret = listdirinternal(dfd, req, stat, skip) | |
|
147 | finally: | |
|
148 | try: | |
|
149 | lib.close(dfd) | |
|
150 | except BaseException: | |
|
151 | pass # we ignore all the errors from closing, not | |
|
152 | # much we can do about that | |
|
153 | return ret | |
|
154 | else: | |
|
155 | listdir = listdirpure | |
|
156 | ||
|
64 | 157 | if os.name != 'nt': |
|
65 | 158 | posixfile = open |
|
66 | 159 |
@@ -320,6 +320,9 b' class hgbuildpy(build_py):' | |||
|
320 | 320 | elif self.distribution.cffi: |
|
321 | 321 | exts = [] |
|
322 | 322 | # cffi modules go here |
|
323 | if sys.platform == 'darwin': | |
|
324 | import setup_osutil_cffi | |
|
325 | exts.append(setup_osutil_cffi.ffi.distutils_extension()) | |
|
323 | 326 | self.distribution.ext_modules = exts |
|
324 | 327 | else: |
|
325 | 328 | h = os.path.join(get_python_inc(), 'Python.h') |
General Comments 0
You need to be logged in to leave comments.
Login now