1 | n/a | /* |
---|
2 | n/a | / Author: Sam Rushing <rushing@nightmare.com> |
---|
3 | n/a | / Hacked for Unix by AMK |
---|
4 | n/a | / $Id$ |
---|
5 | n/a | |
---|
6 | n/a | / Modified to support mmap with offset - to map a 'window' of a file |
---|
7 | n/a | / Author: Yotam Medini yotamm@mellanox.co.il |
---|
8 | n/a | / |
---|
9 | n/a | / mmapmodule.cpp -- map a view of a file into memory |
---|
10 | n/a | / |
---|
11 | n/a | / todo: need permission flags, perhaps a 'chsize' analog |
---|
12 | n/a | / not all functions check range yet!!! |
---|
13 | n/a | / |
---|
14 | n/a | / |
---|
15 | n/a | / This version of mmapmodule.c has been changed significantly |
---|
16 | n/a | / from the original mmapfile.c on which it was based. |
---|
17 | n/a | / The original version of mmapfile is maintained by Sam at |
---|
18 | n/a | / ftp://squirl.nightmare.com/pub/python/python-ext. |
---|
19 | n/a | */ |
---|
20 | n/a | |
---|
21 | n/a | #define PY_SSIZE_T_CLEAN |
---|
22 | n/a | #include <Python.h> |
---|
23 | n/a | #include "structmember.h" |
---|
24 | n/a | |
---|
25 | n/a | #ifndef MS_WINDOWS |
---|
26 | n/a | #define UNIX |
---|
27 | n/a | # ifdef HAVE_FCNTL_H |
---|
28 | n/a | # include <fcntl.h> |
---|
29 | n/a | # endif /* HAVE_FCNTL_H */ |
---|
30 | n/a | #endif |
---|
31 | n/a | |
---|
32 | n/a | #ifdef MS_WINDOWS |
---|
33 | n/a | #include <windows.h> |
---|
34 | n/a | static int |
---|
35 | n/a | my_getpagesize(void) |
---|
36 | n/a | { |
---|
37 | n/a | SYSTEM_INFO si; |
---|
38 | n/a | GetSystemInfo(&si); |
---|
39 | n/a | return si.dwPageSize; |
---|
40 | n/a | } |
---|
41 | n/a | |
---|
42 | n/a | static int |
---|
43 | n/a | my_getallocationgranularity (void) |
---|
44 | n/a | { |
---|
45 | n/a | |
---|
46 | n/a | SYSTEM_INFO si; |
---|
47 | n/a | GetSystemInfo(&si); |
---|
48 | n/a | return si.dwAllocationGranularity; |
---|
49 | n/a | } |
---|
50 | n/a | |
---|
51 | n/a | #endif |
---|
52 | n/a | |
---|
53 | n/a | #ifdef UNIX |
---|
54 | n/a | #include <sys/mman.h> |
---|
55 | n/a | #include <sys/stat.h> |
---|
56 | n/a | |
---|
57 | n/a | #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) |
---|
58 | n/a | static int |
---|
59 | n/a | my_getpagesize(void) |
---|
60 | n/a | { |
---|
61 | n/a | return sysconf(_SC_PAGESIZE); |
---|
62 | n/a | } |
---|
63 | n/a | |
---|
64 | n/a | #define my_getallocationgranularity my_getpagesize |
---|
65 | n/a | #else |
---|
66 | n/a | #define my_getpagesize getpagesize |
---|
67 | n/a | #endif |
---|
68 | n/a | |
---|
69 | n/a | #endif /* UNIX */ |
---|
70 | n/a | |
---|
71 | n/a | #include <string.h> |
---|
72 | n/a | |
---|
73 | n/a | #ifdef HAVE_SYS_TYPES_H |
---|
74 | n/a | #include <sys/types.h> |
---|
75 | n/a | #endif /* HAVE_SYS_TYPES_H */ |
---|
76 | n/a | |
---|
77 | n/a | /* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */ |
---|
78 | n/a | #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) |
---|
79 | n/a | # define MAP_ANONYMOUS MAP_ANON |
---|
80 | n/a | #endif |
---|
81 | n/a | |
---|
82 | n/a | typedef enum |
---|
83 | n/a | { |
---|
84 | n/a | ACCESS_DEFAULT, |
---|
85 | n/a | ACCESS_READ, |
---|
86 | n/a | ACCESS_WRITE, |
---|
87 | n/a | ACCESS_COPY |
---|
88 | n/a | } access_mode; |
---|
89 | n/a | |
---|
90 | n/a | typedef struct { |
---|
91 | n/a | PyObject_HEAD |
---|
92 | n/a | char * data; |
---|
93 | n/a | Py_ssize_t size; |
---|
94 | n/a | Py_ssize_t pos; /* relative to offset */ |
---|
95 | n/a | #ifdef MS_WINDOWS |
---|
96 | n/a | long long offset; |
---|
97 | n/a | #else |
---|
98 | n/a | off_t offset; |
---|
99 | n/a | #endif |
---|
100 | n/a | int exports; |
---|
101 | n/a | |
---|
102 | n/a | #ifdef MS_WINDOWS |
---|
103 | n/a | HANDLE map_handle; |
---|
104 | n/a | HANDLE file_handle; |
---|
105 | n/a | char * tagname; |
---|
106 | n/a | #endif |
---|
107 | n/a | |
---|
108 | n/a | #ifdef UNIX |
---|
109 | n/a | int fd; |
---|
110 | n/a | #endif |
---|
111 | n/a | |
---|
112 | n/a | PyObject *weakreflist; |
---|
113 | n/a | access_mode access; |
---|
114 | n/a | } mmap_object; |
---|
115 | n/a | |
---|
116 | n/a | |
---|
117 | n/a | static void |
---|
118 | n/a | mmap_object_dealloc(mmap_object *m_obj) |
---|
119 | n/a | { |
---|
120 | n/a | #ifdef MS_WINDOWS |
---|
121 | n/a | if (m_obj->data != NULL) |
---|
122 | n/a | UnmapViewOfFile (m_obj->data); |
---|
123 | n/a | if (m_obj->map_handle != NULL) |
---|
124 | n/a | CloseHandle (m_obj->map_handle); |
---|
125 | n/a | if (m_obj->file_handle != INVALID_HANDLE_VALUE) |
---|
126 | n/a | CloseHandle (m_obj->file_handle); |
---|
127 | n/a | if (m_obj->tagname) |
---|
128 | n/a | PyMem_Free(m_obj->tagname); |
---|
129 | n/a | #endif /* MS_WINDOWS */ |
---|
130 | n/a | |
---|
131 | n/a | #ifdef UNIX |
---|
132 | n/a | if (m_obj->fd >= 0) |
---|
133 | n/a | (void) close(m_obj->fd); |
---|
134 | n/a | if (m_obj->data!=NULL) { |
---|
135 | n/a | munmap(m_obj->data, m_obj->size); |
---|
136 | n/a | } |
---|
137 | n/a | #endif /* UNIX */ |
---|
138 | n/a | |
---|
139 | n/a | if (m_obj->weakreflist != NULL) |
---|
140 | n/a | PyObject_ClearWeakRefs((PyObject *) m_obj); |
---|
141 | n/a | Py_TYPE(m_obj)->tp_free((PyObject*)m_obj); |
---|
142 | n/a | } |
---|
143 | n/a | |
---|
144 | n/a | static PyObject * |
---|
145 | n/a | mmap_close_method(mmap_object *self, PyObject *unused) |
---|
146 | n/a | { |
---|
147 | n/a | if (self->exports > 0) { |
---|
148 | n/a | PyErr_SetString(PyExc_BufferError, "cannot close "\ |
---|
149 | n/a | "exported pointers exist"); |
---|
150 | n/a | return NULL; |
---|
151 | n/a | } |
---|
152 | n/a | #ifdef MS_WINDOWS |
---|
153 | n/a | /* For each resource we maintain, we need to check |
---|
154 | n/a | the value is valid, and if so, free the resource |
---|
155 | n/a | and set the member value to an invalid value so |
---|
156 | n/a | the dealloc does not attempt to resource clearing |
---|
157 | n/a | again. |
---|
158 | n/a | TODO - should we check for errors in the close operations??? |
---|
159 | n/a | */ |
---|
160 | n/a | if (self->data != NULL) { |
---|
161 | n/a | UnmapViewOfFile(self->data); |
---|
162 | n/a | self->data = NULL; |
---|
163 | n/a | } |
---|
164 | n/a | if (self->map_handle != NULL) { |
---|
165 | n/a | CloseHandle(self->map_handle); |
---|
166 | n/a | self->map_handle = NULL; |
---|
167 | n/a | } |
---|
168 | n/a | if (self->file_handle != INVALID_HANDLE_VALUE) { |
---|
169 | n/a | CloseHandle(self->file_handle); |
---|
170 | n/a | self->file_handle = INVALID_HANDLE_VALUE; |
---|
171 | n/a | } |
---|
172 | n/a | #endif /* MS_WINDOWS */ |
---|
173 | n/a | |
---|
174 | n/a | #ifdef UNIX |
---|
175 | n/a | if (0 <= self->fd) |
---|
176 | n/a | (void) close(self->fd); |
---|
177 | n/a | self->fd = -1; |
---|
178 | n/a | if (self->data != NULL) { |
---|
179 | n/a | munmap(self->data, self->size); |
---|
180 | n/a | self->data = NULL; |
---|
181 | n/a | } |
---|
182 | n/a | #endif |
---|
183 | n/a | |
---|
184 | n/a | Py_RETURN_NONE; |
---|
185 | n/a | } |
---|
186 | n/a | |
---|
187 | n/a | #ifdef MS_WINDOWS |
---|
188 | n/a | #define CHECK_VALID(err) \ |
---|
189 | n/a | do { \ |
---|
190 | n/a | if (self->map_handle == NULL) { \ |
---|
191 | n/a | PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ |
---|
192 | n/a | return err; \ |
---|
193 | n/a | } \ |
---|
194 | n/a | } while (0) |
---|
195 | n/a | #endif /* MS_WINDOWS */ |
---|
196 | n/a | |
---|
197 | n/a | #ifdef UNIX |
---|
198 | n/a | #define CHECK_VALID(err) \ |
---|
199 | n/a | do { \ |
---|
200 | n/a | if (self->data == NULL) { \ |
---|
201 | n/a | PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ |
---|
202 | n/a | return err; \ |
---|
203 | n/a | } \ |
---|
204 | n/a | } while (0) |
---|
205 | n/a | #endif /* UNIX */ |
---|
206 | n/a | |
---|
207 | n/a | static PyObject * |
---|
208 | n/a | mmap_read_byte_method(mmap_object *self, |
---|
209 | n/a | PyObject *unused) |
---|
210 | n/a | { |
---|
211 | n/a | CHECK_VALID(NULL); |
---|
212 | n/a | if (self->pos >= self->size) { |
---|
213 | n/a | PyErr_SetString(PyExc_ValueError, "read byte out of range"); |
---|
214 | n/a | return NULL; |
---|
215 | n/a | } |
---|
216 | n/a | return PyLong_FromLong((unsigned char)self->data[self->pos++]); |
---|
217 | n/a | } |
---|
218 | n/a | |
---|
219 | n/a | static PyObject * |
---|
220 | n/a | mmap_read_line_method(mmap_object *self, |
---|
221 | n/a | PyObject *unused) |
---|
222 | n/a | { |
---|
223 | n/a | Py_ssize_t remaining; |
---|
224 | n/a | char *start, *eol; |
---|
225 | n/a | PyObject *result; |
---|
226 | n/a | |
---|
227 | n/a | CHECK_VALID(NULL); |
---|
228 | n/a | |
---|
229 | n/a | remaining = (self->pos < self->size) ? self->size - self->pos : 0; |
---|
230 | n/a | if (!remaining) |
---|
231 | n/a | return PyBytes_FromString(""); |
---|
232 | n/a | start = self->data + self->pos; |
---|
233 | n/a | eol = memchr(start, '\n', remaining); |
---|
234 | n/a | if (!eol) |
---|
235 | n/a | eol = self->data + self->size; |
---|
236 | n/a | else |
---|
237 | n/a | ++eol; /* advance past newline */ |
---|
238 | n/a | result = PyBytes_FromStringAndSize(start, (eol - start)); |
---|
239 | n/a | self->pos += (eol - start); |
---|
240 | n/a | return result; |
---|
241 | n/a | } |
---|
242 | n/a | |
---|
243 | n/a | /* Basically the "n" format code with the ability to turn None into -1. */ |
---|
244 | n/a | static int |
---|
245 | n/a | mmap_convert_ssize_t(PyObject *obj, void *result) { |
---|
246 | n/a | Py_ssize_t limit; |
---|
247 | n/a | if (obj == Py_None) { |
---|
248 | n/a | limit = -1; |
---|
249 | n/a | } |
---|
250 | n/a | else if (PyNumber_Check(obj)) { |
---|
251 | n/a | limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError); |
---|
252 | n/a | if (limit == -1 && PyErr_Occurred()) |
---|
253 | n/a | return 0; |
---|
254 | n/a | } |
---|
255 | n/a | else { |
---|
256 | n/a | PyErr_Format(PyExc_TypeError, |
---|
257 | n/a | "integer argument expected, got '%.200s'", |
---|
258 | n/a | Py_TYPE(obj)->tp_name); |
---|
259 | n/a | return 0; |
---|
260 | n/a | } |
---|
261 | n/a | *((Py_ssize_t *)result) = limit; |
---|
262 | n/a | return 1; |
---|
263 | n/a | } |
---|
264 | n/a | |
---|
265 | n/a | static PyObject * |
---|
266 | n/a | mmap_read_method(mmap_object *self, |
---|
267 | n/a | PyObject *args) |
---|
268 | n/a | { |
---|
269 | n/a | Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining; |
---|
270 | n/a | PyObject *result; |
---|
271 | n/a | |
---|
272 | n/a | CHECK_VALID(NULL); |
---|
273 | n/a | if (!PyArg_ParseTuple(args, "|O&:read", mmap_convert_ssize_t, &num_bytes)) |
---|
274 | n/a | return(NULL); |
---|
275 | n/a | |
---|
276 | n/a | /* silently 'adjust' out-of-range requests */ |
---|
277 | n/a | remaining = (self->pos < self->size) ? self->size - self->pos : 0; |
---|
278 | n/a | if (num_bytes < 0 || num_bytes > remaining) |
---|
279 | n/a | num_bytes = remaining; |
---|
280 | n/a | result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes); |
---|
281 | n/a | self->pos += num_bytes; |
---|
282 | n/a | return result; |
---|
283 | n/a | } |
---|
284 | n/a | |
---|
285 | n/a | static PyObject * |
---|
286 | n/a | mmap_gfind(mmap_object *self, |
---|
287 | n/a | PyObject *args, |
---|
288 | n/a | int reverse) |
---|
289 | n/a | { |
---|
290 | n/a | Py_ssize_t start = self->pos; |
---|
291 | n/a | Py_ssize_t end = self->size; |
---|
292 | n/a | Py_buffer view; |
---|
293 | n/a | |
---|
294 | n/a | CHECK_VALID(NULL); |
---|
295 | n/a | if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find", |
---|
296 | n/a | &view, &start, &end)) { |
---|
297 | n/a | return NULL; |
---|
298 | n/a | } else { |
---|
299 | n/a | const char *p, *start_p, *end_p; |
---|
300 | n/a | int sign = reverse ? -1 : 1; |
---|
301 | n/a | const char *needle = view.buf; |
---|
302 | n/a | Py_ssize_t len = view.len; |
---|
303 | n/a | |
---|
304 | n/a | if (start < 0) |
---|
305 | n/a | start += self->size; |
---|
306 | n/a | if (start < 0) |
---|
307 | n/a | start = 0; |
---|
308 | n/a | else if (start > self->size) |
---|
309 | n/a | start = self->size; |
---|
310 | n/a | |
---|
311 | n/a | if (end < 0) |
---|
312 | n/a | end += self->size; |
---|
313 | n/a | if (end < 0) |
---|
314 | n/a | end = 0; |
---|
315 | n/a | else if (end > self->size) |
---|
316 | n/a | end = self->size; |
---|
317 | n/a | |
---|
318 | n/a | start_p = self->data + start; |
---|
319 | n/a | end_p = self->data + end; |
---|
320 | n/a | |
---|
321 | n/a | for (p = (reverse ? end_p - len : start_p); |
---|
322 | n/a | (p >= start_p) && (p + len <= end_p); p += sign) { |
---|
323 | n/a | Py_ssize_t i; |
---|
324 | n/a | for (i = 0; i < len && needle[i] == p[i]; ++i) |
---|
325 | n/a | /* nothing */; |
---|
326 | n/a | if (i == len) { |
---|
327 | n/a | PyBuffer_Release(&view); |
---|
328 | n/a | return PyLong_FromSsize_t(p - self->data); |
---|
329 | n/a | } |
---|
330 | n/a | } |
---|
331 | n/a | PyBuffer_Release(&view); |
---|
332 | n/a | return PyLong_FromLong(-1); |
---|
333 | n/a | } |
---|
334 | n/a | } |
---|
335 | n/a | |
---|
336 | n/a | static PyObject * |
---|
337 | n/a | mmap_find_method(mmap_object *self, |
---|
338 | n/a | PyObject *args) |
---|
339 | n/a | { |
---|
340 | n/a | return mmap_gfind(self, args, 0); |
---|
341 | n/a | } |
---|
342 | n/a | |
---|
343 | n/a | static PyObject * |
---|
344 | n/a | mmap_rfind_method(mmap_object *self, |
---|
345 | n/a | PyObject *args) |
---|
346 | n/a | { |
---|
347 | n/a | return mmap_gfind(self, args, 1); |
---|
348 | n/a | } |
---|
349 | n/a | |
---|
350 | n/a | static int |
---|
351 | n/a | is_writable(mmap_object *self) |
---|
352 | n/a | { |
---|
353 | n/a | if (self->access != ACCESS_READ) |
---|
354 | n/a | return 1; |
---|
355 | n/a | PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map."); |
---|
356 | n/a | return 0; |
---|
357 | n/a | } |
---|
358 | n/a | |
---|
359 | n/a | static int |
---|
360 | n/a | is_resizeable(mmap_object *self) |
---|
361 | n/a | { |
---|
362 | n/a | if (self->exports > 0) { |
---|
363 | n/a | PyErr_SetString(PyExc_BufferError, |
---|
364 | n/a | "mmap can't resize with extant buffers exported."); |
---|
365 | n/a | return 0; |
---|
366 | n/a | } |
---|
367 | n/a | if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT)) |
---|
368 | n/a | return 1; |
---|
369 | n/a | PyErr_Format(PyExc_TypeError, |
---|
370 | n/a | "mmap can't resize a readonly or copy-on-write memory map."); |
---|
371 | n/a | return 0; |
---|
372 | n/a | } |
---|
373 | n/a | |
---|
374 | n/a | |
---|
375 | n/a | static PyObject * |
---|
376 | n/a | mmap_write_method(mmap_object *self, |
---|
377 | n/a | PyObject *args) |
---|
378 | n/a | { |
---|
379 | n/a | Py_buffer data; |
---|
380 | n/a | |
---|
381 | n/a | CHECK_VALID(NULL); |
---|
382 | n/a | if (!PyArg_ParseTuple(args, "y*:write", &data)) |
---|
383 | n/a | return(NULL); |
---|
384 | n/a | |
---|
385 | n/a | if (!is_writable(self)) { |
---|
386 | n/a | PyBuffer_Release(&data); |
---|
387 | n/a | return NULL; |
---|
388 | n/a | } |
---|
389 | n/a | |
---|
390 | n/a | if (self->pos > self->size || self->size - self->pos < data.len) { |
---|
391 | n/a | PyBuffer_Release(&data); |
---|
392 | n/a | PyErr_SetString(PyExc_ValueError, "data out of range"); |
---|
393 | n/a | return NULL; |
---|
394 | n/a | } |
---|
395 | n/a | |
---|
396 | n/a | memcpy(&self->data[self->pos], data.buf, data.len); |
---|
397 | n/a | self->pos += data.len; |
---|
398 | n/a | PyBuffer_Release(&data); |
---|
399 | n/a | return PyLong_FromSsize_t(data.len); |
---|
400 | n/a | } |
---|
401 | n/a | |
---|
402 | n/a | static PyObject * |
---|
403 | n/a | mmap_write_byte_method(mmap_object *self, |
---|
404 | n/a | PyObject *args) |
---|
405 | n/a | { |
---|
406 | n/a | char value; |
---|
407 | n/a | |
---|
408 | n/a | CHECK_VALID(NULL); |
---|
409 | n/a | if (!PyArg_ParseTuple(args, "b:write_byte", &value)) |
---|
410 | n/a | return(NULL); |
---|
411 | n/a | |
---|
412 | n/a | if (!is_writable(self)) |
---|
413 | n/a | return NULL; |
---|
414 | n/a | |
---|
415 | n/a | if (self->pos < self->size) { |
---|
416 | n/a | self->data[self->pos++] = value; |
---|
417 | n/a | Py_RETURN_NONE; |
---|
418 | n/a | } |
---|
419 | n/a | else { |
---|
420 | n/a | PyErr_SetString(PyExc_ValueError, "write byte out of range"); |
---|
421 | n/a | return NULL; |
---|
422 | n/a | } |
---|
423 | n/a | } |
---|
424 | n/a | |
---|
425 | n/a | static PyObject * |
---|
426 | n/a | mmap_size_method(mmap_object *self, |
---|
427 | n/a | PyObject *unused) |
---|
428 | n/a | { |
---|
429 | n/a | CHECK_VALID(NULL); |
---|
430 | n/a | |
---|
431 | n/a | #ifdef MS_WINDOWS |
---|
432 | n/a | if (self->file_handle != INVALID_HANDLE_VALUE) { |
---|
433 | n/a | DWORD low,high; |
---|
434 | n/a | long long size; |
---|
435 | n/a | low = GetFileSize(self->file_handle, &high); |
---|
436 | n/a | if (low == INVALID_FILE_SIZE) { |
---|
437 | n/a | /* It might be that the function appears to have failed, |
---|
438 | n/a | when indeed its size equals INVALID_FILE_SIZE */ |
---|
439 | n/a | DWORD error = GetLastError(); |
---|
440 | n/a | if (error != NO_ERROR) |
---|
441 | n/a | return PyErr_SetFromWindowsErr(error); |
---|
442 | n/a | } |
---|
443 | n/a | if (!high && low < LONG_MAX) |
---|
444 | n/a | return PyLong_FromLong((long)low); |
---|
445 | n/a | size = (((long long)high)<<32) + low; |
---|
446 | n/a | return PyLong_FromLongLong(size); |
---|
447 | n/a | } else { |
---|
448 | n/a | return PyLong_FromSsize_t(self->size); |
---|
449 | n/a | } |
---|
450 | n/a | #endif /* MS_WINDOWS */ |
---|
451 | n/a | |
---|
452 | n/a | #ifdef UNIX |
---|
453 | n/a | { |
---|
454 | n/a | struct _Py_stat_struct status; |
---|
455 | n/a | if (_Py_fstat(self->fd, &status) == -1) |
---|
456 | n/a | return NULL; |
---|
457 | n/a | #ifdef HAVE_LARGEFILE_SUPPORT |
---|
458 | n/a | return PyLong_FromLongLong(status.st_size); |
---|
459 | n/a | #else |
---|
460 | n/a | return PyLong_FromLong(status.st_size); |
---|
461 | n/a | #endif |
---|
462 | n/a | } |
---|
463 | n/a | #endif /* UNIX */ |
---|
464 | n/a | } |
---|
465 | n/a | |
---|
466 | n/a | /* This assumes that you want the entire file mapped, |
---|
467 | n/a | / and when recreating the map will make the new file |
---|
468 | n/a | / have the new size |
---|
469 | n/a | / |
---|
470 | n/a | / Is this really necessary? This could easily be done |
---|
471 | n/a | / from python by just closing and re-opening with the |
---|
472 | n/a | / new size? |
---|
473 | n/a | */ |
---|
474 | n/a | |
---|
475 | n/a | static PyObject * |
---|
476 | n/a | mmap_resize_method(mmap_object *self, |
---|
477 | n/a | PyObject *args) |
---|
478 | n/a | { |
---|
479 | n/a | Py_ssize_t new_size; |
---|
480 | n/a | CHECK_VALID(NULL); |
---|
481 | n/a | if (!PyArg_ParseTuple(args, "n:resize", &new_size) || |
---|
482 | n/a | !is_resizeable(self)) { |
---|
483 | n/a | return NULL; |
---|
484 | n/a | } |
---|
485 | n/a | if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) { |
---|
486 | n/a | PyErr_SetString(PyExc_ValueError, "new size out of range"); |
---|
487 | n/a | return NULL; |
---|
488 | n/a | } |
---|
489 | n/a | |
---|
490 | n/a | { |
---|
491 | n/a | #ifdef MS_WINDOWS |
---|
492 | n/a | DWORD dwErrCode = 0; |
---|
493 | n/a | DWORD off_hi, off_lo, newSizeLow, newSizeHigh; |
---|
494 | n/a | /* First, unmap the file view */ |
---|
495 | n/a | UnmapViewOfFile(self->data); |
---|
496 | n/a | self->data = NULL; |
---|
497 | n/a | /* Close the mapping object */ |
---|
498 | n/a | CloseHandle(self->map_handle); |
---|
499 | n/a | self->map_handle = NULL; |
---|
500 | n/a | /* Move to the desired EOF position */ |
---|
501 | n/a | newSizeHigh = (DWORD)((self->offset + new_size) >> 32); |
---|
502 | n/a | newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF); |
---|
503 | n/a | off_hi = (DWORD)(self->offset >> 32); |
---|
504 | n/a | off_lo = (DWORD)(self->offset & 0xFFFFFFFF); |
---|
505 | n/a | SetFilePointer(self->file_handle, |
---|
506 | n/a | newSizeLow, &newSizeHigh, FILE_BEGIN); |
---|
507 | n/a | /* Change the size of the file */ |
---|
508 | n/a | SetEndOfFile(self->file_handle); |
---|
509 | n/a | /* Create another mapping object and remap the file view */ |
---|
510 | n/a | self->map_handle = CreateFileMapping( |
---|
511 | n/a | self->file_handle, |
---|
512 | n/a | NULL, |
---|
513 | n/a | PAGE_READWRITE, |
---|
514 | n/a | 0, |
---|
515 | n/a | 0, |
---|
516 | n/a | self->tagname); |
---|
517 | n/a | if (self->map_handle != NULL) { |
---|
518 | n/a | self->data = (char *) MapViewOfFile(self->map_handle, |
---|
519 | n/a | FILE_MAP_WRITE, |
---|
520 | n/a | off_hi, |
---|
521 | n/a | off_lo, |
---|
522 | n/a | new_size); |
---|
523 | n/a | if (self->data != NULL) { |
---|
524 | n/a | self->size = new_size; |
---|
525 | n/a | Py_RETURN_NONE; |
---|
526 | n/a | } else { |
---|
527 | n/a | dwErrCode = GetLastError(); |
---|
528 | n/a | CloseHandle(self->map_handle); |
---|
529 | n/a | self->map_handle = NULL; |
---|
530 | n/a | } |
---|
531 | n/a | } else { |
---|
532 | n/a | dwErrCode = GetLastError(); |
---|
533 | n/a | } |
---|
534 | n/a | PyErr_SetFromWindowsErr(dwErrCode); |
---|
535 | n/a | return NULL; |
---|
536 | n/a | #endif /* MS_WINDOWS */ |
---|
537 | n/a | |
---|
538 | n/a | #ifdef UNIX |
---|
539 | n/a | #ifndef HAVE_MREMAP |
---|
540 | n/a | PyErr_SetString(PyExc_SystemError, |
---|
541 | n/a | "mmap: resizing not available--no mremap()"); |
---|
542 | n/a | return NULL; |
---|
543 | n/a | #else |
---|
544 | n/a | void *newmap; |
---|
545 | n/a | |
---|
546 | n/a | if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) { |
---|
547 | n/a | PyErr_SetFromErrno(PyExc_OSError); |
---|
548 | n/a | return NULL; |
---|
549 | n/a | } |
---|
550 | n/a | |
---|
551 | n/a | #ifdef MREMAP_MAYMOVE |
---|
552 | n/a | newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE); |
---|
553 | n/a | #else |
---|
554 | n/a | #if defined(__NetBSD__) |
---|
555 | n/a | newmap = mremap(self->data, self->size, self->data, new_size, 0); |
---|
556 | n/a | #else |
---|
557 | n/a | newmap = mremap(self->data, self->size, new_size, 0); |
---|
558 | n/a | #endif /* __NetBSD__ */ |
---|
559 | n/a | #endif |
---|
560 | n/a | if (newmap == (void *)-1) |
---|
561 | n/a | { |
---|
562 | n/a | PyErr_SetFromErrno(PyExc_OSError); |
---|
563 | n/a | return NULL; |
---|
564 | n/a | } |
---|
565 | n/a | self->data = newmap; |
---|
566 | n/a | self->size = new_size; |
---|
567 | n/a | Py_RETURN_NONE; |
---|
568 | n/a | #endif /* HAVE_MREMAP */ |
---|
569 | n/a | #endif /* UNIX */ |
---|
570 | n/a | } |
---|
571 | n/a | } |
---|
572 | n/a | |
---|
573 | n/a | static PyObject * |
---|
574 | n/a | mmap_tell_method(mmap_object *self, PyObject *unused) |
---|
575 | n/a | { |
---|
576 | n/a | CHECK_VALID(NULL); |
---|
577 | n/a | return PyLong_FromSize_t(self->pos); |
---|
578 | n/a | } |
---|
579 | n/a | |
---|
580 | n/a | static PyObject * |
---|
581 | n/a | mmap_flush_method(mmap_object *self, PyObject *args) |
---|
582 | n/a | { |
---|
583 | n/a | Py_ssize_t offset = 0; |
---|
584 | n/a | Py_ssize_t size = self->size; |
---|
585 | n/a | CHECK_VALID(NULL); |
---|
586 | n/a | if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) |
---|
587 | n/a | return NULL; |
---|
588 | n/a | if (size < 0 || offset < 0 || self->size - offset < size) { |
---|
589 | n/a | PyErr_SetString(PyExc_ValueError, "flush values out of range"); |
---|
590 | n/a | return NULL; |
---|
591 | n/a | } |
---|
592 | n/a | |
---|
593 | n/a | if (self->access == ACCESS_READ || self->access == ACCESS_COPY) |
---|
594 | n/a | return PyLong_FromLong(0); |
---|
595 | n/a | |
---|
596 | n/a | #ifdef MS_WINDOWS |
---|
597 | n/a | return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size)); |
---|
598 | n/a | #elif defined(UNIX) |
---|
599 | n/a | /* XXX semantics of return value? */ |
---|
600 | n/a | /* XXX flags for msync? */ |
---|
601 | n/a | if (-1 == msync(self->data + offset, size, MS_SYNC)) { |
---|
602 | n/a | PyErr_SetFromErrno(PyExc_OSError); |
---|
603 | n/a | return NULL; |
---|
604 | n/a | } |
---|
605 | n/a | return PyLong_FromLong(0); |
---|
606 | n/a | #else |
---|
607 | n/a | PyErr_SetString(PyExc_ValueError, "flush not supported on this system"); |
---|
608 | n/a | return NULL; |
---|
609 | n/a | #endif |
---|
610 | n/a | } |
---|
611 | n/a | |
---|
612 | n/a | static PyObject * |
---|
613 | n/a | mmap_seek_method(mmap_object *self, PyObject *args) |
---|
614 | n/a | { |
---|
615 | n/a | Py_ssize_t dist; |
---|
616 | n/a | int how=0; |
---|
617 | n/a | CHECK_VALID(NULL); |
---|
618 | n/a | if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) |
---|
619 | n/a | return NULL; |
---|
620 | n/a | else { |
---|
621 | n/a | Py_ssize_t where; |
---|
622 | n/a | switch (how) { |
---|
623 | n/a | case 0: /* relative to start */ |
---|
624 | n/a | where = dist; |
---|
625 | n/a | break; |
---|
626 | n/a | case 1: /* relative to current position */ |
---|
627 | n/a | if (PY_SSIZE_T_MAX - self->pos < dist) |
---|
628 | n/a | goto onoutofrange; |
---|
629 | n/a | where = self->pos + dist; |
---|
630 | n/a | break; |
---|
631 | n/a | case 2: /* relative to end */ |
---|
632 | n/a | if (PY_SSIZE_T_MAX - self->size < dist) |
---|
633 | n/a | goto onoutofrange; |
---|
634 | n/a | where = self->size + dist; |
---|
635 | n/a | break; |
---|
636 | n/a | default: |
---|
637 | n/a | PyErr_SetString(PyExc_ValueError, "unknown seek type"); |
---|
638 | n/a | return NULL; |
---|
639 | n/a | } |
---|
640 | n/a | if (where > self->size || where < 0) |
---|
641 | n/a | goto onoutofrange; |
---|
642 | n/a | self->pos = where; |
---|
643 | n/a | Py_RETURN_NONE; |
---|
644 | n/a | } |
---|
645 | n/a | |
---|
646 | n/a | onoutofrange: |
---|
647 | n/a | PyErr_SetString(PyExc_ValueError, "seek out of range"); |
---|
648 | n/a | return NULL; |
---|
649 | n/a | } |
---|
650 | n/a | |
---|
651 | n/a | static PyObject * |
---|
652 | n/a | mmap_move_method(mmap_object *self, PyObject *args) |
---|
653 | n/a | { |
---|
654 | n/a | Py_ssize_t dest, src, cnt; |
---|
655 | n/a | CHECK_VALID(NULL); |
---|
656 | n/a | if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) || |
---|
657 | n/a | !is_writable(self)) { |
---|
658 | n/a | return NULL; |
---|
659 | n/a | } else { |
---|
660 | n/a | /* bounds check the values */ |
---|
661 | n/a | if (dest < 0 || src < 0 || cnt < 0) |
---|
662 | n/a | goto bounds; |
---|
663 | n/a | if (self->size - dest < cnt || self->size - src < cnt) |
---|
664 | n/a | goto bounds; |
---|
665 | n/a | |
---|
666 | n/a | memmove(&self->data[dest], &self->data[src], cnt); |
---|
667 | n/a | |
---|
668 | n/a | Py_RETURN_NONE; |
---|
669 | n/a | |
---|
670 | n/a | bounds: |
---|
671 | n/a | PyErr_SetString(PyExc_ValueError, |
---|
672 | n/a | "source, destination, or count out of range"); |
---|
673 | n/a | return NULL; |
---|
674 | n/a | } |
---|
675 | n/a | } |
---|
676 | n/a | |
---|
677 | n/a | static PyObject * |
---|
678 | n/a | mmap_closed_get(mmap_object *self) |
---|
679 | n/a | { |
---|
680 | n/a | #ifdef MS_WINDOWS |
---|
681 | n/a | return PyBool_FromLong(self->map_handle == NULL ? 1 : 0); |
---|
682 | n/a | #elif defined(UNIX) |
---|
683 | n/a | return PyBool_FromLong(self->data == NULL ? 1 : 0); |
---|
684 | n/a | #endif |
---|
685 | n/a | } |
---|
686 | n/a | |
---|
687 | n/a | static PyObject * |
---|
688 | n/a | mmap__enter__method(mmap_object *self, PyObject *args) |
---|
689 | n/a | { |
---|
690 | n/a | CHECK_VALID(NULL); |
---|
691 | n/a | |
---|
692 | n/a | Py_INCREF(self); |
---|
693 | n/a | return (PyObject *)self; |
---|
694 | n/a | } |
---|
695 | n/a | |
---|
696 | n/a | static PyObject * |
---|
697 | n/a | mmap__exit__method(PyObject *self, PyObject *args) |
---|
698 | n/a | { |
---|
699 | n/a | _Py_IDENTIFIER(close); |
---|
700 | n/a | |
---|
701 | n/a | return _PyObject_CallMethodId(self, &PyId_close, NULL); |
---|
702 | n/a | } |
---|
703 | n/a | |
---|
704 | n/a | #ifdef MS_WINDOWS |
---|
705 | n/a | static PyObject * |
---|
706 | n/a | mmap__sizeof__method(mmap_object *self, void *unused) |
---|
707 | n/a | { |
---|
708 | n/a | Py_ssize_t res; |
---|
709 | n/a | |
---|
710 | n/a | res = _PyObject_SIZE(Py_TYPE(self)); |
---|
711 | n/a | if (self->tagname) |
---|
712 | n/a | res += strlen(self->tagname) + 1; |
---|
713 | n/a | return PyLong_FromSsize_t(res); |
---|
714 | n/a | } |
---|
715 | n/a | #endif |
---|
716 | n/a | |
---|
717 | n/a | static struct PyMethodDef mmap_object_methods[] = { |
---|
718 | n/a | {"close", (PyCFunction) mmap_close_method, METH_NOARGS}, |
---|
719 | n/a | {"find", (PyCFunction) mmap_find_method, METH_VARARGS}, |
---|
720 | n/a | {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS}, |
---|
721 | n/a | {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS}, |
---|
722 | n/a | {"move", (PyCFunction) mmap_move_method, METH_VARARGS}, |
---|
723 | n/a | {"read", (PyCFunction) mmap_read_method, METH_VARARGS}, |
---|
724 | n/a | {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS}, |
---|
725 | n/a | {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS}, |
---|
726 | n/a | {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS}, |
---|
727 | n/a | {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS}, |
---|
728 | n/a | {"size", (PyCFunction) mmap_size_method, METH_NOARGS}, |
---|
729 | n/a | {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS}, |
---|
730 | n/a | {"write", (PyCFunction) mmap_write_method, METH_VARARGS}, |
---|
731 | n/a | {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS}, |
---|
732 | n/a | {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS}, |
---|
733 | n/a | {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS}, |
---|
734 | n/a | #ifdef MS_WINDOWS |
---|
735 | n/a | {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS}, |
---|
736 | n/a | #endif |
---|
737 | n/a | {NULL, NULL} /* sentinel */ |
---|
738 | n/a | }; |
---|
739 | n/a | |
---|
740 | n/a | static PyGetSetDef mmap_object_getset[] = { |
---|
741 | n/a | {"closed", (getter) mmap_closed_get, NULL, NULL}, |
---|
742 | n/a | {NULL} |
---|
743 | n/a | }; |
---|
744 | n/a | |
---|
745 | n/a | |
---|
746 | n/a | /* Functions for treating an mmap'ed file as a buffer */ |
---|
747 | n/a | |
---|
748 | n/a | static int |
---|
749 | n/a | mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags) |
---|
750 | n/a | { |
---|
751 | n/a | CHECK_VALID(-1); |
---|
752 | n/a | if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size, |
---|
753 | n/a | (self->access == ACCESS_READ), flags) < 0) |
---|
754 | n/a | return -1; |
---|
755 | n/a | self->exports++; |
---|
756 | n/a | return 0; |
---|
757 | n/a | } |
---|
758 | n/a | |
---|
759 | n/a | static void |
---|
760 | n/a | mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view) |
---|
761 | n/a | { |
---|
762 | n/a | self->exports--; |
---|
763 | n/a | } |
---|
764 | n/a | |
---|
765 | n/a | static Py_ssize_t |
---|
766 | n/a | mmap_length(mmap_object *self) |
---|
767 | n/a | { |
---|
768 | n/a | CHECK_VALID(-1); |
---|
769 | n/a | return self->size; |
---|
770 | n/a | } |
---|
771 | n/a | |
---|
772 | n/a | static PyObject * |
---|
773 | n/a | mmap_item(mmap_object *self, Py_ssize_t i) |
---|
774 | n/a | { |
---|
775 | n/a | CHECK_VALID(NULL); |
---|
776 | n/a | if (i < 0 || i >= self->size) { |
---|
777 | n/a | PyErr_SetString(PyExc_IndexError, "mmap index out of range"); |
---|
778 | n/a | return NULL; |
---|
779 | n/a | } |
---|
780 | n/a | return PyBytes_FromStringAndSize(self->data + i, 1); |
---|
781 | n/a | } |
---|
782 | n/a | |
---|
783 | n/a | static PyObject * |
---|
784 | n/a | mmap_subscript(mmap_object *self, PyObject *item) |
---|
785 | n/a | { |
---|
786 | n/a | CHECK_VALID(NULL); |
---|
787 | n/a | if (PyIndex_Check(item)) { |
---|
788 | n/a | Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); |
---|
789 | n/a | if (i == -1 && PyErr_Occurred()) |
---|
790 | n/a | return NULL; |
---|
791 | n/a | if (i < 0) |
---|
792 | n/a | i += self->size; |
---|
793 | n/a | if (i < 0 || i >= self->size) { |
---|
794 | n/a | PyErr_SetString(PyExc_IndexError, |
---|
795 | n/a | "mmap index out of range"); |
---|
796 | n/a | return NULL; |
---|
797 | n/a | } |
---|
798 | n/a | return PyLong_FromLong(Py_CHARMASK(self->data[i])); |
---|
799 | n/a | } |
---|
800 | n/a | else if (PySlice_Check(item)) { |
---|
801 | n/a | Py_ssize_t start, stop, step, slicelen; |
---|
802 | n/a | |
---|
803 | n/a | if (PySlice_GetIndicesEx(item, self->size, |
---|
804 | n/a | &start, &stop, &step, &slicelen) < 0) { |
---|
805 | n/a | return NULL; |
---|
806 | n/a | } |
---|
807 | n/a | |
---|
808 | n/a | if (slicelen <= 0) |
---|
809 | n/a | return PyBytes_FromStringAndSize("", 0); |
---|
810 | n/a | else if (step == 1) |
---|
811 | n/a | return PyBytes_FromStringAndSize(self->data + start, |
---|
812 | n/a | slicelen); |
---|
813 | n/a | else { |
---|
814 | n/a | char *result_buf = (char *)PyMem_Malloc(slicelen); |
---|
815 | n/a | Py_ssize_t cur, i; |
---|
816 | n/a | PyObject *result; |
---|
817 | n/a | |
---|
818 | n/a | if (result_buf == NULL) |
---|
819 | n/a | return PyErr_NoMemory(); |
---|
820 | n/a | for (cur = start, i = 0; i < slicelen; |
---|
821 | n/a | cur += step, i++) { |
---|
822 | n/a | result_buf[i] = self->data[cur]; |
---|
823 | n/a | } |
---|
824 | n/a | result = PyBytes_FromStringAndSize(result_buf, |
---|
825 | n/a | slicelen); |
---|
826 | n/a | PyMem_Free(result_buf); |
---|
827 | n/a | return result; |
---|
828 | n/a | } |
---|
829 | n/a | } |
---|
830 | n/a | else { |
---|
831 | n/a | PyErr_SetString(PyExc_TypeError, |
---|
832 | n/a | "mmap indices must be integers"); |
---|
833 | n/a | return NULL; |
---|
834 | n/a | } |
---|
835 | n/a | } |
---|
836 | n/a | |
---|
837 | n/a | static PyObject * |
---|
838 | n/a | mmap_concat(mmap_object *self, PyObject *bb) |
---|
839 | n/a | { |
---|
840 | n/a | CHECK_VALID(NULL); |
---|
841 | n/a | PyErr_SetString(PyExc_SystemError, |
---|
842 | n/a | "mmaps don't support concatenation"); |
---|
843 | n/a | return NULL; |
---|
844 | n/a | } |
---|
845 | n/a | |
---|
846 | n/a | static PyObject * |
---|
847 | n/a | mmap_repeat(mmap_object *self, Py_ssize_t n) |
---|
848 | n/a | { |
---|
849 | n/a | CHECK_VALID(NULL); |
---|
850 | n/a | PyErr_SetString(PyExc_SystemError, |
---|
851 | n/a | "mmaps don't support repeat operation"); |
---|
852 | n/a | return NULL; |
---|
853 | n/a | } |
---|
854 | n/a | |
---|
855 | n/a | static int |
---|
856 | n/a | mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v) |
---|
857 | n/a | { |
---|
858 | n/a | const char *buf; |
---|
859 | n/a | |
---|
860 | n/a | CHECK_VALID(-1); |
---|
861 | n/a | if (i < 0 || i >= self->size) { |
---|
862 | n/a | PyErr_SetString(PyExc_IndexError, "mmap index out of range"); |
---|
863 | n/a | return -1; |
---|
864 | n/a | } |
---|
865 | n/a | if (v == NULL) { |
---|
866 | n/a | PyErr_SetString(PyExc_TypeError, |
---|
867 | n/a | "mmap object doesn't support item deletion"); |
---|
868 | n/a | return -1; |
---|
869 | n/a | } |
---|
870 | n/a | if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) { |
---|
871 | n/a | PyErr_SetString(PyExc_IndexError, |
---|
872 | n/a | "mmap assignment must be length-1 bytes()"); |
---|
873 | n/a | return -1; |
---|
874 | n/a | } |
---|
875 | n/a | if (!is_writable(self)) |
---|
876 | n/a | return -1; |
---|
877 | n/a | buf = PyBytes_AsString(v); |
---|
878 | n/a | self->data[i] = buf[0]; |
---|
879 | n/a | return 0; |
---|
880 | n/a | } |
---|
881 | n/a | |
---|
882 | n/a | static int |
---|
883 | n/a | mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value) |
---|
884 | n/a | { |
---|
885 | n/a | CHECK_VALID(-1); |
---|
886 | n/a | |
---|
887 | n/a | if (!is_writable(self)) |
---|
888 | n/a | return -1; |
---|
889 | n/a | |
---|
890 | n/a | if (PyIndex_Check(item)) { |
---|
891 | n/a | Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); |
---|
892 | n/a | Py_ssize_t v; |
---|
893 | n/a | |
---|
894 | n/a | if (i == -1 && PyErr_Occurred()) |
---|
895 | n/a | return -1; |
---|
896 | n/a | if (i < 0) |
---|
897 | n/a | i += self->size; |
---|
898 | n/a | if (i < 0 || i >= self->size) { |
---|
899 | n/a | PyErr_SetString(PyExc_IndexError, |
---|
900 | n/a | "mmap index out of range"); |
---|
901 | n/a | return -1; |
---|
902 | n/a | } |
---|
903 | n/a | if (value == NULL) { |
---|
904 | n/a | PyErr_SetString(PyExc_TypeError, |
---|
905 | n/a | "mmap doesn't support item deletion"); |
---|
906 | n/a | return -1; |
---|
907 | n/a | } |
---|
908 | n/a | if (!PyIndex_Check(value)) { |
---|
909 | n/a | PyErr_SetString(PyExc_TypeError, |
---|
910 | n/a | "mmap item value must be an int"); |
---|
911 | n/a | return -1; |
---|
912 | n/a | } |
---|
913 | n/a | v = PyNumber_AsSsize_t(value, PyExc_TypeError); |
---|
914 | n/a | if (v == -1 && PyErr_Occurred()) |
---|
915 | n/a | return -1; |
---|
916 | n/a | if (v < 0 || v > 255) { |
---|
917 | n/a | PyErr_SetString(PyExc_ValueError, |
---|
918 | n/a | "mmap item value must be " |
---|
919 | n/a | "in range(0, 256)"); |
---|
920 | n/a | return -1; |
---|
921 | n/a | } |
---|
922 | n/a | self->data[i] = (char) v; |
---|
923 | n/a | return 0; |
---|
924 | n/a | } |
---|
925 | n/a | else if (PySlice_Check(item)) { |
---|
926 | n/a | Py_ssize_t start, stop, step, slicelen; |
---|
927 | n/a | Py_buffer vbuf; |
---|
928 | n/a | |
---|
929 | n/a | if (PySlice_GetIndicesEx(item, |
---|
930 | n/a | self->size, &start, &stop, |
---|
931 | n/a | &step, &slicelen) < 0) { |
---|
932 | n/a | return -1; |
---|
933 | n/a | } |
---|
934 | n/a | if (value == NULL) { |
---|
935 | n/a | PyErr_SetString(PyExc_TypeError, |
---|
936 | n/a | "mmap object doesn't support slice deletion"); |
---|
937 | n/a | return -1; |
---|
938 | n/a | } |
---|
939 | n/a | if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0) |
---|
940 | n/a | return -1; |
---|
941 | n/a | if (vbuf.len != slicelen) { |
---|
942 | n/a | PyErr_SetString(PyExc_IndexError, |
---|
943 | n/a | "mmap slice assignment is wrong size"); |
---|
944 | n/a | PyBuffer_Release(&vbuf); |
---|
945 | n/a | return -1; |
---|
946 | n/a | } |
---|
947 | n/a | |
---|
948 | n/a | if (slicelen == 0) { |
---|
949 | n/a | } |
---|
950 | n/a | else if (step == 1) { |
---|
951 | n/a | memcpy(self->data + start, vbuf.buf, slicelen); |
---|
952 | n/a | } |
---|
953 | n/a | else { |
---|
954 | n/a | Py_ssize_t cur, i; |
---|
955 | n/a | |
---|
956 | n/a | for (cur = start, i = 0; |
---|
957 | n/a | i < slicelen; |
---|
958 | n/a | cur += step, i++) |
---|
959 | n/a | { |
---|
960 | n/a | self->data[cur] = ((char *)vbuf.buf)[i]; |
---|
961 | n/a | } |
---|
962 | n/a | } |
---|
963 | n/a | PyBuffer_Release(&vbuf); |
---|
964 | n/a | return 0; |
---|
965 | n/a | } |
---|
966 | n/a | else { |
---|
967 | n/a | PyErr_SetString(PyExc_TypeError, |
---|
968 | n/a | "mmap indices must be integer"); |
---|
969 | n/a | return -1; |
---|
970 | n/a | } |
---|
971 | n/a | } |
---|
972 | n/a | |
---|
973 | n/a | static PySequenceMethods mmap_as_sequence = { |
---|
974 | n/a | (lenfunc)mmap_length, /*sq_length*/ |
---|
975 | n/a | (binaryfunc)mmap_concat, /*sq_concat*/ |
---|
976 | n/a | (ssizeargfunc)mmap_repeat, /*sq_repeat*/ |
---|
977 | n/a | (ssizeargfunc)mmap_item, /*sq_item*/ |
---|
978 | n/a | 0, /*sq_slice*/ |
---|
979 | n/a | (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/ |
---|
980 | n/a | 0, /*sq_ass_slice*/ |
---|
981 | n/a | }; |
---|
982 | n/a | |
---|
983 | n/a | static PyMappingMethods mmap_as_mapping = { |
---|
984 | n/a | (lenfunc)mmap_length, |
---|
985 | n/a | (binaryfunc)mmap_subscript, |
---|
986 | n/a | (objobjargproc)mmap_ass_subscript, |
---|
987 | n/a | }; |
---|
988 | n/a | |
---|
989 | n/a | static PyBufferProcs mmap_as_buffer = { |
---|
990 | n/a | (getbufferproc)mmap_buffer_getbuf, |
---|
991 | n/a | (releasebufferproc)mmap_buffer_releasebuf, |
---|
992 | n/a | }; |
---|
993 | n/a | |
---|
994 | n/a | static PyObject * |
---|
995 | n/a | new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict); |
---|
996 | n/a | |
---|
997 | n/a | PyDoc_STRVAR(mmap_doc, |
---|
998 | n/a | "Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\ |
---|
999 | n/a | \n\ |
---|
1000 | n/a | Maps length bytes from the file specified by the file handle fileno,\n\ |
---|
1001 | n/a | and returns a mmap object. If length is larger than the current size\n\ |
---|
1002 | n/a | of the file, the file is extended to contain length bytes. If length\n\ |
---|
1003 | n/a | is 0, the maximum length of the map is the current size of the file,\n\ |
---|
1004 | n/a | except that if the file is empty Windows raises an exception (you cannot\n\ |
---|
1005 | n/a | create an empty mapping on Windows).\n\ |
---|
1006 | n/a | \n\ |
---|
1007 | n/a | Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\ |
---|
1008 | n/a | \n\ |
---|
1009 | n/a | Maps length bytes from the file specified by the file descriptor fileno,\n\ |
---|
1010 | n/a | and returns a mmap object. If length is 0, the maximum length of the map\n\ |
---|
1011 | n/a | will be the current size of the file when mmap is called.\n\ |
---|
1012 | n/a | flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\ |
---|
1013 | n/a | private copy-on-write mapping, so changes to the contents of the mmap\n\ |
---|
1014 | n/a | object will be private to this process, and MAP_SHARED creates a mapping\n\ |
---|
1015 | n/a | that's shared with all other processes mapping the same areas of the file.\n\ |
---|
1016 | n/a | The default value is MAP_SHARED.\n\ |
---|
1017 | n/a | \n\ |
---|
1018 | n/a | To map anonymous memory, pass -1 as the fileno (both versions)."); |
---|
1019 | n/a | |
---|
1020 | n/a | |
---|
1021 | n/a | static PyTypeObject mmap_object_type = { |
---|
1022 | n/a | PyVarObject_HEAD_INIT(NULL, 0) |
---|
1023 | n/a | "mmap.mmap", /* tp_name */ |
---|
1024 | n/a | sizeof(mmap_object), /* tp_size */ |
---|
1025 | n/a | 0, /* tp_itemsize */ |
---|
1026 | n/a | /* methods */ |
---|
1027 | n/a | (destructor) mmap_object_dealloc, /* tp_dealloc */ |
---|
1028 | n/a | 0, /* tp_print */ |
---|
1029 | n/a | 0, /* tp_getattr */ |
---|
1030 | n/a | 0, /* tp_setattr */ |
---|
1031 | n/a | 0, /* tp_reserved */ |
---|
1032 | n/a | 0, /* tp_repr */ |
---|
1033 | n/a | 0, /* tp_as_number */ |
---|
1034 | n/a | &mmap_as_sequence, /*tp_as_sequence*/ |
---|
1035 | n/a | &mmap_as_mapping, /*tp_as_mapping*/ |
---|
1036 | n/a | 0, /*tp_hash*/ |
---|
1037 | n/a | 0, /*tp_call*/ |
---|
1038 | n/a | 0, /*tp_str*/ |
---|
1039 | n/a | PyObject_GenericGetAttr, /*tp_getattro*/ |
---|
1040 | n/a | 0, /*tp_setattro*/ |
---|
1041 | n/a | &mmap_as_buffer, /*tp_as_buffer*/ |
---|
1042 | n/a | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
---|
1043 | n/a | mmap_doc, /*tp_doc*/ |
---|
1044 | n/a | 0, /* tp_traverse */ |
---|
1045 | n/a | 0, /* tp_clear */ |
---|
1046 | n/a | 0, /* tp_richcompare */ |
---|
1047 | n/a | offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */ |
---|
1048 | n/a | 0, /* tp_iter */ |
---|
1049 | n/a | 0, /* tp_iternext */ |
---|
1050 | n/a | mmap_object_methods, /* tp_methods */ |
---|
1051 | n/a | 0, /* tp_members */ |
---|
1052 | n/a | mmap_object_getset, /* tp_getset */ |
---|
1053 | n/a | 0, /* tp_base */ |
---|
1054 | n/a | 0, /* tp_dict */ |
---|
1055 | n/a | 0, /* tp_descr_get */ |
---|
1056 | n/a | 0, /* tp_descr_set */ |
---|
1057 | n/a | 0, /* tp_dictoffset */ |
---|
1058 | n/a | 0, /* tp_init */ |
---|
1059 | n/a | PyType_GenericAlloc, /* tp_alloc */ |
---|
1060 | n/a | new_mmap_object, /* tp_new */ |
---|
1061 | n/a | PyObject_Del, /* tp_free */ |
---|
1062 | n/a | }; |
---|
1063 | n/a | |
---|
1064 | n/a | |
---|
1065 | n/a | #ifdef UNIX |
---|
1066 | n/a | #ifdef HAVE_LARGEFILE_SUPPORT |
---|
1067 | n/a | #define _Py_PARSE_OFF_T "L" |
---|
1068 | n/a | #else |
---|
1069 | n/a | #define _Py_PARSE_OFF_T "l" |
---|
1070 | n/a | #endif |
---|
1071 | n/a | |
---|
1072 | n/a | static PyObject * |
---|
1073 | n/a | new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) |
---|
1074 | n/a | { |
---|
1075 | n/a | struct _Py_stat_struct status; |
---|
1076 | n/a | mmap_object *m_obj; |
---|
1077 | n/a | Py_ssize_t map_size; |
---|
1078 | n/a | off_t offset = 0; |
---|
1079 | n/a | int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; |
---|
1080 | n/a | int devzero = -1; |
---|
1081 | n/a | int access = (int)ACCESS_DEFAULT; |
---|
1082 | n/a | static char *keywords[] = {"fileno", "length", |
---|
1083 | n/a | "flags", "prot", |
---|
1084 | n/a | "access", "offset", NULL}; |
---|
1085 | n/a | |
---|
1086 | n/a | if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords, |
---|
1087 | n/a | &fd, &map_size, &flags, &prot, |
---|
1088 | n/a | &access, &offset)) |
---|
1089 | n/a | return NULL; |
---|
1090 | n/a | if (map_size < 0) { |
---|
1091 | n/a | PyErr_SetString(PyExc_OverflowError, |
---|
1092 | n/a | "memory mapped length must be postiive"); |
---|
1093 | n/a | return NULL; |
---|
1094 | n/a | } |
---|
1095 | n/a | if (offset < 0) { |
---|
1096 | n/a | PyErr_SetString(PyExc_OverflowError, |
---|
1097 | n/a | "memory mapped offset must be positive"); |
---|
1098 | n/a | return NULL; |
---|
1099 | n/a | } |
---|
1100 | n/a | |
---|
1101 | n/a | if ((access != (int)ACCESS_DEFAULT) && |
---|
1102 | n/a | ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ)))) |
---|
1103 | n/a | return PyErr_Format(PyExc_ValueError, |
---|
1104 | n/a | "mmap can't specify both access and flags, prot."); |
---|
1105 | n/a | switch ((access_mode)access) { |
---|
1106 | n/a | case ACCESS_READ: |
---|
1107 | n/a | flags = MAP_SHARED; |
---|
1108 | n/a | prot = PROT_READ; |
---|
1109 | n/a | break; |
---|
1110 | n/a | case ACCESS_WRITE: |
---|
1111 | n/a | flags = MAP_SHARED; |
---|
1112 | n/a | prot = PROT_READ | PROT_WRITE; |
---|
1113 | n/a | break; |
---|
1114 | n/a | case ACCESS_COPY: |
---|
1115 | n/a | flags = MAP_PRIVATE; |
---|
1116 | n/a | prot = PROT_READ | PROT_WRITE; |
---|
1117 | n/a | break; |
---|
1118 | n/a | case ACCESS_DEFAULT: |
---|
1119 | n/a | /* map prot to access type */ |
---|
1120 | n/a | if ((prot & PROT_READ) && (prot & PROT_WRITE)) { |
---|
1121 | n/a | /* ACCESS_DEFAULT */ |
---|
1122 | n/a | } |
---|
1123 | n/a | else if (prot & PROT_WRITE) { |
---|
1124 | n/a | access = ACCESS_WRITE; |
---|
1125 | n/a | } |
---|
1126 | n/a | else { |
---|
1127 | n/a | access = ACCESS_READ; |
---|
1128 | n/a | } |
---|
1129 | n/a | break; |
---|
1130 | n/a | default: |
---|
1131 | n/a | return PyErr_Format(PyExc_ValueError, |
---|
1132 | n/a | "mmap invalid access parameter."); |
---|
1133 | n/a | } |
---|
1134 | n/a | |
---|
1135 | n/a | #ifdef __APPLE__ |
---|
1136 | n/a | /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific |
---|
1137 | n/a | fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */ |
---|
1138 | n/a | if (fd != -1) |
---|
1139 | n/a | (void)fcntl(fd, F_FULLFSYNC); |
---|
1140 | n/a | #endif |
---|
1141 | n/a | if (fd != -1 && _Py_fstat_noraise(fd, &status) == 0 |
---|
1142 | n/a | && S_ISREG(status.st_mode)) { |
---|
1143 | n/a | if (map_size == 0) { |
---|
1144 | n/a | if (status.st_size == 0) { |
---|
1145 | n/a | PyErr_SetString(PyExc_ValueError, |
---|
1146 | n/a | "cannot mmap an empty file"); |
---|
1147 | n/a | return NULL; |
---|
1148 | n/a | } |
---|
1149 | n/a | if (offset >= status.st_size) { |
---|
1150 | n/a | PyErr_SetString(PyExc_ValueError, |
---|
1151 | n/a | "mmap offset is greater than file size"); |
---|
1152 | n/a | return NULL; |
---|
1153 | n/a | } |
---|
1154 | n/a | if (status.st_size - offset > PY_SSIZE_T_MAX) { |
---|
1155 | n/a | PyErr_SetString(PyExc_ValueError, |
---|
1156 | n/a | "mmap length is too large"); |
---|
1157 | n/a | return NULL; |
---|
1158 | n/a | } |
---|
1159 | n/a | map_size = (Py_ssize_t) (status.st_size - offset); |
---|
1160 | n/a | } else if (offset > status.st_size || status.st_size - offset < map_size) { |
---|
1161 | n/a | PyErr_SetString(PyExc_ValueError, |
---|
1162 | n/a | "mmap length is greater than file size"); |
---|
1163 | n/a | return NULL; |
---|
1164 | n/a | } |
---|
1165 | n/a | } |
---|
1166 | n/a | m_obj = (mmap_object *)type->tp_alloc(type, 0); |
---|
1167 | n/a | if (m_obj == NULL) {return NULL;} |
---|
1168 | n/a | m_obj->data = NULL; |
---|
1169 | n/a | m_obj->size = map_size; |
---|
1170 | n/a | m_obj->pos = 0; |
---|
1171 | n/a | m_obj->weakreflist = NULL; |
---|
1172 | n/a | m_obj->exports = 0; |
---|
1173 | n/a | m_obj->offset = offset; |
---|
1174 | n/a | if (fd == -1) { |
---|
1175 | n/a | m_obj->fd = -1; |
---|
1176 | n/a | /* Assume the caller wants to map anonymous memory. |
---|
1177 | n/a | This is the same behaviour as Windows. mmap.mmap(-1, size) |
---|
1178 | n/a | on both Windows and Unix map anonymous memory. |
---|
1179 | n/a | */ |
---|
1180 | n/a | #ifdef MAP_ANONYMOUS |
---|
1181 | n/a | /* BSD way to map anonymous memory */ |
---|
1182 | n/a | flags |= MAP_ANONYMOUS; |
---|
1183 | n/a | #else |
---|
1184 | n/a | /* SVR4 method to map anonymous memory is to open /dev/zero */ |
---|
1185 | n/a | fd = devzero = _Py_open("/dev/zero", O_RDWR); |
---|
1186 | n/a | if (devzero == -1) { |
---|
1187 | n/a | Py_DECREF(m_obj); |
---|
1188 | n/a | return NULL; |
---|
1189 | n/a | } |
---|
1190 | n/a | #endif |
---|
1191 | n/a | } |
---|
1192 | n/a | else { |
---|
1193 | n/a | m_obj->fd = _Py_dup(fd); |
---|
1194 | n/a | if (m_obj->fd == -1) { |
---|
1195 | n/a | Py_DECREF(m_obj); |
---|
1196 | n/a | return NULL; |
---|
1197 | n/a | } |
---|
1198 | n/a | } |
---|
1199 | n/a | |
---|
1200 | n/a | m_obj->data = mmap(NULL, map_size, |
---|
1201 | n/a | prot, flags, |
---|
1202 | n/a | fd, offset); |
---|
1203 | n/a | |
---|
1204 | n/a | if (devzero != -1) { |
---|
1205 | n/a | close(devzero); |
---|
1206 | n/a | } |
---|
1207 | n/a | |
---|
1208 | n/a | if (m_obj->data == (char *)-1) { |
---|
1209 | n/a | m_obj->data = NULL; |
---|
1210 | n/a | Py_DECREF(m_obj); |
---|
1211 | n/a | PyErr_SetFromErrno(PyExc_OSError); |
---|
1212 | n/a | return NULL; |
---|
1213 | n/a | } |
---|
1214 | n/a | m_obj->access = (access_mode)access; |
---|
1215 | n/a | return (PyObject *)m_obj; |
---|
1216 | n/a | } |
---|
1217 | n/a | #endif /* UNIX */ |
---|
1218 | n/a | |
---|
1219 | n/a | #ifdef MS_WINDOWS |
---|
1220 | n/a | |
---|
1221 | n/a | /* A note on sizes and offsets: while the actual map size must hold in a |
---|
1222 | n/a | Py_ssize_t, both the total file size and the start offset can be longer |
---|
1223 | n/a | than a Py_ssize_t, so we use long long which is always 64-bit. |
---|
1224 | n/a | */ |
---|
1225 | n/a | |
---|
1226 | n/a | static PyObject * |
---|
1227 | n/a | new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) |
---|
1228 | n/a | { |
---|
1229 | n/a | mmap_object *m_obj; |
---|
1230 | n/a | Py_ssize_t map_size; |
---|
1231 | n/a | long long offset = 0, size; |
---|
1232 | n/a | DWORD off_hi; /* upper 32 bits of offset */ |
---|
1233 | n/a | DWORD off_lo; /* lower 32 bits of offset */ |
---|
1234 | n/a | DWORD size_hi; /* upper 32 bits of size */ |
---|
1235 | n/a | DWORD size_lo; /* lower 32 bits of size */ |
---|
1236 | n/a | char *tagname = ""; |
---|
1237 | n/a | DWORD dwErr = 0; |
---|
1238 | n/a | int fileno; |
---|
1239 | n/a | HANDLE fh = 0; |
---|
1240 | n/a | int access = (access_mode)ACCESS_DEFAULT; |
---|
1241 | n/a | DWORD flProtect, dwDesiredAccess; |
---|
1242 | n/a | static char *keywords[] = { "fileno", "length", |
---|
1243 | n/a | "tagname", |
---|
1244 | n/a | "access", "offset", NULL }; |
---|
1245 | n/a | |
---|
1246 | n/a | if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords, |
---|
1247 | n/a | &fileno, &map_size, |
---|
1248 | n/a | &tagname, &access, &offset)) { |
---|
1249 | n/a | return NULL; |
---|
1250 | n/a | } |
---|
1251 | n/a | |
---|
1252 | n/a | switch((access_mode)access) { |
---|
1253 | n/a | case ACCESS_READ: |
---|
1254 | n/a | flProtect = PAGE_READONLY; |
---|
1255 | n/a | dwDesiredAccess = FILE_MAP_READ; |
---|
1256 | n/a | break; |
---|
1257 | n/a | case ACCESS_DEFAULT: case ACCESS_WRITE: |
---|
1258 | n/a | flProtect = PAGE_READWRITE; |
---|
1259 | n/a | dwDesiredAccess = FILE_MAP_WRITE; |
---|
1260 | n/a | break; |
---|
1261 | n/a | case ACCESS_COPY: |
---|
1262 | n/a | flProtect = PAGE_WRITECOPY; |
---|
1263 | n/a | dwDesiredAccess = FILE_MAP_COPY; |
---|
1264 | n/a | break; |
---|
1265 | n/a | default: |
---|
1266 | n/a | return PyErr_Format(PyExc_ValueError, |
---|
1267 | n/a | "mmap invalid access parameter."); |
---|
1268 | n/a | } |
---|
1269 | n/a | |
---|
1270 | n/a | if (map_size < 0) { |
---|
1271 | n/a | PyErr_SetString(PyExc_OverflowError, |
---|
1272 | n/a | "memory mapped length must be postiive"); |
---|
1273 | n/a | return NULL; |
---|
1274 | n/a | } |
---|
1275 | n/a | if (offset < 0) { |
---|
1276 | n/a | PyErr_SetString(PyExc_OverflowError, |
---|
1277 | n/a | "memory mapped offset must be positive"); |
---|
1278 | n/a | return NULL; |
---|
1279 | n/a | } |
---|
1280 | n/a | |
---|
1281 | n/a | /* assume -1 and 0 both mean invalid filedescriptor |
---|
1282 | n/a | to 'anonymously' map memory. |
---|
1283 | n/a | XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5. |
---|
1284 | n/a | XXX: Should this code be added? |
---|
1285 | n/a | if (fileno == 0) |
---|
1286 | n/a | PyErr_WarnEx(PyExc_DeprecationWarning, |
---|
1287 | n/a | "don't use 0 for anonymous memory", |
---|
1288 | n/a | 1); |
---|
1289 | n/a | */ |
---|
1290 | n/a | if (fileno != -1 && fileno != 0) { |
---|
1291 | n/a | /* Ensure that fileno is within the CRT's valid range */ |
---|
1292 | n/a | _Py_BEGIN_SUPPRESS_IPH |
---|
1293 | n/a | fh = (HANDLE)_get_osfhandle(fileno); |
---|
1294 | n/a | _Py_END_SUPPRESS_IPH |
---|
1295 | n/a | if (fh==(HANDLE)-1) { |
---|
1296 | n/a | PyErr_SetFromErrno(PyExc_OSError); |
---|
1297 | n/a | return NULL; |
---|
1298 | n/a | } |
---|
1299 | n/a | /* Win9x appears to need us seeked to zero */ |
---|
1300 | n/a | lseek(fileno, 0, SEEK_SET); |
---|
1301 | n/a | } |
---|
1302 | n/a | |
---|
1303 | n/a | m_obj = (mmap_object *)type->tp_alloc(type, 0); |
---|
1304 | n/a | if (m_obj == NULL) |
---|
1305 | n/a | return NULL; |
---|
1306 | n/a | /* Set every field to an invalid marker, so we can safely |
---|
1307 | n/a | destruct the object in the face of failure */ |
---|
1308 | n/a | m_obj->data = NULL; |
---|
1309 | n/a | m_obj->file_handle = INVALID_HANDLE_VALUE; |
---|
1310 | n/a | m_obj->map_handle = NULL; |
---|
1311 | n/a | m_obj->tagname = NULL; |
---|
1312 | n/a | m_obj->offset = offset; |
---|
1313 | n/a | |
---|
1314 | n/a | if (fh) { |
---|
1315 | n/a | /* It is necessary to duplicate the handle, so the |
---|
1316 | n/a | Python code can close it on us */ |
---|
1317 | n/a | if (!DuplicateHandle( |
---|
1318 | n/a | GetCurrentProcess(), /* source process handle */ |
---|
1319 | n/a | fh, /* handle to be duplicated */ |
---|
1320 | n/a | GetCurrentProcess(), /* target proc handle */ |
---|
1321 | n/a | (LPHANDLE)&m_obj->file_handle, /* result */ |
---|
1322 | n/a | 0, /* access - ignored due to options value */ |
---|
1323 | n/a | FALSE, /* inherited by child processes? */ |
---|
1324 | n/a | DUPLICATE_SAME_ACCESS)) { /* options */ |
---|
1325 | n/a | dwErr = GetLastError(); |
---|
1326 | n/a | Py_DECREF(m_obj); |
---|
1327 | n/a | PyErr_SetFromWindowsErr(dwErr); |
---|
1328 | n/a | return NULL; |
---|
1329 | n/a | } |
---|
1330 | n/a | if (!map_size) { |
---|
1331 | n/a | DWORD low,high; |
---|
1332 | n/a | low = GetFileSize(fh, &high); |
---|
1333 | n/a | /* low might just happen to have the value INVALID_FILE_SIZE; |
---|
1334 | n/a | so we need to check the last error also. */ |
---|
1335 | n/a | if (low == INVALID_FILE_SIZE && |
---|
1336 | n/a | (dwErr = GetLastError()) != NO_ERROR) { |
---|
1337 | n/a | Py_DECREF(m_obj); |
---|
1338 | n/a | return PyErr_SetFromWindowsErr(dwErr); |
---|
1339 | n/a | } |
---|
1340 | n/a | |
---|
1341 | n/a | size = (((long long) high) << 32) + low; |
---|
1342 | n/a | if (size == 0) { |
---|
1343 | n/a | PyErr_SetString(PyExc_ValueError, |
---|
1344 | n/a | "cannot mmap an empty file"); |
---|
1345 | n/a | Py_DECREF(m_obj); |
---|
1346 | n/a | return NULL; |
---|
1347 | n/a | } |
---|
1348 | n/a | if (offset >= size) { |
---|
1349 | n/a | PyErr_SetString(PyExc_ValueError, |
---|
1350 | n/a | "mmap offset is greater than file size"); |
---|
1351 | n/a | Py_DECREF(m_obj); |
---|
1352 | n/a | return NULL; |
---|
1353 | n/a | } |
---|
1354 | n/a | if (size - offset > PY_SSIZE_T_MAX) { |
---|
1355 | n/a | PyErr_SetString(PyExc_ValueError, |
---|
1356 | n/a | "mmap length is too large"); |
---|
1357 | n/a | Py_DECREF(m_obj); |
---|
1358 | n/a | return NULL; |
---|
1359 | n/a | } |
---|
1360 | n/a | m_obj->size = (Py_ssize_t) (size - offset); |
---|
1361 | n/a | } else { |
---|
1362 | n/a | m_obj->size = map_size; |
---|
1363 | n/a | size = offset + map_size; |
---|
1364 | n/a | } |
---|
1365 | n/a | } |
---|
1366 | n/a | else { |
---|
1367 | n/a | m_obj->size = map_size; |
---|
1368 | n/a | size = offset + map_size; |
---|
1369 | n/a | } |
---|
1370 | n/a | |
---|
1371 | n/a | /* set the initial position */ |
---|
1372 | n/a | m_obj->pos = (size_t) 0; |
---|
1373 | n/a | |
---|
1374 | n/a | m_obj->weakreflist = NULL; |
---|
1375 | n/a | m_obj->exports = 0; |
---|
1376 | n/a | /* set the tag name */ |
---|
1377 | n/a | if (tagname != NULL && *tagname != '\0') { |
---|
1378 | n/a | m_obj->tagname = PyMem_Malloc(strlen(tagname)+1); |
---|
1379 | n/a | if (m_obj->tagname == NULL) { |
---|
1380 | n/a | PyErr_NoMemory(); |
---|
1381 | n/a | Py_DECREF(m_obj); |
---|
1382 | n/a | return NULL; |
---|
1383 | n/a | } |
---|
1384 | n/a | strcpy(m_obj->tagname, tagname); |
---|
1385 | n/a | } |
---|
1386 | n/a | else |
---|
1387 | n/a | m_obj->tagname = NULL; |
---|
1388 | n/a | |
---|
1389 | n/a | m_obj->access = (access_mode)access; |
---|
1390 | n/a | size_hi = (DWORD)(size >> 32); |
---|
1391 | n/a | size_lo = (DWORD)(size & 0xFFFFFFFF); |
---|
1392 | n/a | off_hi = (DWORD)(offset >> 32); |
---|
1393 | n/a | off_lo = (DWORD)(offset & 0xFFFFFFFF); |
---|
1394 | n/a | /* For files, it would be sufficient to pass 0 as size. |
---|
1395 | n/a | For anonymous maps, we have to pass the size explicitly. */ |
---|
1396 | n/a | m_obj->map_handle = CreateFileMapping(m_obj->file_handle, |
---|
1397 | n/a | NULL, |
---|
1398 | n/a | flProtect, |
---|
1399 | n/a | size_hi, |
---|
1400 | n/a | size_lo, |
---|
1401 | n/a | m_obj->tagname); |
---|
1402 | n/a | if (m_obj->map_handle != NULL) { |
---|
1403 | n/a | m_obj->data = (char *) MapViewOfFile(m_obj->map_handle, |
---|
1404 | n/a | dwDesiredAccess, |
---|
1405 | n/a | off_hi, |
---|
1406 | n/a | off_lo, |
---|
1407 | n/a | m_obj->size); |
---|
1408 | n/a | if (m_obj->data != NULL) |
---|
1409 | n/a | return (PyObject *)m_obj; |
---|
1410 | n/a | else { |
---|
1411 | n/a | dwErr = GetLastError(); |
---|
1412 | n/a | CloseHandle(m_obj->map_handle); |
---|
1413 | n/a | m_obj->map_handle = NULL; |
---|
1414 | n/a | } |
---|
1415 | n/a | } else |
---|
1416 | n/a | dwErr = GetLastError(); |
---|
1417 | n/a | Py_DECREF(m_obj); |
---|
1418 | n/a | PyErr_SetFromWindowsErr(dwErr); |
---|
1419 | n/a | return NULL; |
---|
1420 | n/a | } |
---|
1421 | n/a | #endif /* MS_WINDOWS */ |
---|
1422 | n/a | |
---|
1423 | n/a | static void |
---|
1424 | n/a | setint(PyObject *d, const char *name, long value) |
---|
1425 | n/a | { |
---|
1426 | n/a | PyObject *o = PyLong_FromLong(value); |
---|
1427 | n/a | if (o && PyDict_SetItemString(d, name, o) == 0) { |
---|
1428 | n/a | Py_DECREF(o); |
---|
1429 | n/a | } |
---|
1430 | n/a | } |
---|
1431 | n/a | |
---|
1432 | n/a | |
---|
1433 | n/a | static struct PyModuleDef mmapmodule = { |
---|
1434 | n/a | PyModuleDef_HEAD_INIT, |
---|
1435 | n/a | "mmap", |
---|
1436 | n/a | NULL, |
---|
1437 | n/a | -1, |
---|
1438 | n/a | NULL, |
---|
1439 | n/a | NULL, |
---|
1440 | n/a | NULL, |
---|
1441 | n/a | NULL, |
---|
1442 | n/a | NULL |
---|
1443 | n/a | }; |
---|
1444 | n/a | |
---|
1445 | n/a | PyMODINIT_FUNC |
---|
1446 | n/a | PyInit_mmap(void) |
---|
1447 | n/a | { |
---|
1448 | n/a | PyObject *dict, *module; |
---|
1449 | n/a | |
---|
1450 | n/a | if (PyType_Ready(&mmap_object_type) < 0) |
---|
1451 | n/a | return NULL; |
---|
1452 | n/a | |
---|
1453 | n/a | module = PyModule_Create(&mmapmodule); |
---|
1454 | n/a | if (module == NULL) |
---|
1455 | n/a | return NULL; |
---|
1456 | n/a | dict = PyModule_GetDict(module); |
---|
1457 | n/a | if (!dict) |
---|
1458 | n/a | return NULL; |
---|
1459 | n/a | PyDict_SetItemString(dict, "error", PyExc_OSError); |
---|
1460 | n/a | PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type); |
---|
1461 | n/a | #ifdef PROT_EXEC |
---|
1462 | n/a | setint(dict, "PROT_EXEC", PROT_EXEC); |
---|
1463 | n/a | #endif |
---|
1464 | n/a | #ifdef PROT_READ |
---|
1465 | n/a | setint(dict, "PROT_READ", PROT_READ); |
---|
1466 | n/a | #endif |
---|
1467 | n/a | #ifdef PROT_WRITE |
---|
1468 | n/a | setint(dict, "PROT_WRITE", PROT_WRITE); |
---|
1469 | n/a | #endif |
---|
1470 | n/a | |
---|
1471 | n/a | #ifdef MAP_SHARED |
---|
1472 | n/a | setint(dict, "MAP_SHARED", MAP_SHARED); |
---|
1473 | n/a | #endif |
---|
1474 | n/a | #ifdef MAP_PRIVATE |
---|
1475 | n/a | setint(dict, "MAP_PRIVATE", MAP_PRIVATE); |
---|
1476 | n/a | #endif |
---|
1477 | n/a | #ifdef MAP_DENYWRITE |
---|
1478 | n/a | setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE); |
---|
1479 | n/a | #endif |
---|
1480 | n/a | #ifdef MAP_EXECUTABLE |
---|
1481 | n/a | setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE); |
---|
1482 | n/a | #endif |
---|
1483 | n/a | #ifdef MAP_ANONYMOUS |
---|
1484 | n/a | setint(dict, "MAP_ANON", MAP_ANONYMOUS); |
---|
1485 | n/a | setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS); |
---|
1486 | n/a | #endif |
---|
1487 | n/a | |
---|
1488 | n/a | setint(dict, "PAGESIZE", (long)my_getpagesize()); |
---|
1489 | n/a | |
---|
1490 | n/a | setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity()); |
---|
1491 | n/a | |
---|
1492 | n/a | setint(dict, "ACCESS_READ", ACCESS_READ); |
---|
1493 | n/a | setint(dict, "ACCESS_WRITE", ACCESS_WRITE); |
---|
1494 | n/a | setint(dict, "ACCESS_COPY", ACCESS_COPY); |
---|
1495 | n/a | return module; |
---|
1496 | n/a | } |
---|