blob: 223afacf3140f9e2f5c4a0e21bd34488b40bc480 [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>
Antoine Pitrouc53204b2013-08-05 23:17:30 +020023#include "structmember.h"
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
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000100 int 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
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000121 if (m_obj->data != NULL)
122 UnmapViewOfFile (m_obj->data);
123 if (m_obj->map_handle != NULL)
124 CloseHandle (m_obj->map_handle);
125 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
126 CloseHandle (m_obj->file_handle);
127 if (m_obj->tagname)
128 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000129#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000130
131#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 if (m_obj->fd >= 0)
133 (void) close(m_obj->fd);
134 if (m_obj->data!=NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000135 munmap(m_obj->data, m_obj->size);
136 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000137#endif /* UNIX */
138
Antoine Pitrouc53204b2013-08-05 23:17:30 +0200139 if (m_obj->weakreflist != NULL)
140 PyObject_ClearWeakRefs((PyObject *) m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000141 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142}
143
144static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000145mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000146{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 if (self->exports > 0) {
148 PyErr_SetString(PyExc_BufferError, "cannot close "\
149 "exported pointers exist");
150 return NULL;
151 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000152#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000153 /* For each resource we maintain, we need to check
154 the value is valid, and if so, free the resource
155 and set the member value to an invalid value so
156 the dealloc does not attempt to resource clearing
157 again.
158 TODO - should we check for errors in the close operations???
159 */
160 if (self->data != NULL) {
161 UnmapViewOfFile(self->data);
162 self->data = NULL;
163 }
164 if (self->map_handle != NULL) {
165 CloseHandle(self->map_handle);
166 self->map_handle = NULL;
167 }
168 if (self->file_handle != INVALID_HANDLE_VALUE) {
169 CloseHandle(self->file_handle);
170 self->file_handle = INVALID_HANDLE_VALUE;
171 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000172#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000173
174#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 if (0 <= self->fd)
176 (void) close(self->fd);
177 self->fd = -1;
178 if (self->data != NULL) {
179 munmap(self->data, self->size);
180 self->data = NULL;
181 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000182#endif
183
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200184 Py_RETURN_NONE;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000185}
186
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000187#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000188#define CHECK_VALID(err) \
189do { \
190 if (self->map_handle == NULL) { \
191 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
192 return err; \
193 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000194} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000195#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000196
197#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000198#define CHECK_VALID(err) \
199do { \
200 if (self->data == NULL) { \
201 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
202 return err; \
203 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000204} while (0)
205#endif /* UNIX */
206
207static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000208mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000209 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000210{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000211 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700212 if (self->pos >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000213 PyErr_SetString(PyExc_ValueError, "read byte out of range");
214 return NULL;
215 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700216 return PyLong_FromLong((unsigned char)self->data[self->pos++]);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217}
218
219static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000220mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000221 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000222{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700223 Py_ssize_t remaining;
224 char *start, *eol;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000226
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000228
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700229 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
230 if (!remaining)
231 return PyBytes_FromString("");
232 start = self->data + self->pos;
233 eol = memchr(start, '\n', remaining);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234 if (!eol)
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700235 eol = self->data + self->size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000236 else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700237 ++eol; /* advance past newline */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000238 result = PyBytes_FromStringAndSize(start, (eol - start));
239 self->pos += (eol - start);
240 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241}
242
243static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000244mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246{
Benjamin Peterson8f1cdc62016-10-05 23:32:09 -0700247 Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000248 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000249
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000250 CHECK_VALID(NULL);
Serhiy Storchaka762bf402017-03-30 09:15:31 +0300251 if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000253
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000254 /* silently 'adjust' out-of-range requests */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700255 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
256 if (num_bytes < 0 || num_bytes > remaining)
257 num_bytes = remaining;
258 result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000259 self->pos += num_bytes;
260 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000261}
262
263static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000264mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000265 PyObject *args,
266 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000267{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 Py_ssize_t start = self->pos;
269 Py_ssize_t end = self->size;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200270 Py_buffer view;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000271
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200273 if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find",
274 &view, &start, &end)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 return NULL;
276 } else {
277 const char *p, *start_p, *end_p;
278 int sign = reverse ? -1 : 1;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200279 const char *needle = view.buf;
280 Py_ssize_t len = view.len;
Greg Stein834f4dd2001-05-14 09:32:26 +0000281
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 if (start < 0)
283 start += self->size;
284 if (start < 0)
285 start = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700286 else if (start > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000287 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000288
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000289 if (end < 0)
290 end += self->size;
291 if (end < 0)
292 end = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700293 else if (end > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000294 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000295
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000296 start_p = self->data + start;
297 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000298
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000299 for (p = (reverse ? end_p - len : start_p);
300 (p >= start_p) && (p + len <= end_p); p += sign) {
301 Py_ssize_t i;
302 for (i = 0; i < len && needle[i] == p[i]; ++i)
303 /* nothing */;
304 if (i == len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200305 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 return PyLong_FromSsize_t(p - self->data);
307 }
308 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200309 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000310 return PyLong_FromLong(-1);
311 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000312}
313
Georg Brandlfceab5a2008-01-19 20:08:23 +0000314static PyObject *
315mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000316 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000317{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000318 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000319}
320
321static PyObject *
322mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000324{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000326}
327
Tim Petersec0a5f02006-02-16 23:47:20 +0000328static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000329is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000330{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 if (self->access != ACCESS_READ)
332 return 1;
333 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
334 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000335}
336
Tim Petersec0a5f02006-02-16 23:47:20 +0000337static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000338is_resizeable(mmap_object *self)
339{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 if (self->exports > 0) {
341 PyErr_SetString(PyExc_BufferError,
342 "mmap can't resize with extant buffers exported.");
343 return 0;
344 }
345 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
346 return 1;
347 PyErr_Format(PyExc_TypeError,
348 "mmap can't resize a readonly or copy-on-write memory map.");
349 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000350}
351
352
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000353static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000354mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000355 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000356{
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200357 Py_buffer data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000358
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000359 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200360 if (!PyArg_ParseTuple(args, "y*:write", &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000361 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000362
Benjamin Peterson37768362016-10-05 23:29:07 -0700363 if (!is_writable(self)) {
364 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700365 return NULL;
Benjamin Peterson37768362016-10-05 23:29:07 -0700366 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700367
368 if (self->pos > self->size || self->size - self->pos < data.len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200369 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700370 PyErr_SetString(PyExc_ValueError, "data out of range");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000371 return NULL;
372 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200373
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700374 memcpy(&self->data[self->pos], data.buf, data.len);
375 self->pos += data.len;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200376 PyBuffer_Release(&data);
Benjamin Peterson87845bc2016-10-05 22:54:19 -0700377 return PyLong_FromSsize_t(data.len);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000378}
379
380static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000381mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000382 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000383{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000385
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 CHECK_VALID(NULL);
387 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
388 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000389
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000390 if (!is_writable(self))
391 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000392
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000393 if (self->pos < self->size) {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700394 self->data[self->pos++] = value;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200395 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000396 }
397 else {
398 PyErr_SetString(PyExc_ValueError, "write byte out of range");
399 return NULL;
400 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000401}
Tim Petersec0a5f02006-02-16 23:47:20 +0000402
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000403static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000404mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000405 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000406{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000407 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000408
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000409#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000410 if (self->file_handle != INVALID_HANDLE_VALUE) {
411 DWORD low,high;
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700412 long long size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000413 low = GetFileSize(self->file_handle, &high);
414 if (low == INVALID_FILE_SIZE) {
415 /* It might be that the function appears to have failed,
416 when indeed its size equals INVALID_FILE_SIZE */
417 DWORD error = GetLastError();
418 if (error != NO_ERROR)
419 return PyErr_SetFromWindowsErr(error);
420 }
421 if (!high && low < LONG_MAX)
422 return PyLong_FromLong((long)low);
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700423 size = (((long long)high)<<32) + low;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000424 return PyLong_FromLongLong(size);
425 } else {
426 return PyLong_FromSsize_t(self->size);
427 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000428#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429
430#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000431 {
Victor Stinnere134a7f2015-03-30 10:09:31 +0200432 struct _Py_stat_struct status;
433 if (_Py_fstat(self->fd, &status) == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000434 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000435#ifdef HAVE_LARGEFILE_SUPPORT
Victor Stinnere134a7f2015-03-30 10:09:31 +0200436 return PyLong_FromLongLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000437#else
Victor Stinnere134a7f2015-03-30 10:09:31 +0200438 return PyLong_FromLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000439#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000440 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000441#endif /* UNIX */
442}
443
444/* This assumes that you want the entire file mapped,
445 / and when recreating the map will make the new file
446 / have the new size
447 /
448 / Is this really necessary? This could easily be done
449 / from python by just closing and re-opening with the
450 / new size?
451 */
452
453static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000454mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000455 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000456{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000457 Py_ssize_t new_size;
458 CHECK_VALID(NULL);
459 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
460 !is_resizeable(self)) {
461 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700462 }
463 if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) {
464 PyErr_SetString(PyExc_ValueError, "new size out of range");
465 return NULL;
466 }
467
468 {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000469#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 DWORD dwErrCode = 0;
471 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
472 /* First, unmap the file view */
473 UnmapViewOfFile(self->data);
474 self->data = NULL;
475 /* Close the mapping object */
476 CloseHandle(self->map_handle);
477 self->map_handle = NULL;
478 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000479 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
480 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
481 off_hi = (DWORD)(self->offset >> 32);
482 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000483 SetFilePointer(self->file_handle,
484 newSizeLow, &newSizeHigh, FILE_BEGIN);
485 /* Change the size of the file */
486 SetEndOfFile(self->file_handle);
487 /* Create another mapping object and remap the file view */
488 self->map_handle = CreateFileMapping(
489 self->file_handle,
490 NULL,
491 PAGE_READWRITE,
492 0,
493 0,
494 self->tagname);
495 if (self->map_handle != NULL) {
496 self->data = (char *) MapViewOfFile(self->map_handle,
497 FILE_MAP_WRITE,
498 off_hi,
499 off_lo,
500 new_size);
501 if (self->data != NULL) {
502 self->size = new_size;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200503 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000504 } else {
505 dwErrCode = GetLastError();
506 CloseHandle(self->map_handle);
507 self->map_handle = NULL;
508 }
509 } else {
510 dwErrCode = GetLastError();
511 }
512 PyErr_SetFromWindowsErr(dwErrCode);
513 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000514#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515
516#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000517#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000518 PyErr_SetString(PyExc_SystemError,
519 "mmap: resizing not available--no mremap()");
520 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000521#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000522 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000523
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700524 if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200525 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000526 return NULL;
527 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000528
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000529#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000530 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000531#else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700532#if defined(__NetBSD__)
533 newmap = mremap(self->data, self->size, self->data, new_size, 0);
534#else
535 newmap = mremap(self->data, self->size, new_size, 0);
536#endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000537#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000538 if (newmap == (void *)-1)
539 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200540 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000541 return NULL;
542 }
543 self->data = newmap;
544 self->size = new_size;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200545 Py_RETURN_NONE;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000546#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000547#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000548 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000549}
550
551static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000552mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000554 CHECK_VALID(NULL);
555 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000556}
557
558static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000559mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000560{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000561 Py_ssize_t offset = 0;
562 Py_ssize_t size = self->size;
563 CHECK_VALID(NULL);
564 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
565 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700566 if (size < 0 || offset < 0 || self->size - offset < size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 PyErr_SetString(PyExc_ValueError, "flush values out of range");
568 return NULL;
569 }
R. David Murraye194dd62010-10-18 01:14:06 +0000570
571 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
572 return PyLong_FromLong(0);
573
Christian Heimesaf98da12008-01-27 15:18:18 +0000574#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000576#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000577 /* XXX semantics of return value? */
578 /* XXX flags for msync? */
579 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200580 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000581 return NULL;
582 }
583 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000584#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000585 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
586 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000587#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588}
589
590static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000591mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000592{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000593 Py_ssize_t dist;
594 int how=0;
595 CHECK_VALID(NULL);
596 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
597 return NULL;
598 else {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700599 Py_ssize_t where;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000600 switch (how) {
601 case 0: /* relative to start */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000602 where = dist;
603 break;
604 case 1: /* relative to current position */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700605 if (PY_SSIZE_T_MAX - self->pos < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000606 goto onoutofrange;
607 where = self->pos + dist;
608 break;
609 case 2: /* relative to end */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700610 if (PY_SSIZE_T_MAX - self->size < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000611 goto onoutofrange;
612 where = self->size + dist;
613 break;
614 default:
615 PyErr_SetString(PyExc_ValueError, "unknown seek type");
616 return NULL;
617 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700618 if (where > self->size || where < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000619 goto onoutofrange;
620 self->pos = where;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200621 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000622 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000623
Tim Peters5ebfd362001-11-13 23:11:19 +0000624 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000625 PyErr_SetString(PyExc_ValueError, "seek out of range");
626 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000627}
628
629static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000630mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000631{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700632 Py_ssize_t dest, src, cnt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000633 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700634 if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000635 !is_writable(self)) {
636 return NULL;
637 } else {
638 /* bounds check the values */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700639 if (dest < 0 || src < 0 || cnt < 0)
640 goto bounds;
641 if (self->size - dest < cnt || self->size - src < cnt)
642 goto bounds;
643
644 memmove(&self->data[dest], &self->data[src], cnt);
645
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200646 Py_RETURN_NONE;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700647
648 bounds:
649 PyErr_SetString(PyExc_ValueError,
650 "source, destination, or count out of range");
651 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000652 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000653}
654
Georg Brandl0bccc182010-08-01 14:50:00 +0000655static PyObject *
Miss Islington (bot)5ceb7012018-11-27 09:58:07 -0800656mmap_closed_get(mmap_object *self, void *Py_UNUSED(ignored))
Georg Brandl0bccc182010-08-01 14:50:00 +0000657{
658#ifdef MS_WINDOWS
659 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
660#elif defined(UNIX)
661 return PyBool_FromLong(self->data == NULL ? 1 : 0);
662#endif
663}
664
665static PyObject *
666mmap__enter__method(mmap_object *self, PyObject *args)
667{
668 CHECK_VALID(NULL);
669
670 Py_INCREF(self);
671 return (PyObject *)self;
672}
673
674static PyObject *
675mmap__exit__method(PyObject *self, PyObject *args)
676{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200677 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200678
679 return _PyObject_CallMethodId(self, &PyId_close, NULL);
Georg Brandl0bccc182010-08-01 14:50:00 +0000680}
681
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300682#ifdef MS_WINDOWS
683static PyObject *
684mmap__sizeof__method(mmap_object *self, void *unused)
685{
686 Py_ssize_t res;
687
Serhiy Storchaka5c4064e2015-12-19 20:05:25 +0200688 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300689 if (self->tagname)
690 res += strlen(self->tagname) + 1;
691 return PyLong_FromSsize_t(res);
692}
693#endif
694
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000695static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000696 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
697 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
698 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
699 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
700 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
701 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
702 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
703 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
704 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
705 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
706 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
707 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
708 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
709 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000710 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
711 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300712#ifdef MS_WINDOWS
713 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
714#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000715 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000716};
717
Georg Brandl0bccc182010-08-01 14:50:00 +0000718static PyGetSetDef mmap_object_getset[] = {
719 {"closed", (getter) mmap_closed_get, NULL, NULL},
720 {NULL}
721};
722
723
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000724/* Functions for treating an mmap'ed file as a buffer */
725
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000726static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000727mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000728{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000729 CHECK_VALID(-1);
730 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
731 (self->access == ACCESS_READ), flags) < 0)
732 return -1;
733 self->exports++;
734 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000735}
736
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000737static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000738mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000739{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000740 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000741}
742
Martin v. Löwis18e16552006-02-15 17:27:45 +0000743static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000744mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000745{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000746 CHECK_VALID(-1);
747 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000748}
749
750static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000751mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000752{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000753 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700754 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000755 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
756 return NULL;
757 }
758 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000759}
760
761static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000762mmap_subscript(mmap_object *self, PyObject *item)
763{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000764 CHECK_VALID(NULL);
765 if (PyIndex_Check(item)) {
766 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
767 if (i == -1 && PyErr_Occurred())
768 return NULL;
769 if (i < 0)
770 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700771 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000772 PyErr_SetString(PyExc_IndexError,
773 "mmap index out of range");
774 return NULL;
775 }
776 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
777 }
778 else if (PySlice_Check(item)) {
779 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000780
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300781 if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000782 return NULL;
783 }
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300784 slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000785
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000786 if (slicelen <= 0)
787 return PyBytes_FromStringAndSize("", 0);
788 else if (step == 1)
789 return PyBytes_FromStringAndSize(self->data + start,
790 slicelen);
791 else {
792 char *result_buf = (char *)PyMem_Malloc(slicelen);
Miss Islington (bot)f02d1a42019-05-17 00:33:10 -0700793 size_t cur;
794 Py_ssize_t i;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000795 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000796
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000797 if (result_buf == NULL)
798 return PyErr_NoMemory();
799 for (cur = start, i = 0; i < slicelen;
800 cur += step, i++) {
801 result_buf[i] = self->data[cur];
802 }
803 result = PyBytes_FromStringAndSize(result_buf,
804 slicelen);
805 PyMem_Free(result_buf);
806 return result;
807 }
808 }
809 else {
810 PyErr_SetString(PyExc_TypeError,
811 "mmap indices must be integers");
812 return NULL;
813 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000814}
815
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000816static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000817mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000818{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000819 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000820
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000821 CHECK_VALID(-1);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700822 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000823 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
824 return -1;
825 }
826 if (v == NULL) {
827 PyErr_SetString(PyExc_TypeError,
828 "mmap object doesn't support item deletion");
829 return -1;
830 }
831 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
832 PyErr_SetString(PyExc_IndexError,
833 "mmap assignment must be length-1 bytes()");
834 return -1;
835 }
836 if (!is_writable(self))
837 return -1;
838 buf = PyBytes_AsString(v);
839 self->data[i] = buf[0];
840 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000841}
842
Thomas Woutersed03b412007-08-28 21:37:11 +0000843static int
844mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
845{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000846 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000847
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000848 if (!is_writable(self))
849 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000850
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000851 if (PyIndex_Check(item)) {
852 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
853 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000854
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000855 if (i == -1 && PyErr_Occurred())
856 return -1;
857 if (i < 0)
858 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700859 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000860 PyErr_SetString(PyExc_IndexError,
861 "mmap index out of range");
862 return -1;
863 }
864 if (value == NULL) {
865 PyErr_SetString(PyExc_TypeError,
866 "mmap doesn't support item deletion");
867 return -1;
868 }
869 if (!PyIndex_Check(value)) {
870 PyErr_SetString(PyExc_TypeError,
871 "mmap item value must be an int");
872 return -1;
873 }
874 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
875 if (v == -1 && PyErr_Occurred())
876 return -1;
877 if (v < 0 || v > 255) {
878 PyErr_SetString(PyExc_ValueError,
879 "mmap item value must be "
880 "in range(0, 256)");
881 return -1;
882 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000883 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000884 return 0;
885 }
886 else if (PySlice_Check(item)) {
887 Py_ssize_t start, stop, step, slicelen;
888 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000889
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300890 if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000891 return -1;
892 }
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300893 slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000894 if (value == NULL) {
895 PyErr_SetString(PyExc_TypeError,
896 "mmap object doesn't support slice deletion");
897 return -1;
898 }
899 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
900 return -1;
901 if (vbuf.len != slicelen) {
902 PyErr_SetString(PyExc_IndexError,
903 "mmap slice assignment is wrong size");
904 PyBuffer_Release(&vbuf);
905 return -1;
906 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000907
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000908 if (slicelen == 0) {
909 }
910 else if (step == 1) {
911 memcpy(self->data + start, vbuf.buf, slicelen);
912 }
913 else {
Miss Islington (bot)f02d1a42019-05-17 00:33:10 -0700914 size_t cur;
915 Py_ssize_t i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000916
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000917 for (cur = start, i = 0;
918 i < slicelen;
919 cur += step, i++)
920 {
921 self->data[cur] = ((char *)vbuf.buf)[i];
922 }
923 }
924 PyBuffer_Release(&vbuf);
925 return 0;
926 }
927 else {
928 PyErr_SetString(PyExc_TypeError,
929 "mmap indices must be integer");
930 return -1;
931 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000932}
933
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000934static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +0100935 (lenfunc)mmap_length, /*sq_length*/
Miss Islington (bot)631fe1f2018-06-05 06:21:04 -0700936 0, /*sq_concat*/
937 0, /*sq_repeat*/
Stefan Krah23186992012-03-06 15:37:36 +0100938 (ssizeargfunc)mmap_item, /*sq_item*/
939 0, /*sq_slice*/
940 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
941 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000942};
943
Thomas Woutersed03b412007-08-28 21:37:11 +0000944static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000945 (lenfunc)mmap_length,
946 (binaryfunc)mmap_subscript,
947 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000948};
949
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000950static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000951 (getbufferproc)mmap_buffer_getbuf,
952 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000953};
954
Georg Brandl86def6c2008-01-21 20:36:10 +0000955static PyObject *
956new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
957
Christian Heimese1c98112008-01-21 11:20:28 +0000958PyDoc_STRVAR(mmap_doc,
959"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
960\n\
961Maps length bytes from the file specified by the file handle fileno,\n\
962and returns a mmap object. If length is larger than the current size\n\
963of the file, the file is extended to contain length bytes. If length\n\
964is 0, the maximum length of the map is the current size of the file,\n\
965except that if the file is empty Windows raises an exception (you cannot\n\
966create an empty mapping on Windows).\n\
967\n\
968Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
969\n\
970Maps length bytes from the file specified by the file descriptor fileno,\n\
971and returns a mmap object. If length is 0, the maximum length of the map\n\
972will be the current size of the file when mmap is called.\n\
973flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
974private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000975object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000976that's shared with all other processes mapping the same areas of the file.\n\
977The default value is MAP_SHARED.\n\
978\n\
979To map anonymous memory, pass -1 as the fileno (both versions).");
980
981
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000982static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000983 PyVarObject_HEAD_INIT(NULL, 0)
984 "mmap.mmap", /* tp_name */
Benjamin Peterson4d5d2192018-09-10 10:22:55 -0700985 sizeof(mmap_object), /* tp_basicsize */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000986 0, /* tp_itemsize */
987 /* methods */
988 (destructor) mmap_object_dealloc, /* tp_dealloc */
989 0, /* tp_print */
990 0, /* tp_getattr */
991 0, /* tp_setattr */
992 0, /* tp_reserved */
993 0, /* tp_repr */
994 0, /* tp_as_number */
995 &mmap_as_sequence, /*tp_as_sequence*/
996 &mmap_as_mapping, /*tp_as_mapping*/
997 0, /*tp_hash*/
998 0, /*tp_call*/
999 0, /*tp_str*/
1000 PyObject_GenericGetAttr, /*tp_getattro*/
1001 0, /*tp_setattro*/
1002 &mmap_as_buffer, /*tp_as_buffer*/
Stefan Krah23186992012-03-06 15:37:36 +01001003 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001004 mmap_doc, /*tp_doc*/
1005 0, /* tp_traverse */
1006 0, /* tp_clear */
1007 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001008 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001009 0, /* tp_iter */
1010 0, /* tp_iternext */
1011 mmap_object_methods, /* tp_methods */
1012 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001013 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001014 0, /* tp_base */
1015 0, /* tp_dict */
1016 0, /* tp_descr_get */
1017 0, /* tp_descr_set */
1018 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001019 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001020 PyType_GenericAlloc, /* tp_alloc */
1021 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001022 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001023};
1024
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001025
Tim Petersec0a5f02006-02-16 23:47:20 +00001026#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001027#ifdef HAVE_LARGEFILE_SUPPORT
1028#define _Py_PARSE_OFF_T "L"
1029#else
1030#define _Py_PARSE_OFF_T "l"
1031#endif
1032
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001033static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001034new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001035{
Victor Stinnere134a7f2015-03-30 10:09:31 +02001036 struct _Py_stat_struct status;
Miss Islington (bot)56cce1c2018-03-20 12:16:30 -07001037 int fstat_result = -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001038 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001039 Py_ssize_t map_size;
1040 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001041 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1042 int devzero = -1;
1043 int access = (int)ACCESS_DEFAULT;
1044 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001045 "flags", "prot",
1046 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001047
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001048 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1049 &fd, &map_size, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001050 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001051 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001052 if (map_size < 0) {
1053 PyErr_SetString(PyExc_OverflowError,
Miss Islington (bot)56f530e2018-03-20 23:24:41 -07001054 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001055 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001056 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001057 if (offset < 0) {
1058 PyErr_SetString(PyExc_OverflowError,
1059 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001060 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001061 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001062
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001063 if ((access != (int)ACCESS_DEFAULT) &&
1064 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1065 return PyErr_Format(PyExc_ValueError,
1066 "mmap can't specify both access and flags, prot.");
1067 switch ((access_mode)access) {
1068 case ACCESS_READ:
1069 flags = MAP_SHARED;
1070 prot = PROT_READ;
1071 break;
1072 case ACCESS_WRITE:
1073 flags = MAP_SHARED;
1074 prot = PROT_READ | PROT_WRITE;
1075 break;
1076 case ACCESS_COPY:
1077 flags = MAP_PRIVATE;
1078 prot = PROT_READ | PROT_WRITE;
1079 break;
1080 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001081 /* map prot to access type */
1082 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1083 /* ACCESS_DEFAULT */
1084 }
1085 else if (prot & PROT_WRITE) {
1086 access = ACCESS_WRITE;
1087 }
1088 else {
1089 access = ACCESS_READ;
1090 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001091 break;
1092 default:
1093 return PyErr_Format(PyExc_ValueError,
1094 "mmap invalid access parameter.");
1095 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001096
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001097#ifdef __APPLE__
1098 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1099 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1100 if (fd != -1)
1101 (void)fcntl(fd, F_FULLFSYNC);
1102#endif
Miss Islington (bot)56cce1c2018-03-20 12:16:30 -07001103
1104 if (fd != -1) {
1105 Py_BEGIN_ALLOW_THREADS
1106 fstat_result = _Py_fstat_noraise(fd, &status);
1107 Py_END_ALLOW_THREADS
1108 }
1109
1110 if (fd != -1 && fstat_result == 0 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001111 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001112 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001113 PyErr_SetString(PyExc_ValueError,
1114 "cannot mmap an empty file");
1115 return NULL;
1116 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001117 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001118 PyErr_SetString(PyExc_ValueError,
1119 "mmap offset is greater than file size");
1120 return NULL;
1121 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001122 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001123 PyErr_SetString(PyExc_ValueError,
1124 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001125 return NULL;
1126 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001127 map_size = (Py_ssize_t) (status.st_size - offset);
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001128 } else if (offset > status.st_size || status.st_size - offset < map_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001129 PyErr_SetString(PyExc_ValueError,
1130 "mmap length is greater than file size");
1131 return NULL;
1132 }
1133 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001134 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1135 if (m_obj == NULL) {return NULL;}
1136 m_obj->data = NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001137 m_obj->size = map_size;
1138 m_obj->pos = 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001139 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001140 m_obj->exports = 0;
1141 m_obj->offset = offset;
1142 if (fd == -1) {
1143 m_obj->fd = -1;
1144 /* Assume the caller wants to map anonymous memory.
1145 This is the same behaviour as Windows. mmap.mmap(-1, size)
1146 on both Windows and Unix map anonymous memory.
1147 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001148#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001149 /* BSD way to map anonymous memory */
1150 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001151#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001152 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001153 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001154 if (devzero == -1) {
1155 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001156 return NULL;
1157 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001158#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001159 }
1160 else {
1161 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001162 if (m_obj->fd == -1) {
1163 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001164 return NULL;
1165 }
1166 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001167
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001168 m_obj->data = mmap(NULL, map_size,
1169 prot, flags,
1170 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001171
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001172 if (devzero != -1) {
1173 close(devzero);
1174 }
1175
1176 if (m_obj->data == (char *)-1) {
1177 m_obj->data = NULL;
1178 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001179 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001180 return NULL;
1181 }
1182 m_obj->access = (access_mode)access;
1183 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001184}
1185#endif /* UNIX */
1186
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001187#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001188
1189/* A note on sizes and offsets: while the actual map size must hold in a
1190 Py_ssize_t, both the total file size and the start offset can be longer
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001191 than a Py_ssize_t, so we use long long which is always 64-bit.
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001192*/
1193
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001194static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001195new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001196{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001197 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001198 Py_ssize_t map_size;
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001199 long long offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001200 DWORD off_hi; /* upper 32 bits of offset */
1201 DWORD off_lo; /* lower 32 bits of offset */
1202 DWORD size_hi; /* upper 32 bits of size */
1203 DWORD size_lo; /* lower 32 bits of size */
Serhiy Storchakae2f92de2017-11-11 13:06:26 +02001204 const char *tagname = "";
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001205 DWORD dwErr = 0;
1206 int fileno;
1207 HANDLE fh = 0;
1208 int access = (access_mode)ACCESS_DEFAULT;
1209 DWORD flProtect, dwDesiredAccess;
1210 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001211 "tagname",
1212 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001213
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001214 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1215 &fileno, &map_size,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001216 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001217 return NULL;
1218 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001219
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001220 switch((access_mode)access) {
1221 case ACCESS_READ:
1222 flProtect = PAGE_READONLY;
1223 dwDesiredAccess = FILE_MAP_READ;
1224 break;
1225 case ACCESS_DEFAULT: case ACCESS_WRITE:
1226 flProtect = PAGE_READWRITE;
1227 dwDesiredAccess = FILE_MAP_WRITE;
1228 break;
1229 case ACCESS_COPY:
1230 flProtect = PAGE_WRITECOPY;
1231 dwDesiredAccess = FILE_MAP_COPY;
1232 break;
1233 default:
1234 return PyErr_Format(PyExc_ValueError,
1235 "mmap invalid access parameter.");
1236 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001237
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001238 if (map_size < 0) {
1239 PyErr_SetString(PyExc_OverflowError,
Miss Islington (bot)56f530e2018-03-20 23:24:41 -07001240 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001241 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001242 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001243 if (offset < 0) {
1244 PyErr_SetString(PyExc_OverflowError,
1245 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001246 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001247 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001248
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001249 /* assume -1 and 0 both mean invalid filedescriptor
1250 to 'anonymously' map memory.
1251 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1252 XXX: Should this code be added?
1253 if (fileno == 0)
1254 PyErr_WarnEx(PyExc_DeprecationWarning,
1255 "don't use 0 for anonymous memory",
1256 1);
1257 */
1258 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001259 /* Ensure that fileno is within the CRT's valid range */
Steve Dower8fc89802015-04-12 00:26:27 -04001260 _Py_BEGIN_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001261 fh = (HANDLE)_get_osfhandle(fileno);
Steve Dower8fc89802015-04-12 00:26:27 -04001262 _Py_END_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001263 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001264 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001265 return NULL;
1266 }
1267 /* Win9x appears to need us seeked to zero */
1268 lseek(fileno, 0, SEEK_SET);
1269 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001270
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001271 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1272 if (m_obj == NULL)
1273 return NULL;
1274 /* Set every field to an invalid marker, so we can safely
1275 destruct the object in the face of failure */
1276 m_obj->data = NULL;
1277 m_obj->file_handle = INVALID_HANDLE_VALUE;
1278 m_obj->map_handle = NULL;
1279 m_obj->tagname = NULL;
1280 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001281
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001282 if (fh) {
1283 /* It is necessary to duplicate the handle, so the
1284 Python code can close it on us */
1285 if (!DuplicateHandle(
1286 GetCurrentProcess(), /* source process handle */
1287 fh, /* handle to be duplicated */
1288 GetCurrentProcess(), /* target proc handle */
1289 (LPHANDLE)&m_obj->file_handle, /* result */
1290 0, /* access - ignored due to options value */
1291 FALSE, /* inherited by child processes? */
1292 DUPLICATE_SAME_ACCESS)) { /* options */
1293 dwErr = GetLastError();
1294 Py_DECREF(m_obj);
1295 PyErr_SetFromWindowsErr(dwErr);
1296 return NULL;
1297 }
1298 if (!map_size) {
1299 DWORD low,high;
1300 low = GetFileSize(fh, &high);
1301 /* low might just happen to have the value INVALID_FILE_SIZE;
1302 so we need to check the last error also. */
1303 if (low == INVALID_FILE_SIZE &&
1304 (dwErr = GetLastError()) != NO_ERROR) {
1305 Py_DECREF(m_obj);
1306 return PyErr_SetFromWindowsErr(dwErr);
1307 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001308
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001309 size = (((long long) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001310 if (size == 0) {
1311 PyErr_SetString(PyExc_ValueError,
1312 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001313 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001314 return NULL;
1315 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001316 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001317 PyErr_SetString(PyExc_ValueError,
1318 "mmap offset is greater than file size");
1319 Py_DECREF(m_obj);
1320 return NULL;
1321 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001322 if (size - offset > PY_SSIZE_T_MAX) {
1323 PyErr_SetString(PyExc_ValueError,
1324 "mmap length is too large");
1325 Py_DECREF(m_obj);
1326 return NULL;
1327 }
1328 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001329 } else {
1330 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001331 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001332 }
1333 }
1334 else {
1335 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001336 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001337 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001338
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001339 /* set the initial position */
1340 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001341
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001342 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001343 m_obj->exports = 0;
1344 /* set the tag name */
1345 if (tagname != NULL && *tagname != '\0') {
1346 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1347 if (m_obj->tagname == NULL) {
1348 PyErr_NoMemory();
1349 Py_DECREF(m_obj);
1350 return NULL;
1351 }
1352 strcpy(m_obj->tagname, tagname);
1353 }
1354 else
1355 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001356
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001357 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001358 size_hi = (DWORD)(size >> 32);
1359 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001360 off_hi = (DWORD)(offset >> 32);
1361 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001362 /* For files, it would be sufficient to pass 0 as size.
1363 For anonymous maps, we have to pass the size explicitly. */
1364 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1365 NULL,
1366 flProtect,
1367 size_hi,
1368 size_lo,
1369 m_obj->tagname);
1370 if (m_obj->map_handle != NULL) {
1371 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1372 dwDesiredAccess,
1373 off_hi,
1374 off_lo,
1375 m_obj->size);
1376 if (m_obj->data != NULL)
1377 return (PyObject *)m_obj;
1378 else {
1379 dwErr = GetLastError();
1380 CloseHandle(m_obj->map_handle);
1381 m_obj->map_handle = NULL;
1382 }
1383 } else
1384 dwErr = GetLastError();
1385 Py_DECREF(m_obj);
1386 PyErr_SetFromWindowsErr(dwErr);
1387 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001388}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001389#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001390
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001391static void
1392setint(PyObject *d, const char *name, long value)
1393{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001394 PyObject *o = PyLong_FromLong(value);
1395 if (o && PyDict_SetItemString(d, name, o) == 0) {
1396 Py_DECREF(o);
1397 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001398}
1399
Martin v. Löwis1a214512008-06-11 05:26:20 +00001400
1401static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001402 PyModuleDef_HEAD_INIT,
1403 "mmap",
1404 NULL,
1405 -1,
1406 NULL,
1407 NULL,
1408 NULL,
1409 NULL,
1410 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001411};
1412
Mark Hammond62b1ab12002-07-23 06:31:15 +00001413PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001414PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001415{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001416 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001417
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001418 if (PyType_Ready(&mmap_object_type) < 0)
1419 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001420
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001421 module = PyModule_Create(&mmapmodule);
1422 if (module == NULL)
1423 return NULL;
1424 dict = PyModule_GetDict(module);
1425 if (!dict)
1426 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001427 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001428 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001429#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001430 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431#endif
1432#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001433 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001434#endif
1435#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001436 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001437#endif
1438
1439#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001440 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001441#endif
1442#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001443 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001444#endif
1445#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001446 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001447#endif
1448#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001449 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001450#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001451#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001452 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1453 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001454#endif
1455
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001456 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001457
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001458 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001459
Justus Schwabedal5a8a84b2017-11-07 15:51:43 -05001460 setint(dict, "ACCESS_DEFAULT", ACCESS_DEFAULT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001461 setint(dict, "ACCESS_READ", ACCESS_READ);
1462 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1463 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1464 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001465}