Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/core/bigarray.py
3553 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
try:
9
import cPickle as pickle
10
except:
11
import pickle
12
13
import itertools
14
import os
15
import shutil
16
import sys
17
import tempfile
18
import threading
19
import zlib
20
21
from lib.core.compat import xrange
22
from lib.core.enums import MKSTEMP_PREFIX
23
from lib.core.exception import SqlmapSystemException
24
from lib.core.settings import BIGARRAY_CHUNK_SIZE
25
from lib.core.settings import BIGARRAY_COMPRESS_LEVEL
26
27
try:
28
DEFAULT_SIZE_OF = sys.getsizeof(object())
29
except TypeError:
30
DEFAULT_SIZE_OF = 16
31
32
try:
33
# Python 2: basestring covers str and unicode
34
STRING_TYPES = (basestring,)
35
except NameError:
36
# Python 3: str and bytes are separate
37
STRING_TYPES = (str, bytes)
38
39
def _size_of(instance):
40
"""
41
Returns total size of a given instance / object (in bytes)
42
"""
43
44
retval = sys.getsizeof(instance, DEFAULT_SIZE_OF)
45
46
if isinstance(instance, STRING_TYPES):
47
return retval
48
elif isinstance(instance, dict):
49
retval += sum(_size_of(_) for _ in itertools.chain.from_iterable(instance.items()))
50
elif isinstance(instance, (list, tuple, set, frozenset)):
51
retval += sum(_size_of(_) for _ in instance if _ is not instance)
52
53
return retval
54
55
class Cache(object):
56
"""
57
Auxiliary class used for storing cached chunks
58
"""
59
60
def __init__(self, index, data, dirty):
61
self.index = index
62
self.data = data
63
self.dirty = dirty
64
65
class BigArray(list):
66
"""
67
List-like class used for storing large amounts of data (disk cached)
68
69
>>> _ = BigArray(xrange(100000), chunk_size=500 * 1024)
70
>>> _[20] = 0
71
>>> _[-1] = 999
72
>>> _[99999]
73
999
74
>>> _[100000]
75
Traceback (most recent call last):
76
...
77
IndexError: BigArray index out of range
78
>>> _ += [0]
79
>>> sum(_)
80
4999850980
81
>>> _[len(_) // 2] = 17
82
>>> sum(_)
83
4999800997
84
>>> _[100000]
85
0
86
>>> _[0] = [None]
87
>>> _.index(0)
88
20
89
>>> import pickle; __ = pickle.loads(pickle.dumps(_))
90
>>> __.append(1)
91
>>> len(_)
92
100001
93
>>> _ = __
94
>>> _[-1]
95
1
96
>>> _.pop()
97
1
98
>>> len(_)
99
100001
100
>>> len([_ for _ in BigArray(xrange(100000))])
101
100000
102
"""
103
104
def __init__(self, items=None, chunk_size=BIGARRAY_CHUNK_SIZE):
105
self.chunks = [[]]
106
self.chunk_length = sys.maxsize
107
self.cache = None
108
self.filenames = set()
109
self._lock = threading.Lock()
110
self._os_remove = os.remove
111
self._size_counter = 0
112
self._chunk_size = chunk_size
113
114
for item in (items or []):
115
self.append(item)
116
117
def __add__(self, value):
118
retval = BigArray(self)
119
120
for _ in value:
121
retval.append(_)
122
123
return retval
124
125
def __iadd__(self, value):
126
for _ in value:
127
self.append(_)
128
129
return self
130
131
def append(self, value):
132
with self._lock:
133
self.chunks[-1].append(value)
134
135
if self.chunk_length == sys.maxsize:
136
self._size_counter += _size_of(value)
137
if self._size_counter >= self._chunk_size:
138
self.chunk_length = len(self.chunks[-1])
139
self._size_counter = None
140
141
if len(self.chunks[-1]) >= self.chunk_length:
142
filename = self._dump(self.chunks[-1])
143
self.chunks[-1] = filename
144
self.chunks.append([])
145
146
def extend(self, value):
147
for _ in value:
148
self.append(_)
149
150
def pop(self):
151
with self._lock:
152
if not self.chunks[-1] and len(self.chunks) > 1:
153
self.chunks.pop()
154
try:
155
filename = self.chunks[-1]
156
with open(filename, "rb") as f:
157
self.chunks[-1] = pickle.loads(zlib.decompress(f.read()))
158
self._os_remove(filename)
159
self.filenames.discard(filename)
160
except IOError as ex:
161
errMsg = "exception occurred while retrieving data "
162
errMsg += "from a temporary file ('%s')" % ex
163
raise SqlmapSystemException(errMsg)
164
165
return self.chunks[-1].pop()
166
167
def index(self, value):
168
for index in xrange(len(self)):
169
if self[index] == value:
170
return index
171
172
raise ValueError("%s is not in list" % value)
173
174
def __reduce__(self):
175
return (self.__class__, (), self.__getstate__())
176
177
def close(self):
178
with self._lock:
179
while self.filenames:
180
filename = self.filenames.pop()
181
try:
182
self._os_remove(filename)
183
except OSError:
184
pass
185
self.chunks = [[]]
186
self.cache = None
187
self.chunk_length = getattr(sys, "maxsize", None)
188
self._size_counter = 0
189
190
def __del__(self):
191
self.close()
192
193
def _dump(self, chunk):
194
try:
195
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.BIG_ARRAY)
196
self.filenames.add(filename)
197
with os.fdopen(handle, "w+b") as f:
198
f.write(zlib.compress(pickle.dumps(chunk, pickle.HIGHEST_PROTOCOL), BIGARRAY_COMPRESS_LEVEL))
199
return filename
200
except (OSError, IOError) as ex:
201
errMsg = "exception occurred while storing data "
202
errMsg += "to a temporary file ('%s'). Please " % ex
203
errMsg += "make sure that there is enough disk space left. If problem persists, "
204
errMsg += "try to set environment variable 'TEMP' to a location "
205
errMsg += "writeable by the current user"
206
raise SqlmapSystemException(errMsg)
207
208
def _checkcache(self, index):
209
if self.cache is not None and not isinstance(self.cache, Cache):
210
self.cache = None
211
212
if (self.cache and self.cache.index != index and self.cache.dirty):
213
filename = self._dump(self.cache.data)
214
self.chunks[self.cache.index] = filename
215
216
if not (self.cache and self.cache.index == index):
217
try:
218
with open(self.chunks[index], "rb") as f:
219
self.cache = Cache(index, pickle.loads(zlib.decompress(f.read())), False)
220
except Exception as ex:
221
errMsg = "exception occurred while retrieving data "
222
errMsg += "from a temporary file ('%s')" % ex
223
raise SqlmapSystemException(errMsg)
224
225
def __getstate__(self):
226
if self.cache and self.cache.dirty:
227
filename = self._dump(self.cache.data)
228
self.chunks[self.cache.index] = filename
229
self.cache.dirty = False
230
231
return self.chunks, self.filenames, self.chunk_length
232
233
def __setstate__(self, state):
234
self.__init__()
235
chunks, filenames, self.chunk_length = state
236
237
file_mapping = {}
238
self.filenames = set()
239
self.chunks = []
240
241
for filename in filenames:
242
if not os.path.exists(filename):
243
continue
244
245
try:
246
handle, new_filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.BIG_ARRAY)
247
os.close(handle)
248
shutil.copyfile(filename, new_filename)
249
self.filenames.add(new_filename)
250
file_mapping[filename] = new_filename
251
except (OSError, IOError):
252
pass
253
254
for chunk in chunks:
255
if isinstance(chunk, STRING_TYPES):
256
if chunk in file_mapping:
257
self.chunks.append(file_mapping[chunk])
258
else:
259
errMsg = "exception occurred while restoring BigArray chunk "
260
errMsg += "from file '%s'" % chunk
261
raise SqlmapSystemException(errMsg)
262
else:
263
self.chunks.append(chunk)
264
265
def __getitem__(self, y):
266
with self._lock:
267
length = len(self)
268
if length == 0:
269
raise IndexError("BigArray index out of range")
270
271
if y < 0:
272
y += length
273
274
if y < 0 or y >= length:
275
raise IndexError("BigArray index out of range")
276
277
index = y // self.chunk_length
278
offset = y % self.chunk_length
279
chunk = self.chunks[index]
280
281
if isinstance(chunk, list):
282
return chunk[offset]
283
else:
284
self._checkcache(index)
285
return self.cache.data[offset]
286
287
def __setitem__(self, y, value):
288
with self._lock:
289
length = len(self)
290
if length == 0:
291
raise IndexError("BigArray index out of range")
292
293
if y < 0:
294
y += length
295
296
if y < 0 or y >= length:
297
raise IndexError("BigArray index out of range")
298
299
index = y // self.chunk_length
300
offset = y % self.chunk_length
301
chunk = self.chunks[index]
302
303
if isinstance(chunk, list):
304
chunk[offset] = value
305
else:
306
self._checkcache(index)
307
self.cache.data[offset] = value
308
self.cache.dirty = True
309
310
def __repr__(self):
311
return "%s%s" % ("..." if len(self.chunks) > 1 else "", self.chunks[-1].__repr__())
312
313
def __iter__(self):
314
with self._lock:
315
chunks = list(self.chunks)
316
cache_index = self.cache.index if isinstance(self.cache, Cache) else None
317
cache_data = self.cache.data if isinstance(self.cache, Cache) else None
318
319
for idx, chunk in enumerate(chunks):
320
if isinstance(chunk, list):
321
for item in chunk:
322
yield item
323
else:
324
try:
325
if cache_index == idx and cache_data is not None:
326
data = cache_data
327
else:
328
with open(chunk, "rb") as f:
329
data = pickle.loads(zlib.decompress(f.read()))
330
except Exception as ex:
331
errMsg = "exception occurred while retrieving data "
332
errMsg += "from a temporary file ('%s')" % ex
333
raise SqlmapSystemException(errMsg)
334
335
for item in data:
336
yield item
337
338
def __len__(self):
339
return len(self.chunks[-1]) if len(self.chunks) == 1 else (len(self.chunks) - 1) * self.chunk_length + len(self.chunks[-1])
340
341