58 if stat: |
62 if stat: |
59 result.append((fn, _mode_to_kind(st.st_mode), st)) |
63 result.append((fn, _mode_to_kind(st.st_mode), st)) |
60 else: |
64 else: |
61 result.append((fn, _mode_to_kind(st.st_mode))) |
65 result.append((fn, _mode_to_kind(st.st_mode))) |
62 return result |
66 return result |
|
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 |
63 |
156 |
64 if os.name != 'nt': |
157 if os.name != 'nt': |
65 posixfile = open |
158 posixfile = open |
66 |
159 |
67 _SCM_RIGHTS = 0x01 |
160 _SCM_RIGHTS = 0x01 |