Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/core/bigarray.py
2989 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2025 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 sys
16
import tempfile
17
import threading
18
import zlib
19
20
from lib.core.compat import xrange
21
from lib.core.enums import MKSTEMP_PREFIX
22
from lib.core.exception import SqlmapSystemException
23
from lib.core.settings import BIGARRAY_CHUNK_SIZE
24
from lib.core.settings import BIGARRAY_COMPRESS_LEVEL
25
26
try:
27
DEFAULT_SIZE_OF = sys.getsizeof(object())
28
except TypeError:
29
DEFAULT_SIZE_OF = 16
30
31
def _size_of(instance):
32
"""
33
Returns total size of a given instance / object (in bytes)
34
"""
35
36
retval = sys.getsizeof(instance, DEFAULT_SIZE_OF)
37
38
if isinstance(instance, dict):
39
retval += sum(_size_of(_) for _ in itertools.chain.from_iterable(instance.items()))
40
elif hasattr(instance, "__iter__"):
41
retval += sum(_size_of(_) for _ in instance if _ != instance)
42
43
return retval
44
45
class Cache(object):
46
"""
47
Auxiliary class used for storing cached chunks
48
"""
49
50
def __init__(self, index, data, dirty):
51
self.index = index
52
self.data = data
53
self.dirty = dirty
54
55
class BigArray(list):
56
"""
57
List-like class used for storing large amounts of data (disk cached)
58
59
>>> _ = BigArray(xrange(100000))
60
>>> _[20] = 0
61
>>> _[99999]
62
99999
63
>>> _ += [0]
64
>>> _[100000]
65
0
66
>>> _ = _ + [1]
67
>>> _[-1]
68
1
69
>>> len([_ for _ in BigArray(xrange(100000))])
70
100000
71
"""
72
73
def __init__(self, items=None):
74
self.chunks = [[]]
75
self.chunk_length = sys.maxsize
76
self.cache = None
77
self.filenames = set()
78
self._lock = threading.Lock()
79
self._os_remove = os.remove
80
self._size_counter = 0
81
82
for item in (items or []):
83
self.append(item)
84
85
def __add__(self, value):
86
retval = BigArray(self)
87
88
for _ in value:
89
retval.append(_)
90
91
return retval
92
93
def __iadd__(self, value):
94
for _ in value:
95
self.append(_)
96
97
return self
98
99
def append(self, value):
100
with self._lock:
101
self.chunks[-1].append(value)
102
103
if self.chunk_length == sys.maxsize:
104
self._size_counter += _size_of(value)
105
if self._size_counter >= BIGARRAY_CHUNK_SIZE:
106
self.chunk_length = len(self.chunks[-1])
107
self._size_counter = None
108
109
if len(self.chunks[-1]) >= self.chunk_length:
110
filename = self._dump(self.chunks[-1])
111
self.chunks[-1] = filename
112
self.chunks.append([])
113
114
def extend(self, value):
115
for _ in value:
116
self.append(_)
117
118
def pop(self):
119
with self._lock:
120
if not self.chunks[-1] and len(self.chunks) > 1:
121
self.chunks.pop()
122
try:
123
with open(self.chunks[-1], "rb") as f:
124
self.chunks[-1] = pickle.loads(zlib.decompress(f.read()))
125
except IOError as ex:
126
errMsg = "exception occurred while retrieving data "
127
errMsg += "from a temporary file ('%s')" % ex
128
raise SqlmapSystemException(errMsg)
129
130
return self.chunks[-1].pop()
131
132
def index(self, value):
133
for index in xrange(len(self)):
134
if self[index] == value:
135
return index
136
137
return ValueError, "%s is not in list" % value
138
139
def close(self):
140
while self.filenames:
141
filename = self.filenames.pop()
142
try:
143
self._os_remove(filename)
144
except OSError:
145
pass
146
147
def __del__(self):
148
self.close()
149
150
def _dump(self, chunk):
151
try:
152
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.BIG_ARRAY)
153
self.filenames.add(filename)
154
os.close(handle)
155
with open(filename, "w+b") as f:
156
f.write(zlib.compress(pickle.dumps(chunk, pickle.HIGHEST_PROTOCOL), BIGARRAY_COMPRESS_LEVEL))
157
return filename
158
except (OSError, IOError) as ex:
159
errMsg = "exception occurred while storing data "
160
errMsg += "to a temporary file ('%s'). Please " % ex
161
errMsg += "make sure that there is enough disk space left. If problem persists, "
162
errMsg += "try to set environment variable 'TEMP' to a location "
163
errMsg += "writeable by the current user"
164
raise SqlmapSystemException(errMsg)
165
166
def _checkcache(self, index):
167
if self.cache is not None and not isinstance(self.cache, Cache):
168
self.cache = None
169
170
if (self.cache and self.cache.index != index and self.cache.dirty):
171
filename = self._dump(self.cache.data)
172
self.chunks[self.cache.index] = filename
173
174
if not (self.cache and self.cache.index == index):
175
try:
176
with open(self.chunks[index], "rb") as f:
177
self.cache = Cache(index, pickle.loads(zlib.decompress(f.read())), False)
178
except Exception as ex:
179
errMsg = "exception occurred while retrieving data "
180
errMsg += "from a temporary file ('%s')" % ex
181
raise SqlmapSystemException(errMsg)
182
183
def __getstate__(self):
184
return self.chunks, self.filenames
185
186
def __setstate__(self, state):
187
self.__init__()
188
self.chunks, self.filenames = state
189
190
def __getitem__(self, y):
191
length = len(self)
192
if length == 0:
193
raise IndexError("BigArray index out of range")
194
195
while y < 0:
196
y += length
197
198
index = y // self.chunk_length
199
offset = y % self.chunk_length
200
chunk = self.chunks[index]
201
202
if isinstance(chunk, list):
203
return chunk[offset]
204
else:
205
self._checkcache(index)
206
return self.cache.data[offset]
207
208
def __setitem__(self, y, value):
209
index = y // self.chunk_length
210
offset = y % self.chunk_length
211
chunk = self.chunks[index]
212
213
if isinstance(chunk, list):
214
chunk[offset] = value
215
else:
216
self._checkcache(index)
217
self.cache.data[offset] = value
218
self.cache.dirty = True
219
220
def __repr__(self):
221
return "%s%s" % ("..." if len(self.chunks) > 1 else "", self.chunks[-1].__repr__())
222
223
def __iter__(self):
224
for i in xrange(len(self)):
225
try:
226
yield self[i]
227
except IndexError:
228
break
229
230
def __len__(self):
231
return len(self.chunks[-1]) if len(self.chunks) == 1 else (len(self.chunks) - 1) * self.chunk_length + len(self.chunks[-1])
232
233