blob: 6c503b3429b23a2b24508594d2295b09c5e97b54 [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>
Victor Stinner4a21e572020-04-15 02:35:41 +020023#include <stddef.h> // offsetof()
Guido van Rossum09fdf072000-03-31 01:17:07 +000024
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000025#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000026#define UNIX
Benjamin Petersonf6b5cad2015-08-02 12:15:30 -070027# ifdef HAVE_FCNTL_H
Victor Stinnera6cd0cf2011-05-02 01:05:37 +020028# include <fcntl.h>
Benjamin Petersonf6b5cad2015-08-02 12:15:30 -070029# endif /* HAVE_FCNTL_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000030#endif
31
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000032#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000033#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000034static int
35my_getpagesize(void)
36{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000037 SYSTEM_INFO si;
38 GetSystemInfo(&si);
39 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000040}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000041
42static int
43my_getallocationgranularity (void)
44{
45
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000046 SYSTEM_INFO si;
47 GetSystemInfo(&si);
48 return si.dwAllocationGranularity;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000049}
50
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000051#endif
52
53#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000054#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000055#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000056
Fred Drake145f96e2000-10-01 17:50:46 +000057#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
58static int
59my_getpagesize(void)
60{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000061 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000062}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000063
64#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000065#else
66#define my_getpagesize getpagesize
67#endif
68
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000069#endif /* UNIX */
70
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000071#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000072
73#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000074#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000075#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000076
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000077/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000078#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
79# define MAP_ANONYMOUS MAP_ANON
80#endif
81
Tim Peters5ebfd362001-11-13 23:11:19 +000082typedef enum
83{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000084 ACCESS_DEFAULT,
85 ACCESS_READ,
86 ACCESS_WRITE,
87 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000088} access_mode;
89
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000090typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000091 PyObject_HEAD
92 char * data;
Benjamin Petersoncd04db02016-10-05 21:45:48 -070093 Py_ssize_t size;
94 Py_ssize_t pos; /* relative to offset */
Antoine Pitrou97696cb2011-02-21 23:46:27 +000095#ifdef MS_WINDOWS
Benjamin Petersonaf580df2016-09-06 10:46:49 -070096 long long offset;
Antoine Pitrou97696cb2011-02-21 23:46:27 +000097#else
98 off_t offset;
99#endif
Hai Shi06cd5b62019-10-21 14:31:46 +0800100 Py_ssize_t exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000101
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000102#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000103 HANDLE map_handle;
104 HANDLE file_handle;
105 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000106#endif
107
108#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000109 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000111
Antoine Pitrouc53204b2013-08-05 23:17:30 +0200112 PyObject *weakreflist;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000114} mmap_object;
115
Tim Peters5ebfd362001-11-13 23:11:19 +0000116
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000117static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000118mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000119{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000120#ifdef MS_WINDOWS
Davide Rizzodc078942019-03-06 18:08:31 +0100121 Py_BEGIN_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000122 if (m_obj->data != NULL)
123 UnmapViewOfFile (m_obj->data);
124 if (m_obj->map_handle != NULL)
125 CloseHandle (m_obj->map_handle);
126 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
127 CloseHandle (m_obj->file_handle);
Davide Rizzodc078942019-03-06 18:08:31 +0100128 Py_END_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000129 if (m_obj->tagname)
130 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000131#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000132
133#ifdef UNIX
Davide Rizzodc078942019-03-06 18:08:31 +0100134 Py_BEGIN_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000135 if (m_obj->fd >= 0)
136 (void) close(m_obj->fd);
137 if (m_obj->data!=NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000138 munmap(m_obj->data, m_obj->size);
139 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100140 Py_END_ALLOW_THREADS
Davide Rizzodc078942019-03-06 18:08:31 +0100141#endif /* UNIX */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142
Antoine Pitrouc53204b2013-08-05 23:17:30 +0200143 if (m_obj->weakreflist != NULL)
144 PyObject_ClearWeakRefs((PyObject *) m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000146}
147
148static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000149mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000150{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 if (self->exports > 0) {
152 PyErr_SetString(PyExc_BufferError, "cannot close "\
153 "exported pointers exist");
154 return NULL;
155 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000156#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000157 /* For each resource we maintain, we need to check
158 the value is valid, and if so, free the resource
159 and set the member value to an invalid value so
160 the dealloc does not attempt to resource clearing
161 again.
162 TODO - should we check for errors in the close operations???
163 */
Davide Rizzobb9593a2019-03-06 16:52:34 +0100164 HANDLE map_handle = self->map_handle;
165 HANDLE file_handle = self->file_handle;
166 char *data = self->data;
167 self->map_handle = NULL;
168 self->file_handle = INVALID_HANDLE_VALUE;
169 self->data = NULL;
170 Py_BEGIN_ALLOW_THREADS
171 if (data != NULL) {
172 UnmapViewOfFile(data);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000173 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100174 if (map_handle != NULL) {
175 CloseHandle(map_handle);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000176 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100177 if (file_handle != INVALID_HANDLE_VALUE) {
178 CloseHandle(file_handle);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000179 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100180 Py_END_ALLOW_THREADS
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000181#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000182
183#ifdef UNIX
Davide Rizzobb9593a2019-03-06 16:52:34 +0100184 int fd = self->fd;
185 char *data = self->data;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000186 self->fd = -1;
Davide Rizzobb9593a2019-03-06 16:52:34 +0100187 self->data = NULL;
188 Py_BEGIN_ALLOW_THREADS
189 if (0 <= fd)
190 (void) close(fd);
191 if (data != NULL) {
192 munmap(data, self->size);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000193 }
Davide Rizzobb9593a2019-03-06 16:52:34 +0100194 Py_END_ALLOW_THREADS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000195#endif
196
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200197 Py_RETURN_NONE;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000198}
199
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000200#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201#define CHECK_VALID(err) \
202do { \
203 if (self->map_handle == NULL) { \
204 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
205 return err; \
206 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000207} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000208#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000209
210#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000211#define CHECK_VALID(err) \
212do { \
213 if (self->data == NULL) { \
214 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
215 return err; \
216 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217} while (0)
218#endif /* UNIX */
219
220static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000221mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000224 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700225 if (self->pos >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 PyErr_SetString(PyExc_ValueError, "read byte out of range");
227 return NULL;
228 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700229 return PyLong_FromLong((unsigned char)self->data[self->pos++]);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000230}
231
232static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000233mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000235{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700236 Py_ssize_t remaining;
237 char *start, *eol;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000238 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000239
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000240 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700242 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
243 if (!remaining)
244 return PyBytes_FromString("");
245 start = self->data + self->pos;
246 eol = memchr(start, '\n', remaining);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 if (!eol)
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700248 eol = self->data + self->size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000249 else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700250 ++eol; /* advance past newline */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000251 result = PyBytes_FromStringAndSize(start, (eol - start));
252 self->pos += (eol - start);
253 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000254}
255
256static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000257mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000258 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000259{
Benjamin Peterson8f1cdc62016-10-05 23:32:09 -0700260 Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000261 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000262
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 CHECK_VALID(NULL);
Serhiy Storchaka762bf402017-03-30 09:15:31 +0300264 if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000265 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000267 /* silently 'adjust' out-of-range requests */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700268 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
269 if (num_bytes < 0 || num_bytes > remaining)
270 num_bytes = remaining;
271 result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 self->pos += num_bytes;
273 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000274}
275
276static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000277mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000278 PyObject *args,
279 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000280{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000281 Py_ssize_t start = self->pos;
282 Py_ssize_t end = self->size;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200283 Py_buffer view;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000284
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000285 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200286 if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find",
287 &view, &start, &end)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000288 return NULL;
289 } else {
290 const char *p, *start_p, *end_p;
291 int sign = reverse ? -1 : 1;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200292 const char *needle = view.buf;
293 Py_ssize_t len = view.len;
Greg Stein834f4dd2001-05-14 09:32:26 +0000294
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000295 if (start < 0)
296 start += self->size;
297 if (start < 0)
298 start = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700299 else if (start > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000300 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000301
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 if (end < 0)
303 end += self->size;
304 if (end < 0)
305 end = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700306 else if (end > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000307 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000308
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309 start_p = self->data + start;
310 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000311
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 for (p = (reverse ? end_p - len : start_p);
313 (p >= start_p) && (p + len <= end_p); p += sign) {
314 Py_ssize_t i;
315 for (i = 0; i < len && needle[i] == p[i]; ++i)
316 /* nothing */;
317 if (i == len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200318 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 return PyLong_FromSsize_t(p - self->data);
320 }
321 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200322 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 return PyLong_FromLong(-1);
324 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000325}
326
Georg Brandlfceab5a2008-01-19 20:08:23 +0000327static PyObject *
328mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000330{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000332}
333
334static PyObject *
335mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000336 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000337{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000338 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000339}
340
Tim Petersec0a5f02006-02-16 23:47:20 +0000341static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000342is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000343{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000344 if (self->access != ACCESS_READ)
345 return 1;
346 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
347 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000348}
349
Tim Petersec0a5f02006-02-16 23:47:20 +0000350static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000351is_resizeable(mmap_object *self)
352{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000353 if (self->exports > 0) {
354 PyErr_SetString(PyExc_BufferError,
355 "mmap can't resize with extant buffers exported.");
356 return 0;
357 }
358 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
359 return 1;
360 PyErr_Format(PyExc_TypeError,
361 "mmap can't resize a readonly or copy-on-write memory map.");
362 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000363}
364
365
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000366static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000367mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000368 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000369{
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200370 Py_buffer data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000371
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000372 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200373 if (!PyArg_ParseTuple(args, "y*:write", &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000375
Benjamin Peterson37768362016-10-05 23:29:07 -0700376 if (!is_writable(self)) {
377 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700378 return NULL;
Benjamin Peterson37768362016-10-05 23:29:07 -0700379 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700380
381 if (self->pos > self->size || self->size - self->pos < data.len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200382 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700383 PyErr_SetString(PyExc_ValueError, "data out of range");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 return NULL;
385 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200386
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700387 memcpy(&self->data[self->pos], data.buf, data.len);
388 self->pos += data.len;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200389 PyBuffer_Release(&data);
Benjamin Peterson87845bc2016-10-05 22:54:19 -0700390 return PyLong_FromSsize_t(data.len);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000391}
392
393static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000394mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000395 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000396{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000398
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000399 CHECK_VALID(NULL);
400 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
401 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000402
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000403 if (!is_writable(self))
404 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000405
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 if (self->pos < self->size) {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700407 self->data[self->pos++] = value;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200408 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000409 }
410 else {
411 PyErr_SetString(PyExc_ValueError, "write byte out of range");
412 return NULL;
413 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000414}
Tim Petersec0a5f02006-02-16 23:47:20 +0000415
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000416static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000417mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000418 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000419{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000420 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000421
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000422#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000423 if (self->file_handle != INVALID_HANDLE_VALUE) {
424 DWORD low,high;
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700425 long long size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000426 low = GetFileSize(self->file_handle, &high);
427 if (low == INVALID_FILE_SIZE) {
428 /* It might be that the function appears to have failed,
429 when indeed its size equals INVALID_FILE_SIZE */
430 DWORD error = GetLastError();
431 if (error != NO_ERROR)
432 return PyErr_SetFromWindowsErr(error);
433 }
434 if (!high && low < LONG_MAX)
435 return PyLong_FromLong((long)low);
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700436 size = (((long long)high)<<32) + low;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000437 return PyLong_FromLongLong(size);
438 } else {
439 return PyLong_FromSsize_t(self->size);
440 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000441#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000442
443#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000444 {
Victor Stinnere134a7f2015-03-30 10:09:31 +0200445 struct _Py_stat_struct status;
446 if (_Py_fstat(self->fd, &status) == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000447 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000448#ifdef HAVE_LARGEFILE_SUPPORT
Victor Stinnere134a7f2015-03-30 10:09:31 +0200449 return PyLong_FromLongLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000450#else
Victor Stinnere134a7f2015-03-30 10:09:31 +0200451 return PyLong_FromLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000452#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000453 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000454#endif /* UNIX */
455}
456
457/* This assumes that you want the entire file mapped,
458 / and when recreating the map will make the new file
459 / have the new size
460 /
461 / Is this really necessary? This could easily be done
462 / from python by just closing and re-opening with the
463 / new size?
464 */
465
466static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000467mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000469{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 Py_ssize_t new_size;
471 CHECK_VALID(NULL);
472 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
473 !is_resizeable(self)) {
474 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700475 }
476 if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) {
477 PyErr_SetString(PyExc_ValueError, "new size out of range");
478 return NULL;
479 }
480
481 {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000482#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000483 DWORD dwErrCode = 0;
484 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
485 /* First, unmap the file view */
486 UnmapViewOfFile(self->data);
487 self->data = NULL;
488 /* Close the mapping object */
489 CloseHandle(self->map_handle);
490 self->map_handle = NULL;
491 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000492 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
493 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
494 off_hi = (DWORD)(self->offset >> 32);
495 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000496 SetFilePointer(self->file_handle,
497 newSizeLow, &newSizeHigh, FILE_BEGIN);
498 /* Change the size of the file */
499 SetEndOfFile(self->file_handle);
500 /* Create another mapping object and remap the file view */
501 self->map_handle = CreateFileMapping(
502 self->file_handle,
503 NULL,
504 PAGE_READWRITE,
505 0,
506 0,
507 self->tagname);
508 if (self->map_handle != NULL) {
509 self->data = (char *) MapViewOfFile(self->map_handle,
510 FILE_MAP_WRITE,
511 off_hi,
512 off_lo,
513 new_size);
514 if (self->data != NULL) {
515 self->size = new_size;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200516 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000517 } else {
518 dwErrCode = GetLastError();
519 CloseHandle(self->map_handle);
520 self->map_handle = NULL;
521 }
522 } else {
523 dwErrCode = GetLastError();
524 }
525 PyErr_SetFromWindowsErr(dwErrCode);
526 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000527#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000528
529#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000530#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000531 PyErr_SetString(PyExc_SystemError,
532 "mmap: resizing not available--no mremap()");
533 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000534#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000535 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000536
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700537 if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200538 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000539 return NULL;
540 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000541
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000542#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000543 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000544#else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700545#if defined(__NetBSD__)
546 newmap = mremap(self->data, self->size, self->data, new_size, 0);
547#else
548 newmap = mremap(self->data, self->size, new_size, 0);
549#endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000550#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000551 if (newmap == (void *)-1)
552 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200553 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000554 return NULL;
555 }
556 self->data = newmap;
557 self->size = new_size;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200558 Py_RETURN_NONE;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000559#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000560#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000561 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000562}
563
564static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000565mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000566{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 CHECK_VALID(NULL);
568 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000569}
570
571static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000572mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000573{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000574 Py_ssize_t offset = 0;
575 Py_ssize_t size = self->size;
576 CHECK_VALID(NULL);
577 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
578 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700579 if (size < 0 || offset < 0 || self->size - offset < size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000580 PyErr_SetString(PyExc_ValueError, "flush values out of range");
581 return NULL;
582 }
R. David Murraye194dd62010-10-18 01:14:06 +0000583
584 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
Berker Peksage7d4b2f2018-08-22 21:21:05 +0300585 Py_RETURN_NONE;
R. David Murraye194dd62010-10-18 01:14:06 +0000586
Christian Heimesaf98da12008-01-27 15:18:18 +0000587#ifdef MS_WINDOWS
Berker Peksage7d4b2f2018-08-22 21:21:05 +0300588 if (!FlushViewOfFile(self->data+offset, size)) {
589 PyErr_SetFromWindowsErr(GetLastError());
590 return NULL;
591 }
592 Py_RETURN_NONE;
Christian Heimesaf98da12008-01-27 15:18:18 +0000593#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000594 /* XXX flags for msync? */
595 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200596 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000597 return NULL;
598 }
Berker Peksage7d4b2f2018-08-22 21:21:05 +0300599 Py_RETURN_NONE;
Christian Heimesaf98da12008-01-27 15:18:18 +0000600#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000601 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
602 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000603#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000604}
605
606static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000607mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000608{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000609 Py_ssize_t dist;
610 int how=0;
611 CHECK_VALID(NULL);
612 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
613 return NULL;
614 else {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700615 Py_ssize_t where;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000616 switch (how) {
617 case 0: /* relative to start */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000618 where = dist;
619 break;
620 case 1: /* relative to current position */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700621 if (PY_SSIZE_T_MAX - self->pos < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000622 goto onoutofrange;
623 where = self->pos + dist;
624 break;
625 case 2: /* relative to end */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700626 if (PY_SSIZE_T_MAX - self->size < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000627 goto onoutofrange;
628 where = self->size + dist;
629 break;
630 default:
631 PyErr_SetString(PyExc_ValueError, "unknown seek type");
632 return NULL;
633 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700634 if (where > self->size || where < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000635 goto onoutofrange;
636 self->pos = where;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200637 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000638 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000639
Tim Peters5ebfd362001-11-13 23:11:19 +0000640 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000641 PyErr_SetString(PyExc_ValueError, "seek out of range");
642 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000643}
644
645static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000646mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000647{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700648 Py_ssize_t dest, src, cnt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000649 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700650 if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000651 !is_writable(self)) {
652 return NULL;
653 } else {
654 /* bounds check the values */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700655 if (dest < 0 || src < 0 || cnt < 0)
656 goto bounds;
657 if (self->size - dest < cnt || self->size - src < cnt)
658 goto bounds;
659
660 memmove(&self->data[dest], &self->data[src], cnt);
661
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200662 Py_RETURN_NONE;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700663
664 bounds:
665 PyErr_SetString(PyExc_ValueError,
666 "source, destination, or count out of range");
667 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000668 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000669}
670
Georg Brandl0bccc182010-08-01 14:50:00 +0000671static PyObject *
Serhiy Storchakad4f9cf52018-11-27 19:34:35 +0200672mmap_closed_get(mmap_object *self, void *Py_UNUSED(ignored))
Georg Brandl0bccc182010-08-01 14:50:00 +0000673{
674#ifdef MS_WINDOWS
675 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
676#elif defined(UNIX)
677 return PyBool_FromLong(self->data == NULL ? 1 : 0);
678#endif
679}
680
681static PyObject *
682mmap__enter__method(mmap_object *self, PyObject *args)
683{
684 CHECK_VALID(NULL);
685
686 Py_INCREF(self);
687 return (PyObject *)self;
688}
689
690static PyObject *
691mmap__exit__method(PyObject *self, PyObject *args)
692{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200693 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200694
Jeroen Demeyer762f93f2019-07-08 10:19:25 +0200695 return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
Georg Brandl0bccc182010-08-01 14:50:00 +0000696}
697
Taine Zhaod8ca2352019-10-17 18:41:35 +0800698static PyObject *
699mmap__repr__method(PyObject *self)
700{
701 mmap_object *mobj = (mmap_object *)self;
702
703#ifdef MS_WINDOWS
704#define _Py_FORMAT_OFFSET "lld"
705 if (mobj->map_handle == NULL)
706#elif defined(UNIX)
707# ifdef HAVE_LARGEFILE_SUPPORT
708# define _Py_FORMAT_OFFSET "lld"
709# else
710# define _Py_FORMAT_OFFSET "ld"
711# endif
712 if (mobj->data == NULL)
713#endif
714 {
715 return PyUnicode_FromFormat("<%s closed=True>", Py_TYPE(self)->tp_name);
716 } else {
717 const char *access_str;
718
719 switch (mobj->access) {
720 case ACCESS_DEFAULT:
721 access_str = "ACCESS_DEFAULT";
722 break;
723 case ACCESS_READ:
724 access_str = "ACCESS_READ";
725 break;
726 case ACCESS_WRITE:
727 access_str = "ACCESS_WRITE";
728 break;
729 case ACCESS_COPY:
730 access_str = "ACCESS_COPY";
731 break;
732 default:
733 Py_UNREACHABLE();
734 }
735
736 return PyUnicode_FromFormat("<%s closed=False, access=%s, length=%zd, "
737 "pos=%zd, offset=%" _Py_FORMAT_OFFSET ">",
738 Py_TYPE(self)->tp_name, access_str,
739 mobj->size, mobj->pos, mobj->offset);
740 }
741}
742
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300743#ifdef MS_WINDOWS
744static PyObject *
745mmap__sizeof__method(mmap_object *self, void *unused)
746{
747 Py_ssize_t res;
748
Serhiy Storchaka5c4064e2015-12-19 20:05:25 +0200749 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300750 if (self->tagname)
751 res += strlen(self->tagname) + 1;
752 return PyLong_FromSsize_t(res);
753}
754#endif
755
Zackery Spytz02db6962019-05-27 10:48:17 -0600756#ifdef HAVE_MADVISE
757static PyObject *
758mmap_madvise_method(mmap_object *self, PyObject *args)
759{
760 int option;
761 Py_ssize_t start = 0, length;
762
763 CHECK_VALID(NULL);
764 length = self->size;
765
766 if (!PyArg_ParseTuple(args, "i|nn:madvise", &option, &start, &length)) {
767 return NULL;
768 }
769
770 if (start < 0 || start >= self->size) {
771 PyErr_SetString(PyExc_ValueError, "madvise start out of bounds");
772 return NULL;
773 }
774 if (length < 0) {
775 PyErr_SetString(PyExc_ValueError, "madvise length invalid");
776 return NULL;
777 }
778 if (PY_SSIZE_T_MAX - start < length) {
779 PyErr_SetString(PyExc_OverflowError, "madvise length too large");
780 return NULL;
781 }
782
783 if (start + length > self->size) {
784 length = self->size - start;
785 }
786
787 if (madvise(self->data + start, length, option) != 0) {
788 PyErr_SetFromErrno(PyExc_OSError);
789 return NULL;
790 }
791
792 Py_RETURN_NONE;
793}
794#endif // HAVE_MADVISE
795
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000796static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000797 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
798 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
799 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
800 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
Zackery Spytz02db6962019-05-27 10:48:17 -0600801#ifdef HAVE_MADVISE
802 {"madvise", (PyCFunction) mmap_madvise_method, METH_VARARGS},
803#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000804 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
805 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
806 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
807 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
808 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
809 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
810 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
811 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
812 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
813 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000814 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
815 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300816#ifdef MS_WINDOWS
817 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
818#endif
Ethan Smith7c4185d2020-04-09 21:25:53 -0700819 {"__class_getitem__", (PyCFunction)Py_GenericAlias, METH_O|METH_CLASS,
820 PyDoc_STR("See PEP 585")},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000821 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000822};
823
Georg Brandl0bccc182010-08-01 14:50:00 +0000824static PyGetSetDef mmap_object_getset[] = {
825 {"closed", (getter) mmap_closed_get, NULL, NULL},
826 {NULL}
827};
828
829
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000830/* Functions for treating an mmap'ed file as a buffer */
831
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000832static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000833mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000834{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000835 CHECK_VALID(-1);
836 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
837 (self->access == ACCESS_READ), flags) < 0)
838 return -1;
839 self->exports++;
840 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000841}
842
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000843static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000844mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000845{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000846 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000847}
848
Martin v. Löwis18e16552006-02-15 17:27:45 +0000849static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000850mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000851{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000852 CHECK_VALID(-1);
853 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000854}
855
856static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000857mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000858{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000859 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700860 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000861 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
862 return NULL;
863 }
864 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000865}
866
867static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000868mmap_subscript(mmap_object *self, PyObject *item)
869{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000870 CHECK_VALID(NULL);
871 if (PyIndex_Check(item)) {
872 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
873 if (i == -1 && PyErr_Occurred())
874 return NULL;
875 if (i < 0)
876 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700877 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000878 PyErr_SetString(PyExc_IndexError,
879 "mmap index out of range");
880 return NULL;
881 }
882 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
883 }
884 else if (PySlice_Check(item)) {
885 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000886
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300887 if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000888 return NULL;
889 }
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300890 slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000891
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000892 if (slicelen <= 0)
893 return PyBytes_FromStringAndSize("", 0);
894 else if (step == 1)
895 return PyBytes_FromStringAndSize(self->data + start,
896 slicelen);
897 else {
898 char *result_buf = (char *)PyMem_Malloc(slicelen);
Zackery Spytz14514d92019-05-17 01:13:03 -0600899 size_t cur;
900 Py_ssize_t i;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000901 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000902
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000903 if (result_buf == NULL)
904 return PyErr_NoMemory();
905 for (cur = start, i = 0; i < slicelen;
906 cur += step, i++) {
907 result_buf[i] = self->data[cur];
908 }
909 result = PyBytes_FromStringAndSize(result_buf,
910 slicelen);
911 PyMem_Free(result_buf);
912 return result;
913 }
914 }
915 else {
916 PyErr_SetString(PyExc_TypeError,
917 "mmap indices must be integers");
918 return NULL;
919 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000920}
921
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000922static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000923mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000924{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000925 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000926
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000927 CHECK_VALID(-1);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700928 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000929 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
930 return -1;
931 }
932 if (v == NULL) {
933 PyErr_SetString(PyExc_TypeError,
934 "mmap object doesn't support item deletion");
935 return -1;
936 }
937 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
938 PyErr_SetString(PyExc_IndexError,
939 "mmap assignment must be length-1 bytes()");
940 return -1;
941 }
942 if (!is_writable(self))
943 return -1;
944 buf = PyBytes_AsString(v);
945 self->data[i] = buf[0];
946 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000947}
948
Thomas Woutersed03b412007-08-28 21:37:11 +0000949static int
950mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
951{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000952 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000953
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000954 if (!is_writable(self))
955 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000956
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000957 if (PyIndex_Check(item)) {
958 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
959 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000960
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000961 if (i == -1 && PyErr_Occurred())
962 return -1;
963 if (i < 0)
964 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700965 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000966 PyErr_SetString(PyExc_IndexError,
967 "mmap index out of range");
968 return -1;
969 }
970 if (value == NULL) {
971 PyErr_SetString(PyExc_TypeError,
972 "mmap doesn't support item deletion");
973 return -1;
974 }
975 if (!PyIndex_Check(value)) {
976 PyErr_SetString(PyExc_TypeError,
977 "mmap item value must be an int");
978 return -1;
979 }
980 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
981 if (v == -1 && PyErr_Occurred())
982 return -1;
983 if (v < 0 || v > 255) {
984 PyErr_SetString(PyExc_ValueError,
985 "mmap item value must be "
986 "in range(0, 256)");
987 return -1;
988 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000989 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000990 return 0;
991 }
992 else if (PySlice_Check(item)) {
993 Py_ssize_t start, stop, step, slicelen;
994 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000995
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300996 if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000997 return -1;
998 }
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300999 slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001000 if (value == NULL) {
1001 PyErr_SetString(PyExc_TypeError,
1002 "mmap object doesn't support slice deletion");
1003 return -1;
1004 }
1005 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
1006 return -1;
1007 if (vbuf.len != slicelen) {
1008 PyErr_SetString(PyExc_IndexError,
1009 "mmap slice assignment is wrong size");
1010 PyBuffer_Release(&vbuf);
1011 return -1;
1012 }
Thomas Woutersed03b412007-08-28 21:37:11 +00001013
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001014 if (slicelen == 0) {
1015 }
1016 else if (step == 1) {
1017 memcpy(self->data + start, vbuf.buf, slicelen);
1018 }
1019 else {
Zackery Spytz14514d92019-05-17 01:13:03 -06001020 size_t cur;
1021 Py_ssize_t i;
Guido van Rossum98297ee2007-11-06 21:34:58 +00001022
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001023 for (cur = start, i = 0;
1024 i < slicelen;
1025 cur += step, i++)
1026 {
1027 self->data[cur] = ((char *)vbuf.buf)[i];
1028 }
1029 }
1030 PyBuffer_Release(&vbuf);
1031 return 0;
1032 }
1033 else {
1034 PyErr_SetString(PyExc_TypeError,
1035 "mmap indices must be integer");
1036 return -1;
1037 }
Thomas Woutersed03b412007-08-28 21:37:11 +00001038}
1039
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001040static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +01001041 (lenfunc)mmap_length, /*sq_length*/
Zackery Spytze9e39762018-06-05 06:59:41 -06001042 0, /*sq_concat*/
1043 0, /*sq_repeat*/
Stefan Krah23186992012-03-06 15:37:36 +01001044 (ssizeargfunc)mmap_item, /*sq_item*/
1045 0, /*sq_slice*/
1046 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
1047 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001048};
1049
Thomas Woutersed03b412007-08-28 21:37:11 +00001050static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001051 (lenfunc)mmap_length,
1052 (binaryfunc)mmap_subscript,
1053 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +00001054};
1055
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001056static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001057 (getbufferproc)mmap_buffer_getbuf,
1058 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001059};
1060
Georg Brandl86def6c2008-01-21 20:36:10 +00001061static PyObject *
1062new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1063
Christian Heimese1c98112008-01-21 11:20:28 +00001064PyDoc_STRVAR(mmap_doc,
1065"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1066\n\
1067Maps length bytes from the file specified by the file handle fileno,\n\
1068and returns a mmap object. If length is larger than the current size\n\
1069of the file, the file is extended to contain length bytes. If length\n\
1070is 0, the maximum length of the map is the current size of the file,\n\
1071except that if the file is empty Windows raises an exception (you cannot\n\
1072create an empty mapping on Windows).\n\
1073\n\
1074Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1075\n\
1076Maps length bytes from the file specified by the file descriptor fileno,\n\
1077and returns a mmap object. If length is 0, the maximum length of the map\n\
1078will be the current size of the file when mmap is called.\n\
1079flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1080private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001081object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001082that's shared with all other processes mapping the same areas of the file.\n\
1083The default value is MAP_SHARED.\n\
1084\n\
1085To map anonymous memory, pass -1 as the fileno (both versions).");
1086
1087
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001089 PyVarObject_HEAD_INIT(NULL, 0)
1090 "mmap.mmap", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02001091 sizeof(mmap_object), /* tp_basicsize */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001092 0, /* tp_itemsize */
1093 /* methods */
Taine Zhaod8ca2352019-10-17 18:41:35 +08001094 (destructor)mmap_object_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001095 0, /* tp_vectorcall_offset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001096 0, /* tp_getattr */
1097 0, /* tp_setattr */
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001098 0, /* tp_as_async */
Taine Zhaod8ca2352019-10-17 18:41:35 +08001099 (reprfunc)mmap__repr__method, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001100 0, /* tp_as_number */
Taine Zhaod8ca2352019-10-17 18:41:35 +08001101 &mmap_as_sequence, /* tp_as_sequence */
1102 &mmap_as_mapping, /* tp_as_mapping */
1103 0, /* tp_hash */
1104 0, /* tp_call */
1105 0, /* tp_str */
1106 PyObject_GenericGetAttr, /* tp_getattro */
1107 0, /* tp_setattro */
1108 &mmap_as_buffer, /* tp_as_buffer */
1109 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
1110 mmap_doc, /* tp_doc */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001111 0, /* tp_traverse */
1112 0, /* tp_clear */
1113 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001114 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001115 0, /* tp_iter */
1116 0, /* tp_iternext */
1117 mmap_object_methods, /* tp_methods */
1118 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001119 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001120 0, /* tp_base */
1121 0, /* tp_dict */
1122 0, /* tp_descr_get */
1123 0, /* tp_descr_set */
1124 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001125 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001126 PyType_GenericAlloc, /* tp_alloc */
1127 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001128 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001129};
1130
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001131
Tim Petersec0a5f02006-02-16 23:47:20 +00001132#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001133#ifdef HAVE_LARGEFILE_SUPPORT
1134#define _Py_PARSE_OFF_T "L"
1135#else
1136#define _Py_PARSE_OFF_T "l"
1137#endif
1138
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001139static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001140new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001141{
Victor Stinnere134a7f2015-03-30 10:09:31 +02001142 struct _Py_stat_struct status;
Zackery Spytzd6e14042018-03-14 14:08:01 -06001143 int fstat_result = -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001144 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001145 Py_ssize_t map_size;
1146 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001147 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1148 int devzero = -1;
1149 int access = (int)ACCESS_DEFAULT;
1150 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001151 "flags", "prot",
1152 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001153
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001154 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1155 &fd, &map_size, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001156 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001157 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001158 if (map_size < 0) {
1159 PyErr_SetString(PyExc_OverflowError,
Zackery Spytz9308dea2018-03-21 00:02:37 -06001160 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001161 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001162 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001163 if (offset < 0) {
1164 PyErr_SetString(PyExc_OverflowError,
1165 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001166 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001167 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001168
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001169 if ((access != (int)ACCESS_DEFAULT) &&
1170 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1171 return PyErr_Format(PyExc_ValueError,
1172 "mmap can't specify both access and flags, prot.");
1173 switch ((access_mode)access) {
1174 case ACCESS_READ:
1175 flags = MAP_SHARED;
1176 prot = PROT_READ;
1177 break;
1178 case ACCESS_WRITE:
1179 flags = MAP_SHARED;
1180 prot = PROT_READ | PROT_WRITE;
1181 break;
1182 case ACCESS_COPY:
1183 flags = MAP_PRIVATE;
1184 prot = PROT_READ | PROT_WRITE;
1185 break;
1186 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001187 /* map prot to access type */
1188 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1189 /* ACCESS_DEFAULT */
1190 }
1191 else if (prot & PROT_WRITE) {
1192 access = ACCESS_WRITE;
1193 }
1194 else {
1195 access = ACCESS_READ;
1196 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001197 break;
1198 default:
1199 return PyErr_Format(PyExc_ValueError,
1200 "mmap invalid access parameter.");
1201 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001202
Steve Dowerb82e17e2019-05-23 08:45:22 -07001203 if (PySys_Audit("mmap.__new__", "ini" _Py_PARSE_OFF_T,
Zackery Spytz08286d52019-06-21 09:31:59 -06001204 fd, map_size, access, offset) < 0) {
Steve Dowerb82e17e2019-05-23 08:45:22 -07001205 return NULL;
1206 }
1207
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001208#ifdef __APPLE__
1209 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1210 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1211 if (fd != -1)
1212 (void)fcntl(fd, F_FULLFSYNC);
1213#endif
Nir Soffer4484f9d2018-03-12 01:39:22 +02001214
1215 if (fd != -1) {
1216 Py_BEGIN_ALLOW_THREADS
1217 fstat_result = _Py_fstat_noraise(fd, &status);
1218 Py_END_ALLOW_THREADS
1219 }
1220
1221 if (fd != -1 && fstat_result == 0 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001222 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001223 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001224 PyErr_SetString(PyExc_ValueError,
1225 "cannot mmap an empty file");
1226 return NULL;
1227 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001228 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001229 PyErr_SetString(PyExc_ValueError,
1230 "mmap offset is greater than file size");
1231 return NULL;
1232 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001233 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001234 PyErr_SetString(PyExc_ValueError,
1235 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001236 return NULL;
1237 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001238 map_size = (Py_ssize_t) (status.st_size - offset);
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001239 } else if (offset > status.st_size || status.st_size - offset < map_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001240 PyErr_SetString(PyExc_ValueError,
1241 "mmap length is greater than file size");
1242 return NULL;
1243 }
1244 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001245 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1246 if (m_obj == NULL) {return NULL;}
1247 m_obj->data = NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001248 m_obj->size = map_size;
1249 m_obj->pos = 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001250 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001251 m_obj->exports = 0;
1252 m_obj->offset = offset;
1253 if (fd == -1) {
1254 m_obj->fd = -1;
1255 /* Assume the caller wants to map anonymous memory.
1256 This is the same behaviour as Windows. mmap.mmap(-1, size)
1257 on both Windows and Unix map anonymous memory.
1258 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001259#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001260 /* BSD way to map anonymous memory */
1261 flags |= MAP_ANONYMOUS;
Lihua Zhao4fb15022019-05-21 18:50:14 +08001262
1263 /* VxWorks only supports MAP_ANONYMOUS with MAP_PRIVATE flag */
1264#ifdef __VXWORKS__
1265 flags &= ~MAP_SHARED;
1266 flags |= MAP_PRIVATE;
1267#endif
1268
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001269#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001270 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001271 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001272 if (devzero == -1) {
1273 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001274 return NULL;
1275 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001276#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001277 }
1278 else {
1279 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001280 if (m_obj->fd == -1) {
1281 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001282 return NULL;
1283 }
1284 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001285
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001286 m_obj->data = mmap(NULL, map_size,
1287 prot, flags,
1288 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001289
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001290 if (devzero != -1) {
1291 close(devzero);
1292 }
1293
1294 if (m_obj->data == (char *)-1) {
1295 m_obj->data = NULL;
1296 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001297 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001298 return NULL;
1299 }
1300 m_obj->access = (access_mode)access;
1301 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001302}
1303#endif /* UNIX */
1304
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001305#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001306
1307/* A note on sizes and offsets: while the actual map size must hold in a
1308 Py_ssize_t, both the total file size and the start offset can be longer
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001309 than a Py_ssize_t, so we use long long which is always 64-bit.
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001310*/
1311
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001312static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001313new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001314{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001315 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001316 Py_ssize_t map_size;
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001317 long long offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001318 DWORD off_hi; /* upper 32 bits of offset */
1319 DWORD off_lo; /* lower 32 bits of offset */
1320 DWORD size_hi; /* upper 32 bits of size */
1321 DWORD size_lo; /* lower 32 bits of size */
Serhiy Storchakae2f92de2017-11-11 13:06:26 +02001322 const char *tagname = "";
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001323 DWORD dwErr = 0;
1324 int fileno;
1325 HANDLE fh = 0;
1326 int access = (access_mode)ACCESS_DEFAULT;
1327 DWORD flProtect, dwDesiredAccess;
1328 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001329 "tagname",
1330 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001331
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001332 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1333 &fileno, &map_size,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001334 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001335 return NULL;
1336 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001337
Steve Dowerb82e17e2019-05-23 08:45:22 -07001338 if (PySys_Audit("mmap.__new__", "iniL",
1339 fileno, map_size, access, offset) < 0) {
1340 return NULL;
1341 }
1342
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001343 switch((access_mode)access) {
1344 case ACCESS_READ:
1345 flProtect = PAGE_READONLY;
1346 dwDesiredAccess = FILE_MAP_READ;
1347 break;
1348 case ACCESS_DEFAULT: case ACCESS_WRITE:
1349 flProtect = PAGE_READWRITE;
1350 dwDesiredAccess = FILE_MAP_WRITE;
1351 break;
1352 case ACCESS_COPY:
1353 flProtect = PAGE_WRITECOPY;
1354 dwDesiredAccess = FILE_MAP_COPY;
1355 break;
1356 default:
1357 return PyErr_Format(PyExc_ValueError,
1358 "mmap invalid access parameter.");
1359 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001360
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001361 if (map_size < 0) {
1362 PyErr_SetString(PyExc_OverflowError,
Zackery Spytz9308dea2018-03-21 00:02:37 -06001363 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001364 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001365 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001366 if (offset < 0) {
1367 PyErr_SetString(PyExc_OverflowError,
1368 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001369 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001370 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001371
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001372 /* assume -1 and 0 both mean invalid filedescriptor
1373 to 'anonymously' map memory.
1374 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1375 XXX: Should this code be added?
1376 if (fileno == 0)
1377 PyErr_WarnEx(PyExc_DeprecationWarning,
1378 "don't use 0 for anonymous memory",
1379 1);
1380 */
1381 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001382 /* Ensure that fileno is within the CRT's valid range */
Steve Dower8fc89802015-04-12 00:26:27 -04001383 _Py_BEGIN_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001384 fh = (HANDLE)_get_osfhandle(fileno);
Steve Dower8fc89802015-04-12 00:26:27 -04001385 _Py_END_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001386 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001387 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001388 return NULL;
1389 }
1390 /* Win9x appears to need us seeked to zero */
1391 lseek(fileno, 0, SEEK_SET);
1392 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001393
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001394 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1395 if (m_obj == NULL)
1396 return NULL;
1397 /* Set every field to an invalid marker, so we can safely
1398 destruct the object in the face of failure */
1399 m_obj->data = NULL;
1400 m_obj->file_handle = INVALID_HANDLE_VALUE;
1401 m_obj->map_handle = NULL;
1402 m_obj->tagname = NULL;
1403 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001404
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001405 if (fh) {
1406 /* It is necessary to duplicate the handle, so the
1407 Python code can close it on us */
1408 if (!DuplicateHandle(
1409 GetCurrentProcess(), /* source process handle */
1410 fh, /* handle to be duplicated */
1411 GetCurrentProcess(), /* target proc handle */
1412 (LPHANDLE)&m_obj->file_handle, /* result */
1413 0, /* access - ignored due to options value */
1414 FALSE, /* inherited by child processes? */
1415 DUPLICATE_SAME_ACCESS)) { /* options */
1416 dwErr = GetLastError();
1417 Py_DECREF(m_obj);
1418 PyErr_SetFromWindowsErr(dwErr);
1419 return NULL;
1420 }
1421 if (!map_size) {
1422 DWORD low,high;
1423 low = GetFileSize(fh, &high);
1424 /* low might just happen to have the value INVALID_FILE_SIZE;
1425 so we need to check the last error also. */
1426 if (low == INVALID_FILE_SIZE &&
1427 (dwErr = GetLastError()) != NO_ERROR) {
1428 Py_DECREF(m_obj);
1429 return PyErr_SetFromWindowsErr(dwErr);
1430 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001431
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001432 size = (((long long) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001433 if (size == 0) {
1434 PyErr_SetString(PyExc_ValueError,
1435 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001436 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001437 return NULL;
1438 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001439 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001440 PyErr_SetString(PyExc_ValueError,
1441 "mmap offset is greater than file size");
1442 Py_DECREF(m_obj);
1443 return NULL;
1444 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001445 if (size - offset > PY_SSIZE_T_MAX) {
1446 PyErr_SetString(PyExc_ValueError,
1447 "mmap length is too large");
1448 Py_DECREF(m_obj);
1449 return NULL;
1450 }
1451 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001452 } else {
1453 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001454 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001455 }
1456 }
1457 else {
1458 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001459 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001460 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001461
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001462 /* set the initial position */
1463 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001464
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001465 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001466 m_obj->exports = 0;
1467 /* set the tag name */
1468 if (tagname != NULL && *tagname != '\0') {
1469 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1470 if (m_obj->tagname == NULL) {
1471 PyErr_NoMemory();
1472 Py_DECREF(m_obj);
1473 return NULL;
1474 }
1475 strcpy(m_obj->tagname, tagname);
1476 }
1477 else
1478 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001479
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001480 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001481 size_hi = (DWORD)(size >> 32);
1482 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001483 off_hi = (DWORD)(offset >> 32);
1484 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001485 /* For files, it would be sufficient to pass 0 as size.
1486 For anonymous maps, we have to pass the size explicitly. */
1487 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1488 NULL,
1489 flProtect,
1490 size_hi,
1491 size_lo,
1492 m_obj->tagname);
1493 if (m_obj->map_handle != NULL) {
1494 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1495 dwDesiredAccess,
1496 off_hi,
1497 off_lo,
1498 m_obj->size);
1499 if (m_obj->data != NULL)
1500 return (PyObject *)m_obj;
1501 else {
1502 dwErr = GetLastError();
1503 CloseHandle(m_obj->map_handle);
1504 m_obj->map_handle = NULL;
1505 }
1506 } else
1507 dwErr = GetLastError();
1508 Py_DECREF(m_obj);
1509 PyErr_SetFromWindowsErr(dwErr);
1510 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001511}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001512#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001513
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001514static void
1515setint(PyObject *d, const char *name, long value)
1516{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001517 PyObject *o = PyLong_FromLong(value);
Hai Shi56a45142019-09-16 00:56:57 -05001518 if (o) {
1519 PyDict_SetItemString(d, name, o);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001520 Py_DECREF(o);
1521 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001522}
1523
Martin v. Löwis1a214512008-06-11 05:26:20 +00001524
1525static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001526 PyModuleDef_HEAD_INIT,
1527 "mmap",
1528 NULL,
1529 -1,
1530 NULL,
1531 NULL,
1532 NULL,
1533 NULL,
1534 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001535};
1536
Mark Hammond62b1ab12002-07-23 06:31:15 +00001537PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001538PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001539{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001540 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001541
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001542 if (PyType_Ready(&mmap_object_type) < 0)
1543 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001544
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001545 module = PyModule_Create(&mmapmodule);
1546 if (module == NULL)
1547 return NULL;
1548 dict = PyModule_GetDict(module);
1549 if (!dict)
1550 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001551 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001552 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001553#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001554 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001555#endif
1556#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001557 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001558#endif
1559#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001560 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001561#endif
1562
1563#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001564 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001565#endif
1566#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001567 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001568#endif
1569#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001570 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001571#endif
1572#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001573 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001574#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001575#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001576 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1577 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001578#endif
1579
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001580 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001581
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001582 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001583
Justus Schwabedal5a8a84b2017-11-07 15:51:43 -05001584 setint(dict, "ACCESS_DEFAULT", ACCESS_DEFAULT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001585 setint(dict, "ACCESS_READ", ACCESS_READ);
1586 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1587 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Zackery Spytz02db6962019-05-27 10:48:17 -06001588
1589#ifdef HAVE_MADVISE
1590 // Conventional advice values
1591#ifdef MADV_NORMAL
1592 setint(dict, "MADV_NORMAL", MADV_NORMAL);
1593#endif
1594#ifdef MADV_RANDOM
1595 setint(dict, "MADV_RANDOM", MADV_RANDOM);
1596#endif
1597#ifdef MADV_SEQUENTIAL
1598 setint(dict, "MADV_SEQUENTIAL", MADV_SEQUENTIAL);
1599#endif
1600#ifdef MADV_WILLNEED
1601 setint(dict, "MADV_WILLNEED", MADV_WILLNEED);
1602#endif
1603#ifdef MADV_DONTNEED
1604 setint(dict, "MADV_DONTNEED", MADV_DONTNEED);
1605#endif
1606
1607 // Linux-specific advice values
1608#ifdef MADV_REMOVE
1609 setint(dict, "MADV_REMOVE", MADV_REMOVE);
1610#endif
1611#ifdef MADV_DONTFORK
1612 setint(dict, "MADV_DONTFORK", MADV_DONTFORK);
1613#endif
1614#ifdef MADV_DOFORK
1615 setint(dict, "MADV_DOFORK", MADV_DOFORK);
1616#endif
1617#ifdef MADV_HWPOISON
1618 setint(dict, "MADV_HWPOISON", MADV_HWPOISON);
1619#endif
1620#ifdef MADV_MERGEABLE
1621 setint(dict, "MADV_MERGEABLE", MADV_MERGEABLE);
1622#endif
1623#ifdef MADV_UNMERGEABLE
1624 setint(dict, "MADV_UNMERGEABLE", MADV_UNMERGEABLE);
1625#endif
1626#ifdef MADV_SOFT_OFFLINE
1627 setint(dict, "MADV_SOFT_OFFLINE", MADV_SOFT_OFFLINE);
1628#endif
1629#ifdef MADV_HUGEPAGE
1630 setint(dict, "MADV_HUGEPAGE", MADV_HUGEPAGE);
1631#endif
1632#ifdef MADV_NOHUGEPAGE
1633 setint(dict, "MADV_NOHUGEPAGE", MADV_NOHUGEPAGE);
1634#endif
1635#ifdef MADV_DONTDUMP
1636 setint(dict, "MADV_DONTDUMP", MADV_DONTDUMP);
1637#endif
1638#ifdef MADV_DODUMP
1639 setint(dict, "MADV_DODUMP", MADV_DODUMP);
1640#endif
1641#ifdef MADV_FREE // (Also present on FreeBSD and macOS.)
1642 setint(dict, "MADV_FREE", MADV_FREE);
1643#endif
1644
1645 // FreeBSD-specific
1646#ifdef MADV_NOSYNC
1647 setint(dict, "MADV_NOSYNC", MADV_NOSYNC);
1648#endif
1649#ifdef MADV_AUTOSYNC
1650 setint(dict, "MADV_AUTOSYNC", MADV_AUTOSYNC);
1651#endif
1652#ifdef MADV_NOCORE
1653 setint(dict, "MADV_NOCORE", MADV_NOCORE);
1654#endif
1655#ifdef MADV_CORE
1656 setint(dict, "MADV_CORE", MADV_CORE);
1657#endif
1658#ifdef MADV_PROTECT
1659 setint(dict, "MADV_PROTECT", MADV_PROTECT);
1660#endif
1661#endif // HAVE_MADVISE
1662
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001663 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001664}