blob: 49214a1defce899fa2f2af2d3a4a557903870d37 [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 *
656mmap_closed_get(mmap_object *self)
657{
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);
793 Py_ssize_t cur, i;
794 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000795
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000796 if (result_buf == NULL)
797 return PyErr_NoMemory();
798 for (cur = start, i = 0; i < slicelen;
799 cur += step, i++) {
800 result_buf[i] = self->data[cur];
801 }
802 result = PyBytes_FromStringAndSize(result_buf,
803 slicelen);
804 PyMem_Free(result_buf);
805 return result;
806 }
807 }
808 else {
809 PyErr_SetString(PyExc_TypeError,
810 "mmap indices must be integers");
811 return NULL;
812 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000813}
814
815static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000816mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000817{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000818 CHECK_VALID(NULL);
819 PyErr_SetString(PyExc_SystemError,
820 "mmaps don't support concatenation");
821 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000822}
823
824static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000825mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000826{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000827 CHECK_VALID(NULL);
828 PyErr_SetString(PyExc_SystemError,
829 "mmaps don't support repeat operation");
830 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000831}
832
833static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000834mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000835{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000836 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000837
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000838 CHECK_VALID(-1);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700839 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000840 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
841 return -1;
842 }
843 if (v == NULL) {
844 PyErr_SetString(PyExc_TypeError,
845 "mmap object doesn't support item deletion");
846 return -1;
847 }
848 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
849 PyErr_SetString(PyExc_IndexError,
850 "mmap assignment must be length-1 bytes()");
851 return -1;
852 }
853 if (!is_writable(self))
854 return -1;
855 buf = PyBytes_AsString(v);
856 self->data[i] = buf[0];
857 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000858}
859
Thomas Woutersed03b412007-08-28 21:37:11 +0000860static int
861mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
862{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000863 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000864
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000865 if (!is_writable(self))
866 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000867
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000868 if (PyIndex_Check(item)) {
869 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
870 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000871
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000872 if (i == -1 && PyErr_Occurred())
873 return -1;
874 if (i < 0)
875 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700876 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000877 PyErr_SetString(PyExc_IndexError,
878 "mmap index out of range");
879 return -1;
880 }
881 if (value == NULL) {
882 PyErr_SetString(PyExc_TypeError,
883 "mmap doesn't support item deletion");
884 return -1;
885 }
886 if (!PyIndex_Check(value)) {
887 PyErr_SetString(PyExc_TypeError,
888 "mmap item value must be an int");
889 return -1;
890 }
891 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
892 if (v == -1 && PyErr_Occurred())
893 return -1;
894 if (v < 0 || v > 255) {
895 PyErr_SetString(PyExc_ValueError,
896 "mmap item value must be "
897 "in range(0, 256)");
898 return -1;
899 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000900 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000901 return 0;
902 }
903 else if (PySlice_Check(item)) {
904 Py_ssize_t start, stop, step, slicelen;
905 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000906
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300907 if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000908 return -1;
909 }
Serhiy Storchakab879fe82017-04-08 09:53:51 +0300910 slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000911 if (value == NULL) {
912 PyErr_SetString(PyExc_TypeError,
913 "mmap object doesn't support slice deletion");
914 return -1;
915 }
916 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
917 return -1;
918 if (vbuf.len != slicelen) {
919 PyErr_SetString(PyExc_IndexError,
920 "mmap slice assignment is wrong size");
921 PyBuffer_Release(&vbuf);
922 return -1;
923 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000924
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000925 if (slicelen == 0) {
926 }
927 else if (step == 1) {
928 memcpy(self->data + start, vbuf.buf, slicelen);
929 }
930 else {
931 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000932
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000933 for (cur = start, i = 0;
934 i < slicelen;
935 cur += step, i++)
936 {
937 self->data[cur] = ((char *)vbuf.buf)[i];
938 }
939 }
940 PyBuffer_Release(&vbuf);
941 return 0;
942 }
943 else {
944 PyErr_SetString(PyExc_TypeError,
945 "mmap indices must be integer");
946 return -1;
947 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000948}
949
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000950static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +0100951 (lenfunc)mmap_length, /*sq_length*/
952 (binaryfunc)mmap_concat, /*sq_concat*/
953 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
954 (ssizeargfunc)mmap_item, /*sq_item*/
955 0, /*sq_slice*/
956 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
957 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000958};
959
Thomas Woutersed03b412007-08-28 21:37:11 +0000960static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000961 (lenfunc)mmap_length,
962 (binaryfunc)mmap_subscript,
963 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000964};
965
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000966static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000967 (getbufferproc)mmap_buffer_getbuf,
968 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000969};
970
Georg Brandl86def6c2008-01-21 20:36:10 +0000971static PyObject *
972new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
973
Christian Heimese1c98112008-01-21 11:20:28 +0000974PyDoc_STRVAR(mmap_doc,
975"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
976\n\
977Maps length bytes from the file specified by the file handle fileno,\n\
978and returns a mmap object. If length is larger than the current size\n\
979of the file, the file is extended to contain length bytes. If length\n\
980is 0, the maximum length of the map is the current size of the file,\n\
981except that if the file is empty Windows raises an exception (you cannot\n\
982create an empty mapping on Windows).\n\
983\n\
984Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
985\n\
986Maps length bytes from the file specified by the file descriptor fileno,\n\
987and returns a mmap object. If length is 0, the maximum length of the map\n\
988will be the current size of the file when mmap is called.\n\
989flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
990private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000991object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000992that's shared with all other processes mapping the same areas of the file.\n\
993The default value is MAP_SHARED.\n\
994\n\
995To map anonymous memory, pass -1 as the fileno (both versions).");
996
997
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000998static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000999 PyVarObject_HEAD_INIT(NULL, 0)
1000 "mmap.mmap", /* tp_name */
1001 sizeof(mmap_object), /* tp_size */
1002 0, /* tp_itemsize */
1003 /* methods */
1004 (destructor) mmap_object_dealloc, /* tp_dealloc */
1005 0, /* tp_print */
1006 0, /* tp_getattr */
1007 0, /* tp_setattr */
1008 0, /* tp_reserved */
1009 0, /* tp_repr */
1010 0, /* tp_as_number */
1011 &mmap_as_sequence, /*tp_as_sequence*/
1012 &mmap_as_mapping, /*tp_as_mapping*/
1013 0, /*tp_hash*/
1014 0, /*tp_call*/
1015 0, /*tp_str*/
1016 PyObject_GenericGetAttr, /*tp_getattro*/
1017 0, /*tp_setattro*/
1018 &mmap_as_buffer, /*tp_as_buffer*/
Stefan Krah23186992012-03-06 15:37:36 +01001019 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001020 mmap_doc, /*tp_doc*/
1021 0, /* tp_traverse */
1022 0, /* tp_clear */
1023 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001024 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001025 0, /* tp_iter */
1026 0, /* tp_iternext */
1027 mmap_object_methods, /* tp_methods */
1028 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001029 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001030 0, /* tp_base */
1031 0, /* tp_dict */
1032 0, /* tp_descr_get */
1033 0, /* tp_descr_set */
1034 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001035 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001036 PyType_GenericAlloc, /* tp_alloc */
1037 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001038 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001039};
1040
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001041
Tim Petersec0a5f02006-02-16 23:47:20 +00001042#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001043#ifdef HAVE_LARGEFILE_SUPPORT
1044#define _Py_PARSE_OFF_T "L"
1045#else
1046#define _Py_PARSE_OFF_T "l"
1047#endif
1048
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001049static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001050new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001051{
Victor Stinnere134a7f2015-03-30 10:09:31 +02001052 struct _Py_stat_struct status;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001053 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001054 Py_ssize_t map_size;
1055 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001056 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1057 int devzero = -1;
1058 int access = (int)ACCESS_DEFAULT;
1059 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001060 "flags", "prot",
1061 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001062
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001063 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1064 &fd, &map_size, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001065 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001066 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001067 if (map_size < 0) {
1068 PyErr_SetString(PyExc_OverflowError,
1069 "memory mapped length must be postiive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001070 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001071 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001072 if (offset < 0) {
1073 PyErr_SetString(PyExc_OverflowError,
1074 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001075 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001076 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001077
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001078 if ((access != (int)ACCESS_DEFAULT) &&
1079 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1080 return PyErr_Format(PyExc_ValueError,
1081 "mmap can't specify both access and flags, prot.");
1082 switch ((access_mode)access) {
1083 case ACCESS_READ:
1084 flags = MAP_SHARED;
1085 prot = PROT_READ;
1086 break;
1087 case ACCESS_WRITE:
1088 flags = MAP_SHARED;
1089 prot = PROT_READ | PROT_WRITE;
1090 break;
1091 case ACCESS_COPY:
1092 flags = MAP_PRIVATE;
1093 prot = PROT_READ | PROT_WRITE;
1094 break;
1095 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001096 /* map prot to access type */
1097 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1098 /* ACCESS_DEFAULT */
1099 }
1100 else if (prot & PROT_WRITE) {
1101 access = ACCESS_WRITE;
1102 }
1103 else {
1104 access = ACCESS_READ;
1105 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001106 break;
1107 default:
1108 return PyErr_Format(PyExc_ValueError,
1109 "mmap invalid access parameter.");
1110 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001111
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001112#ifdef __APPLE__
1113 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1114 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1115 if (fd != -1)
1116 (void)fcntl(fd, F_FULLFSYNC);
1117#endif
Victor Stinnere134a7f2015-03-30 10:09:31 +02001118 if (fd != -1 && _Py_fstat_noraise(fd, &status) == 0
1119 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001120 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001121 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001122 PyErr_SetString(PyExc_ValueError,
1123 "cannot mmap an empty file");
1124 return NULL;
1125 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001126 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001127 PyErr_SetString(PyExc_ValueError,
1128 "mmap offset is greater than file size");
1129 return NULL;
1130 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001131 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001132 PyErr_SetString(PyExc_ValueError,
1133 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001134 return NULL;
1135 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001136 map_size = (Py_ssize_t) (status.st_size - offset);
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001137 } else if (offset > status.st_size || status.st_size - offset < map_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001138 PyErr_SetString(PyExc_ValueError,
1139 "mmap length is greater than file size");
1140 return NULL;
1141 }
1142 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001143 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1144 if (m_obj == NULL) {return NULL;}
1145 m_obj->data = NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001146 m_obj->size = map_size;
1147 m_obj->pos = 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001148 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001149 m_obj->exports = 0;
1150 m_obj->offset = offset;
1151 if (fd == -1) {
1152 m_obj->fd = -1;
1153 /* Assume the caller wants to map anonymous memory.
1154 This is the same behaviour as Windows. mmap.mmap(-1, size)
1155 on both Windows and Unix map anonymous memory.
1156 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001157#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001158 /* BSD way to map anonymous memory */
1159 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001160#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001161 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001162 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001163 if (devzero == -1) {
1164 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001165 return NULL;
1166 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001167#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001168 }
1169 else {
1170 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001171 if (m_obj->fd == -1) {
1172 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001173 return NULL;
1174 }
1175 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001176
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001177 m_obj->data = mmap(NULL, map_size,
1178 prot, flags,
1179 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001180
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001181 if (devzero != -1) {
1182 close(devzero);
1183 }
1184
1185 if (m_obj->data == (char *)-1) {
1186 m_obj->data = NULL;
1187 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001188 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001189 return NULL;
1190 }
1191 m_obj->access = (access_mode)access;
1192 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001193}
1194#endif /* UNIX */
1195
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001196#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001197
1198/* A note on sizes and offsets: while the actual map size must hold in a
1199 Py_ssize_t, both the total file size and the start offset can be longer
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001200 than a Py_ssize_t, so we use long long which is always 64-bit.
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001201*/
1202
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001203static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001204new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001205{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001206 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001207 Py_ssize_t map_size;
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001208 long long offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001209 DWORD off_hi; /* upper 32 bits of offset */
1210 DWORD off_lo; /* lower 32 bits of offset */
1211 DWORD size_hi; /* upper 32 bits of size */
1212 DWORD size_lo; /* lower 32 bits of size */
1213 char *tagname = "";
1214 DWORD dwErr = 0;
1215 int fileno;
1216 HANDLE fh = 0;
1217 int access = (access_mode)ACCESS_DEFAULT;
1218 DWORD flProtect, dwDesiredAccess;
1219 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001220 "tagname",
1221 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001222
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001223 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1224 &fileno, &map_size,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001225 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001226 return NULL;
1227 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001228
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001229 switch((access_mode)access) {
1230 case ACCESS_READ:
1231 flProtect = PAGE_READONLY;
1232 dwDesiredAccess = FILE_MAP_READ;
1233 break;
1234 case ACCESS_DEFAULT: case ACCESS_WRITE:
1235 flProtect = PAGE_READWRITE;
1236 dwDesiredAccess = FILE_MAP_WRITE;
1237 break;
1238 case ACCESS_COPY:
1239 flProtect = PAGE_WRITECOPY;
1240 dwDesiredAccess = FILE_MAP_COPY;
1241 break;
1242 default:
1243 return PyErr_Format(PyExc_ValueError,
1244 "mmap invalid access parameter.");
1245 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001246
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001247 if (map_size < 0) {
1248 PyErr_SetString(PyExc_OverflowError,
1249 "memory mapped length must be postiive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001250 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001251 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001252 if (offset < 0) {
1253 PyErr_SetString(PyExc_OverflowError,
1254 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001255 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001256 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001257
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001258 /* assume -1 and 0 both mean invalid filedescriptor
1259 to 'anonymously' map memory.
1260 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1261 XXX: Should this code be added?
1262 if (fileno == 0)
1263 PyErr_WarnEx(PyExc_DeprecationWarning,
1264 "don't use 0 for anonymous memory",
1265 1);
1266 */
1267 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001268 /* Ensure that fileno is within the CRT's valid range */
Steve Dower8fc89802015-04-12 00:26:27 -04001269 _Py_BEGIN_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001270 fh = (HANDLE)_get_osfhandle(fileno);
Steve Dower8fc89802015-04-12 00:26:27 -04001271 _Py_END_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001272 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001273 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001274 return NULL;
1275 }
1276 /* Win9x appears to need us seeked to zero */
1277 lseek(fileno, 0, SEEK_SET);
1278 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001279
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001280 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1281 if (m_obj == NULL)
1282 return NULL;
1283 /* Set every field to an invalid marker, so we can safely
1284 destruct the object in the face of failure */
1285 m_obj->data = NULL;
1286 m_obj->file_handle = INVALID_HANDLE_VALUE;
1287 m_obj->map_handle = NULL;
1288 m_obj->tagname = NULL;
1289 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001291 if (fh) {
1292 /* It is necessary to duplicate the handle, so the
1293 Python code can close it on us */
1294 if (!DuplicateHandle(
1295 GetCurrentProcess(), /* source process handle */
1296 fh, /* handle to be duplicated */
1297 GetCurrentProcess(), /* target proc handle */
1298 (LPHANDLE)&m_obj->file_handle, /* result */
1299 0, /* access - ignored due to options value */
1300 FALSE, /* inherited by child processes? */
1301 DUPLICATE_SAME_ACCESS)) { /* options */
1302 dwErr = GetLastError();
1303 Py_DECREF(m_obj);
1304 PyErr_SetFromWindowsErr(dwErr);
1305 return NULL;
1306 }
1307 if (!map_size) {
1308 DWORD low,high;
1309 low = GetFileSize(fh, &high);
1310 /* low might just happen to have the value INVALID_FILE_SIZE;
1311 so we need to check the last error also. */
1312 if (low == INVALID_FILE_SIZE &&
1313 (dwErr = GetLastError()) != NO_ERROR) {
1314 Py_DECREF(m_obj);
1315 return PyErr_SetFromWindowsErr(dwErr);
1316 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001317
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001318 size = (((long long) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001319 if (size == 0) {
1320 PyErr_SetString(PyExc_ValueError,
1321 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001322 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001323 return NULL;
1324 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001325 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001326 PyErr_SetString(PyExc_ValueError,
1327 "mmap offset is greater than file size");
1328 Py_DECREF(m_obj);
1329 return NULL;
1330 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001331 if (size - offset > PY_SSIZE_T_MAX) {
1332 PyErr_SetString(PyExc_ValueError,
1333 "mmap length is too large");
1334 Py_DECREF(m_obj);
1335 return NULL;
1336 }
1337 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001338 } else {
1339 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001340 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001341 }
1342 }
1343 else {
1344 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001345 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001346 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001347
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001348 /* set the initial position */
1349 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001350
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001351 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001352 m_obj->exports = 0;
1353 /* set the tag name */
1354 if (tagname != NULL && *tagname != '\0') {
1355 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1356 if (m_obj->tagname == NULL) {
1357 PyErr_NoMemory();
1358 Py_DECREF(m_obj);
1359 return NULL;
1360 }
1361 strcpy(m_obj->tagname, tagname);
1362 }
1363 else
1364 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001365
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001366 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001367 size_hi = (DWORD)(size >> 32);
1368 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001369 off_hi = (DWORD)(offset >> 32);
1370 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001371 /* For files, it would be sufficient to pass 0 as size.
1372 For anonymous maps, we have to pass the size explicitly. */
1373 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1374 NULL,
1375 flProtect,
1376 size_hi,
1377 size_lo,
1378 m_obj->tagname);
1379 if (m_obj->map_handle != NULL) {
1380 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1381 dwDesiredAccess,
1382 off_hi,
1383 off_lo,
1384 m_obj->size);
1385 if (m_obj->data != NULL)
1386 return (PyObject *)m_obj;
1387 else {
1388 dwErr = GetLastError();
1389 CloseHandle(m_obj->map_handle);
1390 m_obj->map_handle = NULL;
1391 }
1392 } else
1393 dwErr = GetLastError();
1394 Py_DECREF(m_obj);
1395 PyErr_SetFromWindowsErr(dwErr);
1396 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001397}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001398#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001399
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001400static void
1401setint(PyObject *d, const char *name, long value)
1402{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001403 PyObject *o = PyLong_FromLong(value);
1404 if (o && PyDict_SetItemString(d, name, o) == 0) {
1405 Py_DECREF(o);
1406 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001407}
1408
Martin v. Löwis1a214512008-06-11 05:26:20 +00001409
1410static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001411 PyModuleDef_HEAD_INIT,
1412 "mmap",
1413 NULL,
1414 -1,
1415 NULL,
1416 NULL,
1417 NULL,
1418 NULL,
1419 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001420};
1421
Mark Hammond62b1ab12002-07-23 06:31:15 +00001422PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001423PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001424{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001425 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001426
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001427 if (PyType_Ready(&mmap_object_type) < 0)
1428 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001429
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001430 module = PyModule_Create(&mmapmodule);
1431 if (module == NULL)
1432 return NULL;
1433 dict = PyModule_GetDict(module);
1434 if (!dict)
1435 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001436 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001437 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001438#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001439 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001440#endif
1441#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001442 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001443#endif
1444#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001445 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001446#endif
1447
1448#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001449 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001450#endif
1451#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001452 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001453#endif
1454#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001455 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001456#endif
1457#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001458 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001459#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001460#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001461 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1462 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001463#endif
1464
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001465 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001466
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001467 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001468
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001469 setint(dict, "ACCESS_READ", ACCESS_READ);
1470 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1471 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1472 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001473}