##// END OF EJS Templates
cffi: fix a bytes vs str issue on macOS when listing directories...
Matt Harbison -
r50502:d122c8fd stable
parent child Browse files
Show More
@@ -1,114 +1,114
1 1 # osutil.py - CFFI version of osutil.c
2 2 #
3 3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8
9 9 import os
10 10 import stat as statmod
11 11
12 12 from ..pure.osutil import *
13 13
14 14 from .. import pycompat
15 15
16 16 if pycompat.isdarwin:
17 17 from . import _osutil # pytype: disable=import-error
18 18
19 19 ffi = _osutil.ffi
20 20 lib = _osutil.lib
21 21
22 22 listdir_batch_size = 4096
23 23 # tweakable number, only affects performance, which chunks
24 24 # of bytes do we get back from getattrlistbulk
25 25
26 26 attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty
27 27
28 28 attrkinds[lib.VREG] = statmod.S_IFREG
29 29 attrkinds[lib.VDIR] = statmod.S_IFDIR
30 30 attrkinds[lib.VLNK] = statmod.S_IFLNK
31 31 attrkinds[lib.VBLK] = statmod.S_IFBLK
32 32 attrkinds[lib.VCHR] = statmod.S_IFCHR
33 33 attrkinds[lib.VFIFO] = statmod.S_IFIFO
34 34 attrkinds[lib.VSOCK] = statmod.S_IFSOCK
35 35
36 36 class stat_res:
37 37 def __init__(self, st_mode, st_mtime, st_size):
38 38 self.st_mode = st_mode
39 39 self.st_mtime = st_mtime
40 40 self.st_size = st_size
41 41
42 42 tv_sec_ofs = ffi.offsetof(b"struct timespec", b"tv_sec")
43 43 buf = ffi.new(b"char[]", listdir_batch_size)
44 44
45 45 def listdirinternal(dfd, req, stat, skip):
46 46 ret = []
47 47 while True:
48 48 r = lib.getattrlistbulk(dfd, req, buf, listdir_batch_size, 0)
49 49 if r == 0:
50 50 break
51 51 if r == -1:
52 52 raise OSError(ffi.errno, os.strerror(ffi.errno))
53 53 cur = ffi.cast(b"val_attrs_t*", buf)
54 54 for i in range(r):
55 55 lgt = cur.length
56 56 assert lgt == ffi.cast(b'uint32_t*', cur)[0]
57 57 ofs = cur.name_info.attr_dataoffset
58 58 str_lgt = cur.name_info.attr_length
59 59 base_ofs = ffi.offsetof(b'val_attrs_t', b'name_info')
60 name = str(
60 name = bytes(
61 61 ffi.buffer(
62 62 ffi.cast(b"char*", cur) + base_ofs + ofs, str_lgt - 1
63 63 )
64 64 )
65 65 tp = attrkinds[cur.obj_type]
66 66 if name == b"." or name == b"..":
67 67 continue
68 68 if skip == name and tp == statmod.S_ISDIR:
69 69 return []
70 70 if stat:
71 71 mtime = cur.mtime.tv_sec
72 72 mode = (cur.accessmask & ~lib.S_IFMT) | tp
73 73 ret.append(
74 74 (
75 75 name,
76 76 tp,
77 77 stat_res(
78 78 st_mode=mode,
79 79 st_mtime=mtime,
80 80 st_size=cur.datalength,
81 81 ),
82 82 )
83 83 )
84 84 else:
85 85 ret.append((name, tp))
86 86 cur = ffi.cast(
87 87 b"val_attrs_t*", int(ffi.cast(b"intptr_t", cur)) + lgt
88 88 )
89 89 return ret
90 90
91 91 def listdir(path, stat=False, skip=None):
92 92 req = ffi.new(b"struct attrlist*")
93 93 req.bitmapcount = lib.ATTR_BIT_MAP_COUNT
94 94 req.commonattr = (
95 95 lib.ATTR_CMN_RETURNED_ATTRS
96 96 | lib.ATTR_CMN_NAME
97 97 | lib.ATTR_CMN_OBJTYPE
98 98 | lib.ATTR_CMN_ACCESSMASK
99 99 | lib.ATTR_CMN_MODTIME
100 100 )
101 101 req.fileattr = lib.ATTR_FILE_DATALENGTH
102 102 dfd = lib.open(path, lib.O_RDONLY, 0)
103 103 if dfd == -1:
104 104 raise OSError(ffi.errno, os.strerror(ffi.errno))
105 105
106 106 try:
107 107 ret = listdirinternal(dfd, req, stat, skip)
108 108 finally:
109 109 try:
110 110 lib.close(dfd)
111 111 except BaseException:
112 112 pass # we ignore all the errors from closing, not
113 113 # much we can do about that
114 114 return ret
General Comments 0
You need to be logged in to leave comments. Login now