Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
keewenaw
GitHub Repository: keewenaw/ethereum-wallet-cracker
Path: blob/main/test/lib/python3.9/site-packages/pip/_internal/utils/unpacking.py
4804 views
1
"""Utilities related archives.
2
"""
3
4
import logging
5
import os
6
import shutil
7
import stat
8
import tarfile
9
import zipfile
10
from typing import Iterable, List, Optional
11
from zipfile import ZipInfo
12
13
from pip._internal.exceptions import InstallationError
14
from pip._internal.utils.filetypes import (
15
BZ2_EXTENSIONS,
16
TAR_EXTENSIONS,
17
XZ_EXTENSIONS,
18
ZIP_EXTENSIONS,
19
)
20
from pip._internal.utils.misc import ensure_dir
21
22
logger = logging.getLogger(__name__)
23
24
25
SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS
26
27
try:
28
import bz2 # noqa
29
30
SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS
31
except ImportError:
32
logger.debug("bz2 module is not available")
33
34
try:
35
# Only for Python 3.3+
36
import lzma # noqa
37
38
SUPPORTED_EXTENSIONS += XZ_EXTENSIONS
39
except ImportError:
40
logger.debug("lzma module is not available")
41
42
43
def current_umask() -> int:
44
"""Get the current umask which involves having to set it temporarily."""
45
mask = os.umask(0)
46
os.umask(mask)
47
return mask
48
49
50
def split_leading_dir(path: str) -> List[str]:
51
path = path.lstrip("/").lstrip("\\")
52
if "/" in path and (
53
("\\" in path and path.find("/") < path.find("\\")) or "\\" not in path
54
):
55
return path.split("/", 1)
56
elif "\\" in path:
57
return path.split("\\", 1)
58
else:
59
return [path, ""]
60
61
62
def has_leading_dir(paths: Iterable[str]) -> bool:
63
"""Returns true if all the paths have the same leading path name
64
(i.e., everything is in one subdirectory in an archive)"""
65
common_prefix = None
66
for path in paths:
67
prefix, rest = split_leading_dir(path)
68
if not prefix:
69
return False
70
elif common_prefix is None:
71
common_prefix = prefix
72
elif prefix != common_prefix:
73
return False
74
return True
75
76
77
def is_within_directory(directory: str, target: str) -> bool:
78
"""
79
Return true if the absolute path of target is within the directory
80
"""
81
abs_directory = os.path.abspath(directory)
82
abs_target = os.path.abspath(target)
83
84
prefix = os.path.commonprefix([abs_directory, abs_target])
85
return prefix == abs_directory
86
87
88
def set_extracted_file_to_default_mode_plus_executable(path: str) -> None:
89
"""
90
Make file present at path have execute for user/group/world
91
(chmod +x) is no-op on windows per python docs
92
"""
93
os.chmod(path, (0o777 & ~current_umask() | 0o111))
94
95
96
def zip_item_is_executable(info: ZipInfo) -> bool:
97
mode = info.external_attr >> 16
98
# if mode and regular file and any execute permissions for
99
# user/group/world?
100
return bool(mode and stat.S_ISREG(mode) and mode & 0o111)
101
102
103
def unzip_file(filename: str, location: str, flatten: bool = True) -> None:
104
"""
105
Unzip the file (with path `filename`) to the destination `location`. All
106
files are written based on system defaults and umask (i.e. permissions are
107
not preserved), except that regular file members with any execute
108
permissions (user, group, or world) have "chmod +x" applied after being
109
written. Note that for windows, any execute changes using os.chmod are
110
no-ops per the python docs.
111
"""
112
ensure_dir(location)
113
zipfp = open(filename, "rb")
114
try:
115
zip = zipfile.ZipFile(zipfp, allowZip64=True)
116
leading = has_leading_dir(zip.namelist()) and flatten
117
for info in zip.infolist():
118
name = info.filename
119
fn = name
120
if leading:
121
fn = split_leading_dir(name)[1]
122
fn = os.path.join(location, fn)
123
dir = os.path.dirname(fn)
124
if not is_within_directory(location, fn):
125
message = (
126
"The zip file ({}) has a file ({}) trying to install "
127
"outside target directory ({})"
128
)
129
raise InstallationError(message.format(filename, fn, location))
130
if fn.endswith("/") or fn.endswith("\\"):
131
# A directory
132
ensure_dir(fn)
133
else:
134
ensure_dir(dir)
135
# Don't use read() to avoid allocating an arbitrarily large
136
# chunk of memory for the file's content
137
fp = zip.open(name)
138
try:
139
with open(fn, "wb") as destfp:
140
shutil.copyfileobj(fp, destfp)
141
finally:
142
fp.close()
143
if zip_item_is_executable(info):
144
set_extracted_file_to_default_mode_plus_executable(fn)
145
finally:
146
zipfp.close()
147
148
149
def untar_file(filename: str, location: str) -> None:
150
"""
151
Untar the file (with path `filename`) to the destination `location`.
152
All files are written based on system defaults and umask (i.e. permissions
153
are not preserved), except that regular file members with any execute
154
permissions (user, group, or world) have "chmod +x" applied after being
155
written. Note that for windows, any execute changes using os.chmod are
156
no-ops per the python docs.
157
"""
158
ensure_dir(location)
159
if filename.lower().endswith(".gz") or filename.lower().endswith(".tgz"):
160
mode = "r:gz"
161
elif filename.lower().endswith(BZ2_EXTENSIONS):
162
mode = "r:bz2"
163
elif filename.lower().endswith(XZ_EXTENSIONS):
164
mode = "r:xz"
165
elif filename.lower().endswith(".tar"):
166
mode = "r"
167
else:
168
logger.warning(
169
"Cannot determine compression type for file %s",
170
filename,
171
)
172
mode = "r:*"
173
tar = tarfile.open(filename, mode, encoding="utf-8")
174
try:
175
leading = has_leading_dir([member.name for member in tar.getmembers()])
176
for member in tar.getmembers():
177
fn = member.name
178
if leading:
179
fn = split_leading_dir(fn)[1]
180
path = os.path.join(location, fn)
181
if not is_within_directory(location, path):
182
message = (
183
"The tar file ({}) has a file ({}) trying to install "
184
"outside target directory ({})"
185
)
186
raise InstallationError(message.format(filename, path, location))
187
if member.isdir():
188
ensure_dir(path)
189
elif member.issym():
190
try:
191
tar._extract_member(member, path)
192
except Exception as exc:
193
# Some corrupt tar files seem to produce this
194
# (specifically bad symlinks)
195
logger.warning(
196
"In the tar file %s the member %s is invalid: %s",
197
filename,
198
member.name,
199
exc,
200
)
201
continue
202
else:
203
try:
204
fp = tar.extractfile(member)
205
except (KeyError, AttributeError) as exc:
206
# Some corrupt tar files seem to produce this
207
# (specifically bad symlinks)
208
logger.warning(
209
"In the tar file %s the member %s is invalid: %s",
210
filename,
211
member.name,
212
exc,
213
)
214
continue
215
ensure_dir(os.path.dirname(path))
216
assert fp is not None
217
with open(path, "wb") as destfp:
218
shutil.copyfileobj(fp, destfp)
219
fp.close()
220
# Update the timestamp (useful for cython compiled files)
221
tar.utime(member, path)
222
# member have any execute permissions for user/group/world?
223
if member.mode & 0o111:
224
set_extracted_file_to_default_mode_plus_executable(path)
225
finally:
226
tar.close()
227
228
229
def unpack_file(
230
filename: str,
231
location: str,
232
content_type: Optional[str] = None,
233
) -> None:
234
filename = os.path.realpath(filename)
235
if (
236
content_type == "application/zip"
237
or filename.lower().endswith(ZIP_EXTENSIONS)
238
or zipfile.is_zipfile(filename)
239
):
240
unzip_file(filename, location, flatten=not filename.endswith(".whl"))
241
elif (
242
content_type == "application/x-gzip"
243
or tarfile.is_tarfile(filename)
244
or filename.lower().endswith(TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS)
245
):
246
untar_file(filename, location)
247
else:
248
# FIXME: handle?
249
# FIXME: magic signatures?
250
logger.critical(
251
"Cannot unpack file %s (downloaded from %s, content-type: %s); "
252
"cannot detect archive format",
253
filename,
254
location,
255
content_type,
256
)
257
raise InstallationError(f"Cannot determine archive format of {location}")
258
259