15 """Extracts archives."""
30 CheckedJoin returns os.path.join(output, path). It does sanity checks to
31 ensure the resulting path is under output, but shouldn't be used on untrusted
34 path = os.path.normpath(path)
35 if os.path.isabs(path)
or path.startswith(
'.'):
36 raise ValueError(path)
37 return os.path.join(output, path)
56 IterateZip opens the zip file at path and returns a generator of entry objects
59 with zipfile.ZipFile(path,
'r')
as zip_file:
60 for info
in zip_file.infolist():
61 if info.filename.endswith(
'/'):
63 yield FileEntry(info.filename,
None, zip_file.open(info))
68 IterateTar opens the tar.gz or tar.bz2 file at path and returns a generator of
69 entry objects for each file in it.
71 with tarfile.open(path,
'r:' + compression)
as tar_file:
78 yield FileEntry(info.name, info.mode, tar_file.extractfile(info))
80 raise ValueError(
'Unknown entry type "%s"' % (info.name, ))
84 parser = optparse.OptionParser(usage=
'Usage: %prog ARCHIVE OUTPUT')
85 parser.add_option(
'--no-prefix', dest=
'no_prefix', action=
'store_true',
86 help=
'Do not remove a prefix from paths in the archive.')
87 options, args = parser.parse_args(args)
93 archive, output = args
95 if not os.path.exists(archive):
99 with open(archive,
'rb')
as f:
100 sha256 = hashlib.sha256()
102 chunk = f.read(1024 * 1024)
106 digest = sha256.hexdigest()
108 stamp_path = os.path.join(output,
".boringssl_archive_digest")
109 if os.path.exists(stamp_path):
110 with open(stamp_path)
as f:
111 if f.read().strip() == digest:
112 print(
"Already up-to-date.")
115 if archive.endswith(
'.zip'):
117 elif archive.endswith(
'.tar.gz'):
119 elif archive.endswith(
'.tar.bz2'):
122 raise ValueError(archive)
125 if os.path.exists(output):
126 print(
"Removing %s" % (output, ))
127 shutil.rmtree(output)
129 print(
"Extracting %s to %s" % (archive, output))
132 for entry
in entries:
134 if '\\' in entry.path
or entry.path.startswith(
'/'):
135 raise ValueError(entry.path)
137 if not options.no_prefix:
138 new_prefix, rest = entry.path.split(
'/', 1)
143 if prefix != new_prefix:
144 raise ValueError((prefix, new_prefix))
150 if not os.path.isdir(os.path.dirname(fixed_path)):
151 os.makedirs(os.path.dirname(fixed_path))
152 if isinstance(entry, FileEntry):
153 with open(fixed_path,
'wb')
as out:
154 shutil.copyfileobj(entry.fileobj, out)
155 elif isinstance(entry, SymlinkEntry):
156 os.symlink(entry.target, fixed_path)
158 raise TypeError(
'unknown entry type')
163 if entry.mode
is not None:
164 os.chmod(fixed_path, entry.mode)
168 if num_extracted % 100 == 0:
169 print(
"Extracted %d files..." % (num_extracted,))
173 with open(stamp_path,
'w')
as f:
176 print(
"Done. Extracted %d files." % (num_extracted,))
180 if __name__ ==
'__main__':
181 sys.exit(
main(sys.argv[1:]))