Mercurial > public > mercurial-scm > hg
comparison mercurial/cffi/osutil.py @ 33572:857876ebaed4 stable 4.3-rc
merge default into stable for code freeze
author | Kevin Bullock <kbullock+mercurial@ringworld.org> |
---|---|
date | Wed, 19 Jul 2017 07:51:41 -0500 |
parents | 9cc438bf7d9a 0e8b0b9a7acc |
children | dacfcdd8b94e |
comparison
equal
deleted
inserted
replaced
33202:c1994c986d77 | 33572:857876ebaed4 |
---|---|
1 # osutil.py - CFFI version of osutil.c | |
2 # | |
3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.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 | |
1 from __future__ import absolute_import | 8 from __future__ import absolute_import |
2 | 9 |
3 import cffi | 10 import os |
11 import stat as statmod | |
4 | 12 |
5 ffi = cffi.FFI() | 13 from ..pure.osutil import * |
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 | 14 |
13 typedef struct val_attrs { | 15 from .. import ( |
14 uint32_t length; | 16 pycompat, |
15 attribute_set_t returned; | 17 ) |
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 | 18 |
25 typedef uint32_t attrgroup_t; | 19 if pycompat.sysplatform == 'darwin': |
20 from . import _osutil | |
26 | 21 |
27 typedef struct attrlist { | 22 ffi = _osutil.ffi |
28 uint16_t bitmapcount; /* number of attr. bit sets in list */ | 23 lib = _osutil.lib |
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 | 24 |
38 typedef struct attribute_set { | 25 listdir_batch_size = 4096 |
39 ...; | 26 # tweakable number, only affects performance, which chunks |
40 } attribute_set_t; | 27 # of bytes do we get back from getattrlistbulk |
41 | 28 |
42 typedef struct attrreference { | 29 attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty |
43 int attr_dataoffset; | |
44 int attr_length; | |
45 ...; | |
46 } attrreference_t; | |
47 | 30 |
48 typedef int ... off_t; | 31 attrkinds[lib.VREG] = statmod.S_IFREG |
32 attrkinds[lib.VDIR] = statmod.S_IFDIR | |
33 attrkinds[lib.VLNK] = statmod.S_IFLNK | |
34 attrkinds[lib.VBLK] = statmod.S_IFBLK | |
35 attrkinds[lib.VCHR] = statmod.S_IFCHR | |
36 attrkinds[lib.VFIFO] = statmod.S_IFIFO | |
37 attrkinds[lib.VSOCK] = statmod.S_IFSOCK | |
49 | 38 |
50 typedef struct val_attrs { | 39 class stat_res(object): |
51 uint32_t length; | 40 def __init__(self, st_mode, st_mtime, st_size): |
52 attribute_set_t returned; | 41 self.st_mode = st_mode |
53 attrreference_t name_info; | 42 self.st_mtime = st_mtime |
54 uint32_t obj_type; | 43 self.st_size = st_size |
55 struct timespec mtime; | |
56 uint32_t accessmask; | |
57 off_t datalength; | |
58 ...; | |
59 } val_attrs_t; | |
60 | 44 |
61 /* the exact layout of the above struct will be figured out during build time */ | 45 tv_sec_ofs = ffi.offsetof("struct timespec", "tv_sec") |
46 buf = ffi.new("char[]", listdir_batch_size) | |
62 | 47 |
63 typedef int ... time_t; | 48 def listdirinternal(dfd, req, stat, skip): |
49 ret = [] | |
50 while True: | |
51 r = lib.getattrlistbulk(dfd, req, buf, listdir_batch_size, 0) | |
52 if r == 0: | |
53 break | |
54 if r == -1: | |
55 raise OSError(ffi.errno, os.strerror(ffi.errno)) | |
56 cur = ffi.cast("val_attrs_t*", buf) | |
57 for i in range(r): | |
58 lgt = cur.length | |
59 assert lgt == ffi.cast('uint32_t*', cur)[0] | |
60 ofs = cur.name_info.attr_dataoffset | |
61 str_lgt = cur.name_info.attr_length | |
62 base_ofs = ffi.offsetof('val_attrs_t', 'name_info') | |
63 name = str(ffi.buffer(ffi.cast("char*", cur) + base_ofs + ofs, | |
64 str_lgt - 1)) | |
65 tp = attrkinds[cur.obj_type] | |
66 if name == "." or name == "..": | |
67 continue | |
68 if skip == name and tp == statmod.S_ISDIR: | |
69 return [] | |
70 if stat: | |
71 mtime = cur.mtime.tv_sec | |
72 mode = (cur.accessmask & ~lib.S_IFMT)| tp | |
73 ret.append((name, tp, stat_res(st_mode=mode, st_mtime=mtime, | |
74 st_size=cur.datalength))) | |
75 else: | |
76 ret.append((name, tp)) | |
77 cur = ffi.cast("val_attrs_t*", int(ffi.cast("intptr_t", cur)) | |
78 + lgt) | |
79 return ret | |
64 | 80 |
65 typedef struct timespec { | 81 def listdir(path, stat=False, skip=None): |
66 time_t tv_sec; | 82 req = ffi.new("struct attrlist*") |
67 ...; | 83 req.bitmapcount = lib.ATTR_BIT_MAP_COUNT |
68 }; | 84 req.commonattr = (lib.ATTR_CMN_RETURNED_ATTRS | |
85 lib.ATTR_CMN_NAME | | |
86 lib.ATTR_CMN_OBJTYPE | | |
87 lib.ATTR_CMN_ACCESSMASK | | |
88 lib.ATTR_CMN_MODTIME) | |
89 req.fileattr = lib.ATTR_FILE_DATALENGTH | |
90 dfd = lib.open(path, lib.O_RDONLY, 0) | |
91 if dfd == -1: | |
92 raise OSError(ffi.errno, os.strerror(ffi.errno)) | |
69 | 93 |
70 int getattrlist(const char* path, struct attrlist * attrList, void * attrBuf, | 94 try: |
71 size_t attrBufSize, unsigned int options); | 95 ret = listdirinternal(dfd, req, stat, skip) |
72 | 96 finally: |
73 int getattrlistbulk(int dirfd, struct attrlist * attrList, void * attrBuf, | 97 try: |
74 size_t attrBufSize, uint64_t options); | 98 lib.close(dfd) |
75 | 99 except BaseException: |
76 #define ATTR_BIT_MAP_COUNT ... | 100 pass # we ignore all the errors from closing, not |
77 #define ATTR_CMN_NAME ... | 101 # much we can do about that |
78 #define ATTR_CMN_OBJTYPE ... | 102 return ret |
79 #define ATTR_CMN_MODTIME ... | |
80 #define ATTR_CMN_ACCESSMASK ... | |
81 #define ATTR_CMN_ERROR ... | |
82 #define ATTR_CMN_RETURNED_ATTRS ... | |
83 #define ATTR_FILE_DATALENGTH ... | |
84 | |
85 #define VREG ... | |
86 #define VDIR ... | |
87 #define VLNK ... | |
88 #define VBLK ... | |
89 #define VCHR ... | |
90 #define VFIFO ... | |
91 #define VSOCK ... | |
92 | |
93 #define S_IFMT ... | |
94 | |
95 int open(const char *path, int oflag, int perm); | |
96 int close(int); | |
97 | |
98 #define O_RDONLY ... | |
99 ''') | |
100 | |
101 if __name__ == '__main__': | |
102 ffi.compile() |