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()