Update sdk/platform-tools to version 26.0.0.
[android_tools.git] / sdk / platform-tools / systrace / catapult / telemetry / third_party / modulegraph / modulegraph / zipio.py
blob34d580e4b614bbd6278df25e0f9f8020e8bc0e21
1 """
2 A helper module that can work with paths
3 that can refer to data inside a zipfile
5 XXX: Need to determine if isdir("zipfile.zip")
6 should return True or False. Currently returns
7 True, but that might do the wrong thing with
8 data-files that are zipfiles.
9 """
10 import os as _os
11 import zipfile as _zipfile
12 import errno as _errno
13 import time as _time
14 import sys as _sys
15 import stat as _stat
17 _DFLT_DIR_MODE = (
18 _stat.S_IFDIR
19 | _stat.S_IXOTH
20 | _stat.S_IXGRP
21 | _stat.S_IXUSR
22 | _stat.S_IROTH
23 | _stat.S_IRGRP
24 | _stat.S_IRUSR)
26 _DFLT_FILE_MODE = (
27 _stat.S_IFREG
28 | _stat.S_IROTH
29 | _stat.S_IRGRP
30 | _stat.S_IRUSR)
33 if _sys.version_info[0] == 2:
34 from StringIO import StringIO as _BaseStringIO
35 from StringIO import StringIO as _BaseBytesIO
37 class _StringIO (_BaseStringIO):
38 def __enter__(self):
39 return self
41 def __exit__(self, exc_type, exc_value, traceback):
42 self.close()
43 return False
45 class _BytesIO (_BaseBytesIO):
46 def __enter__(self):
47 return self
49 def __exit__(self, exc_type, exc_value, traceback):
50 self.close()
51 return False
53 else:
54 from io import StringIO as _StringIO
55 from io import BytesIO as _BytesIO
60 def _locate(path):
61 full_path = path
62 if _os.path.exists(path):
63 return path, None
65 else:
66 rest = []
67 root = _os.path.splitdrive(path)
68 while path and path != root:
69 path, bn = _os.path.split(path)
70 rest.append(bn)
71 if _os.path.exists(path):
72 break
74 if path == root:
75 raise IOError(
76 _errno.ENOENT, full_path,
77 "No such file or directory")
79 if not _os.path.isfile(path):
80 raise IOError(
81 _errno.ENOENT, full_path,
82 "No such file or directory")
84 rest.reverse()
85 return path, '/'.join(rest).strip('/')
87 _open = open
88 def open(path, mode='r'):
89 if 'w' in mode or 'a' in mode:
90 raise IOError(
91 _errno.EINVAL, path, "Write access not supported")
92 elif 'r+' in mode:
93 raise IOError(
94 _errno.EINVAL, path, "Write access not supported")
96 full_path = path
97 path, rest = _locate(path)
98 if not rest:
99 return _open(path, mode)
101 else:
102 try:
103 zf = _zipfile.ZipFile(path, 'r')
105 except _zipfile.error:
106 raise IOError(
107 _errno.ENOENT, full_path,
108 "No such file or directory")
110 try:
111 data = zf.read(rest)
112 except (_zipfile.error, KeyError):
113 zf.close()
114 raise IOError(
115 _errno.ENOENT, full_path,
116 "No such file or directory")
117 zf.close()
119 if mode == 'rb':
120 return _BytesIO(data)
122 else:
123 if _sys.version_info[0] == 3:
124 data = data.decode('ascii')
126 return _StringIO(data)
128 def listdir(path):
129 full_path = path
130 path, rest = _locate(path)
131 if not rest and not _os.path.isfile(path):
132 return _os.listdir(path)
134 else:
135 try:
136 zf = _zipfile.ZipFile(path, 'r')
138 except _zipfile.error:
139 raise IOError(
140 _errno.ENOENT, full_path,
141 "No such file or directory")
143 result = set()
144 seen = False
145 try:
146 for nm in zf.namelist():
147 if rest is None:
148 seen = True
149 value = nm.split('/')[0]
150 if value:
151 result.add(value)
153 elif nm.startswith(rest):
154 if nm == rest:
155 seen = True
156 value = ''
157 pass
158 elif nm[len(rest)] == '/':
159 seen = True
160 value = nm[len(rest)+1:].split('/')[0]
161 else:
162 value = None
164 if value:
165 result.add(value)
166 except _zipfile.error:
167 zf.close()
168 raise IOError(
169 _errno.ENOENT, full_path,
170 "No such file or directory")
172 zf.close()
174 if not seen:
175 raise IOError(
176 _errno.ENOENT, full_path,
177 "No such file or directory")
179 return list(result)
181 def isfile(path):
182 full_path = path
183 path, rest = _locate(path)
184 if not rest:
185 ok = _os.path.isfile(path)
186 if ok:
187 try:
188 zf = _zipfile.ZipFile(path, 'r')
189 return False
190 except (_zipfile.error, IOError):
191 return True
192 return False
194 zf = None
195 try:
196 zf = _zipfile.ZipFile(path, 'r')
197 info = zf.getinfo(rest)
198 zf.close()
199 return True
200 except (KeyError, _zipfile.error):
201 if zf is not None:
202 zf.close()
204 # Check if this is a directory
205 try:
206 info = zf.getinfo(rest + '/')
207 except KeyError:
208 pass
209 else:
210 return False
212 rest = rest + '/'
213 for nm in zf.namelist():
214 if nm.startswith(rest):
215 # Directory
216 return False
218 # No trace in zipfile
219 raise IOError(
220 _errno.ENOENT, full_path,
221 "No such file or directory")
226 def isdir(path):
227 full_path = path
228 path, rest = _locate(path)
229 if not rest:
230 ok = _os.path.isdir(path)
231 if not ok:
232 try:
233 zf = _zipfile.ZipFile(path, 'r')
234 except (_zipfile.error, IOError):
235 return False
236 return True
237 return True
239 zf = None
240 try:
241 try:
242 zf = _zipfile.ZipFile(path)
243 except _zipfile.error:
244 raise IOError(
245 _errno.ENOENT, full_path,
246 "No such file or directory")
248 try:
249 info = zf.getinfo(rest)
250 except KeyError:
251 pass
252 else:
253 # File found
254 return False
256 rest = rest + '/'
257 try:
258 info = zf.getinfo(rest)
259 except KeyError:
260 pass
261 else:
262 # Directory entry found
263 return True
265 for nm in zf.namelist():
266 if nm.startswith(rest):
267 return True
269 raise IOError(
270 _errno.ENOENT, full_path,
271 "No such file or directory")
272 finally:
273 if zf is not None:
274 zf.close()
277 def islink(path):
278 full_path = path
279 path, rest = _locate(path)
280 if not rest:
281 return _os.path.islink(path)
283 try:
284 zf = _zipfile.ZipFile(path)
285 except _zipfile.error:
286 raise IOError(
287 _errno.ENOENT, full_path,
288 "No such file or directory")
289 try:
292 try:
293 info = zf.getinfo(rest)
294 except KeyError:
295 pass
296 else:
297 # File
298 return False
300 rest += '/'
301 try:
302 info = zf.getinfo(rest)
303 except KeyError:
304 pass
305 else:
306 # Directory
307 return False
309 for nm in zf.namelist():
310 if nm.startswith(rest):
311 # Directory without listing
312 return False
314 raise IOError(
315 _errno.ENOENT, full_path,
316 "No such file or directory")
318 finally:
319 zf.close()
322 def readlink(path):
323 full_path = path
324 path, rest = _locate(path)
325 if rest:
326 # No symlinks inside zipfiles
327 raise OSError(
328 _errno.ENOENT, full_path,
329 "No such file or directory")
331 return _os.readlink(path)
333 def getmode(path):
334 full_path = path
335 path, rest = _locate(path)
336 if not rest:
337 return _os.stat(path).st_mode
339 zf = None
340 try:
341 zf = _zipfile.ZipFile(path)
342 info = None
344 try:
345 info = zf.getinfo(rest)
346 except KeyError:
347 pass
349 if info is None:
350 try:
351 info = zf.getinfo(rest + '/')
352 except KeyError:
353 pass
355 if info is None:
356 rest = rest + '/'
357 for nm in zf.namelist():
358 if nm.startswith(rest):
359 break
360 else:
361 raise IOError(
362 _errno.ENOENT, full_path,
363 "No such file or directory")
365 # Directory exists, but has no entry of its own.
366 return _DFLT_DIR_MODE
368 # The mode is stored without file-type in external_attr.
369 if (info.external_attr >> 16) != 0:
370 return _stat.S_IFREG | (info.external_attr >> 16)
371 else:
372 return _DFLT_FILE_MODE
375 except KeyError:
376 if zf is not None:
377 zf.close()
378 raise IOError(
379 _errno.ENOENT, full_path,
380 "No such file or directory")
382 def getmtime(path):
383 full_path = path
384 path, rest = _locate(path)
385 if not rest:
386 return _os.path.getmtime(path)
388 zf = None
389 try:
390 zf = _zipfile.ZipFile(path)
391 info = None
393 try:
394 info = zf.getinfo(rest)
395 except KeyError:
396 pass
398 if info is None:
399 try:
400 info = zf.getinfo(rest + '/')
401 except KeyError:
402 pass
404 if info is None:
405 rest = rest + '/'
406 for nm in zf.namelist():
407 if nm.startswith(rest):
408 break
409 else:
410 raise IOError(
411 _errno.ENOENT, full_path,
412 "No such file or directory")
414 # Directory exists, but has no entry of its
415 # own, fake mtime by using the timestamp of
416 # the zipfile itself.
417 return _os.path.getmtime(path)
419 return _time.mktime(info.date_time + (0, 0, -1))
421 except KeyError:
422 if zf is not None:
423 zf.close()
424 raise IOError(
425 _errno.ENOENT, full_path,
426 "No such file or directory")