Branch data Line data Source code
1 : : /*
2 : : / Author: Sam Rushing <rushing@nightmare.com>
3 : : / Hacked for Unix by AMK
4 : : / $Id$
5 : :
6 : : / Modified to support mmap with offset - to map a 'window' of a file
7 : : / Author: Yotam Medini yotamm@mellanox.co.il
8 : : /
9 : : / mmapmodule.cpp -- map a view of a file into memory
10 : : /
11 : : / todo: need permission flags, perhaps a 'chsize' analog
12 : : / not all functions check range yet!!!
13 : : /
14 : : /
15 : : / This version of mmapmodule.c has been changed significantly
16 : : / from the original mmapfile.c on which it was based.
17 : : / The original version of mmapfile is maintained by Sam at
18 : : / ftp://squirl.nightmare.com/pub/python/python-ext.
19 : : */
20 : :
21 : : #ifndef Py_BUILD_CORE_BUILTIN
22 : : # define Py_BUILD_CORE_MODULE 1
23 : : #endif
24 : :
25 : : #define PY_SSIZE_T_CLEAN
26 : : #include <Python.h>
27 : : #include "pycore_bytesobject.h" // _PyBytes_Find()
28 : : #include "pycore_fileutils.h" // _Py_stat_struct
29 : : #include "structmember.h" // PyMemberDef
30 : : #include <stddef.h> // offsetof()
31 : :
32 : : // to support MS_WINDOWS_SYSTEM OpenFileMappingA / CreateFileMappingA
33 : : // need to be replaced with OpenFileMappingW / CreateFileMappingW
34 : : #if !defined(MS_WINDOWS) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_GAMES)
35 : :
36 : : #ifndef MS_WINDOWS
37 : : #define UNIX
38 : : # ifdef HAVE_FCNTL_H
39 : : # include <fcntl.h>
40 : : # endif /* HAVE_FCNTL_H */
41 : : #endif
42 : :
43 : : #ifdef MS_WINDOWS
44 : : #include <windows.h>
45 : : static int
46 : : my_getpagesize(void)
47 : : {
48 : : SYSTEM_INFO si;
49 : : GetSystemInfo(&si);
50 : : return si.dwPageSize;
51 : : }
52 : :
53 : : static int
54 : : my_getallocationgranularity (void)
55 : : {
56 : :
57 : : SYSTEM_INFO si;
58 : : GetSystemInfo(&si);
59 : : return si.dwAllocationGranularity;
60 : : }
61 : :
62 : : #endif
63 : :
64 : : #ifdef UNIX
65 : : #include <sys/mman.h>
66 : : #include <sys/stat.h>
67 : :
68 : : #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
69 : : static int
70 : 2 : my_getpagesize(void)
71 : : {
72 : 2 : return sysconf(_SC_PAGESIZE);
73 : : }
74 : :
75 : : #define my_getallocationgranularity my_getpagesize
76 : : #else
77 : : #define my_getpagesize getpagesize
78 : : #endif
79 : :
80 : : #endif /* UNIX */
81 : :
82 : : #include <string.h>
83 : :
84 : : #ifdef HAVE_SYS_TYPES_H
85 : : #include <sys/types.h>
86 : : #endif /* HAVE_SYS_TYPES_H */
87 : :
88 : : /* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
89 : : #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
90 : : # define MAP_ANONYMOUS MAP_ANON
91 : : #endif
92 : :
93 : : typedef enum
94 : : {
95 : : ACCESS_DEFAULT,
96 : : ACCESS_READ,
97 : : ACCESS_WRITE,
98 : : ACCESS_COPY
99 : : } access_mode;
100 : :
101 : : typedef struct {
102 : : PyObject_HEAD
103 : : char * data;
104 : : Py_ssize_t size;
105 : : Py_ssize_t pos; /* relative to offset */
106 : : #ifdef MS_WINDOWS
107 : : long long offset;
108 : : #else
109 : : off_t offset;
110 : : #endif
111 : : Py_ssize_t exports;
112 : :
113 : : #ifdef MS_WINDOWS
114 : : HANDLE map_handle;
115 : : HANDLE file_handle;
116 : : char * tagname;
117 : : #endif
118 : :
119 : : #ifdef UNIX
120 : : int fd;
121 : : #endif
122 : :
123 : : PyObject *weakreflist;
124 : : access_mode access;
125 : : } mmap_object;
126 : :
127 : : static int
128 : 0 : mmap_object_traverse(mmap_object *m_obj, visitproc visit, void *arg)
129 : : {
130 [ # # # # ]: 0 : Py_VISIT(Py_TYPE(m_obj));
131 : 0 : return 0;
132 : : }
133 : :
134 : : static void
135 : 0 : mmap_object_dealloc(mmap_object *m_obj)
136 : : {
137 : 0 : PyTypeObject *tp = Py_TYPE(m_obj);
138 : 0 : PyObject_GC_UnTrack(m_obj);
139 : :
140 : : #ifdef MS_WINDOWS
141 : : Py_BEGIN_ALLOW_THREADS
142 : : if (m_obj->data != NULL)
143 : : UnmapViewOfFile (m_obj->data);
144 : : if (m_obj->map_handle != NULL)
145 : : CloseHandle (m_obj->map_handle);
146 : : if (m_obj->file_handle != INVALID_HANDLE_VALUE)
147 : : CloseHandle (m_obj->file_handle);
148 : : Py_END_ALLOW_THREADS
149 : : if (m_obj->tagname)
150 : : PyMem_Free(m_obj->tagname);
151 : : #endif /* MS_WINDOWS */
152 : :
153 : : #ifdef UNIX
154 : 0 : Py_BEGIN_ALLOW_THREADS
155 [ # # ]: 0 : if (m_obj->fd >= 0)
156 : 0 : (void) close(m_obj->fd);
157 [ # # ]: 0 : if (m_obj->data!=NULL) {
158 : 0 : munmap(m_obj->data, m_obj->size);
159 : : }
160 : 0 : Py_END_ALLOW_THREADS
161 : : #endif /* UNIX */
162 : :
163 [ # # ]: 0 : if (m_obj->weakreflist != NULL)
164 : 0 : PyObject_ClearWeakRefs((PyObject *) m_obj);
165 : :
166 : 0 : tp->tp_free(m_obj);
167 : 0 : Py_DECREF(tp);
168 : 0 : }
169 : :
170 : : static PyObject *
171 : 0 : mmap_close_method(mmap_object *self, PyObject *unused)
172 : : {
173 [ # # ]: 0 : if (self->exports > 0) {
174 : 0 : PyErr_SetString(PyExc_BufferError, "cannot close "\
175 : : "exported pointers exist");
176 : 0 : return NULL;
177 : : }
178 : : #ifdef MS_WINDOWS
179 : : /* For each resource we maintain, we need to check
180 : : the value is valid, and if so, free the resource
181 : : and set the member value to an invalid value so
182 : : the dealloc does not attempt to resource clearing
183 : : again.
184 : : TODO - should we check for errors in the close operations???
185 : : */
186 : : HANDLE map_handle = self->map_handle;
187 : : HANDLE file_handle = self->file_handle;
188 : : char *data = self->data;
189 : : self->map_handle = NULL;
190 : : self->file_handle = INVALID_HANDLE_VALUE;
191 : : self->data = NULL;
192 : : Py_BEGIN_ALLOW_THREADS
193 : : if (data != NULL) {
194 : : UnmapViewOfFile(data);
195 : : }
196 : : if (map_handle != NULL) {
197 : : CloseHandle(map_handle);
198 : : }
199 : : if (file_handle != INVALID_HANDLE_VALUE) {
200 : : CloseHandle(file_handle);
201 : : }
202 : : Py_END_ALLOW_THREADS
203 : : #endif /* MS_WINDOWS */
204 : :
205 : : #ifdef UNIX
206 : 0 : int fd = self->fd;
207 : 0 : char *data = self->data;
208 : 0 : self->fd = -1;
209 : 0 : self->data = NULL;
210 : 0 : Py_BEGIN_ALLOW_THREADS
211 [ # # ]: 0 : if (0 <= fd)
212 : 0 : (void) close(fd);
213 [ # # ]: 0 : if (data != NULL) {
214 : 0 : munmap(data, self->size);
215 : : }
216 : 0 : Py_END_ALLOW_THREADS
217 : : #endif
218 : :
219 : 0 : Py_RETURN_NONE;
220 : : }
221 : :
222 : : #ifdef MS_WINDOWS
223 : : #define CHECK_VALID(err) \
224 : : do { \
225 : : if (self->map_handle == NULL) { \
226 : : PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
227 : : return err; \
228 : : } \
229 : : } while (0)
230 : : #endif /* MS_WINDOWS */
231 : :
232 : : #ifdef UNIX
233 : : #define CHECK_VALID(err) \
234 : : do { \
235 : : if (self->data == NULL) { \
236 : : PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
237 : : return err; \
238 : : } \
239 : : } while (0)
240 : : #endif /* UNIX */
241 : :
242 : : static PyObject *
243 : 0 : mmap_read_byte_method(mmap_object *self,
244 : : PyObject *unused)
245 : : {
246 [ # # ]: 0 : CHECK_VALID(NULL);
247 [ # # ]: 0 : if (self->pos >= self->size) {
248 : 0 : PyErr_SetString(PyExc_ValueError, "read byte out of range");
249 : 0 : return NULL;
250 : : }
251 : 0 : return PyLong_FromLong((unsigned char)self->data[self->pos++]);
252 : : }
253 : :
254 : : static PyObject *
255 : 0 : mmap_read_line_method(mmap_object *self,
256 : : PyObject *unused)
257 : : {
258 : : Py_ssize_t remaining;
259 : : char *start, *eol;
260 : : PyObject *result;
261 : :
262 [ # # ]: 0 : CHECK_VALID(NULL);
263 : :
264 [ # # ]: 0 : remaining = (self->pos < self->size) ? self->size - self->pos : 0;
265 [ # # ]: 0 : if (!remaining)
266 : 0 : return PyBytes_FromString("");
267 : 0 : start = self->data + self->pos;
268 : 0 : eol = memchr(start, '\n', remaining);
269 [ # # ]: 0 : if (!eol)
270 : 0 : eol = self->data + self->size;
271 : : else
272 : 0 : ++eol; /* advance past newline */
273 : 0 : result = PyBytes_FromStringAndSize(start, (eol - start));
274 : 0 : self->pos += (eol - start);
275 : 0 : return result;
276 : : }
277 : :
278 : : static PyObject *
279 : 0 : mmap_read_method(mmap_object *self,
280 : : PyObject *args)
281 : : {
282 : 0 : Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining;
283 : : PyObject *result;
284 : :
285 [ # # ]: 0 : CHECK_VALID(NULL);
286 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes))
287 : 0 : return(NULL);
288 : :
289 : : /* silently 'adjust' out-of-range requests */
290 [ # # ]: 0 : remaining = (self->pos < self->size) ? self->size - self->pos : 0;
291 [ # # # # ]: 0 : if (num_bytes < 0 || num_bytes > remaining)
292 : 0 : num_bytes = remaining;
293 : 0 : result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes);
294 : 0 : self->pos += num_bytes;
295 : 0 : return result;
296 : : }
297 : :
298 : : static PyObject *
299 : 0 : mmap_gfind(mmap_object *self,
300 : : PyObject *args,
301 : : int reverse)
302 : : {
303 : 0 : Py_ssize_t start = self->pos;
304 : 0 : Py_ssize_t end = self->size;
305 : : Py_buffer view;
306 : :
307 [ # # ]: 0 : CHECK_VALID(NULL);
308 [ # # # # ]: 0 : if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find",
309 : : &view, &start, &end)) {
310 : 0 : return NULL;
311 : : }
312 : : else {
313 [ # # ]: 0 : if (start < 0)
314 : 0 : start += self->size;
315 [ # # ]: 0 : if (start < 0)
316 : 0 : start = 0;
317 [ # # ]: 0 : else if (start > self->size)
318 : 0 : start = self->size;
319 : :
320 [ # # ]: 0 : if (end < 0)
321 : 0 : end += self->size;
322 [ # # ]: 0 : if (end < 0)
323 : 0 : end = 0;
324 [ # # ]: 0 : else if (end > self->size)
325 : 0 : end = self->size;
326 : :
327 : : Py_ssize_t res;
328 [ # # ]: 0 : if (reverse) {
329 : 0 : res = _PyBytes_ReverseFind(
330 : 0 : self->data + start, end - start,
331 : 0 : view.buf, view.len, start);
332 : : }
333 : : else {
334 : 0 : res = _PyBytes_Find(
335 : 0 : self->data + start, end - start,
336 : 0 : view.buf, view.len, start);
337 : : }
338 : 0 : PyBuffer_Release(&view);
339 : 0 : return PyLong_FromSsize_t(res);
340 : : }
341 : : }
342 : :
343 : : static PyObject *
344 : 0 : mmap_find_method(mmap_object *self,
345 : : PyObject *args)
346 : : {
347 : 0 : return mmap_gfind(self, args, 0);
348 : : }
349 : :
350 : : static PyObject *
351 : 0 : mmap_rfind_method(mmap_object *self,
352 : : PyObject *args)
353 : : {
354 : 0 : return mmap_gfind(self, args, 1);
355 : : }
356 : :
357 : : static int
358 : 0 : is_writable(mmap_object *self)
359 : : {
360 [ # # ]: 0 : if (self->access != ACCESS_READ)
361 : 0 : return 1;
362 : 0 : PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
363 : 0 : return 0;
364 : : }
365 : :
366 : : static int
367 : 0 : is_resizeable(mmap_object *self)
368 : : {
369 [ # # ]: 0 : if (self->exports > 0) {
370 : 0 : PyErr_SetString(PyExc_BufferError,
371 : : "mmap can't resize with extant buffers exported.");
372 : 0 : return 0;
373 : : }
374 [ # # # # ]: 0 : if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
375 : 0 : return 1;
376 : 0 : PyErr_Format(PyExc_TypeError,
377 : : "mmap can't resize a readonly or copy-on-write memory map.");
378 : 0 : return 0;
379 : :
380 : : }
381 : :
382 : :
383 : : static PyObject *
384 : 0 : mmap_write_method(mmap_object *self,
385 : : PyObject *args)
386 : : {
387 : : Py_buffer data;
388 : :
389 [ # # ]: 0 : CHECK_VALID(NULL);
390 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "y*:write", &data))
391 : 0 : return(NULL);
392 : :
393 [ # # ]: 0 : if (!is_writable(self)) {
394 : 0 : PyBuffer_Release(&data);
395 : 0 : return NULL;
396 : : }
397 : :
398 [ # # # # ]: 0 : if (self->pos > self->size || self->size - self->pos < data.len) {
399 : 0 : PyBuffer_Release(&data);
400 : 0 : PyErr_SetString(PyExc_ValueError, "data out of range");
401 : 0 : return NULL;
402 : : }
403 : :
404 : 0 : memcpy(&self->data[self->pos], data.buf, data.len);
405 : 0 : self->pos += data.len;
406 : 0 : PyBuffer_Release(&data);
407 : 0 : return PyLong_FromSsize_t(data.len);
408 : : }
409 : :
410 : : static PyObject *
411 : 0 : mmap_write_byte_method(mmap_object *self,
412 : : PyObject *args)
413 : : {
414 : : char value;
415 : :
416 [ # # ]: 0 : CHECK_VALID(NULL);
417 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "b:write_byte", &value))
418 : 0 : return(NULL);
419 : :
420 [ # # ]: 0 : if (!is_writable(self))
421 : 0 : return NULL;
422 : :
423 [ # # ]: 0 : if (self->pos < self->size) {
424 : 0 : self->data[self->pos++] = value;
425 : 0 : Py_RETURN_NONE;
426 : : }
427 : : else {
428 : 0 : PyErr_SetString(PyExc_ValueError, "write byte out of range");
429 : 0 : return NULL;
430 : : }
431 : : }
432 : :
433 : : static PyObject *
434 : 0 : mmap_size_method(mmap_object *self,
435 : : PyObject *unused)
436 : : {
437 [ # # ]: 0 : CHECK_VALID(NULL);
438 : :
439 : : #ifdef MS_WINDOWS
440 : : if (self->file_handle != INVALID_HANDLE_VALUE) {
441 : : DWORD low,high;
442 : : long long size;
443 : : low = GetFileSize(self->file_handle, &high);
444 : : if (low == INVALID_FILE_SIZE) {
445 : : /* It might be that the function appears to have failed,
446 : : when indeed its size equals INVALID_FILE_SIZE */
447 : : DWORD error = GetLastError();
448 : : if (error != NO_ERROR)
449 : : return PyErr_SetFromWindowsErr(error);
450 : : }
451 : : if (!high && low < LONG_MAX)
452 : : return PyLong_FromLong((long)low);
453 : : size = (((long long)high)<<32) + low;
454 : : return PyLong_FromLongLong(size);
455 : : } else {
456 : : return PyLong_FromSsize_t(self->size);
457 : : }
458 : : #endif /* MS_WINDOWS */
459 : :
460 : : #ifdef UNIX
461 : : {
462 : : struct _Py_stat_struct status;
463 [ # # ]: 0 : if (_Py_fstat(self->fd, &status) == -1)
464 : 0 : return NULL;
465 : : #ifdef HAVE_LARGEFILE_SUPPORT
466 : : return PyLong_FromLongLong(status.st_size);
467 : : #else
468 : 0 : return PyLong_FromLong(status.st_size);
469 : : #endif
470 : : }
471 : : #endif /* UNIX */
472 : : }
473 : :
474 : : /* This assumes that you want the entire file mapped,
475 : : / and when recreating the map will make the new file
476 : : / have the new size
477 : : /
478 : : / Is this really necessary? This could easily be done
479 : : / from python by just closing and re-opening with the
480 : : / new size?
481 : : */
482 : :
483 : : static PyObject *
484 : 0 : mmap_resize_method(mmap_object *self,
485 : : PyObject *args)
486 : : {
487 : : Py_ssize_t new_size;
488 [ # # ]: 0 : CHECK_VALID(NULL);
489 [ # # # # ]: 0 : if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
490 : 0 : !is_resizeable(self)) {
491 : 0 : return NULL;
492 : : }
493 [ # # # # ]: 0 : if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) {
494 : 0 : PyErr_SetString(PyExc_ValueError, "new size out of range");
495 : 0 : return NULL;
496 : : }
497 : :
498 : : {
499 : : #ifdef MS_WINDOWS
500 : : DWORD error = 0, file_resize_error = 0;
501 : : char* old_data = self->data;
502 : : LARGE_INTEGER offset, max_size;
503 : : offset.QuadPart = self->offset;
504 : : max_size.QuadPart = self->offset + new_size;
505 : : /* close the file mapping */
506 : : CloseHandle(self->map_handle);
507 : : /* if the file mapping still exists, it cannot be resized. */
508 : : if (self->tagname) {
509 : : self->map_handle = OpenFileMappingA(FILE_MAP_WRITE, FALSE,
510 : : self->tagname);
511 : : if (self->map_handle) {
512 : : PyErr_SetFromWindowsErr(ERROR_USER_MAPPED_FILE);
513 : : return NULL;
514 : : }
515 : : } else {
516 : : self->map_handle = NULL;
517 : : }
518 : :
519 : : /* if it's not the paging file, unmap the view and resize the file */
520 : : if (self->file_handle != INVALID_HANDLE_VALUE) {
521 : : if (!UnmapViewOfFile(self->data)) {
522 : : return PyErr_SetFromWindowsErr(GetLastError());
523 : : };
524 : : self->data = NULL;
525 : : /* resize the file */
526 : : if (!SetFilePointerEx(self->file_handle, max_size, NULL,
527 : : FILE_BEGIN) ||
528 : : !SetEndOfFile(self->file_handle)) {
529 : : /* resizing failed. try to remap the file */
530 : : file_resize_error = GetLastError();
531 : : max_size.QuadPart = self->size;
532 : : new_size = self->size;
533 : : }
534 : : }
535 : :
536 : : /* create a new file mapping and map a new view */
537 : : /* FIXME: call CreateFileMappingW with wchar_t tagname */
538 : : self->map_handle = CreateFileMappingA(
539 : : self->file_handle,
540 : : NULL,
541 : : PAGE_READWRITE,
542 : : max_size.HighPart,
543 : : max_size.LowPart,
544 : : self->tagname);
545 : :
546 : : error = GetLastError();
547 : : /* ERROR_ALREADY_EXISTS implies that between our closing the handle above and
548 : : calling CreateFileMapping here, someone's created a different mapping with
549 : : the same name. There's nothing we can usefully do so we invalidate our
550 : : mapping and error out.
551 : : */
552 : : if (error == ERROR_ALREADY_EXISTS) {
553 : : CloseHandle(self->map_handle);
554 : : self->map_handle = NULL;
555 : : }
556 : : else if (self->map_handle != NULL) {
557 : : self->data = MapViewOfFile(self->map_handle,
558 : : FILE_MAP_WRITE,
559 : : offset.HighPart,
560 : : offset.LowPart,
561 : : new_size);
562 : : if (self->data != NULL) {
563 : : /* copy the old view if using the paging file */
564 : : if (self->file_handle == INVALID_HANDLE_VALUE) {
565 : : memcpy(self->data, old_data,
566 : : self->size < new_size ? self->size : new_size);
567 : : if (!UnmapViewOfFile(old_data)) {
568 : : error = GetLastError();
569 : : }
570 : : }
571 : : self->size = new_size;
572 : : }
573 : : else {
574 : : error = GetLastError();
575 : : CloseHandle(self->map_handle);
576 : : self->map_handle = NULL;
577 : : }
578 : : }
579 : :
580 : : if (error) {
581 : : return PyErr_SetFromWindowsErr(error);
582 : : return NULL;
583 : : }
584 : : /* It's possible for a resize to fail, typically because another mapping
585 : : is still held against the same underlying file. Even if nothing has
586 : : failed -- ie we're still returning a valid file mapping -- raise the
587 : : error as an exception as the resize won't have happened
588 : : */
589 : : if (file_resize_error) {
590 : : PyErr_SetFromWindowsErr(file_resize_error);
591 : : return NULL;
592 : : }
593 : : Py_RETURN_NONE;
594 : : #endif /* MS_WINDOWS */
595 : :
596 : : #ifdef UNIX
597 : : #ifndef HAVE_MREMAP
598 : : PyErr_SetString(PyExc_SystemError,
599 : : "mmap: resizing not available--no mremap()");
600 : : return NULL;
601 : : #else
602 : : void *newmap;
603 : :
604 [ # # # # ]: 0 : if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
605 : 0 : PyErr_SetFromErrno(PyExc_OSError);
606 : 0 : return NULL;
607 : : }
608 : :
609 : : #ifdef MREMAP_MAYMOVE
610 : 0 : newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
611 : : #else
612 : : #if defined(__NetBSD__)
613 : : newmap = mremap(self->data, self->size, self->data, new_size, 0);
614 : : #else
615 : : newmap = mremap(self->data, self->size, new_size, 0);
616 : : #endif /* __NetBSD__ */
617 : : #endif
618 [ # # ]: 0 : if (newmap == (void *)-1)
619 : : {
620 : 0 : PyErr_SetFromErrno(PyExc_OSError);
621 : 0 : return NULL;
622 : : }
623 : 0 : self->data = newmap;
624 : 0 : self->size = new_size;
625 : 0 : Py_RETURN_NONE;
626 : : #endif /* HAVE_MREMAP */
627 : : #endif /* UNIX */
628 : : }
629 : : }
630 : :
631 : : static PyObject *
632 : 0 : mmap_tell_method(mmap_object *self, PyObject *unused)
633 : : {
634 [ # # ]: 0 : CHECK_VALID(NULL);
635 : 0 : return PyLong_FromSize_t(self->pos);
636 : : }
637 : :
638 : : static PyObject *
639 : 0 : mmap_flush_method(mmap_object *self, PyObject *args)
640 : : {
641 : 0 : Py_ssize_t offset = 0;
642 : 0 : Py_ssize_t size = self->size;
643 [ # # ]: 0 : CHECK_VALID(NULL);
644 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
645 : 0 : return NULL;
646 [ # # # # : 0 : if (size < 0 || offset < 0 || self->size - offset < size) {
# # ]
647 : 0 : PyErr_SetString(PyExc_ValueError, "flush values out of range");
648 : 0 : return NULL;
649 : : }
650 : :
651 [ # # # # ]: 0 : if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
652 : 0 : Py_RETURN_NONE;
653 : :
654 : : #if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)
655 : : if (!FlushViewOfFile(self->data+offset, size)) {
656 : : PyErr_SetFromWindowsErr(GetLastError());
657 : : return NULL;
658 : : }
659 : : Py_RETURN_NONE;
660 : : #elif defined(UNIX)
661 : : /* XXX flags for msync? */
662 [ # # ]: 0 : if (-1 == msync(self->data + offset, size, MS_SYNC)) {
663 : 0 : PyErr_SetFromErrno(PyExc_OSError);
664 : 0 : return NULL;
665 : : }
666 : 0 : Py_RETURN_NONE;
667 : : #else
668 : : PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
669 : : return NULL;
670 : : #endif
671 : : }
672 : :
673 : : static PyObject *
674 : 0 : mmap_seek_method(mmap_object *self, PyObject *args)
675 : : {
676 : : Py_ssize_t dist;
677 : 0 : int how=0;
678 [ # # ]: 0 : CHECK_VALID(NULL);
679 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
680 : 0 : return NULL;
681 : : else {
682 : : Py_ssize_t where;
683 [ # # # # ]: 0 : switch (how) {
684 : 0 : case 0: /* relative to start */
685 : 0 : where = dist;
686 : 0 : break;
687 : 0 : case 1: /* relative to current position */
688 [ # # ]: 0 : if (PY_SSIZE_T_MAX - self->pos < dist)
689 : 0 : goto onoutofrange;
690 : 0 : where = self->pos + dist;
691 : 0 : break;
692 : 0 : case 2: /* relative to end */
693 [ # # ]: 0 : if (PY_SSIZE_T_MAX - self->size < dist)
694 : 0 : goto onoutofrange;
695 : 0 : where = self->size + dist;
696 : 0 : break;
697 : 0 : default:
698 : 0 : PyErr_SetString(PyExc_ValueError, "unknown seek type");
699 : 0 : return NULL;
700 : : }
701 [ # # # # ]: 0 : if (where > self->size || where < 0)
702 : 0 : goto onoutofrange;
703 : 0 : self->pos = where;
704 : 0 : Py_RETURN_NONE;
705 : : }
706 : :
707 : 0 : onoutofrange:
708 : 0 : PyErr_SetString(PyExc_ValueError, "seek out of range");
709 : 0 : return NULL;
710 : : }
711 : :
712 : : static PyObject *
713 : 0 : mmap_move_method(mmap_object *self, PyObject *args)
714 : : {
715 : : Py_ssize_t dest, src, cnt;
716 [ # # ]: 0 : CHECK_VALID(NULL);
717 [ # # # # ]: 0 : if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
718 : 0 : !is_writable(self)) {
719 : 0 : return NULL;
720 : : } else {
721 : : /* bounds check the values */
722 [ # # # # : 0 : if (dest < 0 || src < 0 || cnt < 0)
# # ]
723 : 0 : goto bounds;
724 [ # # # # ]: 0 : if (self->size - dest < cnt || self->size - src < cnt)
725 : 0 : goto bounds;
726 : :
727 : 0 : memmove(&self->data[dest], &self->data[src], cnt);
728 : :
729 : 0 : Py_RETURN_NONE;
730 : :
731 : 0 : bounds:
732 : 0 : PyErr_SetString(PyExc_ValueError,
733 : : "source, destination, or count out of range");
734 : 0 : return NULL;
735 : : }
736 : : }
737 : :
738 : : static PyObject *
739 : 0 : mmap_closed_get(mmap_object *self, void *Py_UNUSED(ignored))
740 : : {
741 : : #ifdef MS_WINDOWS
742 : : return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
743 : : #elif defined(UNIX)
744 : 0 : return PyBool_FromLong(self->data == NULL ? 1 : 0);
745 : : #endif
746 : : }
747 : :
748 : : static PyObject *
749 : 0 : mmap__enter__method(mmap_object *self, PyObject *args)
750 : : {
751 [ # # ]: 0 : CHECK_VALID(NULL);
752 : :
753 : 0 : return Py_NewRef(self);
754 : : }
755 : :
756 : : static PyObject *
757 : 0 : mmap__exit__method(PyObject *self, PyObject *args)
758 : : {
759 : 0 : return mmap_close_method((mmap_object *)self, NULL);
760 : : }
761 : :
762 : : static PyObject *
763 : 0 : mmap__repr__method(PyObject *self)
764 : : {
765 : 0 : mmap_object *mobj = (mmap_object *)self;
766 : :
767 : : #ifdef MS_WINDOWS
768 : : #define _Py_FORMAT_OFFSET "lld"
769 : : if (mobj->map_handle == NULL)
770 : : #elif defined(UNIX)
771 : : # ifdef HAVE_LARGEFILE_SUPPORT
772 : : # define _Py_FORMAT_OFFSET "lld"
773 : : # else
774 : : # define _Py_FORMAT_OFFSET "ld"
775 : : # endif
776 [ # # ]: 0 : if (mobj->data == NULL)
777 : : #endif
778 : : {
779 : 0 : return PyUnicode_FromFormat("<%s closed=True>", Py_TYPE(self)->tp_name);
780 : : } else {
781 : : const char *access_str;
782 : :
783 [ # # # # : 0 : switch (mobj->access) {
# ]
784 : 0 : case ACCESS_DEFAULT:
785 : 0 : access_str = "ACCESS_DEFAULT";
786 : 0 : break;
787 : 0 : case ACCESS_READ:
788 : 0 : access_str = "ACCESS_READ";
789 : 0 : break;
790 : 0 : case ACCESS_WRITE:
791 : 0 : access_str = "ACCESS_WRITE";
792 : 0 : break;
793 : 0 : case ACCESS_COPY:
794 : 0 : access_str = "ACCESS_COPY";
795 : 0 : break;
796 : 0 : default:
797 : 0 : Py_UNREACHABLE();
798 : : }
799 : :
800 : 0 : return PyUnicode_FromFormat("<%s closed=False, access=%s, length=%zd, "
801 : : "pos=%zd, offset=%" _Py_FORMAT_OFFSET ">",
802 : 0 : Py_TYPE(self)->tp_name, access_str,
803 : : mobj->size, mobj->pos, mobj->offset);
804 : : }
805 : : }
806 : :
807 : : #ifdef MS_WINDOWS
808 : : static PyObject *
809 : : mmap__sizeof__method(mmap_object *self, void *unused)
810 : : {
811 : : size_t res = _PyObject_SIZE(Py_TYPE(self));
812 : : if (self->tagname) {
813 : : res += strlen(self->tagname) + 1;
814 : : }
815 : : return PyLong_FromSize_t(res);
816 : : }
817 : : #endif
818 : :
819 : : #ifdef HAVE_MADVISE
820 : : static PyObject *
821 : 0 : mmap_madvise_method(mmap_object *self, PyObject *args)
822 : : {
823 : : int option;
824 : 0 : Py_ssize_t start = 0, length;
825 : :
826 [ # # ]: 0 : CHECK_VALID(NULL);
827 : 0 : length = self->size;
828 : :
829 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "i|nn:madvise", &option, &start, &length)) {
830 : 0 : return NULL;
831 : : }
832 : :
833 [ # # # # ]: 0 : if (start < 0 || start >= self->size) {
834 : 0 : PyErr_SetString(PyExc_ValueError, "madvise start out of bounds");
835 : 0 : return NULL;
836 : : }
837 [ # # ]: 0 : if (length < 0) {
838 : 0 : PyErr_SetString(PyExc_ValueError, "madvise length invalid");
839 : 0 : return NULL;
840 : : }
841 [ # # ]: 0 : if (PY_SSIZE_T_MAX - start < length) {
842 : 0 : PyErr_SetString(PyExc_OverflowError, "madvise length too large");
843 : 0 : return NULL;
844 : : }
845 : :
846 [ # # ]: 0 : if (start + length > self->size) {
847 : 0 : length = self->size - start;
848 : : }
849 : :
850 [ # # ]: 0 : if (madvise(self->data + start, length, option) != 0) {
851 : 0 : PyErr_SetFromErrno(PyExc_OSError);
852 : 0 : return NULL;
853 : : }
854 : :
855 : 0 : Py_RETURN_NONE;
856 : : }
857 : : #endif // HAVE_MADVISE
858 : :
859 : : static struct PyMemberDef mmap_object_members[] = {
860 : : {"__weaklistoffset__", T_PYSSIZET, offsetof(mmap_object, weakreflist), READONLY},
861 : : {NULL},
862 : : };
863 : :
864 : : static struct PyMethodDef mmap_object_methods[] = {
865 : : {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
866 : : {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
867 : : {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
868 : : {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
869 : : #ifdef HAVE_MADVISE
870 : : {"madvise", (PyCFunction) mmap_madvise_method, METH_VARARGS},
871 : : #endif
872 : : {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
873 : : {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
874 : : {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
875 : : {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
876 : : {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
877 : : {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
878 : : {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
879 : : {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
880 : : {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
881 : : {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
882 : : {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
883 : : {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
884 : : #ifdef MS_WINDOWS
885 : : {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
886 : : #endif
887 : : {NULL, NULL} /* sentinel */
888 : : };
889 : :
890 : : static PyGetSetDef mmap_object_getset[] = {
891 : : {"closed", (getter) mmap_closed_get, NULL, NULL},
892 : : {NULL}
893 : : };
894 : :
895 : :
896 : : /* Functions for treating an mmap'ed file as a buffer */
897 : :
898 : : static int
899 : 0 : mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
900 : : {
901 [ # # ]: 0 : CHECK_VALID(-1);
902 [ # # ]: 0 : if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
903 : 0 : (self->access == ACCESS_READ), flags) < 0)
904 : 0 : return -1;
905 : 0 : self->exports++;
906 : 0 : return 0;
907 : : }
908 : :
909 : : static void
910 : 0 : mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
911 : : {
912 : 0 : self->exports--;
913 : 0 : }
914 : :
915 : : static Py_ssize_t
916 : 0 : mmap_length(mmap_object *self)
917 : : {
918 [ # # ]: 0 : CHECK_VALID(-1);
919 : 0 : return self->size;
920 : : }
921 : :
922 : : static PyObject *
923 : 0 : mmap_item(mmap_object *self, Py_ssize_t i)
924 : : {
925 [ # # ]: 0 : CHECK_VALID(NULL);
926 [ # # # # ]: 0 : if (i < 0 || i >= self->size) {
927 : 0 : PyErr_SetString(PyExc_IndexError, "mmap index out of range");
928 : 0 : return NULL;
929 : : }
930 : 0 : return PyBytes_FromStringAndSize(self->data + i, 1);
931 : : }
932 : :
933 : : static PyObject *
934 : 0 : mmap_subscript(mmap_object *self, PyObject *item)
935 : : {
936 [ # # ]: 0 : CHECK_VALID(NULL);
937 [ # # ]: 0 : if (PyIndex_Check(item)) {
938 : 0 : Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
939 [ # # # # ]: 0 : if (i == -1 && PyErr_Occurred())
940 : 0 : return NULL;
941 [ # # ]: 0 : if (i < 0)
942 : 0 : i += self->size;
943 [ # # # # ]: 0 : if (i < 0 || i >= self->size) {
944 : 0 : PyErr_SetString(PyExc_IndexError,
945 : : "mmap index out of range");
946 : 0 : return NULL;
947 : : }
948 : 0 : return PyLong_FromLong(Py_CHARMASK(self->data[i]));
949 : : }
950 [ # # ]: 0 : else if (PySlice_Check(item)) {
951 : : Py_ssize_t start, stop, step, slicelen;
952 : :
953 [ # # ]: 0 : if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
954 : 0 : return NULL;
955 : : }
956 : 0 : slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
957 : :
958 [ # # ]: 0 : if (slicelen <= 0)
959 : 0 : return PyBytes_FromStringAndSize("", 0);
960 [ # # ]: 0 : else if (step == 1)
961 : 0 : return PyBytes_FromStringAndSize(self->data + start,
962 : : slicelen);
963 : : else {
964 : 0 : char *result_buf = (char *)PyMem_Malloc(slicelen);
965 : : size_t cur;
966 : : Py_ssize_t i;
967 : : PyObject *result;
968 : :
969 [ # # ]: 0 : if (result_buf == NULL)
970 : 0 : return PyErr_NoMemory();
971 [ # # ]: 0 : for (cur = start, i = 0; i < slicelen;
972 : 0 : cur += step, i++) {
973 : 0 : result_buf[i] = self->data[cur];
974 : : }
975 : 0 : result = PyBytes_FromStringAndSize(result_buf,
976 : : slicelen);
977 : 0 : PyMem_Free(result_buf);
978 : 0 : return result;
979 : : }
980 : : }
981 : : else {
982 : 0 : PyErr_SetString(PyExc_TypeError,
983 : : "mmap indices must be integers");
984 : 0 : return NULL;
985 : : }
986 : : }
987 : :
988 : : static int
989 : 0 : mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
990 : : {
991 : : const char *buf;
992 : :
993 [ # # ]: 0 : CHECK_VALID(-1);
994 [ # # # # ]: 0 : if (i < 0 || i >= self->size) {
995 : 0 : PyErr_SetString(PyExc_IndexError, "mmap index out of range");
996 : 0 : return -1;
997 : : }
998 [ # # ]: 0 : if (v == NULL) {
999 : 0 : PyErr_SetString(PyExc_TypeError,
1000 : : "mmap object doesn't support item deletion");
1001 : 0 : return -1;
1002 : : }
1003 [ # # # # ]: 0 : if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
1004 : 0 : PyErr_SetString(PyExc_IndexError,
1005 : : "mmap assignment must be length-1 bytes()");
1006 : 0 : return -1;
1007 : : }
1008 [ # # ]: 0 : if (!is_writable(self))
1009 : 0 : return -1;
1010 : 0 : buf = PyBytes_AsString(v);
1011 : 0 : self->data[i] = buf[0];
1012 : 0 : return 0;
1013 : : }
1014 : :
1015 : : static int
1016 : 0 : mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
1017 : : {
1018 [ # # ]: 0 : CHECK_VALID(-1);
1019 : :
1020 [ # # ]: 0 : if (!is_writable(self))
1021 : 0 : return -1;
1022 : :
1023 [ # # ]: 0 : if (PyIndex_Check(item)) {
1024 : 0 : Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1025 : : Py_ssize_t v;
1026 : :
1027 [ # # # # ]: 0 : if (i == -1 && PyErr_Occurred())
1028 : 0 : return -1;
1029 [ # # ]: 0 : if (i < 0)
1030 : 0 : i += self->size;
1031 [ # # # # ]: 0 : if (i < 0 || i >= self->size) {
1032 : 0 : PyErr_SetString(PyExc_IndexError,
1033 : : "mmap index out of range");
1034 : 0 : return -1;
1035 : : }
1036 [ # # ]: 0 : if (value == NULL) {
1037 : 0 : PyErr_SetString(PyExc_TypeError,
1038 : : "mmap doesn't support item deletion");
1039 : 0 : return -1;
1040 : : }
1041 [ # # ]: 0 : if (!PyIndex_Check(value)) {
1042 : 0 : PyErr_SetString(PyExc_TypeError,
1043 : : "mmap item value must be an int");
1044 : 0 : return -1;
1045 : : }
1046 : 0 : v = PyNumber_AsSsize_t(value, PyExc_TypeError);
1047 [ # # # # ]: 0 : if (v == -1 && PyErr_Occurred())
1048 : 0 : return -1;
1049 [ # # # # ]: 0 : if (v < 0 || v > 255) {
1050 : 0 : PyErr_SetString(PyExc_ValueError,
1051 : : "mmap item value must be "
1052 : : "in range(0, 256)");
1053 : 0 : return -1;
1054 : : }
1055 : 0 : self->data[i] = (char) v;
1056 : 0 : return 0;
1057 : : }
1058 [ # # ]: 0 : else if (PySlice_Check(item)) {
1059 : : Py_ssize_t start, stop, step, slicelen;
1060 : : Py_buffer vbuf;
1061 : :
1062 [ # # ]: 0 : if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
1063 : 0 : return -1;
1064 : : }
1065 : 0 : slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
1066 [ # # ]: 0 : if (value == NULL) {
1067 : 0 : PyErr_SetString(PyExc_TypeError,
1068 : : "mmap object doesn't support slice deletion");
1069 : 0 : return -1;
1070 : : }
1071 [ # # ]: 0 : if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
1072 : 0 : return -1;
1073 [ # # ]: 0 : if (vbuf.len != slicelen) {
1074 : 0 : PyErr_SetString(PyExc_IndexError,
1075 : : "mmap slice assignment is wrong size");
1076 : 0 : PyBuffer_Release(&vbuf);
1077 : 0 : return -1;
1078 : : }
1079 : :
1080 [ # # ]: 0 : if (slicelen == 0) {
1081 : : }
1082 [ # # ]: 0 : else if (step == 1) {
1083 : 0 : memcpy(self->data + start, vbuf.buf, slicelen);
1084 : : }
1085 : : else {
1086 : : size_t cur;
1087 : : Py_ssize_t i;
1088 : :
1089 [ # # ]: 0 : for (cur = start, i = 0;
1090 : : i < slicelen;
1091 : 0 : cur += step, i++)
1092 : : {
1093 : 0 : self->data[cur] = ((char *)vbuf.buf)[i];
1094 : : }
1095 : : }
1096 : 0 : PyBuffer_Release(&vbuf);
1097 : 0 : return 0;
1098 : : }
1099 : : else {
1100 : 0 : PyErr_SetString(PyExc_TypeError,
1101 : : "mmap indices must be integer");
1102 : 0 : return -1;
1103 : : }
1104 : : }
1105 : :
1106 : : static PyObject *
1107 : : new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1108 : :
1109 : : PyDoc_STRVAR(mmap_doc,
1110 : : "Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1111 : : \n\
1112 : : Maps length bytes from the file specified by the file handle fileno,\n\
1113 : : and returns a mmap object. If length is larger than the current size\n\
1114 : : of the file, the file is extended to contain length bytes. If length\n\
1115 : : is 0, the maximum length of the map is the current size of the file,\n\
1116 : : except that if the file is empty Windows raises an exception (you cannot\n\
1117 : : create an empty mapping on Windows).\n\
1118 : : \n\
1119 : : Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1120 : : \n\
1121 : : Maps length bytes from the file specified by the file descriptor fileno,\n\
1122 : : and returns a mmap object. If length is 0, the maximum length of the map\n\
1123 : : will be the current size of the file when mmap is called.\n\
1124 : : flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1125 : : private copy-on-write mapping, so changes to the contents of the mmap\n\
1126 : : object will be private to this process, and MAP_SHARED creates a mapping\n\
1127 : : that's shared with all other processes mapping the same areas of the file.\n\
1128 : : The default value is MAP_SHARED.\n\
1129 : : \n\
1130 : : To map anonymous memory, pass -1 as the fileno (both versions).");
1131 : :
1132 : :
1133 : : static PyType_Slot mmap_object_slots[] = {
1134 : : {Py_tp_new, new_mmap_object},
1135 : : {Py_tp_dealloc, mmap_object_dealloc},
1136 : : {Py_tp_repr, mmap__repr__method},
1137 : : {Py_tp_doc, (void *)mmap_doc},
1138 : : {Py_tp_methods, mmap_object_methods},
1139 : : {Py_tp_members, mmap_object_members},
1140 : : {Py_tp_getset, mmap_object_getset},
1141 : : {Py_tp_getattro, PyObject_GenericGetAttr},
1142 : : {Py_tp_traverse, mmap_object_traverse},
1143 : :
1144 : : /* as sequence */
1145 : : {Py_sq_length, mmap_length},
1146 : : {Py_sq_item, mmap_item},
1147 : : {Py_sq_ass_item, mmap_ass_item},
1148 : :
1149 : : /* as mapping */
1150 : : {Py_mp_length, mmap_length},
1151 : : {Py_mp_subscript, mmap_subscript},
1152 : : {Py_mp_ass_subscript, mmap_ass_subscript},
1153 : :
1154 : : /* as buffer */
1155 : : {Py_bf_getbuffer, mmap_buffer_getbuf},
1156 : : {Py_bf_releasebuffer, mmap_buffer_releasebuf},
1157 : : {0, NULL},
1158 : : };
1159 : :
1160 : : static PyType_Spec mmap_object_spec = {
1161 : : .name = "mmap.mmap",
1162 : : .basicsize = sizeof(mmap_object),
1163 : : .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
1164 : : Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
1165 : : .slots = mmap_object_slots,
1166 : : };
1167 : :
1168 : :
1169 : : #ifdef UNIX
1170 : : #ifdef HAVE_LARGEFILE_SUPPORT
1171 : : #define _Py_PARSE_OFF_T "L"
1172 : : #else
1173 : : #define _Py_PARSE_OFF_T "l"
1174 : : #endif
1175 : :
1176 : : static PyObject *
1177 : 0 : new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
1178 : : {
1179 : : struct _Py_stat_struct status;
1180 : 0 : int fstat_result = -1;
1181 : : mmap_object *m_obj;
1182 : : Py_ssize_t map_size;
1183 : 0 : off_t offset = 0;
1184 : 0 : int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1185 : 0 : int devzero = -1;
1186 : 0 : int access = (int)ACCESS_DEFAULT;
1187 : : static char *keywords[] = {"fileno", "length",
1188 : : "flags", "prot",
1189 : : "access", "offset", NULL};
1190 : :
1191 [ # # ]: 0 : if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1192 : : &fd, &map_size, &flags, &prot,
1193 : : &access, &offset))
1194 : 0 : return NULL;
1195 [ # # ]: 0 : if (map_size < 0) {
1196 : 0 : PyErr_SetString(PyExc_OverflowError,
1197 : : "memory mapped length must be positive");
1198 : 0 : return NULL;
1199 : : }
1200 [ # # ]: 0 : if (offset < 0) {
1201 : 0 : PyErr_SetString(PyExc_OverflowError,
1202 : : "memory mapped offset must be positive");
1203 : 0 : return NULL;
1204 : : }
1205 : :
1206 [ # # ]: 0 : if ((access != (int)ACCESS_DEFAULT) &&
1207 [ # # # # ]: 0 : ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1208 : 0 : return PyErr_Format(PyExc_ValueError,
1209 : : "mmap can't specify both access and flags, prot.");
1210 [ # # # # : 0 : switch ((access_mode)access) {
# ]
1211 : 0 : case ACCESS_READ:
1212 : 0 : flags = MAP_SHARED;
1213 : 0 : prot = PROT_READ;
1214 : 0 : break;
1215 : 0 : case ACCESS_WRITE:
1216 : 0 : flags = MAP_SHARED;
1217 : 0 : prot = PROT_READ | PROT_WRITE;
1218 : 0 : break;
1219 : 0 : case ACCESS_COPY:
1220 : 0 : flags = MAP_PRIVATE;
1221 : 0 : prot = PROT_READ | PROT_WRITE;
1222 : 0 : break;
1223 : 0 : case ACCESS_DEFAULT:
1224 : : /* map prot to access type */
1225 [ # # # # ]: 0 : if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1226 : : /* ACCESS_DEFAULT */
1227 : : }
1228 [ # # ]: 0 : else if (prot & PROT_WRITE) {
1229 : 0 : access = ACCESS_WRITE;
1230 : : }
1231 : : else {
1232 : 0 : access = ACCESS_READ;
1233 : : }
1234 : 0 : break;
1235 : 0 : default:
1236 : 0 : return PyErr_Format(PyExc_ValueError,
1237 : : "mmap invalid access parameter.");
1238 : : }
1239 : :
1240 [ # # ]: 0 : if (PySys_Audit("mmap.__new__", "ini" _Py_PARSE_OFF_T,
1241 : : fd, map_size, access, offset) < 0) {
1242 : 0 : return NULL;
1243 : : }
1244 : :
1245 : : #ifdef __APPLE__
1246 : : /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1247 : : fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1248 : : if (fd != -1)
1249 : : (void)fcntl(fd, F_FULLFSYNC);
1250 : : #endif
1251 : :
1252 [ # # ]: 0 : if (fd != -1) {
1253 : 0 : Py_BEGIN_ALLOW_THREADS
1254 : 0 : fstat_result = _Py_fstat_noraise(fd, &status);
1255 : 0 : Py_END_ALLOW_THREADS
1256 : : }
1257 : :
1258 [ # # # # : 0 : if (fd != -1 && fstat_result == 0 && S_ISREG(status.st_mode)) {
# # ]
1259 [ # # ]: 0 : if (map_size == 0) {
1260 [ # # ]: 0 : if (status.st_size == 0) {
1261 : 0 : PyErr_SetString(PyExc_ValueError,
1262 : : "cannot mmap an empty file");
1263 : 0 : return NULL;
1264 : : }
1265 [ # # ]: 0 : if (offset >= status.st_size) {
1266 : 0 : PyErr_SetString(PyExc_ValueError,
1267 : : "mmap offset is greater than file size");
1268 : 0 : return NULL;
1269 : : }
1270 : : if (status.st_size - offset > PY_SSIZE_T_MAX) {
1271 : : PyErr_SetString(PyExc_ValueError,
1272 : : "mmap length is too large");
1273 : : return NULL;
1274 : : }
1275 : 0 : map_size = (Py_ssize_t) (status.st_size - offset);
1276 [ # # # # ]: 0 : } else if (offset > status.st_size || status.st_size - offset < map_size) {
1277 : 0 : PyErr_SetString(PyExc_ValueError,
1278 : : "mmap length is greater than file size");
1279 : 0 : return NULL;
1280 : : }
1281 : : }
1282 : 0 : m_obj = (mmap_object *)type->tp_alloc(type, 0);
1283 [ # # ]: 0 : if (m_obj == NULL) {return NULL;}
1284 : 0 : m_obj->data = NULL;
1285 : 0 : m_obj->size = map_size;
1286 : 0 : m_obj->pos = 0;
1287 : 0 : m_obj->weakreflist = NULL;
1288 : 0 : m_obj->exports = 0;
1289 : 0 : m_obj->offset = offset;
1290 [ # # ]: 0 : if (fd == -1) {
1291 : 0 : m_obj->fd = -1;
1292 : : /* Assume the caller wants to map anonymous memory.
1293 : : This is the same behaviour as Windows. mmap.mmap(-1, size)
1294 : : on both Windows and Unix map anonymous memory.
1295 : : */
1296 : : #ifdef MAP_ANONYMOUS
1297 : : /* BSD way to map anonymous memory */
1298 : 0 : flags |= MAP_ANONYMOUS;
1299 : :
1300 : : /* VxWorks only supports MAP_ANONYMOUS with MAP_PRIVATE flag */
1301 : : #ifdef __VXWORKS__
1302 : : flags &= ~MAP_SHARED;
1303 : : flags |= MAP_PRIVATE;
1304 : : #endif
1305 : :
1306 : : #else
1307 : : /* SVR4 method to map anonymous memory is to open /dev/zero */
1308 : : fd = devzero = _Py_open("/dev/zero", O_RDWR);
1309 : : if (devzero == -1) {
1310 : : Py_DECREF(m_obj);
1311 : : return NULL;
1312 : : }
1313 : : #endif
1314 : : }
1315 : : else {
1316 : 0 : m_obj->fd = _Py_dup(fd);
1317 [ # # ]: 0 : if (m_obj->fd == -1) {
1318 : 0 : Py_DECREF(m_obj);
1319 : 0 : return NULL;
1320 : : }
1321 : : }
1322 : :
1323 : 0 : Py_BEGIN_ALLOW_THREADS
1324 : 0 : m_obj->data = mmap(NULL, map_size, prot, flags, fd, offset);
1325 : 0 : Py_END_ALLOW_THREADS
1326 : :
1327 [ # # ]: 0 : if (devzero != -1) {
1328 : 0 : close(devzero);
1329 : : }
1330 : :
1331 [ # # ]: 0 : if (m_obj->data == (char *)-1) {
1332 : 0 : m_obj->data = NULL;
1333 : 0 : Py_DECREF(m_obj);
1334 : 0 : PyErr_SetFromErrno(PyExc_OSError);
1335 : 0 : return NULL;
1336 : : }
1337 : 0 : m_obj->access = (access_mode)access;
1338 : 0 : return (PyObject *)m_obj;
1339 : : }
1340 : : #endif /* UNIX */
1341 : :
1342 : : #ifdef MS_WINDOWS
1343 : :
1344 : : /* A note on sizes and offsets: while the actual map size must hold in a
1345 : : Py_ssize_t, both the total file size and the start offset can be longer
1346 : : than a Py_ssize_t, so we use long long which is always 64-bit.
1347 : : */
1348 : :
1349 : : static PyObject *
1350 : : new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
1351 : : {
1352 : : mmap_object *m_obj;
1353 : : Py_ssize_t map_size;
1354 : : long long offset = 0, size;
1355 : : DWORD off_hi; /* upper 32 bits of offset */
1356 : : DWORD off_lo; /* lower 32 bits of offset */
1357 : : DWORD size_hi; /* upper 32 bits of size */
1358 : : DWORD size_lo; /* lower 32 bits of size */
1359 : : const char *tagname = "";
1360 : : DWORD dwErr = 0;
1361 : : int fileno;
1362 : : HANDLE fh = 0;
1363 : : int access = (access_mode)ACCESS_DEFAULT;
1364 : : DWORD flProtect, dwDesiredAccess;
1365 : : static char *keywords[] = { "fileno", "length",
1366 : : "tagname",
1367 : : "access", "offset", NULL };
1368 : :
1369 : : if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1370 : : &fileno, &map_size,
1371 : : &tagname, &access, &offset)) {
1372 : : return NULL;
1373 : : }
1374 : :
1375 : : if (PySys_Audit("mmap.__new__", "iniL",
1376 : : fileno, map_size, access, offset) < 0) {
1377 : : return NULL;
1378 : : }
1379 : :
1380 : : switch((access_mode)access) {
1381 : : case ACCESS_READ:
1382 : : flProtect = PAGE_READONLY;
1383 : : dwDesiredAccess = FILE_MAP_READ;
1384 : : break;
1385 : : case ACCESS_DEFAULT: case ACCESS_WRITE:
1386 : : flProtect = PAGE_READWRITE;
1387 : : dwDesiredAccess = FILE_MAP_WRITE;
1388 : : break;
1389 : : case ACCESS_COPY:
1390 : : flProtect = PAGE_WRITECOPY;
1391 : : dwDesiredAccess = FILE_MAP_COPY;
1392 : : break;
1393 : : default:
1394 : : return PyErr_Format(PyExc_ValueError,
1395 : : "mmap invalid access parameter.");
1396 : : }
1397 : :
1398 : : if (map_size < 0) {
1399 : : PyErr_SetString(PyExc_OverflowError,
1400 : : "memory mapped length must be positive");
1401 : : return NULL;
1402 : : }
1403 : : if (offset < 0) {
1404 : : PyErr_SetString(PyExc_OverflowError,
1405 : : "memory mapped offset must be positive");
1406 : : return NULL;
1407 : : }
1408 : :
1409 : : /* assume -1 and 0 both mean invalid filedescriptor
1410 : : to 'anonymously' map memory.
1411 : : XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1412 : : XXX: Should this code be added?
1413 : : if (fileno == 0)
1414 : : PyErr_WarnEx(PyExc_DeprecationWarning,
1415 : : "don't use 0 for anonymous memory",
1416 : : 1);
1417 : : */
1418 : : if (fileno != -1 && fileno != 0) {
1419 : : /* Ensure that fileno is within the CRT's valid range */
1420 : : fh = _Py_get_osfhandle(fileno);
1421 : : if (fh == INVALID_HANDLE_VALUE)
1422 : : return NULL;
1423 : :
1424 : : /* Win9x appears to need us seeked to zero */
1425 : : lseek(fileno, 0, SEEK_SET);
1426 : : }
1427 : :
1428 : : m_obj = (mmap_object *)type->tp_alloc(type, 0);
1429 : : if (m_obj == NULL)
1430 : : return NULL;
1431 : : /* Set every field to an invalid marker, so we can safely
1432 : : destruct the object in the face of failure */
1433 : : m_obj->data = NULL;
1434 : : m_obj->file_handle = INVALID_HANDLE_VALUE;
1435 : : m_obj->map_handle = NULL;
1436 : : m_obj->tagname = NULL;
1437 : : m_obj->offset = offset;
1438 : :
1439 : : if (fh) {
1440 : : /* It is necessary to duplicate the handle, so the
1441 : : Python code can close it on us */
1442 : : if (!DuplicateHandle(
1443 : : GetCurrentProcess(), /* source process handle */
1444 : : fh, /* handle to be duplicated */
1445 : : GetCurrentProcess(), /* target proc handle */
1446 : : (LPHANDLE)&m_obj->file_handle, /* result */
1447 : : 0, /* access - ignored due to options value */
1448 : : FALSE, /* inherited by child processes? */
1449 : : DUPLICATE_SAME_ACCESS)) { /* options */
1450 : : dwErr = GetLastError();
1451 : : Py_DECREF(m_obj);
1452 : : PyErr_SetFromWindowsErr(dwErr);
1453 : : return NULL;
1454 : : }
1455 : : if (!map_size) {
1456 : : DWORD low,high;
1457 : : low = GetFileSize(fh, &high);
1458 : : /* low might just happen to have the value INVALID_FILE_SIZE;
1459 : : so we need to check the last error also. */
1460 : : if (low == INVALID_FILE_SIZE &&
1461 : : (dwErr = GetLastError()) != NO_ERROR) {
1462 : : Py_DECREF(m_obj);
1463 : : return PyErr_SetFromWindowsErr(dwErr);
1464 : : }
1465 : :
1466 : : size = (((long long) high) << 32) + low;
1467 : : if (size == 0) {
1468 : : PyErr_SetString(PyExc_ValueError,
1469 : : "cannot mmap an empty file");
1470 : : Py_DECREF(m_obj);
1471 : : return NULL;
1472 : : }
1473 : : if (offset >= size) {
1474 : : PyErr_SetString(PyExc_ValueError,
1475 : : "mmap offset is greater than file size");
1476 : : Py_DECREF(m_obj);
1477 : : return NULL;
1478 : : }
1479 : : if (size - offset > PY_SSIZE_T_MAX) {
1480 : : PyErr_SetString(PyExc_ValueError,
1481 : : "mmap length is too large");
1482 : : Py_DECREF(m_obj);
1483 : : return NULL;
1484 : : }
1485 : : m_obj->size = (Py_ssize_t) (size - offset);
1486 : : } else {
1487 : : m_obj->size = map_size;
1488 : : size = offset + map_size;
1489 : : }
1490 : : }
1491 : : else {
1492 : : m_obj->size = map_size;
1493 : : size = offset + map_size;
1494 : : }
1495 : :
1496 : : /* set the initial position */
1497 : : m_obj->pos = (size_t) 0;
1498 : :
1499 : : m_obj->weakreflist = NULL;
1500 : : m_obj->exports = 0;
1501 : : /* set the tag name */
1502 : : if (tagname != NULL && *tagname != '\0') {
1503 : : m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1504 : : if (m_obj->tagname == NULL) {
1505 : : PyErr_NoMemory();
1506 : : Py_DECREF(m_obj);
1507 : : return NULL;
1508 : : }
1509 : : strcpy(m_obj->tagname, tagname);
1510 : : }
1511 : : else
1512 : : m_obj->tagname = NULL;
1513 : :
1514 : : m_obj->access = (access_mode)access;
1515 : : size_hi = (DWORD)(size >> 32);
1516 : : size_lo = (DWORD)(size & 0xFFFFFFFF);
1517 : : off_hi = (DWORD)(offset >> 32);
1518 : : off_lo = (DWORD)(offset & 0xFFFFFFFF);
1519 : : /* For files, it would be sufficient to pass 0 as size.
1520 : : For anonymous maps, we have to pass the size explicitly. */
1521 : : m_obj->map_handle = CreateFileMappingA(m_obj->file_handle,
1522 : : NULL,
1523 : : flProtect,
1524 : : size_hi,
1525 : : size_lo,
1526 : : m_obj->tagname);
1527 : : if (m_obj->map_handle != NULL) {
1528 : : m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1529 : : dwDesiredAccess,
1530 : : off_hi,
1531 : : off_lo,
1532 : : m_obj->size);
1533 : : if (m_obj->data != NULL)
1534 : : return (PyObject *)m_obj;
1535 : : else {
1536 : : dwErr = GetLastError();
1537 : : CloseHandle(m_obj->map_handle);
1538 : : m_obj->map_handle = NULL;
1539 : : }
1540 : : } else
1541 : : dwErr = GetLastError();
1542 : : Py_DECREF(m_obj);
1543 : : PyErr_SetFromWindowsErr(dwErr);
1544 : : return NULL;
1545 : : }
1546 : : #endif /* MS_WINDOWS */
1547 : :
1548 : : static int
1549 : 1 : mmap_exec(PyObject *module)
1550 : : {
1551 : 1 : Py_INCREF(PyExc_OSError);
1552 [ - + ]: 1 : if (PyModule_AddObject(module, "error", PyExc_OSError) < 0) {
1553 : 0 : Py_DECREF(PyExc_OSError);
1554 : 0 : return -1;
1555 : : }
1556 : :
1557 : 1 : PyObject *mmap_object_type = PyType_FromModuleAndSpec(module,
1558 : : &mmap_object_spec, NULL);
1559 [ - + ]: 1 : if (mmap_object_type == NULL) {
1560 : 0 : return -1;
1561 : : }
1562 : 1 : int rc = PyModule_AddType(module, (PyTypeObject *)mmap_object_type);
1563 : 1 : Py_DECREF(mmap_object_type);
1564 [ - + ]: 1 : if (rc < 0) {
1565 : 0 : return -1;
1566 : : }
1567 : :
1568 : : #define ADD_INT_MACRO(module, constant) \
1569 : : do { \
1570 : : if (PyModule_AddIntConstant(module, #constant, constant) < 0) { \
1571 : : return -1; \
1572 : : } \
1573 : : } while (0)
1574 : :
1575 : : #ifdef PROT_EXEC
1576 [ - + ]: 1 : ADD_INT_MACRO(module, PROT_EXEC);
1577 : : #endif
1578 : : #ifdef PROT_READ
1579 [ - + ]: 1 : ADD_INT_MACRO(module, PROT_READ);
1580 : : #endif
1581 : : #ifdef PROT_WRITE
1582 [ - + ]: 1 : ADD_INT_MACRO(module, PROT_WRITE);
1583 : : #endif
1584 : :
1585 : : #ifdef MAP_SHARED
1586 [ - + ]: 1 : ADD_INT_MACRO(module, MAP_SHARED);
1587 : : #endif
1588 : : #ifdef MAP_PRIVATE
1589 [ - + ]: 1 : ADD_INT_MACRO(module, MAP_PRIVATE);
1590 : : #endif
1591 : : #ifdef MAP_DENYWRITE
1592 [ - + ]: 1 : ADD_INT_MACRO(module, MAP_DENYWRITE);
1593 : : #endif
1594 : : #ifdef MAP_EXECUTABLE
1595 [ - + ]: 1 : ADD_INT_MACRO(module, MAP_EXECUTABLE);
1596 : : #endif
1597 : : #ifdef MAP_ANONYMOUS
1598 [ - + ]: 1 : if (PyModule_AddIntConstant(module, "MAP_ANON", MAP_ANONYMOUS) < 0 ) {
1599 : 0 : return -1;
1600 : : }
1601 [ - + ]: 1 : ADD_INT_MACRO(module, MAP_ANONYMOUS);
1602 : : #endif
1603 : : #ifdef MAP_POPULATE
1604 [ - + ]: 1 : ADD_INT_MACRO(module, MAP_POPULATE);
1605 : : #endif
1606 : : #ifdef MAP_STACK
1607 : : // Mostly a no-op on Linux and NetBSD, but useful on OpenBSD
1608 : : // for stack usage (even on x86 arch)
1609 [ - + ]: 1 : ADD_INT_MACRO(module, MAP_STACK);
1610 : : #endif
1611 : : #ifdef MAP_ALIGNED_SUPER
1612 : : ADD_INT_MACRO(module, MAP_ALIGNED_SUPER);
1613 : : #endif
1614 : : #ifdef MAP_CONCEAL
1615 : : ADD_INT_MACRO(module, MAP_CONCEAL);
1616 : : #endif
1617 [ - + ]: 1 : if (PyModule_AddIntConstant(module, "PAGESIZE", (long)my_getpagesize()) < 0 ) {
1618 : 0 : return -1;
1619 : : }
1620 : :
1621 [ - + ]: 1 : if (PyModule_AddIntConstant(module, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity()) < 0 ) {
1622 : 0 : return -1;
1623 : : }
1624 : :
1625 [ - + ]: 1 : ADD_INT_MACRO(module, ACCESS_DEFAULT);
1626 [ - + ]: 1 : ADD_INT_MACRO(module, ACCESS_READ);
1627 [ - + ]: 1 : ADD_INT_MACRO(module, ACCESS_WRITE);
1628 [ - + ]: 1 : ADD_INT_MACRO(module, ACCESS_COPY);
1629 : :
1630 : : #ifdef HAVE_MADVISE
1631 : : // Conventional advice values
1632 : : #ifdef MADV_NORMAL
1633 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_NORMAL);
1634 : : #endif
1635 : : #ifdef MADV_RANDOM
1636 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_RANDOM);
1637 : : #endif
1638 : : #ifdef MADV_SEQUENTIAL
1639 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_SEQUENTIAL);
1640 : : #endif
1641 : : #ifdef MADV_WILLNEED
1642 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_WILLNEED);
1643 : : #endif
1644 : : #ifdef MADV_DONTNEED
1645 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_DONTNEED);
1646 : : #endif
1647 : :
1648 : : // Linux-specific advice values
1649 : : #ifdef MADV_REMOVE
1650 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_REMOVE);
1651 : : #endif
1652 : : #ifdef MADV_DONTFORK
1653 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_DONTFORK);
1654 : : #endif
1655 : : #ifdef MADV_DOFORK
1656 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_DOFORK);
1657 : : #endif
1658 : : #ifdef MADV_HWPOISON
1659 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_HWPOISON);
1660 : : #endif
1661 : : #ifdef MADV_MERGEABLE
1662 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_MERGEABLE);
1663 : : #endif
1664 : : #ifdef MADV_UNMERGEABLE
1665 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_UNMERGEABLE);
1666 : : #endif
1667 : : #ifdef MADV_SOFT_OFFLINE
1668 : : ADD_INT_MACRO(module, MADV_SOFT_OFFLINE);
1669 : : #endif
1670 : : #ifdef MADV_HUGEPAGE
1671 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_HUGEPAGE);
1672 : : #endif
1673 : : #ifdef MADV_NOHUGEPAGE
1674 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_NOHUGEPAGE);
1675 : : #endif
1676 : : #ifdef MADV_DONTDUMP
1677 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_DONTDUMP);
1678 : : #endif
1679 : : #ifdef MADV_DODUMP
1680 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_DODUMP);
1681 : : #endif
1682 : : #ifdef MADV_FREE // (Also present on FreeBSD and macOS.)
1683 [ - + ]: 1 : ADD_INT_MACRO(module, MADV_FREE);
1684 : : #endif
1685 : :
1686 : : // FreeBSD-specific
1687 : : #ifdef MADV_NOSYNC
1688 : : ADD_INT_MACRO(module, MADV_NOSYNC);
1689 : : #endif
1690 : : #ifdef MADV_AUTOSYNC
1691 : : ADD_INT_MACRO(module, MADV_AUTOSYNC);
1692 : : #endif
1693 : : #ifdef MADV_NOCORE
1694 : : ADD_INT_MACRO(module, MADV_NOCORE);
1695 : : #endif
1696 : : #ifdef MADV_CORE
1697 : : ADD_INT_MACRO(module, MADV_CORE);
1698 : : #endif
1699 : : #ifdef MADV_PROTECT
1700 : : ADD_INT_MACRO(module, MADV_PROTECT);
1701 : : #endif
1702 : :
1703 : : // Darwin-specific
1704 : : #ifdef MADV_FREE_REUSABLE // (As MADV_FREE but reclaims more faithful for task_info/Activity Monitor...)
1705 : : ADD_INT_MACRO(module, MADV_FREE_REUSABLE);
1706 : : #endif
1707 : : #ifdef MADV_FREE_REUSE // (Reuse pages previously tagged as reusable)
1708 : : ADD_INT_MACRO(module, MADV_FREE_REUSE);
1709 : : #endif
1710 : : #endif // HAVE_MADVISE
1711 : 1 : return 0;
1712 : : }
1713 : :
1714 : : static PyModuleDef_Slot mmap_slots[] = {
1715 : : {Py_mod_exec, mmap_exec},
1716 : : {0, NULL}
1717 : : };
1718 : :
1719 : : static struct PyModuleDef mmapmodule = {
1720 : : .m_base = PyModuleDef_HEAD_INIT,
1721 : : .m_name = "mmap",
1722 : : .m_size = 0,
1723 : : .m_slots = mmap_slots,
1724 : : };
1725 : :
1726 : : PyMODINIT_FUNC
1727 : 1 : PyInit_mmap(void)
1728 : : {
1729 : 1 : return PyModuleDef_Init(&mmapmodule);
1730 : : }
1731 : :
1732 : : #endif /* !MS_WINDOWS || MS_WINDOWS_DESKTOP || MS_WINDOWS_GAMES */
|