blob: 1e66962d37b0e0ca38e5159b1ebfe75cb01de1c4 [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
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000129static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000130mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000131{
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +0100132 PyTypeObject *tp = Py_TYPE(m_obj);
133
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000134#ifdef MS_WINDOWS
Davide Rizzodc078942019-03-06 18:08:31 +0100135 Py_BEGIN_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 if (m_obj->data != NULL)
137 UnmapViewOfFile (m_obj->data);
138 if (m_obj->map_handle != NULL)
139 CloseHandle (m_obj->map_handle);
140 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
141 CloseHandle (m_obj->file_handle);
Davide Rizzodc078942019-03-06 18:08:31 +0100142 Py_END_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000143 if (m_obj->tagname)
144 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000145#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000146
147#ifdef UNIX
Davide Rizzodc078942019-03-06 18:08:31 +0100148 Py_BEGIN_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000149 if (m_obj->fd >= 0)
150 (void) close(m_obj->fd);
151 if (m_obj->data!=NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000152 munmap(m_obj->data, m_obj->size);
153 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100154 Py_END_ALLOW_THREADS
Davide Rizzodc078942019-03-06 18:08:31 +0100155#endif /* UNIX */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000156
Antoine Pitrouc53204b2013-08-05 23:17:30 +0200157 if (m_obj->weakreflist != NULL)
158 PyObject_ClearWeakRefs((PyObject *) m_obj);
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +0100159
160 tp->tp_free(m_obj);
161 Py_DECREF(tp);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000162}
163
164static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000165mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000166{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 if (self->exports > 0) {
168 PyErr_SetString(PyExc_BufferError, "cannot close "\
169 "exported pointers exist");
170 return NULL;
171 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000172#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000173 /* For each resource we maintain, we need to check
174 the value is valid, and if so, free the resource
175 and set the member value to an invalid value so
176 the dealloc does not attempt to resource clearing
177 again.
178 TODO - should we check for errors in the close operations???
179 */
Davide Rizzobb9593a2019-03-06 16:52:34 +0100180 HANDLE map_handle = self->map_handle;
181 HANDLE file_handle = self->file_handle;
182 char *data = self->data;
183 self->map_handle = NULL;
184 self->file_handle = INVALID_HANDLE_VALUE;
185 self->data = NULL;
186 Py_BEGIN_ALLOW_THREADS
187 if (data != NULL) {
188 UnmapViewOfFile(data);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100190 if (map_handle != NULL) {
191 CloseHandle(map_handle);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000192 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100193 if (file_handle != INVALID_HANDLE_VALUE) {
194 CloseHandle(file_handle);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100196 Py_END_ALLOW_THREADS
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000197#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000198
199#ifdef UNIX
Davide Rizzobb9593a2019-03-06 16:52:34 +0100200 int fd = self->fd;
201 char *data = self->data;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000202 self->fd = -1;
Davide Rizzobb9593a2019-03-06 16:52:34 +0100203 self->data = NULL;
204 Py_BEGIN_ALLOW_THREADS
205 if (0 <= fd)
206 (void) close(fd);
207 if (data != NULL) {
208 munmap(data, self->size);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000209 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100210 Py_END_ALLOW_THREADS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000211#endif
212
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200213 Py_RETURN_NONE;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000214}
215
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000216#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217#define CHECK_VALID(err) \
218do { \
219 if (self->map_handle == NULL) { \
220 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
221 return err; \
222 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000224#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000225
226#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227#define CHECK_VALID(err) \
228do { \
229 if (self->data == NULL) { \
230 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
231 return err; \
232 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000233} while (0)
234#endif /* UNIX */
235
236static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000237mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000238 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000239{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000240 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700241 if (self->pos >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 PyErr_SetString(PyExc_ValueError, "read byte out of range");
243 return NULL;
244 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700245 return PyLong_FromLong((unsigned char)self->data[self->pos++]);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246}
247
248static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000249mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000250 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000251{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700252 Py_ssize_t remaining;
253 char *start, *eol;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000254 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000255
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000256 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000257
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700258 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
259 if (!remaining)
260 return PyBytes_FromString("");
261 start = self->data + self->pos;
262 eol = memchr(start, '\n', remaining);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 if (!eol)
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700264 eol = self->data + self->size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000265 else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700266 ++eol; /* advance past newline */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000267 result = PyBytes_FromStringAndSize(start, (eol - start));
268 self->pos += (eol - start);
269 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000270}
271
272static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000273mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000275{
Benjamin Peterson8f1cdc62016-10-05 23:32:09 -0700276 Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000278
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000279 CHECK_VALID(NULL);
Serhiy Storchaka762bf402017-03-30 09:15:31 +0300280 if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000281 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000282
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000283 /* silently 'adjust' out-of-range requests */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700284 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
285 if (num_bytes < 0 || num_bytes > remaining)
286 num_bytes = remaining;
287 result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000288 self->pos += num_bytes;
289 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000290}
291
292static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000293mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000294 PyObject *args,
295 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000296{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000297 Py_ssize_t start = self->pos;
298 Py_ssize_t end = self->size;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200299 Py_buffer view;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000300
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000301 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200302 if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find",
303 &view, &start, &end)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000304 return NULL;
305 } else {
306 const char *p, *start_p, *end_p;
307 int sign = reverse ? -1 : 1;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200308 const char *needle = view.buf;
309 Py_ssize_t len = view.len;
Greg Stein834f4dd2001-05-14 09:32:26 +0000310
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000311 if (start < 0)
312 start += self->size;
313 if (start < 0)
314 start = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700315 else if (start > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000316 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000317
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000318 if (end < 0)
319 end += self->size;
320 if (end < 0)
321 end = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700322 else if (end > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 start_p = self->data + start;
326 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000327
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000328 for (p = (reverse ? end_p - len : start_p);
329 (p >= start_p) && (p + len <= end_p); p += sign) {
330 Py_ssize_t i;
331 for (i = 0; i < len && needle[i] == p[i]; ++i)
332 /* nothing */;
333 if (i == len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200334 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000335 return PyLong_FromSsize_t(p - self->data);
336 }
337 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200338 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000339 return PyLong_FromLong(-1);
340 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000341}
342
Georg Brandlfceab5a2008-01-19 20:08:23 +0000343static PyObject *
344mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000345 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000346{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000347 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000348}
349
350static PyObject *
351mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000353{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000354 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000355}
356
Tim Petersec0a5f02006-02-16 23:47:20 +0000357static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000358is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000359{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000360 if (self->access != ACCESS_READ)
361 return 1;
362 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
363 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000364}
365
Tim Petersec0a5f02006-02-16 23:47:20 +0000366static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000367is_resizeable(mmap_object *self)
368{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000369 if (self->exports > 0) {
370 PyErr_SetString(PyExc_BufferError,
371 "mmap can't resize with extant buffers exported.");
372 return 0;
373 }
374 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
375 return 1;
376 PyErr_Format(PyExc_TypeError,
377 "mmap can't resize a readonly or copy-on-write memory map.");
378 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000379}
380
381
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000382static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000383mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000385{
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200386 Py_buffer data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000387
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000388 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200389 if (!PyArg_ParseTuple(args, "y*:write", &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000390 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000391
Benjamin Peterson37768362016-10-05 23:29:07 -0700392 if (!is_writable(self)) {
393 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700394 return NULL;
Benjamin Peterson37768362016-10-05 23:29:07 -0700395 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700396
397 if (self->pos > self->size || self->size - self->pos < data.len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200398 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700399 PyErr_SetString(PyExc_ValueError, "data out of range");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000400 return NULL;
401 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200402
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700403 memcpy(&self->data[self->pos], data.buf, data.len);
404 self->pos += data.len;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200405 PyBuffer_Release(&data);
Benjamin Peterson87845bc2016-10-05 22:54:19 -0700406 return PyLong_FromSsize_t(data.len);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000407}
408
409static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000410mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000411 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000412{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000413 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000414
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000415 CHECK_VALID(NULL);
416 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
417 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000418
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 if (!is_writable(self))
420 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000421
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000422 if (self->pos < self->size) {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700423 self->data[self->pos++] = value;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200424 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000425 }
426 else {
427 PyErr_SetString(PyExc_ValueError, "write byte out of range");
428 return NULL;
429 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000430}
Tim Petersec0a5f02006-02-16 23:47:20 +0000431
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000432static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000433mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000434 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000435{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000436 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000437
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000438#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000439 if (self->file_handle != INVALID_HANDLE_VALUE) {
440 DWORD low,high;
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700441 long long size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000442 low = GetFileSize(self->file_handle, &high);
443 if (low == INVALID_FILE_SIZE) {
444 /* It might be that the function appears to have failed,
445 when indeed its size equals INVALID_FILE_SIZE */
446 DWORD error = GetLastError();
447 if (error != NO_ERROR)
448 return PyErr_SetFromWindowsErr(error);
449 }
450 if (!high && low < LONG_MAX)
451 return PyLong_FromLong((long)low);
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700452 size = (((long long)high)<<32) + low;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000453 return PyLong_FromLongLong(size);
454 } else {
455 return PyLong_FromSsize_t(self->size);
456 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000457#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000458
459#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000460 {
Victor Stinnere134a7f2015-03-30 10:09:31 +0200461 struct _Py_stat_struct status;
462 if (_Py_fstat(self->fd, &status) == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000463 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000464#ifdef HAVE_LARGEFILE_SUPPORT
Victor Stinnere134a7f2015-03-30 10:09:31 +0200465 return PyLong_FromLongLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000466#else
Victor Stinnere134a7f2015-03-30 10:09:31 +0200467 return PyLong_FromLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000468#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000469 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000470#endif /* UNIX */
471}
472
473/* This assumes that you want the entire file mapped,
474 / and when recreating the map will make the new file
475 / have the new size
476 /
477 / Is this really necessary? This could easily be done
478 / from python by just closing and re-opening with the
479 / new size?
480 */
481
482static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000483mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000484 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000485{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000486 Py_ssize_t new_size;
487 CHECK_VALID(NULL);
488 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
489 !is_resizeable(self)) {
490 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700491 }
492 if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) {
493 PyErr_SetString(PyExc_ValueError, "new size out of range");
494 return NULL;
495 }
496
497 {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000498#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000499 DWORD dwErrCode = 0;
500 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
501 /* First, unmap the file view */
502 UnmapViewOfFile(self->data);
503 self->data = NULL;
504 /* Close the mapping object */
505 CloseHandle(self->map_handle);
506 self->map_handle = NULL;
507 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000508 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
509 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
510 off_hi = (DWORD)(self->offset >> 32);
511 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000512 SetFilePointer(self->file_handle,
513 newSizeLow, &newSizeHigh, FILE_BEGIN);
514 /* Change the size of the file */
515 SetEndOfFile(self->file_handle);
516 /* Create another mapping object and remap the file view */
517 self->map_handle = CreateFileMapping(
518 self->file_handle,
519 NULL,
520 PAGE_READWRITE,
521 0,
522 0,
523 self->tagname);
524 if (self->map_handle != NULL) {
525 self->data = (char *) MapViewOfFile(self->map_handle,
526 FILE_MAP_WRITE,
527 off_hi,
528 off_lo,
529 new_size);
530 if (self->data != NULL) {
531 self->size = new_size;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200532 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000533 } else {
534 dwErrCode = GetLastError();
535 CloseHandle(self->map_handle);
536 self->map_handle = NULL;
537 }
538 } else {
539 dwErrCode = GetLastError();
540 }
541 PyErr_SetFromWindowsErr(dwErrCode);
542 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000543#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000544
545#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000546#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000547 PyErr_SetString(PyExc_SystemError,
548 "mmap: resizing not available--no mremap()");
549 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000551 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000552
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700553 if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200554 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000555 return NULL;
556 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000558#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000559 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000560#else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700561#if defined(__NetBSD__)
562 newmap = mremap(self->data, self->size, self->data, new_size, 0);
563#else
564 newmap = mremap(self->data, self->size, new_size, 0);
565#endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000566#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 if (newmap == (void *)-1)
568 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200569 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000570 return NULL;
571 }
572 self->data = newmap;
573 self->size = new_size;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200574 Py_RETURN_NONE;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000575#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000576#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000577 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000578}
579
580static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000581mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000582{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000583 CHECK_VALID(NULL);
584 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000585}
586
587static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000588mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000589{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000590 Py_ssize_t offset = 0;
591 Py_ssize_t size = self->size;
592 CHECK_VALID(NULL);
593 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
594 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700595 if (size < 0 || offset < 0 || self->size - offset < size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000596 PyErr_SetString(PyExc_ValueError, "flush values out of range");
597 return NULL;
598 }
R. David Murraye194dd62010-10-18 01:14:06 +0000599
600 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
Berker Peksage7d4b2f2018-08-22 21:21:05 +0300601 Py_RETURN_NONE;
R. David Murraye194dd62010-10-18 01:14:06 +0000602
Christian Heimesaf98da12008-01-27 15:18:18 +0000603#ifdef MS_WINDOWS
Berker Peksage7d4b2f2018-08-22 21:21:05 +0300604 if (!FlushViewOfFile(self->data+offset, size)) {
605 PyErr_SetFromWindowsErr(GetLastError());
606 return NULL;
607 }
608 Py_RETURN_NONE;
Christian Heimesaf98da12008-01-27 15:18:18 +0000609#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000610 /* XXX flags for msync? */
611 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200612 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000613 return NULL;
614 }
Berker Peksage7d4b2f2018-08-22 21:21:05 +0300615 Py_RETURN_NONE;
Christian Heimesaf98da12008-01-27 15:18:18 +0000616#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000617 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
618 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000619#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000620}
621
622static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000623mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000625 Py_ssize_t dist;
626 int how=0;
627 CHECK_VALID(NULL);
628 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
629 return NULL;
630 else {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700631 Py_ssize_t where;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000632 switch (how) {
633 case 0: /* relative to start */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000634 where = dist;
635 break;
636 case 1: /* relative to current position */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700637 if (PY_SSIZE_T_MAX - self->pos < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000638 goto onoutofrange;
639 where = self->pos + dist;
640 break;
641 case 2: /* relative to end */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700642 if (PY_SSIZE_T_MAX - self->size < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000643 goto onoutofrange;
644 where = self->size + dist;
645 break;
646 default:
647 PyErr_SetString(PyExc_ValueError, "unknown seek type");
648 return NULL;
649 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700650 if (where > self->size || where < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000651 goto onoutofrange;
652 self->pos = where;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200653 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000654 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000655
Tim Peters5ebfd362001-11-13 23:11:19 +0000656 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000657 PyErr_SetString(PyExc_ValueError, "seek out of range");
658 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000659}
660
661static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000662mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000663{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700664 Py_ssize_t dest, src, cnt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000665 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700666 if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000667 !is_writable(self)) {
668 return NULL;
669 } else {
670 /* bounds check the values */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700671 if (dest < 0 || src < 0 || cnt < 0)
672 goto bounds;
673 if (self->size - dest < cnt || self->size - src < cnt)
674 goto bounds;
675
676 memmove(&self->data[dest], &self->data[src], cnt);
677
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200678 Py_RETURN_NONE;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700679
680 bounds:
681 PyErr_SetString(PyExc_ValueError,
682 "source, destination, or count out of range");
683 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000684 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000685}
686
Georg Brandl0bccc182010-08-01 14:50:00 +0000687static PyObject *
Serhiy Storchakad4f9cf52018-11-27 19:34:35 +0200688mmap_closed_get(mmap_object *self, void *Py_UNUSED(ignored))
Georg Brandl0bccc182010-08-01 14:50:00 +0000689{
690#ifdef MS_WINDOWS
691 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
692#elif defined(UNIX)
693 return PyBool_FromLong(self->data == NULL ? 1 : 0);
694#endif
695}
696
697static PyObject *
698mmap__enter__method(mmap_object *self, PyObject *args)
699{
700 CHECK_VALID(NULL);
701
702 Py_INCREF(self);
703 return (PyObject *)self;
704}
705
706static PyObject *
707mmap__exit__method(PyObject *self, PyObject *args)
708{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200709 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200710
Jeroen Demeyer762f93f2019-07-08 10:19:25 +0200711 return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
Georg Brandl0bccc182010-08-01 14:50:00 +0000712}
713
Taine Zhaod8ca2352019-10-17 18:41:35 +0800714static PyObject *
715mmap__repr__method(PyObject *self)
716{
717 mmap_object *mobj = (mmap_object *)self;
718
719#ifdef MS_WINDOWS
720#define _Py_FORMAT_OFFSET "lld"
721 if (mobj->map_handle == NULL)
722#elif defined(UNIX)
723# ifdef HAVE_LARGEFILE_SUPPORT
724# define _Py_FORMAT_OFFSET "lld"
725# else
726# define _Py_FORMAT_OFFSET "ld"
727# endif
728 if (mobj->data == NULL)
729#endif
730 {
731 return PyUnicode_FromFormat("<%s closed=True>", Py_TYPE(self)->tp_name);
732 } else {
733 const char *access_str;
734
735 switch (mobj->access) {
736 case ACCESS_DEFAULT:
737 access_str = "ACCESS_DEFAULT";
738 break;
739 case ACCESS_READ:
740 access_str = "ACCESS_READ";
741 break;
742 case ACCESS_WRITE:
743 access_str = "ACCESS_WRITE";
744 break;
745 case ACCESS_COPY:
746 access_str = "ACCESS_COPY";
747 break;
748 default:
749 Py_UNREACHABLE();
750 }
751
752 return PyUnicode_FromFormat("<%s closed=False, access=%s, length=%zd, "
753 "pos=%zd, offset=%" _Py_FORMAT_OFFSET ">",
754 Py_TYPE(self)->tp_name, access_str,
755 mobj->size, mobj->pos, mobj->offset);
756 }
757}
758
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300759#ifdef MS_WINDOWS
760static PyObject *
761mmap__sizeof__method(mmap_object *self, void *unused)
762{
763 Py_ssize_t res;
764
Serhiy Storchaka5c4064e2015-12-19 20:05:25 +0200765 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300766 if (self->tagname)
767 res += strlen(self->tagname) + 1;
768 return PyLong_FromSsize_t(res);
769}
770#endif
771
Zackery Spytz02db6962019-05-27 10:48:17 -0600772#ifdef HAVE_MADVISE
773static PyObject *
774mmap_madvise_method(mmap_object *self, PyObject *args)
775{
776 int option;
777 Py_ssize_t start = 0, length;
778
779 CHECK_VALID(NULL);
780 length = self->size;
781
782 if (!PyArg_ParseTuple(args, "i|nn:madvise", &option, &start, &length)) {
783 return NULL;
784 }
785
786 if (start < 0 || start >= self->size) {
787 PyErr_SetString(PyExc_ValueError, "madvise start out of bounds");
788 return NULL;
789 }
790 if (length < 0) {
791 PyErr_SetString(PyExc_ValueError, "madvise length invalid");
792 return NULL;
793 }
794 if (PY_SSIZE_T_MAX - start < length) {
795 PyErr_SetString(PyExc_OverflowError, "madvise length too large");
796 return NULL;
797 }
798
799 if (start + length > self->size) {
800 length = self->size - start;
801 }
802
803 if (madvise(self->data + start, length, option) != 0) {
804 PyErr_SetFromErrno(PyExc_OSError);
805 return NULL;
806 }
807
808 Py_RETURN_NONE;
809}
810#endif // HAVE_MADVISE
811
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +0100812static struct PyMemberDef mmap_object_members[] = {
813 {"__weaklistoffset__", T_PYSSIZET, offsetof(mmap_object, weakreflist), READONLY},
814 {NULL},
815};
816
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000817static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000818 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
819 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
820 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
821 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
Zackery Spytz02db6962019-05-27 10:48:17 -0600822#ifdef HAVE_MADVISE
823 {"madvise", (PyCFunction) mmap_madvise_method, METH_VARARGS},
824#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000825 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
826 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
827 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
828 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
829 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
830 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
831 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
832 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
833 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
834 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000835 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
836 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300837#ifdef MS_WINDOWS
838 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
839#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000840 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000841};
842
Georg Brandl0bccc182010-08-01 14:50:00 +0000843static PyGetSetDef mmap_object_getset[] = {
844 {"closed", (getter) mmap_closed_get, NULL, NULL},
845 {NULL}
846};
847
848
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849/* Functions for treating an mmap'ed file as a buffer */
850
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000851static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000852mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000853{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000854 CHECK_VALID(-1);
855 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
856 (self->access == ACCESS_READ), flags) < 0)
857 return -1;
858 self->exports++;
859 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000860}
861
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000862static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000863mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000864{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000865 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000866}
867
Martin v. Löwis18e16552006-02-15 17:27:45 +0000868static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000869mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000870{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000871 CHECK_VALID(-1);
872 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000873}
874
875static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000876mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000877{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000878 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700879 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000880 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
881 return NULL;
882 }
883 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000884}
885
886static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000887mmap_subscript(mmap_object *self, PyObject *item)
888{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000889 CHECK_VALID(NULL);
890 if (PyIndex_Check(item)) {
891 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
892 if (i == -1 && PyErr_Occurred())
893 return NULL;
894 if (i < 0)
895 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700896 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000897 PyErr_SetString(PyExc_IndexError,
898 "mmap index out of range");
899 return NULL;
900 }
901 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
902 }
903 else if (PySlice_Check(item)) {
904 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000905
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300906 if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000907 return NULL;
908 }
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300909 slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000910
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000911 if (slicelen <= 0)
912 return PyBytes_FromStringAndSize("", 0);
913 else if (step == 1)
914 return PyBytes_FromStringAndSize(self->data + start,
915 slicelen);
916 else {
917 char *result_buf = (char *)PyMem_Malloc(slicelen);
Zackery Spytz14514d92019-05-17 01:13:03 -0600918 size_t cur;
919 Py_ssize_t i;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000920 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000921
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000922 if (result_buf == NULL)
923 return PyErr_NoMemory();
924 for (cur = start, i = 0; i < slicelen;
925 cur += step, i++) {
926 result_buf[i] = self->data[cur];
927 }
928 result = PyBytes_FromStringAndSize(result_buf,
929 slicelen);
930 PyMem_Free(result_buf);
931 return result;
932 }
933 }
934 else {
935 PyErr_SetString(PyExc_TypeError,
936 "mmap indices must be integers");
937 return NULL;
938 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000939}
940
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000941static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000942mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000943{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000944 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000945
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000946 CHECK_VALID(-1);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700947 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000948 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
949 return -1;
950 }
951 if (v == NULL) {
952 PyErr_SetString(PyExc_TypeError,
953 "mmap object doesn't support item deletion");
954 return -1;
955 }
956 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
957 PyErr_SetString(PyExc_IndexError,
958 "mmap assignment must be length-1 bytes()");
959 return -1;
960 }
961 if (!is_writable(self))
962 return -1;
963 buf = PyBytes_AsString(v);
964 self->data[i] = buf[0];
965 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000966}
967
Thomas Woutersed03b412007-08-28 21:37:11 +0000968static int
969mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
970{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000971 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000972
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000973 if (!is_writable(self))
974 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000975
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000976 if (PyIndex_Check(item)) {
977 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
978 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000979
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000980 if (i == -1 && PyErr_Occurred())
981 return -1;
982 if (i < 0)
983 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700984 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000985 PyErr_SetString(PyExc_IndexError,
986 "mmap index out of range");
987 return -1;
988 }
989 if (value == NULL) {
990 PyErr_SetString(PyExc_TypeError,
991 "mmap doesn't support item deletion");
992 return -1;
993 }
994 if (!PyIndex_Check(value)) {
995 PyErr_SetString(PyExc_TypeError,
996 "mmap item value must be an int");
997 return -1;
998 }
999 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
1000 if (v == -1 && PyErr_Occurred())
1001 return -1;
1002 if (v < 0 || v > 255) {
1003 PyErr_SetString(PyExc_ValueError,
1004 "mmap item value must be "
1005 "in range(0, 256)");
1006 return -1;
1007 }
Antoine Pitrou22e41552010-08-15 18:07:50 +00001008 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001009 return 0;
1010 }
1011 else if (PySlice_Check(item)) {
1012 Py_ssize_t start, stop, step, slicelen;
1013 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +00001014
Serhiy Storchakab879fe82017-04-08 09:53:51 +03001015 if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001016 return -1;
1017 }
Serhiy Storchakab879fe82017-04-08 09:53:51 +03001018 slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001019 if (value == NULL) {
1020 PyErr_SetString(PyExc_TypeError,
1021 "mmap object doesn't support slice deletion");
1022 return -1;
1023 }
1024 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
1025 return -1;
1026 if (vbuf.len != slicelen) {
1027 PyErr_SetString(PyExc_IndexError,
1028 "mmap slice assignment is wrong size");
1029 PyBuffer_Release(&vbuf);
1030 return -1;
1031 }
Thomas Woutersed03b412007-08-28 21:37:11 +00001032
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001033 if (slicelen == 0) {
1034 }
1035 else if (step == 1) {
1036 memcpy(self->data + start, vbuf.buf, slicelen);
1037 }
1038 else {
Zackery Spytz14514d92019-05-17 01:13:03 -06001039 size_t cur;
1040 Py_ssize_t i;
Guido van Rossum98297ee2007-11-06 21:34:58 +00001041
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001042 for (cur = start, i = 0;
1043 i < slicelen;
1044 cur += step, i++)
1045 {
1046 self->data[cur] = ((char *)vbuf.buf)[i];
1047 }
1048 }
1049 PyBuffer_Release(&vbuf);
1050 return 0;
1051 }
1052 else {
1053 PyErr_SetString(PyExc_TypeError,
1054 "mmap indices must be integer");
1055 return -1;
1056 }
Thomas Woutersed03b412007-08-28 21:37:11 +00001057}
1058
Georg Brandl86def6c2008-01-21 20:36:10 +00001059static PyObject *
1060new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1061
Christian Heimese1c98112008-01-21 11:20:28 +00001062PyDoc_STRVAR(mmap_doc,
1063"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1064\n\
1065Maps length bytes from the file specified by the file handle fileno,\n\
1066and returns a mmap object. If length is larger than the current size\n\
1067of the file, the file is extended to contain length bytes. If length\n\
1068is 0, the maximum length of the map is the current size of the file,\n\
1069except that if the file is empty Windows raises an exception (you cannot\n\
1070create an empty mapping on Windows).\n\
1071\n\
1072Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1073\n\
1074Maps length bytes from the file specified by the file descriptor fileno,\n\
1075and returns a mmap object. If length is 0, the maximum length of the map\n\
1076will be the current size of the file when mmap is called.\n\
1077flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1078private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001079object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001080that's shared with all other processes mapping the same areas of the file.\n\
1081The default value is MAP_SHARED.\n\
1082\n\
1083To map anonymous memory, pass -1 as the fileno (both versions).");
1084
1085
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001086static PyType_Slot mmap_object_slots[] = {
1087 {Py_tp_new, new_mmap_object},
1088 {Py_tp_alloc, PyType_GenericAlloc},
1089 {Py_tp_dealloc, mmap_object_dealloc},
1090 {Py_tp_free, PyObject_Del},
1091 {Py_tp_repr, mmap__repr__method},
1092 {Py_tp_doc, (void *)mmap_doc},
1093 {Py_tp_methods, mmap_object_methods},
1094 {Py_tp_members, mmap_object_members},
1095 {Py_tp_getset, mmap_object_getset},
1096 {Py_tp_getattro, PyObject_GenericGetAttr},
1097
1098 /* as sequence */
1099 {Py_sq_length, mmap_length},
1100 {Py_sq_item, mmap_item},
1101 {Py_sq_ass_item, mmap_ass_item},
1102
1103 /* as mapping */
1104 {Py_mp_length, mmap_length},
1105 {Py_mp_subscript, mmap_subscript},
1106 {Py_mp_ass_subscript, mmap_ass_subscript},
1107
1108 /* as buffer */
1109 {Py_bf_getbuffer, mmap_buffer_getbuf},
1110 {Py_bf_releasebuffer, mmap_buffer_releasebuf},
1111 {0, NULL},
1112};
1113
1114static PyType_Spec mmap_object_spec = {
1115 .name = "mmap.mmap",
1116 .basicsize = sizeof(mmap_object),
1117 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1118 .slots = mmap_object_slots,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001119};
1120
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001121
Tim Petersec0a5f02006-02-16 23:47:20 +00001122#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001123#ifdef HAVE_LARGEFILE_SUPPORT
1124#define _Py_PARSE_OFF_T "L"
1125#else
1126#define _Py_PARSE_OFF_T "l"
1127#endif
1128
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001129static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001130new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001131{
Victor Stinnere134a7f2015-03-30 10:09:31 +02001132 struct _Py_stat_struct status;
Zackery Spytzd6e14042018-03-14 14:08:01 -06001133 int fstat_result = -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001134 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001135 Py_ssize_t map_size;
1136 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001137 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1138 int devzero = -1;
1139 int access = (int)ACCESS_DEFAULT;
1140 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001141 "flags", "prot",
1142 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001143
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001144 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1145 &fd, &map_size, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001146 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001147 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001148 if (map_size < 0) {
1149 PyErr_SetString(PyExc_OverflowError,
Zackery Spytz9308dea2018-03-21 00:02:37 -06001150 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001151 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001152 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001153 if (offset < 0) {
1154 PyErr_SetString(PyExc_OverflowError,
1155 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001156 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001157 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001158
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001159 if ((access != (int)ACCESS_DEFAULT) &&
1160 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1161 return PyErr_Format(PyExc_ValueError,
1162 "mmap can't specify both access and flags, prot.");
1163 switch ((access_mode)access) {
1164 case ACCESS_READ:
1165 flags = MAP_SHARED;
1166 prot = PROT_READ;
1167 break;
1168 case ACCESS_WRITE:
1169 flags = MAP_SHARED;
1170 prot = PROT_READ | PROT_WRITE;
1171 break;
1172 case ACCESS_COPY:
1173 flags = MAP_PRIVATE;
1174 prot = PROT_READ | PROT_WRITE;
1175 break;
1176 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001177 /* map prot to access type */
1178 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1179 /* ACCESS_DEFAULT */
1180 }
1181 else if (prot & PROT_WRITE) {
1182 access = ACCESS_WRITE;
1183 }
1184 else {
1185 access = ACCESS_READ;
1186 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001187 break;
1188 default:
1189 return PyErr_Format(PyExc_ValueError,
1190 "mmap invalid access parameter.");
1191 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001192
Steve Dowerb82e17e2019-05-23 08:45:22 -07001193 if (PySys_Audit("mmap.__new__", "ini" _Py_PARSE_OFF_T,
Zackery Spytz08286d52019-06-21 09:31:59 -06001194 fd, map_size, access, offset) < 0) {
Steve Dowerb82e17e2019-05-23 08:45:22 -07001195 return NULL;
1196 }
1197
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001198#ifdef __APPLE__
1199 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1200 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1201 if (fd != -1)
1202 (void)fcntl(fd, F_FULLFSYNC);
1203#endif
Nir Soffer4484f9d2018-03-12 01:39:22 +02001204
1205 if (fd != -1) {
1206 Py_BEGIN_ALLOW_THREADS
1207 fstat_result = _Py_fstat_noraise(fd, &status);
1208 Py_END_ALLOW_THREADS
1209 }
1210
1211 if (fd != -1 && fstat_result == 0 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001212 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001213 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001214 PyErr_SetString(PyExc_ValueError,
1215 "cannot mmap an empty file");
1216 return NULL;
1217 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001218 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001219 PyErr_SetString(PyExc_ValueError,
1220 "mmap offset is greater than file size");
1221 return NULL;
1222 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001223 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001224 PyErr_SetString(PyExc_ValueError,
1225 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001226 return NULL;
1227 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001228 map_size = (Py_ssize_t) (status.st_size - offset);
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001229 } else if (offset > status.st_size || status.st_size - offset < map_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001230 PyErr_SetString(PyExc_ValueError,
1231 "mmap length is greater than file size");
1232 return NULL;
1233 }
1234 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001235 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1236 if (m_obj == NULL) {return NULL;}
1237 m_obj->data = NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001238 m_obj->size = map_size;
1239 m_obj->pos = 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001240 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001241 m_obj->exports = 0;
1242 m_obj->offset = offset;
1243 if (fd == -1) {
1244 m_obj->fd = -1;
1245 /* Assume the caller wants to map anonymous memory.
1246 This is the same behaviour as Windows. mmap.mmap(-1, size)
1247 on both Windows and Unix map anonymous memory.
1248 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001249#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001250 /* BSD way to map anonymous memory */
1251 flags |= MAP_ANONYMOUS;
Lihua Zhao4fb15022019-05-21 18:50:14 +08001252
1253 /* VxWorks only supports MAP_ANONYMOUS with MAP_PRIVATE flag */
1254#ifdef __VXWORKS__
1255 flags &= ~MAP_SHARED;
1256 flags |= MAP_PRIVATE;
1257#endif
1258
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001259#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001260 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001261 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001262 if (devzero == -1) {
1263 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001264 return NULL;
1265 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001266#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001267 }
1268 else {
1269 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001270 if (m_obj->fd == -1) {
1271 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001272 return NULL;
1273 }
1274 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001275
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001276 m_obj->data = mmap(NULL, map_size,
1277 prot, flags,
1278 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001279
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001280 if (devzero != -1) {
1281 close(devzero);
1282 }
1283
1284 if (m_obj->data == (char *)-1) {
1285 m_obj->data = NULL;
1286 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001287 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001288 return NULL;
1289 }
1290 m_obj->access = (access_mode)access;
1291 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001292}
1293#endif /* UNIX */
1294
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001295#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001296
1297/* A note on sizes and offsets: while the actual map size must hold in a
1298 Py_ssize_t, both the total file size and the start offset can be longer
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001299 than a Py_ssize_t, so we use long long which is always 64-bit.
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001300*/
1301
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001302static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001303new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001304{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001305 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001306 Py_ssize_t map_size;
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001307 long long offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001308 DWORD off_hi; /* upper 32 bits of offset */
1309 DWORD off_lo; /* lower 32 bits of offset */
1310 DWORD size_hi; /* upper 32 bits of size */
1311 DWORD size_lo; /* lower 32 bits of size */
Serhiy Storchakae2f92de2017-11-11 13:06:26 +02001312 const char *tagname = "";
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001313 DWORD dwErr = 0;
1314 int fileno;
1315 HANDLE fh = 0;
1316 int access = (access_mode)ACCESS_DEFAULT;
1317 DWORD flProtect, dwDesiredAccess;
1318 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001319 "tagname",
1320 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001321
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001322 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1323 &fileno, &map_size,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001324 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001325 return NULL;
1326 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001327
Steve Dowerb82e17e2019-05-23 08:45:22 -07001328 if (PySys_Audit("mmap.__new__", "iniL",
1329 fileno, map_size, access, offset) < 0) {
1330 return NULL;
1331 }
1332
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001333 switch((access_mode)access) {
1334 case ACCESS_READ:
1335 flProtect = PAGE_READONLY;
1336 dwDesiredAccess = FILE_MAP_READ;
1337 break;
1338 case ACCESS_DEFAULT: case ACCESS_WRITE:
1339 flProtect = PAGE_READWRITE;
1340 dwDesiredAccess = FILE_MAP_WRITE;
1341 break;
1342 case ACCESS_COPY:
1343 flProtect = PAGE_WRITECOPY;
1344 dwDesiredAccess = FILE_MAP_COPY;
1345 break;
1346 default:
1347 return PyErr_Format(PyExc_ValueError,
1348 "mmap invalid access parameter.");
1349 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001350
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001351 if (map_size < 0) {
1352 PyErr_SetString(PyExc_OverflowError,
Zackery Spytz9308dea2018-03-21 00:02:37 -06001353 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001354 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001355 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001356 if (offset < 0) {
1357 PyErr_SetString(PyExc_OverflowError,
1358 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001359 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001360 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001361
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001362 /* assume -1 and 0 both mean invalid filedescriptor
1363 to 'anonymously' map memory.
1364 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1365 XXX: Should this code be added?
1366 if (fileno == 0)
1367 PyErr_WarnEx(PyExc_DeprecationWarning,
1368 "don't use 0 for anonymous memory",
1369 1);
1370 */
1371 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001372 /* Ensure that fileno is within the CRT's valid range */
Steve Dower8fc89802015-04-12 00:26:27 -04001373 _Py_BEGIN_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001374 fh = (HANDLE)_get_osfhandle(fileno);
Steve Dower8fc89802015-04-12 00:26:27 -04001375 _Py_END_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001376 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001377 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001378 return NULL;
1379 }
1380 /* Win9x appears to need us seeked to zero */
1381 lseek(fileno, 0, SEEK_SET);
1382 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001383
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001384 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1385 if (m_obj == NULL)
1386 return NULL;
1387 /* Set every field to an invalid marker, so we can safely
1388 destruct the object in the face of failure */
1389 m_obj->data = NULL;
1390 m_obj->file_handle = INVALID_HANDLE_VALUE;
1391 m_obj->map_handle = NULL;
1392 m_obj->tagname = NULL;
1393 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001394
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001395 if (fh) {
1396 /* It is necessary to duplicate the handle, so the
1397 Python code can close it on us */
1398 if (!DuplicateHandle(
1399 GetCurrentProcess(), /* source process handle */
1400 fh, /* handle to be duplicated */
1401 GetCurrentProcess(), /* target proc handle */
1402 (LPHANDLE)&m_obj->file_handle, /* result */
1403 0, /* access - ignored due to options value */
1404 FALSE, /* inherited by child processes? */
1405 DUPLICATE_SAME_ACCESS)) { /* options */
1406 dwErr = GetLastError();
1407 Py_DECREF(m_obj);
1408 PyErr_SetFromWindowsErr(dwErr);
1409 return NULL;
1410 }
1411 if (!map_size) {
1412 DWORD low,high;
1413 low = GetFileSize(fh, &high);
1414 /* low might just happen to have the value INVALID_FILE_SIZE;
1415 so we need to check the last error also. */
1416 if (low == INVALID_FILE_SIZE &&
1417 (dwErr = GetLastError()) != NO_ERROR) {
1418 Py_DECREF(m_obj);
1419 return PyErr_SetFromWindowsErr(dwErr);
1420 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001421
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001422 size = (((long long) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001423 if (size == 0) {
1424 PyErr_SetString(PyExc_ValueError,
1425 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001426 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001427 return NULL;
1428 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001429 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001430 PyErr_SetString(PyExc_ValueError,
1431 "mmap offset is greater than file size");
1432 Py_DECREF(m_obj);
1433 return NULL;
1434 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001435 if (size - offset > PY_SSIZE_T_MAX) {
1436 PyErr_SetString(PyExc_ValueError,
1437 "mmap length is too large");
1438 Py_DECREF(m_obj);
1439 return NULL;
1440 }
1441 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001442 } else {
1443 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001444 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001445 }
1446 }
1447 else {
1448 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001449 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001450 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001451
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001452 /* set the initial position */
1453 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001454
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001455 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001456 m_obj->exports = 0;
1457 /* set the tag name */
1458 if (tagname != NULL && *tagname != '\0') {
1459 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1460 if (m_obj->tagname == NULL) {
1461 PyErr_NoMemory();
1462 Py_DECREF(m_obj);
1463 return NULL;
1464 }
1465 strcpy(m_obj->tagname, tagname);
1466 }
1467 else
1468 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001469
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001470 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001471 size_hi = (DWORD)(size >> 32);
1472 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001473 off_hi = (DWORD)(offset >> 32);
1474 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001475 /* For files, it would be sufficient to pass 0 as size.
1476 For anonymous maps, we have to pass the size explicitly. */
1477 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1478 NULL,
1479 flProtect,
1480 size_hi,
1481 size_lo,
1482 m_obj->tagname);
1483 if (m_obj->map_handle != NULL) {
1484 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1485 dwDesiredAccess,
1486 off_hi,
1487 off_lo,
1488 m_obj->size);
1489 if (m_obj->data != NULL)
1490 return (PyObject *)m_obj;
1491 else {
1492 dwErr = GetLastError();
1493 CloseHandle(m_obj->map_handle);
1494 m_obj->map_handle = NULL;
1495 }
1496 } else
1497 dwErr = GetLastError();
1498 Py_DECREF(m_obj);
1499 PyErr_SetFromWindowsErr(dwErr);
1500 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001501}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001502#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001503
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001504static int
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001505mmap_traverse(PyObject *module, visitproc visit, void *arg)
1506{
1507 mmap_state *state = get_mmap_state(module);
1508 Py_VISIT(state->mmap_object_type);
1509 return 0;
1510}
1511
1512static int
1513mmap_clear(PyObject *module)
1514{
1515 mmap_state *state = get_mmap_state(module);
1516 Py_CLEAR(state->mmap_object_type);
1517 return 0;
1518}
1519
1520static void
1521mmap_free(void *module)
1522{
1523 mmap_clear((PyObject *)module);
1524}
1525
1526static int
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001527mmap_exec(PyObject *module)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001528{
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001529 mmap_state *state = get_mmap_state(module);
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001530
1531 Py_INCREF(PyExc_OSError);
1532 if (PyModule_AddObject(module, "error", PyExc_OSError) < 0) {
1533 Py_DECREF(PyExc_OSError);
1534 return -1;
1535 }
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001536
1537 state->mmap_object_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1538 &mmap_object_spec,
1539 NULL);
1540 if (state->mmap_object_type == NULL) {
1541 return -1;
1542 }
1543 if (PyModule_AddType(module, state->mmap_object_type) < 0) {
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001544 return -1;
1545 }
1546
1547#define ADD_INT_MACRO(module, constant) \
1548 do { \
1549 if (PyModule_AddIntConstant(module, #constant, constant) < 0) { \
1550 return -1; \
1551 } \
1552 } while (0)
1553
1554#ifdef PROT_EXEC
1555 ADD_INT_MACRO(module, PROT_EXEC);
1556#endif
1557#ifdef PROT_READ
1558 ADD_INT_MACRO(module, PROT_READ);
1559#endif
1560#ifdef PROT_WRITE
1561 ADD_INT_MACRO(module, PROT_WRITE);
1562#endif
1563
1564#ifdef MAP_SHARED
1565 ADD_INT_MACRO(module, MAP_SHARED);
1566#endif
1567#ifdef MAP_PRIVATE
1568 ADD_INT_MACRO(module, MAP_PRIVATE);
1569#endif
1570#ifdef MAP_DENYWRITE
1571 ADD_INT_MACRO(module, MAP_DENYWRITE);
1572#endif
1573#ifdef MAP_EXECUTABLE
1574 ADD_INT_MACRO(module, MAP_EXECUTABLE);
1575#endif
1576#ifdef MAP_ANONYMOUS
1577 if (PyModule_AddIntConstant(module, "MAP_ANON", MAP_ANONYMOUS) < 0 ) {
1578 return -1;
1579 }
1580 ADD_INT_MACRO(module, MAP_ANONYMOUS);
1581#endif
1582#ifdef MAP_POPULATE
1583 ADD_INT_MACRO(module, MAP_POPULATE);
1584#endif
1585 if (PyModule_AddIntConstant(module, "PAGESIZE", (long)my_getpagesize()) < 0 ) {
1586 return -1;
1587 }
1588
1589 if (PyModule_AddIntConstant(module, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity()) < 0 ) {
1590 return -1;
1591 }
1592
1593 ADD_INT_MACRO(module, ACCESS_DEFAULT);
1594 ADD_INT_MACRO(module, ACCESS_READ);
1595 ADD_INT_MACRO(module, ACCESS_WRITE);
1596 ADD_INT_MACRO(module, ACCESS_COPY);
1597
1598#ifdef HAVE_MADVISE
1599 // Conventional advice values
1600#ifdef MADV_NORMAL
1601 ADD_INT_MACRO(module, MADV_NORMAL);
1602#endif
1603#ifdef MADV_RANDOM
1604 ADD_INT_MACRO(module, MADV_RANDOM);
1605#endif
1606#ifdef MADV_SEQUENTIAL
1607 ADD_INT_MACRO(module, MADV_SEQUENTIAL);
1608#endif
1609#ifdef MADV_WILLNEED
1610 ADD_INT_MACRO(module, MADV_WILLNEED);
1611#endif
1612#ifdef MADV_DONTNEED
1613 ADD_INT_MACRO(module, MADV_DONTNEED);
1614#endif
1615
1616 // Linux-specific advice values
1617#ifdef MADV_REMOVE
1618 ADD_INT_MACRO(module, MADV_REMOVE);
1619#endif
1620#ifdef MADV_DONTFORK
1621 ADD_INT_MACRO(module, MADV_DONTFORK);
1622#endif
1623#ifdef MADV_DOFORK
1624 ADD_INT_MACRO(module, MADV_DOFORK);
1625#endif
1626#ifdef MADV_HWPOISON
1627 ADD_INT_MACRO(module, MADV_HWPOISON);
1628#endif
1629#ifdef MADV_MERGEABLE
1630 ADD_INT_MACRO(module, MADV_MERGEABLE);
1631#endif
1632#ifdef MADV_UNMERGEABLE
1633 ADD_INT_MACRO(module, MADV_UNMERGEABLE);
1634#endif
1635#ifdef MADV_SOFT_OFFLINE
1636 ADD_INT_MACRO(module, MADV_SOFT_OFFLINE);
1637#endif
1638#ifdef MADV_HUGEPAGE
1639 ADD_INT_MACRO(module, MADV_HUGEPAGE);
1640#endif
1641#ifdef MADV_NOHUGEPAGE
1642 ADD_INT_MACRO(module, MADV_NOHUGEPAGE);
1643#endif
1644#ifdef MADV_DONTDUMP
1645 ADD_INT_MACRO(module, MADV_DONTDUMP);
1646#endif
1647#ifdef MADV_DODUMP
1648 ADD_INT_MACRO(module, MADV_DODUMP);
1649#endif
1650#ifdef MADV_FREE // (Also present on FreeBSD and macOS.)
1651 ADD_INT_MACRO(module, MADV_FREE);
1652#endif
1653
1654 // FreeBSD-specific
1655#ifdef MADV_NOSYNC
1656 ADD_INT_MACRO(module, MADV_NOSYNC);
1657#endif
1658#ifdef MADV_AUTOSYNC
1659 ADD_INT_MACRO(module, MADV_AUTOSYNC);
1660#endif
1661#ifdef MADV_NOCORE
1662 ADD_INT_MACRO(module, MADV_NOCORE);
1663#endif
1664#ifdef MADV_CORE
1665 ADD_INT_MACRO(module, MADV_CORE);
1666#endif
1667#ifdef MADV_PROTECT
1668 ADD_INT_MACRO(module, MADV_PROTECT);
1669#endif
David CARLIER0e62efc2020-11-21 11:39:56 +00001670
1671 // Darwin-specific
1672#ifdef MADV_FREE_REUSABLE // (As MADV_FREE but reclaims more faithful for task_info/Activity Monitor...)
1673 ADD_INT_MACRO(module, MADV_FREE_REUSABLE);
1674#endif
1675#ifdef MADV_FREE_REUSE // (Reuse pages previously tagged as reusable)
1676 ADD_INT_MACRO(module, MADV_FREE_REUSE);
1677#endif
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001678#endif // HAVE_MADVISE
1679 return 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001680}
1681
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001682static PyModuleDef_Slot mmap_slots[] = {
1683 {Py_mod_exec, mmap_exec},
1684 {0, NULL}
1685};
Martin v. Löwis1a214512008-06-11 05:26:20 +00001686
1687static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001688 PyModuleDef_HEAD_INIT,
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001689 .m_name = "mmap",
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001690 .m_size = sizeof(mmap_state),
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001691 .m_slots = mmap_slots,
Erlend Egeberg Aasland74b4eda2020-11-03 10:38:31 +01001692 .m_traverse = mmap_traverse,
1693 .m_clear = mmap_clear,
1694 .m_free = mmap_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001695};
1696
Mark Hammond62b1ab12002-07-23 06:31:15 +00001697PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001698PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001699{
Dong-hee Na3ad52e32020-06-06 00:01:02 +09001700 return PyModuleDef_Init(&mmapmodule);
Tim Peters5ebfd362001-11-13 23:11:19 +00001701}