blob: 8327ba677ecce7839c45040fddf2a2461b37bfba [file] [log] [blame]
Guido van Rossum09fdf072000-03-31 01:17:07 +00001/*
2 / Author: Sam Rushing <rushing@nightmare.com>
Andrew M. Kuchling10f9c072001-11-05 21:25:42 +00003 / Hacked for Unix by AMK
Guido van Rossum09fdf072000-03-31 01:17:07 +00004 / $Id$
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00005
Guido van Rossum8ce8a782007-11-01 19:42:39 +00006 / Modified to support mmap with offset - to map a 'window' of a file
7 / Author: Yotam Medini yotamm@mellanox.co.il
8 /
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00009 / 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 /
Mark Hammond071864a2000-07-30 02:46:26 +000015 / 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
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000018 / ftp://squirl.nightmare.com/pub/python/python-ext.
19*/
20
Martin v. Löwiscfe7e092006-02-17 06:59:14 +000021#define PY_SSIZE_T_CLEAN
Guido van Rossum09fdf072000-03-31 01:17:07 +000022#include <Python.h>
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +010023#include "structmember.h" // PyMemberDef
Victor Stinner4a21e572020-04-15 02:35:41 +020024#include <stddef.h> // offsetof()
Guido van Rossum09fdf072000-03-31 01:17:07 +000025
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000026#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000027#define UNIX
Benjamin Petersonf6b5cad2015-08-02 12:15:30 -070028# ifdef HAVE_FCNTL_H
Victor Stinnera6cd0cf2011-05-02 01:05:37 +020029# include <fcntl.h>
Benjamin Petersonf6b5cad2015-08-02 12:15:30 -070030# endif /* HAVE_FCNTL_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000031#endif
32
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000033#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000034#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000035static int
36my_getpagesize(void)
37{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000038 SYSTEM_INFO si;
39 GetSystemInfo(&si);
40 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000041}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000042
43static int
44my_getallocationgranularity (void)
45{
46
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000047 SYSTEM_INFO si;
48 GetSystemInfo(&si);
49 return si.dwAllocationGranularity;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000050}
51
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000052#endif
53
54#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000055#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000056#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000057
Fred Drake145f96e2000-10-01 17:50:46 +000058#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
59static int
60my_getpagesize(void)
61{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000062 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000063}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000064
65#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000066#else
67#define my_getpagesize getpagesize
68#endif
69
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000070#endif /* UNIX */
71
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000073
74#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000075#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000076#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000077
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000078/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000079#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
80# define MAP_ANONYMOUS MAP_ANON
81#endif
82
Tim Peters5ebfd362001-11-13 23:11:19 +000083typedef enum
84{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000085 ACCESS_DEFAULT,
86 ACCESS_READ,
87 ACCESS_WRITE,
88 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000089} access_mode;
90
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000091typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000092 PyObject_HEAD
93 char * data;
Benjamin Petersoncd04db02016-10-05 21:45:48 -070094 Py_ssize_t size;
95 Py_ssize_t pos; /* relative to offset */
Antoine Pitrou97696cb2011-02-21 23:46:27 +000096#ifdef MS_WINDOWS
Benjamin Petersonaf580df2016-09-06 10:46:49 -070097 long long offset;
Antoine Pitrou97696cb2011-02-21 23:46:27 +000098#else
99 off_t offset;
100#endif
Hai Shi06cd5b62019-10-21 14:31:46 +0800101 Py_ssize_t exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000102
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000103#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 HANDLE map_handle;
105 HANDLE file_handle;
106 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107#endif
108
109#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000112
Antoine Pitrouc53204b2013-08-05 23:17:30 +0200113 PyObject *weakreflist;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000114 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000115} mmap_object;
116
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +0100117typedef struct {
118 PyTypeObject *mmap_object_type;
119} mmap_state;
120
121static mmap_state *
122get_mmap_state(PyObject *module)
123{
124 mmap_state *state = PyModule_GetState(module);
125 assert(state);
126 return state;
127}
Tim Peters5ebfd362001-11-13 23:11:19 +0000128
Miss Islington (bot)da8097a2021-05-27 09:43:56 -0700129static int
130mmap_object_traverse(mmap_object *m_obj, visitproc visit, void *arg)
131{
132 Py_VISIT(Py_TYPE(m_obj));
133 return 0;
134}
135
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000136static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000137mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138{
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +0100139 PyTypeObject *tp = Py_TYPE(m_obj);
Miss Islington (bot)da8097a2021-05-27 09:43:56 -0700140 PyObject_GC_UnTrack(m_obj);
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +0100141
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000142#ifdef MS_WINDOWS
Davide Rizzodc078942019-03-06 18:08:31 +0100143 Py_BEGIN_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000144 if (m_obj->data != NULL)
145 UnmapViewOfFile (m_obj->data);
146 if (m_obj->map_handle != NULL)
147 CloseHandle (m_obj->map_handle);
148 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
149 CloseHandle (m_obj->file_handle);
Davide Rizzodc078942019-03-06 18:08:31 +0100150 Py_END_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 if (m_obj->tagname)
152 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000153#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000154
155#ifdef UNIX
Davide Rizzodc078942019-03-06 18:08:31 +0100156 Py_BEGIN_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000157 if (m_obj->fd >= 0)
158 (void) close(m_obj->fd);
159 if (m_obj->data!=NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000160 munmap(m_obj->data, m_obj->size);
161 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100162 Py_END_ALLOW_THREADS
Davide Rizzodc078942019-03-06 18:08:31 +0100163#endif /* UNIX */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000164
Antoine Pitrouc53204b2013-08-05 23:17:30 +0200165 if (m_obj->weakreflist != NULL)
166 PyObject_ClearWeakRefs((PyObject *) m_obj);
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +0100167
168 tp->tp_free(m_obj);
169 Py_DECREF(tp);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000170}
171
172static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000173mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000174{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 if (self->exports > 0) {
176 PyErr_SetString(PyExc_BufferError, "cannot close "\
177 "exported pointers exist");
178 return NULL;
179 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000180#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000181 /* For each resource we maintain, we need to check
182 the value is valid, and if so, free the resource
183 and set the member value to an invalid value so
184 the dealloc does not attempt to resource clearing
185 again.
186 TODO - should we check for errors in the close operations???
187 */
Davide Rizzobb9593a2019-03-06 16:52:34 +0100188 HANDLE map_handle = self->map_handle;
189 HANDLE file_handle = self->file_handle;
190 char *data = self->data;
191 self->map_handle = NULL;
192 self->file_handle = INVALID_HANDLE_VALUE;
193 self->data = NULL;
194 Py_BEGIN_ALLOW_THREADS
195 if (data != NULL) {
196 UnmapViewOfFile(data);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000197 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100198 if (map_handle != NULL) {
199 CloseHandle(map_handle);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000200 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100201 if (file_handle != INVALID_HANDLE_VALUE) {
202 CloseHandle(file_handle);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100204 Py_END_ALLOW_THREADS
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000205#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000206
207#ifdef UNIX
Davide Rizzobb9593a2019-03-06 16:52:34 +0100208 int fd = self->fd;
209 char *data = self->data;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 self->fd = -1;
Davide Rizzobb9593a2019-03-06 16:52:34 +0100211 self->data = NULL;
212 Py_BEGIN_ALLOW_THREADS
213 if (0 <= fd)
214 (void) close(fd);
215 if (data != NULL) {
216 munmap(data, self->size);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100218 Py_END_ALLOW_THREADS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000219#endif
220
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200221 Py_RETURN_NONE;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000222}
223
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000224#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225#define CHECK_VALID(err) \
226do { \
227 if (self->map_handle == NULL) { \
228 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
229 return err; \
230 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000231} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000232#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000233
234#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000235#define CHECK_VALID(err) \
236do { \
237 if (self->data == NULL) { \
238 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
239 return err; \
240 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241} while (0)
242#endif /* UNIX */
243
244static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000245mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000246 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000247{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000248 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700249 if (self->pos >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000250 PyErr_SetString(PyExc_ValueError, "read byte out of range");
251 return NULL;
252 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700253 return PyLong_FromLong((unsigned char)self->data[self->pos++]);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000254}
255
256static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000257mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000258 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000259{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700260 Py_ssize_t remaining;
261 char *start, *eol;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000263
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000264 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000265
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700266 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
267 if (!remaining)
268 return PyBytes_FromString("");
269 start = self->data + self->pos;
270 eol = memchr(start, '\n', remaining);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000271 if (!eol)
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700272 eol = self->data + self->size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000273 else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700274 ++eol; /* advance past newline */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 result = PyBytes_FromStringAndSize(start, (eol - start));
276 self->pos += (eol - start);
277 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000278}
279
280static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000281mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000283{
Benjamin Peterson8f1cdc62016-10-05 23:32:09 -0700284 Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000285 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000286
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000287 CHECK_VALID(NULL);
Serhiy Storchaka762bf402017-03-30 09:15:31 +0300288 if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000289 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 /* silently 'adjust' out-of-range requests */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700292 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
293 if (num_bytes < 0 || num_bytes > remaining)
294 num_bytes = remaining;
295 result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000296 self->pos += num_bytes;
297 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000298}
299
300static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000301mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 PyObject *args,
303 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000304{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000305 Py_ssize_t start = self->pos;
306 Py_ssize_t end = self->size;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200307 Py_buffer view;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000308
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200310 if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find",
311 &view, &start, &end)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 return NULL;
313 } else {
314 const char *p, *start_p, *end_p;
315 int sign = reverse ? -1 : 1;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200316 const char *needle = view.buf;
317 Py_ssize_t len = view.len;
Greg Stein834f4dd2001-05-14 09:32:26 +0000318
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 if (start < 0)
320 start += self->size;
321 if (start < 0)
322 start = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700323 else if (start > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000324 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000325
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000326 if (end < 0)
327 end += self->size;
328 if (end < 0)
329 end = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700330 else if (end > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000332
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 start_p = self->data + start;
334 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000335
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000336 for (p = (reverse ? end_p - len : start_p);
337 (p >= start_p) && (p + len <= end_p); p += sign) {
338 Py_ssize_t i;
339 for (i = 0; i < len && needle[i] == p[i]; ++i)
340 /* nothing */;
341 if (i == len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200342 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000343 return PyLong_FromSsize_t(p - self->data);
344 }
345 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200346 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000347 return PyLong_FromLong(-1);
348 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000349}
350
Georg Brandlfceab5a2008-01-19 20:08:23 +0000351static PyObject *
352mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000353 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000354{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000355 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000356}
357
358static PyObject *
359mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000360 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000361{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000362 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000363}
364
Tim Petersec0a5f02006-02-16 23:47:20 +0000365static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000366is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000367{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000368 if (self->access != ACCESS_READ)
369 return 1;
370 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
371 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000372}
373
Tim Petersec0a5f02006-02-16 23:47:20 +0000374static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000375is_resizeable(mmap_object *self)
376{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000377 if (self->exports > 0) {
378 PyErr_SetString(PyExc_BufferError,
379 "mmap can't resize with extant buffers exported.");
380 return 0;
381 }
382 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
383 return 1;
384 PyErr_Format(PyExc_TypeError,
385 "mmap can't resize a readonly or copy-on-write memory map.");
386 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000387}
388
389
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000390static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000391mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000392 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000393{
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200394 Py_buffer data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000395
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000396 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200397 if (!PyArg_ParseTuple(args, "y*:write", &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000398 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000399
Benjamin Peterson37768362016-10-05 23:29:07 -0700400 if (!is_writable(self)) {
401 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700402 return NULL;
Benjamin Peterson37768362016-10-05 23:29:07 -0700403 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700404
405 if (self->pos > self->size || self->size - self->pos < data.len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200406 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700407 PyErr_SetString(PyExc_ValueError, "data out of range");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 return NULL;
409 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200410
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700411 memcpy(&self->data[self->pos], data.buf, data.len);
412 self->pos += data.len;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200413 PyBuffer_Release(&data);
Benjamin Peterson87845bc2016-10-05 22:54:19 -0700414 return PyLong_FromSsize_t(data.len);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000415}
416
417static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000418mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000420{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000421 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000422
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000423 CHECK_VALID(NULL);
424 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
425 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000426
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000427 if (!is_writable(self))
428 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000429
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000430 if (self->pos < self->size) {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700431 self->data[self->pos++] = value;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200432 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000433 }
434 else {
435 PyErr_SetString(PyExc_ValueError, "write byte out of range");
436 return NULL;
437 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000438}
Tim Petersec0a5f02006-02-16 23:47:20 +0000439
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000440static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000441mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000442 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000443{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000444 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000445
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000446#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000447 if (self->file_handle != INVALID_HANDLE_VALUE) {
448 DWORD low,high;
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700449 long long size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000450 low = GetFileSize(self->file_handle, &high);
451 if (low == INVALID_FILE_SIZE) {
452 /* It might be that the function appears to have failed,
453 when indeed its size equals INVALID_FILE_SIZE */
454 DWORD error = GetLastError();
455 if (error != NO_ERROR)
456 return PyErr_SetFromWindowsErr(error);
457 }
458 if (!high && low < LONG_MAX)
459 return PyLong_FromLong((long)low);
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700460 size = (((long long)high)<<32) + low;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000461 return PyLong_FromLongLong(size);
462 } else {
463 return PyLong_FromSsize_t(self->size);
464 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000465#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000466
467#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 {
Victor Stinnere134a7f2015-03-30 10:09:31 +0200469 struct _Py_stat_struct status;
470 if (_Py_fstat(self->fd, &status) == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000471 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000472#ifdef HAVE_LARGEFILE_SUPPORT
Victor Stinnere134a7f2015-03-30 10:09:31 +0200473 return PyLong_FromLongLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000474#else
Victor Stinnere134a7f2015-03-30 10:09:31 +0200475 return PyLong_FromLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000476#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000477 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000478#endif /* UNIX */
479}
480
481/* This assumes that you want the entire file mapped,
482 / and when recreating the map will make the new file
483 / have the new size
484 /
485 / Is this really necessary? This could easily be done
486 / from python by just closing and re-opening with the
487 / new size?
488 */
489
490static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000491mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000492 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000493{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000494 Py_ssize_t new_size;
495 CHECK_VALID(NULL);
496 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
497 !is_resizeable(self)) {
498 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700499 }
500 if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) {
501 PyErr_SetString(PyExc_ValueError, "new size out of range");
502 return NULL;
503 }
504
505 {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000506#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000507 DWORD dwErrCode = 0;
508 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
509 /* First, unmap the file view */
510 UnmapViewOfFile(self->data);
511 self->data = NULL;
512 /* Close the mapping object */
513 CloseHandle(self->map_handle);
514 self->map_handle = NULL;
515 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000516 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
517 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
518 off_hi = (DWORD)(self->offset >> 32);
519 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000520 SetFilePointer(self->file_handle,
521 newSizeLow, &newSizeHigh, FILE_BEGIN);
522 /* Change the size of the file */
523 SetEndOfFile(self->file_handle);
524 /* Create another mapping object and remap the file view */
525 self->map_handle = CreateFileMapping(
526 self->file_handle,
527 NULL,
528 PAGE_READWRITE,
529 0,
530 0,
531 self->tagname);
532 if (self->map_handle != NULL) {
533 self->data = (char *) MapViewOfFile(self->map_handle,
534 FILE_MAP_WRITE,
535 off_hi,
536 off_lo,
537 new_size);
538 if (self->data != NULL) {
539 self->size = new_size;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200540 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000541 } else {
542 dwErrCode = GetLastError();
543 CloseHandle(self->map_handle);
544 self->map_handle = NULL;
545 }
546 } else {
547 dwErrCode = GetLastError();
548 }
549 PyErr_SetFromWindowsErr(dwErrCode);
550 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000551#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552
553#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000554#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000555 PyErr_SetString(PyExc_SystemError,
556 "mmap: resizing not available--no mremap()");
557 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000558#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000559 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000560
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700561 if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200562 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000563 return NULL;
564 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000565
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000566#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000568#else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700569#if defined(__NetBSD__)
570 newmap = mremap(self->data, self->size, self->data, new_size, 0);
571#else
572 newmap = mremap(self->data, self->size, new_size, 0);
573#endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000574#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 if (newmap == (void *)-1)
576 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200577 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000578 return NULL;
579 }
580 self->data = newmap;
581 self->size = new_size;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200582 Py_RETURN_NONE;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000583#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000584#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000585 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000586}
587
588static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000589mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000590{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000591 CHECK_VALID(NULL);
592 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000593}
594
595static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000596mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000597{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000598 Py_ssize_t offset = 0;
599 Py_ssize_t size = self->size;
600 CHECK_VALID(NULL);
601 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
602 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700603 if (size < 0 || offset < 0 || self->size - offset < size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000604 PyErr_SetString(PyExc_ValueError, "flush values out of range");
605 return NULL;
606 }
R. David Murraye194dd62010-10-18 01:14:06 +0000607
608 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
Berker Peksage7d4b2f2018-08-22 21:21:05 +0300609 Py_RETURN_NONE;
R. David Murraye194dd62010-10-18 01:14:06 +0000610
Christian Heimesaf98da12008-01-27 15:18:18 +0000611#ifdef MS_WINDOWS
Berker Peksage7d4b2f2018-08-22 21:21:05 +0300612 if (!FlushViewOfFile(self->data+offset, size)) {
613 PyErr_SetFromWindowsErr(GetLastError());
614 return NULL;
615 }
616 Py_RETURN_NONE;
Christian Heimesaf98da12008-01-27 15:18:18 +0000617#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000618 /* XXX flags for msync? */
619 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200620 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000621 return NULL;
622 }
Berker Peksage7d4b2f2018-08-22 21:21:05 +0300623 Py_RETURN_NONE;
Christian Heimesaf98da12008-01-27 15:18:18 +0000624#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000625 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
626 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000627#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628}
629
630static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000631mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000632{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000633 Py_ssize_t dist;
634 int how=0;
635 CHECK_VALID(NULL);
636 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
637 return NULL;
638 else {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700639 Py_ssize_t where;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000640 switch (how) {
641 case 0: /* relative to start */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000642 where = dist;
643 break;
644 case 1: /* relative to current position */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700645 if (PY_SSIZE_T_MAX - self->pos < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000646 goto onoutofrange;
647 where = self->pos + dist;
648 break;
649 case 2: /* relative to end */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700650 if (PY_SSIZE_T_MAX - self->size < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000651 goto onoutofrange;
652 where = self->size + dist;
653 break;
654 default:
655 PyErr_SetString(PyExc_ValueError, "unknown seek type");
656 return NULL;
657 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700658 if (where > self->size || where < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000659 goto onoutofrange;
660 self->pos = where;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200661 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000662 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000663
Tim Peters5ebfd362001-11-13 23:11:19 +0000664 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000665 PyErr_SetString(PyExc_ValueError, "seek out of range");
666 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000667}
668
669static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000670mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000671{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700672 Py_ssize_t dest, src, cnt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000673 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700674 if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000675 !is_writable(self)) {
676 return NULL;
677 } else {
678 /* bounds check the values */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700679 if (dest < 0 || src < 0 || cnt < 0)
680 goto bounds;
681 if (self->size - dest < cnt || self->size - src < cnt)
682 goto bounds;
683
684 memmove(&self->data[dest], &self->data[src], cnt);
685
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200686 Py_RETURN_NONE;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700687
688 bounds:
689 PyErr_SetString(PyExc_ValueError,
690 "source, destination, or count out of range");
691 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000692 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000693}
694
Georg Brandl0bccc182010-08-01 14:50:00 +0000695static PyObject *
Serhiy Storchakad4f9cf52018-11-27 19:34:35 +0200696mmap_closed_get(mmap_object *self, void *Py_UNUSED(ignored))
Georg Brandl0bccc182010-08-01 14:50:00 +0000697{
698#ifdef MS_WINDOWS
699 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
700#elif defined(UNIX)
701 return PyBool_FromLong(self->data == NULL ? 1 : 0);
702#endif
703}
704
705static PyObject *
706mmap__enter__method(mmap_object *self, PyObject *args)
707{
708 CHECK_VALID(NULL);
709
710 Py_INCREF(self);
711 return (PyObject *)self;
712}
713
714static PyObject *
715mmap__exit__method(PyObject *self, PyObject *args)
716{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200717 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200718
Jeroen Demeyer762f93f2019-07-08 10:19:25 +0200719 return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
Georg Brandl0bccc182010-08-01 14:50:00 +0000720}
721
Taine Zhaod8ca2352019-10-17 18:41:35 +0800722static PyObject *
723mmap__repr__method(PyObject *self)
724{
725 mmap_object *mobj = (mmap_object *)self;
726
727#ifdef MS_WINDOWS
728#define _Py_FORMAT_OFFSET "lld"
729 if (mobj->map_handle == NULL)
730#elif defined(UNIX)
731# ifdef HAVE_LARGEFILE_SUPPORT
732# define _Py_FORMAT_OFFSET "lld"
733# else
734# define _Py_FORMAT_OFFSET "ld"
735# endif
736 if (mobj->data == NULL)
737#endif
738 {
739 return PyUnicode_FromFormat("<%s closed=True>", Py_TYPE(self)->tp_name);
740 } else {
741 const char *access_str;
742
743 switch (mobj->access) {
744 case ACCESS_DEFAULT:
745 access_str = "ACCESS_DEFAULT";
746 break;
747 case ACCESS_READ:
748 access_str = "ACCESS_READ";
749 break;
750 case ACCESS_WRITE:
751 access_str = "ACCESS_WRITE";
752 break;
753 case ACCESS_COPY:
754 access_str = "ACCESS_COPY";
755 break;
756 default:
757 Py_UNREACHABLE();
758 }
759
760 return PyUnicode_FromFormat("<%s closed=False, access=%s, length=%zd, "
761 "pos=%zd, offset=%" _Py_FORMAT_OFFSET ">",
762 Py_TYPE(self)->tp_name, access_str,
763 mobj->size, mobj->pos, mobj->offset);
764 }
765}
766
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300767#ifdef MS_WINDOWS
768static PyObject *
769mmap__sizeof__method(mmap_object *self, void *unused)
770{
771 Py_ssize_t res;
772
Serhiy Storchaka5c4064e2015-12-19 20:05:25 +0200773 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300774 if (self->tagname)
775 res += strlen(self->tagname) + 1;
776 return PyLong_FromSsize_t(res);
777}
778#endif
779
Zackery Spytz02db6962019-05-27 10:48:17 -0600780#ifdef HAVE_MADVISE
781static PyObject *
782mmap_madvise_method(mmap_object *self, PyObject *args)
783{
784 int option;
785 Py_ssize_t start = 0, length;
786
787 CHECK_VALID(NULL);
788 length = self->size;
789
790 if (!PyArg_ParseTuple(args, "i|nn:madvise", &option, &start, &length)) {
791 return NULL;
792 }
793
794 if (start < 0 || start >= self->size) {
795 PyErr_SetString(PyExc_ValueError, "madvise start out of bounds");
796 return NULL;
797 }
798 if (length < 0) {
799 PyErr_SetString(PyExc_ValueError, "madvise length invalid");
800 return NULL;
801 }
802 if (PY_SSIZE_T_MAX - start < length) {
803 PyErr_SetString(PyExc_OverflowError, "madvise length too large");
804 return NULL;
805 }
806
807 if (start + length > self->size) {
808 length = self->size - start;
809 }
810
811 if (madvise(self->data + start, length, option) != 0) {
812 PyErr_SetFromErrno(PyExc_OSError);
813 return NULL;
814 }
815
816 Py_RETURN_NONE;
817}
818#endif // HAVE_MADVISE
819
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +0100820static struct PyMemberDef mmap_object_members[] = {
821 {"__weaklistoffset__", T_PYSSIZET, offsetof(mmap_object, weakreflist), READONLY},
822 {NULL},
823};
824
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000825static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000826 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
827 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
828 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
829 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
Zackery Spytz02db6962019-05-27 10:48:17 -0600830#ifdef HAVE_MADVISE
831 {"madvise", (PyCFunction) mmap_madvise_method, METH_VARARGS},
832#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000833 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
834 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
835 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
836 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
837 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
838 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
839 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
840 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
841 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
842 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000843 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
844 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300845#ifdef MS_WINDOWS
846 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
847#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000848 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849};
850
Georg Brandl0bccc182010-08-01 14:50:00 +0000851static PyGetSetDef mmap_object_getset[] = {
852 {"closed", (getter) mmap_closed_get, NULL, NULL},
853 {NULL}
854};
855
856
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000857/* Functions for treating an mmap'ed file as a buffer */
858
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000859static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000860mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000861{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000862 CHECK_VALID(-1);
863 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
864 (self->access == ACCESS_READ), flags) < 0)
865 return -1;
866 self->exports++;
867 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000868}
869
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000870static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000871mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000872{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000873 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000874}
875
Martin v. Löwis18e16552006-02-15 17:27:45 +0000876static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000877mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000878{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000879 CHECK_VALID(-1);
880 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000881}
882
883static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000884mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000885{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000886 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700887 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000888 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
889 return NULL;
890 }
891 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000892}
893
894static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000895mmap_subscript(mmap_object *self, PyObject *item)
896{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000897 CHECK_VALID(NULL);
898 if (PyIndex_Check(item)) {
899 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
900 if (i == -1 && PyErr_Occurred())
901 return NULL;
902 if (i < 0)
903 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700904 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000905 PyErr_SetString(PyExc_IndexError,
906 "mmap index out of range");
907 return NULL;
908 }
909 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
910 }
911 else if (PySlice_Check(item)) {
912 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000913
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300914 if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000915 return NULL;
916 }
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300917 slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000918
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000919 if (slicelen <= 0)
920 return PyBytes_FromStringAndSize("", 0);
921 else if (step == 1)
922 return PyBytes_FromStringAndSize(self->data + start,
923 slicelen);
924 else {
925 char *result_buf = (char *)PyMem_Malloc(slicelen);
Zackery Spytz14514d92019-05-17 01:13:03 -0600926 size_t cur;
927 Py_ssize_t i;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000928 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000929
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000930 if (result_buf == NULL)
931 return PyErr_NoMemory();
932 for (cur = start, i = 0; i < slicelen;
933 cur += step, i++) {
934 result_buf[i] = self->data[cur];
935 }
936 result = PyBytes_FromStringAndSize(result_buf,
937 slicelen);
938 PyMem_Free(result_buf);
939 return result;
940 }
941 }
942 else {
943 PyErr_SetString(PyExc_TypeError,
944 "mmap indices must be integers");
945 return NULL;
946 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000947}
948
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000949static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000950mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000951{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000952 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000953
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000954 CHECK_VALID(-1);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700955 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000956 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
957 return -1;
958 }
959 if (v == NULL) {
960 PyErr_SetString(PyExc_TypeError,
961 "mmap object doesn't support item deletion");
962 return -1;
963 }
964 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
965 PyErr_SetString(PyExc_IndexError,
966 "mmap assignment must be length-1 bytes()");
967 return -1;
968 }
969 if (!is_writable(self))
970 return -1;
971 buf = PyBytes_AsString(v);
972 self->data[i] = buf[0];
973 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000974}
975
Thomas Woutersed03b412007-08-28 21:37:11 +0000976static int
977mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
978{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000979 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000980
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000981 if (!is_writable(self))
982 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000983
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000984 if (PyIndex_Check(item)) {
985 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
986 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000987
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000988 if (i == -1 && PyErr_Occurred())
989 return -1;
990 if (i < 0)
991 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700992 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000993 PyErr_SetString(PyExc_IndexError,
994 "mmap index out of range");
995 return -1;
996 }
997 if (value == NULL) {
998 PyErr_SetString(PyExc_TypeError,
999 "mmap doesn't support item deletion");
1000 return -1;
1001 }
1002 if (!PyIndex_Check(value)) {
1003 PyErr_SetString(PyExc_TypeError,
1004 "mmap item value must be an int");
1005 return -1;
1006 }
1007 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
1008 if (v == -1 && PyErr_Occurred())
1009 return -1;
1010 if (v < 0 || v > 255) {
1011 PyErr_SetString(PyExc_ValueError,
1012 "mmap item value must be "
1013 "in range(0, 256)");
1014 return -1;
1015 }
Antoine Pitrou22e41552010-08-15 18:07:50 +00001016 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001017 return 0;
1018 }
1019 else if (PySlice_Check(item)) {
1020 Py_ssize_t start, stop, step, slicelen;
1021 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +00001022
Serhiy Storchakab879fe82017-04-08 09:53:51 +03001023 if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001024 return -1;
1025 }
Serhiy Storchakab879fe82017-04-08 09:53:51 +03001026 slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001027 if (value == NULL) {
1028 PyErr_SetString(PyExc_TypeError,
1029 "mmap object doesn't support slice deletion");
1030 return -1;
1031 }
1032 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
1033 return -1;
1034 if (vbuf.len != slicelen) {
1035 PyErr_SetString(PyExc_IndexError,
1036 "mmap slice assignment is wrong size");
1037 PyBuffer_Release(&vbuf);
1038 return -1;
1039 }
Thomas Woutersed03b412007-08-28 21:37:11 +00001040
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001041 if (slicelen == 0) {
1042 }
1043 else if (step == 1) {
1044 memcpy(self->data + start, vbuf.buf, slicelen);
1045 }
1046 else {
Zackery Spytz14514d92019-05-17 01:13:03 -06001047 size_t cur;
1048 Py_ssize_t i;
Guido van Rossum98297ee2007-11-06 21:34:58 +00001049
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001050 for (cur = start, i = 0;
1051 i < slicelen;
1052 cur += step, i++)
1053 {
1054 self->data[cur] = ((char *)vbuf.buf)[i];
1055 }
1056 }
1057 PyBuffer_Release(&vbuf);
1058 return 0;
1059 }
1060 else {
1061 PyErr_SetString(PyExc_TypeError,
1062 "mmap indices must be integer");
1063 return -1;
1064 }
Thomas Woutersed03b412007-08-28 21:37:11 +00001065}
1066
Georg Brandl86def6c2008-01-21 20:36:10 +00001067static PyObject *
1068new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1069
Christian Heimese1c98112008-01-21 11:20:28 +00001070PyDoc_STRVAR(mmap_doc,
1071"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1072\n\
1073Maps length bytes from the file specified by the file handle fileno,\n\
1074and returns a mmap object. If length is larger than the current size\n\
1075of the file, the file is extended to contain length bytes. If length\n\
1076is 0, the maximum length of the map is the current size of the file,\n\
1077except that if the file is empty Windows raises an exception (you cannot\n\
1078create an empty mapping on Windows).\n\
1079\n\
1080Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1081\n\
1082Maps length bytes from the file specified by the file descriptor fileno,\n\
1083and returns a mmap object. If length is 0, the maximum length of the map\n\
1084will be the current size of the file when mmap is called.\n\
1085flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1086private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001087object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001088that's shared with all other processes mapping the same areas of the file.\n\
1089The default value is MAP_SHARED.\n\
1090\n\
1091To map anonymous memory, pass -1 as the fileno (both versions).");
1092
1093
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001094static PyType_Slot mmap_object_slots[] = {
1095 {Py_tp_new, new_mmap_object},
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001096 {Py_tp_dealloc, mmap_object_dealloc},
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001097 {Py_tp_repr, mmap__repr__method},
1098 {Py_tp_doc, (void *)mmap_doc},
1099 {Py_tp_methods, mmap_object_methods},
1100 {Py_tp_members, mmap_object_members},
1101 {Py_tp_getset, mmap_object_getset},
1102 {Py_tp_getattro, PyObject_GenericGetAttr},
Miss Islington (bot)da8097a2021-05-27 09:43:56 -07001103 {Py_tp_traverse, mmap_object_traverse},
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001104
1105 /* as sequence */
1106 {Py_sq_length, mmap_length},
1107 {Py_sq_item, mmap_item},
1108 {Py_sq_ass_item, mmap_ass_item},
1109
1110 /* as mapping */
1111 {Py_mp_length, mmap_length},
1112 {Py_mp_subscript, mmap_subscript},
1113 {Py_mp_ass_subscript, mmap_ass_subscript},
1114
1115 /* as buffer */
1116 {Py_bf_getbuffer, mmap_buffer_getbuf},
1117 {Py_bf_releasebuffer, mmap_buffer_releasebuf},
1118 {0, NULL},
1119};
1120
1121static PyType_Spec mmap_object_spec = {
1122 .name = "mmap.mmap",
1123 .basicsize = sizeof(mmap_object),
Miss Islington (bot)da8097a2021-05-27 09:43:56 -07001124 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC),
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001125 .slots = mmap_object_slots,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001126};
1127
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001128
Tim Petersec0a5f02006-02-16 23:47:20 +00001129#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001130#ifdef HAVE_LARGEFILE_SUPPORT
1131#define _Py_PARSE_OFF_T "L"
1132#else
1133#define _Py_PARSE_OFF_T "l"
1134#endif
1135
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001136static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001137new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001138{
Victor Stinnere134a7f2015-03-30 10:09:31 +02001139 struct _Py_stat_struct status;
Zackery Spytzd6e14042018-03-14 14:08:01 -06001140 int fstat_result = -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001141 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001142 Py_ssize_t map_size;
1143 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001144 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1145 int devzero = -1;
1146 int access = (int)ACCESS_DEFAULT;
1147 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001148 "flags", "prot",
1149 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001150
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001151 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1152 &fd, &map_size, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001153 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001154 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001155 if (map_size < 0) {
1156 PyErr_SetString(PyExc_OverflowError,
Zackery Spytz9308dea2018-03-21 00:02:37 -06001157 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001158 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001159 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001160 if (offset < 0) {
1161 PyErr_SetString(PyExc_OverflowError,
1162 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001163 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001164 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001165
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001166 if ((access != (int)ACCESS_DEFAULT) &&
1167 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1168 return PyErr_Format(PyExc_ValueError,
1169 "mmap can't specify both access and flags, prot.");
1170 switch ((access_mode)access) {
1171 case ACCESS_READ:
1172 flags = MAP_SHARED;
1173 prot = PROT_READ;
1174 break;
1175 case ACCESS_WRITE:
1176 flags = MAP_SHARED;
1177 prot = PROT_READ | PROT_WRITE;
1178 break;
1179 case ACCESS_COPY:
1180 flags = MAP_PRIVATE;
1181 prot = PROT_READ | PROT_WRITE;
1182 break;
1183 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001184 /* map prot to access type */
1185 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1186 /* ACCESS_DEFAULT */
1187 }
1188 else if (prot & PROT_WRITE) {
1189 access = ACCESS_WRITE;
1190 }
1191 else {
1192 access = ACCESS_READ;
1193 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001194 break;
1195 default:
1196 return PyErr_Format(PyExc_ValueError,
1197 "mmap invalid access parameter.");
1198 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001199
Steve Dowerb82e17e2019-05-23 08:45:22 -07001200 if (PySys_Audit("mmap.__new__", "ini" _Py_PARSE_OFF_T,
Zackery Spytz08286d52019-06-21 09:31:59 -06001201 fd, map_size, access, offset) < 0) {
Steve Dowerb82e17e2019-05-23 08:45:22 -07001202 return NULL;
1203 }
1204
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001205#ifdef __APPLE__
1206 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1207 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1208 if (fd != -1)
1209 (void)fcntl(fd, F_FULLFSYNC);
1210#endif
Nir Soffer4484f9d2018-03-12 01:39:22 +02001211
1212 if (fd != -1) {
1213 Py_BEGIN_ALLOW_THREADS
1214 fstat_result = _Py_fstat_noraise(fd, &status);
1215 Py_END_ALLOW_THREADS
1216 }
1217
1218 if (fd != -1 && fstat_result == 0 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001219 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001220 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001221 PyErr_SetString(PyExc_ValueError,
1222 "cannot mmap an empty file");
1223 return NULL;
1224 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001225 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001226 PyErr_SetString(PyExc_ValueError,
1227 "mmap offset is greater than file size");
1228 return NULL;
1229 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001230 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001231 PyErr_SetString(PyExc_ValueError,
1232 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001233 return NULL;
1234 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001235 map_size = (Py_ssize_t) (status.st_size - offset);
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001236 } else if (offset > status.st_size || status.st_size - offset < map_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001237 PyErr_SetString(PyExc_ValueError,
1238 "mmap length is greater than file size");
1239 return NULL;
1240 }
1241 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001242 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1243 if (m_obj == NULL) {return NULL;}
1244 m_obj->data = NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001245 m_obj->size = map_size;
1246 m_obj->pos = 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001247 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001248 m_obj->exports = 0;
1249 m_obj->offset = offset;
1250 if (fd == -1) {
1251 m_obj->fd = -1;
1252 /* Assume the caller wants to map anonymous memory.
1253 This is the same behaviour as Windows. mmap.mmap(-1, size)
1254 on both Windows and Unix map anonymous memory.
1255 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001256#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001257 /* BSD way to map anonymous memory */
1258 flags |= MAP_ANONYMOUS;
Lihua Zhao4fb15022019-05-21 18:50:14 +08001259
1260 /* VxWorks only supports MAP_ANONYMOUS with MAP_PRIVATE flag */
1261#ifdef __VXWORKS__
1262 flags &= ~MAP_SHARED;
1263 flags |= MAP_PRIVATE;
1264#endif
1265
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001266#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001267 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001268 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001269 if (devzero == -1) {
1270 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001271 return NULL;
1272 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001273#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001274 }
1275 else {
1276 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001277 if (m_obj->fd == -1) {
1278 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001279 return NULL;
1280 }
1281 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001282
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001283 m_obj->data = mmap(NULL, map_size,
1284 prot, flags,
1285 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001286
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001287 if (devzero != -1) {
1288 close(devzero);
1289 }
1290
1291 if (m_obj->data == (char *)-1) {
1292 m_obj->data = NULL;
1293 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001294 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001295 return NULL;
1296 }
1297 m_obj->access = (access_mode)access;
1298 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001299}
1300#endif /* UNIX */
1301
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001302#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001303
1304/* A note on sizes and offsets: while the actual map size must hold in a
1305 Py_ssize_t, both the total file size and the start offset can be longer
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001306 than a Py_ssize_t, so we use long long which is always 64-bit.
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001307*/
1308
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001309static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001310new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001311{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001312 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001313 Py_ssize_t map_size;
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001314 long long offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001315 DWORD off_hi; /* upper 32 bits of offset */
1316 DWORD off_lo; /* lower 32 bits of offset */
1317 DWORD size_hi; /* upper 32 bits of size */
1318 DWORD size_lo; /* lower 32 bits of size */
Serhiy Storchakae2f92de2017-11-11 13:06:26 +02001319 const char *tagname = "";
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001320 DWORD dwErr = 0;
1321 int fileno;
1322 HANDLE fh = 0;
1323 int access = (access_mode)ACCESS_DEFAULT;
1324 DWORD flProtect, dwDesiredAccess;
1325 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001326 "tagname",
1327 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001328
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001329 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1330 &fileno, &map_size,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001331 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001332 return NULL;
1333 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001334
Steve Dowerb82e17e2019-05-23 08:45:22 -07001335 if (PySys_Audit("mmap.__new__", "iniL",
1336 fileno, map_size, access, offset) < 0) {
1337 return NULL;
1338 }
1339
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001340 switch((access_mode)access) {
1341 case ACCESS_READ:
1342 flProtect = PAGE_READONLY;
1343 dwDesiredAccess = FILE_MAP_READ;
1344 break;
1345 case ACCESS_DEFAULT: case ACCESS_WRITE:
1346 flProtect = PAGE_READWRITE;
1347 dwDesiredAccess = FILE_MAP_WRITE;
1348 break;
1349 case ACCESS_COPY:
1350 flProtect = PAGE_WRITECOPY;
1351 dwDesiredAccess = FILE_MAP_COPY;
1352 break;
1353 default:
1354 return PyErr_Format(PyExc_ValueError,
1355 "mmap invalid access parameter.");
1356 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001357
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001358 if (map_size < 0) {
1359 PyErr_SetString(PyExc_OverflowError,
Zackery Spytz9308dea2018-03-21 00:02:37 -06001360 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001361 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001362 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001363 if (offset < 0) {
1364 PyErr_SetString(PyExc_OverflowError,
1365 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001366 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001367 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001368
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001369 /* assume -1 and 0 both mean invalid filedescriptor
1370 to 'anonymously' map memory.
1371 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1372 XXX: Should this code be added?
1373 if (fileno == 0)
1374 PyErr_WarnEx(PyExc_DeprecationWarning,
1375 "don't use 0 for anonymous memory",
1376 1);
1377 */
1378 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001379 /* Ensure that fileno is within the CRT's valid range */
Segev Finer5e437fb2021-04-24 01:00:27 +03001380 fh = _Py_get_osfhandle(fileno);
1381 if (fh == INVALID_HANDLE_VALUE)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001382 return NULL;
Segev Finer5e437fb2021-04-24 01:00:27 +03001383
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001384 /* Win9x appears to need us seeked to zero */
1385 lseek(fileno, 0, SEEK_SET);
1386 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001387
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001388 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1389 if (m_obj == NULL)
1390 return NULL;
1391 /* Set every field to an invalid marker, so we can safely
1392 destruct the object in the face of failure */
1393 m_obj->data = NULL;
1394 m_obj->file_handle = INVALID_HANDLE_VALUE;
1395 m_obj->map_handle = NULL;
1396 m_obj->tagname = NULL;
1397 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001398
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001399 if (fh) {
1400 /* It is necessary to duplicate the handle, so the
1401 Python code can close it on us */
1402 if (!DuplicateHandle(
1403 GetCurrentProcess(), /* source process handle */
1404 fh, /* handle to be duplicated */
1405 GetCurrentProcess(), /* target proc handle */
1406 (LPHANDLE)&m_obj->file_handle, /* result */
1407 0, /* access - ignored due to options value */
1408 FALSE, /* inherited by child processes? */
1409 DUPLICATE_SAME_ACCESS)) { /* options */
1410 dwErr = GetLastError();
1411 Py_DECREF(m_obj);
1412 PyErr_SetFromWindowsErr(dwErr);
1413 return NULL;
1414 }
1415 if (!map_size) {
1416 DWORD low,high;
1417 low = GetFileSize(fh, &high);
1418 /* low might just happen to have the value INVALID_FILE_SIZE;
1419 so we need to check the last error also. */
1420 if (low == INVALID_FILE_SIZE &&
1421 (dwErr = GetLastError()) != NO_ERROR) {
1422 Py_DECREF(m_obj);
1423 return PyErr_SetFromWindowsErr(dwErr);
1424 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001425
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001426 size = (((long long) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001427 if (size == 0) {
1428 PyErr_SetString(PyExc_ValueError,
1429 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001430 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001431 return NULL;
1432 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001433 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001434 PyErr_SetString(PyExc_ValueError,
1435 "mmap offset is greater than file size");
1436 Py_DECREF(m_obj);
1437 return NULL;
1438 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001439 if (size - offset > PY_SSIZE_T_MAX) {
1440 PyErr_SetString(PyExc_ValueError,
1441 "mmap length is too large");
1442 Py_DECREF(m_obj);
1443 return NULL;
1444 }
1445 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001446 } else {
1447 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001448 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001449 }
1450 }
1451 else {
1452 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001453 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001454 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001455
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001456 /* set the initial position */
1457 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001458
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001459 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001460 m_obj->exports = 0;
1461 /* set the tag name */
1462 if (tagname != NULL && *tagname != '\0') {
1463 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1464 if (m_obj->tagname == NULL) {
1465 PyErr_NoMemory();
1466 Py_DECREF(m_obj);
1467 return NULL;
1468 }
1469 strcpy(m_obj->tagname, tagname);
1470 }
1471 else
1472 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001473
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001474 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001475 size_hi = (DWORD)(size >> 32);
1476 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001477 off_hi = (DWORD)(offset >> 32);
1478 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001479 /* For files, it would be sufficient to pass 0 as size.
1480 For anonymous maps, we have to pass the size explicitly. */
1481 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1482 NULL,
1483 flProtect,
1484 size_hi,
1485 size_lo,
1486 m_obj->tagname);
1487 if (m_obj->map_handle != NULL) {
1488 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1489 dwDesiredAccess,
1490 off_hi,
1491 off_lo,
1492 m_obj->size);
1493 if (m_obj->data != NULL)
1494 return (PyObject *)m_obj;
1495 else {
1496 dwErr = GetLastError();
1497 CloseHandle(m_obj->map_handle);
1498 m_obj->map_handle = NULL;
1499 }
1500 } else
1501 dwErr = GetLastError();
1502 Py_DECREF(m_obj);
1503 PyErr_SetFromWindowsErr(dwErr);
1504 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001505}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001506#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001507
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001508static int
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001509mmap_traverse(PyObject *module, visitproc visit, void *arg)
1510{
1511 mmap_state *state = get_mmap_state(module);
1512 Py_VISIT(state->mmap_object_type);
1513 return 0;
1514}
1515
1516static int
1517mmap_clear(PyObject *module)
1518{
1519 mmap_state *state = get_mmap_state(module);
1520 Py_CLEAR(state->mmap_object_type);
1521 return 0;
1522}
1523
1524static void
1525mmap_free(void *module)
1526{
1527 mmap_clear((PyObject *)module);
1528}
1529
1530static int
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001531mmap_exec(PyObject *module)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001532{
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001533 mmap_state *state = get_mmap_state(module);
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001534
1535 Py_INCREF(PyExc_OSError);
1536 if (PyModule_AddObject(module, "error", PyExc_OSError) < 0) {
1537 Py_DECREF(PyExc_OSError);
1538 return -1;
1539 }
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001540
1541 state->mmap_object_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1542 &mmap_object_spec,
1543 NULL);
1544 if (state->mmap_object_type == NULL) {
1545 return -1;
1546 }
1547 if (PyModule_AddType(module, state->mmap_object_type) < 0) {
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001548 return -1;
1549 }
1550
1551#define ADD_INT_MACRO(module, constant) \
1552 do { \
1553 if (PyModule_AddIntConstant(module, #constant, constant) < 0) { \
1554 return -1; \
1555 } \
1556 } while (0)
1557
1558#ifdef PROT_EXEC
1559 ADD_INT_MACRO(module, PROT_EXEC);
1560#endif
1561#ifdef PROT_READ
1562 ADD_INT_MACRO(module, PROT_READ);
1563#endif
1564#ifdef PROT_WRITE
1565 ADD_INT_MACRO(module, PROT_WRITE);
1566#endif
1567
1568#ifdef MAP_SHARED
1569 ADD_INT_MACRO(module, MAP_SHARED);
1570#endif
1571#ifdef MAP_PRIVATE
1572 ADD_INT_MACRO(module, MAP_PRIVATE);
1573#endif
1574#ifdef MAP_DENYWRITE
1575 ADD_INT_MACRO(module, MAP_DENYWRITE);
1576#endif
1577#ifdef MAP_EXECUTABLE
1578 ADD_INT_MACRO(module, MAP_EXECUTABLE);
1579#endif
1580#ifdef MAP_ANONYMOUS
1581 if (PyModule_AddIntConstant(module, "MAP_ANON", MAP_ANONYMOUS) < 0 ) {
1582 return -1;
1583 }
1584 ADD_INT_MACRO(module, MAP_ANONYMOUS);
1585#endif
1586#ifdef MAP_POPULATE
1587 ADD_INT_MACRO(module, MAP_POPULATE);
1588#endif
1589 if (PyModule_AddIntConstant(module, "PAGESIZE", (long)my_getpagesize()) < 0 ) {
1590 return -1;
1591 }
1592
1593 if (PyModule_AddIntConstant(module, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity()) < 0 ) {
1594 return -1;
1595 }
1596
1597 ADD_INT_MACRO(module, ACCESS_DEFAULT);
1598 ADD_INT_MACRO(module, ACCESS_READ);
1599 ADD_INT_MACRO(module, ACCESS_WRITE);
1600 ADD_INT_MACRO(module, ACCESS_COPY);
1601
1602#ifdef HAVE_MADVISE
1603 // Conventional advice values
1604#ifdef MADV_NORMAL
1605 ADD_INT_MACRO(module, MADV_NORMAL);
1606#endif
1607#ifdef MADV_RANDOM
1608 ADD_INT_MACRO(module, MADV_RANDOM);
1609#endif
1610#ifdef MADV_SEQUENTIAL
1611 ADD_INT_MACRO(module, MADV_SEQUENTIAL);
1612#endif
1613#ifdef MADV_WILLNEED
1614 ADD_INT_MACRO(module, MADV_WILLNEED);
1615#endif
1616#ifdef MADV_DONTNEED
1617 ADD_INT_MACRO(module, MADV_DONTNEED);
1618#endif
1619
1620 // Linux-specific advice values
1621#ifdef MADV_REMOVE
1622 ADD_INT_MACRO(module, MADV_REMOVE);
1623#endif
1624#ifdef MADV_DONTFORK
1625 ADD_INT_MACRO(module, MADV_DONTFORK);
1626#endif
1627#ifdef MADV_DOFORK
1628 ADD_INT_MACRO(module, MADV_DOFORK);
1629#endif
1630#ifdef MADV_HWPOISON
1631 ADD_INT_MACRO(module, MADV_HWPOISON);
1632#endif
1633#ifdef MADV_MERGEABLE
1634 ADD_INT_MACRO(module, MADV_MERGEABLE);
1635#endif
1636#ifdef MADV_UNMERGEABLE
1637 ADD_INT_MACRO(module, MADV_UNMERGEABLE);
1638#endif
1639#ifdef MADV_SOFT_OFFLINE
1640 ADD_INT_MACRO(module, MADV_SOFT_OFFLINE);
1641#endif
1642#ifdef MADV_HUGEPAGE
1643 ADD_INT_MACRO(module, MADV_HUGEPAGE);
1644#endif
1645#ifdef MADV_NOHUGEPAGE
1646 ADD_INT_MACRO(module, MADV_NOHUGEPAGE);
1647#endif
1648#ifdef MADV_DONTDUMP
1649 ADD_INT_MACRO(module, MADV_DONTDUMP);
1650#endif
1651#ifdef MADV_DODUMP
1652 ADD_INT_MACRO(module, MADV_DODUMP);
1653#endif
1654#ifdef MADV_FREE // (Also present on FreeBSD and macOS.)
1655 ADD_INT_MACRO(module, MADV_FREE);
1656#endif
1657
1658 // FreeBSD-specific
1659#ifdef MADV_NOSYNC
1660 ADD_INT_MACRO(module, MADV_NOSYNC);
1661#endif
1662#ifdef MADV_AUTOSYNC
1663 ADD_INT_MACRO(module, MADV_AUTOSYNC);
1664#endif
1665#ifdef MADV_NOCORE
1666 ADD_INT_MACRO(module, MADV_NOCORE);
1667#endif
1668#ifdef MADV_CORE
1669 ADD_INT_MACRO(module, MADV_CORE);
1670#endif
1671#ifdef MADV_PROTECT
1672 ADD_INT_MACRO(module, MADV_PROTECT);
1673#endif
David CARLIER0e62efc2020-11-21 11:39:56 +00001674
1675 // Darwin-specific
1676#ifdef MADV_FREE_REUSABLE // (As MADV_FREE but reclaims more faithful for task_info/Activity Monitor...)
1677 ADD_INT_MACRO(module, MADV_FREE_REUSABLE);
1678#endif
1679#ifdef MADV_FREE_REUSE // (Reuse pages previously tagged as reusable)
1680 ADD_INT_MACRO(module, MADV_FREE_REUSE);
1681#endif
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001682#endif // HAVE_MADVISE
1683 return 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001684}
1685
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001686static PyModuleDef_Slot mmap_slots[] = {
1687 {Py_mod_exec, mmap_exec},
1688 {0, NULL}
1689};
Martin v. Löwis1a214512008-06-11 05:26:20 +00001690
1691static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001692 PyModuleDef_HEAD_INIT,
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001693 .m_name = "mmap",
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001694 .m_size = sizeof(mmap_state),
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001695 .m_slots = mmap_slots,
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001696 .m_traverse = mmap_traverse,
1697 .m_clear = mmap_clear,
1698 .m_free = mmap_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001699};
1700
Mark Hammond62b1ab12002-07-23 06:31:15 +00001701PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001702PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001703{
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001704 return PyModuleDef_Init(&mmapmodule);
Tim Peters5ebfd362001-11-13 23:11:19 +00001705}