blob: 9afb79fe2ce05289da74a7711c89ecb8db68a7fc [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;
Miss Islington (bot)56cce1c2018-03-20 12:16:30 -07001053 int fstat_result = -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001054 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001055 Py_ssize_t map_size;
1056 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001057 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1058 int devzero = -1;
1059 int access = (int)ACCESS_DEFAULT;
1060 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001061 "flags", "prot",
1062 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001063
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001064 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1065 &fd, &map_size, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001066 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001067 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001068 if (map_size < 0) {
1069 PyErr_SetString(PyExc_OverflowError,
Miss Islington (bot)56f530e2018-03-20 23:24:41 -07001070 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001071 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001072 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001073 if (offset < 0) {
1074 PyErr_SetString(PyExc_OverflowError,
1075 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001076 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001077 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001078
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001079 if ((access != (int)ACCESS_DEFAULT) &&
1080 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1081 return PyErr_Format(PyExc_ValueError,
1082 "mmap can't specify both access and flags, prot.");
1083 switch ((access_mode)access) {
1084 case ACCESS_READ:
1085 flags = MAP_SHARED;
1086 prot = PROT_READ;
1087 break;
1088 case ACCESS_WRITE:
1089 flags = MAP_SHARED;
1090 prot = PROT_READ | PROT_WRITE;
1091 break;
1092 case ACCESS_COPY:
1093 flags = MAP_PRIVATE;
1094 prot = PROT_READ | PROT_WRITE;
1095 break;
1096 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001097 /* map prot to access type */
1098 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1099 /* ACCESS_DEFAULT */
1100 }
1101 else if (prot & PROT_WRITE) {
1102 access = ACCESS_WRITE;
1103 }
1104 else {
1105 access = ACCESS_READ;
1106 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001107 break;
1108 default:
1109 return PyErr_Format(PyExc_ValueError,
1110 "mmap invalid access parameter.");
1111 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001112
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001113#ifdef __APPLE__
1114 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1115 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1116 if (fd != -1)
1117 (void)fcntl(fd, F_FULLFSYNC);
1118#endif
Miss Islington (bot)56cce1c2018-03-20 12:16:30 -07001119
1120 if (fd != -1) {
1121 Py_BEGIN_ALLOW_THREADS
1122 fstat_result = _Py_fstat_noraise(fd, &status);
1123 Py_END_ALLOW_THREADS
1124 }
1125
1126 if (fd != -1 && fstat_result == 0 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001127 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001128 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001129 PyErr_SetString(PyExc_ValueError,
1130 "cannot mmap an empty file");
1131 return NULL;
1132 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001133 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001134 PyErr_SetString(PyExc_ValueError,
1135 "mmap offset is greater than file size");
1136 return NULL;
1137 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001138 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001139 PyErr_SetString(PyExc_ValueError,
1140 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001141 return NULL;
1142 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001143 map_size = (Py_ssize_t) (status.st_size - offset);
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001144 } else if (offset > status.st_size || status.st_size - offset < map_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001145 PyErr_SetString(PyExc_ValueError,
1146 "mmap length is greater than file size");
1147 return NULL;
1148 }
1149 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001150 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1151 if (m_obj == NULL) {return NULL;}
1152 m_obj->data = NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001153 m_obj->size = map_size;
1154 m_obj->pos = 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001155 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001156 m_obj->exports = 0;
1157 m_obj->offset = offset;
1158 if (fd == -1) {
1159 m_obj->fd = -1;
1160 /* Assume the caller wants to map anonymous memory.
1161 This is the same behaviour as Windows. mmap.mmap(-1, size)
1162 on both Windows and Unix map anonymous memory.
1163 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001164#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001165 /* BSD way to map anonymous memory */
1166 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001167#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001168 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001169 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001170 if (devzero == -1) {
1171 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001172 return NULL;
1173 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001174#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001175 }
1176 else {
1177 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001178 if (m_obj->fd == -1) {
1179 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001180 return NULL;
1181 }
1182 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001183
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001184 m_obj->data = mmap(NULL, map_size,
1185 prot, flags,
1186 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001187
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001188 if (devzero != -1) {
1189 close(devzero);
1190 }
1191
1192 if (m_obj->data == (char *)-1) {
1193 m_obj->data = NULL;
1194 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001195 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001196 return NULL;
1197 }
1198 m_obj->access = (access_mode)access;
1199 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001200}
1201#endif /* UNIX */
1202
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001203#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001204
1205/* A note on sizes and offsets: while the actual map size must hold in a
1206 Py_ssize_t, both the total file size and the start offset can be longer
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001207 than a Py_ssize_t, so we use long long which is always 64-bit.
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001208*/
1209
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001210static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001211new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001212{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001213 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001214 Py_ssize_t map_size;
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001215 long long offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001216 DWORD off_hi; /* upper 32 bits of offset */
1217 DWORD off_lo; /* lower 32 bits of offset */
1218 DWORD size_hi; /* upper 32 bits of size */
1219 DWORD size_lo; /* lower 32 bits of size */
Serhiy Storchakae2f92de2017-11-11 13:06:26 +02001220 const char *tagname = "";
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001221 DWORD dwErr = 0;
1222 int fileno;
1223 HANDLE fh = 0;
1224 int access = (access_mode)ACCESS_DEFAULT;
1225 DWORD flProtect, dwDesiredAccess;
1226 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001227 "tagname",
1228 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001229
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001230 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1231 &fileno, &map_size,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001232 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001233 return NULL;
1234 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001235
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001236 switch((access_mode)access) {
1237 case ACCESS_READ:
1238 flProtect = PAGE_READONLY;
1239 dwDesiredAccess = FILE_MAP_READ;
1240 break;
1241 case ACCESS_DEFAULT: case ACCESS_WRITE:
1242 flProtect = PAGE_READWRITE;
1243 dwDesiredAccess = FILE_MAP_WRITE;
1244 break;
1245 case ACCESS_COPY:
1246 flProtect = PAGE_WRITECOPY;
1247 dwDesiredAccess = FILE_MAP_COPY;
1248 break;
1249 default:
1250 return PyErr_Format(PyExc_ValueError,
1251 "mmap invalid access parameter.");
1252 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001253
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001254 if (map_size < 0) {
1255 PyErr_SetString(PyExc_OverflowError,
Miss Islington (bot)56f530e2018-03-20 23:24:41 -07001256 "memory mapped length must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001257 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001258 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001259 if (offset < 0) {
1260 PyErr_SetString(PyExc_OverflowError,
1261 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001262 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001263 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001264
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001265 /* assume -1 and 0 both mean invalid filedescriptor
1266 to 'anonymously' map memory.
1267 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1268 XXX: Should this code be added?
1269 if (fileno == 0)
1270 PyErr_WarnEx(PyExc_DeprecationWarning,
1271 "don't use 0 for anonymous memory",
1272 1);
1273 */
1274 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001275 /* Ensure that fileno is within the CRT's valid range */
Steve Dower8fc89802015-04-12 00:26:27 -04001276 _Py_BEGIN_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001277 fh = (HANDLE)_get_osfhandle(fileno);
Steve Dower8fc89802015-04-12 00:26:27 -04001278 _Py_END_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001279 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001280 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001281 return NULL;
1282 }
1283 /* Win9x appears to need us seeked to zero */
1284 lseek(fileno, 0, SEEK_SET);
1285 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001286
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001287 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1288 if (m_obj == NULL)
1289 return NULL;
1290 /* Set every field to an invalid marker, so we can safely
1291 destruct the object in the face of failure */
1292 m_obj->data = NULL;
1293 m_obj->file_handle = INVALID_HANDLE_VALUE;
1294 m_obj->map_handle = NULL;
1295 m_obj->tagname = NULL;
1296 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001297
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001298 if (fh) {
1299 /* It is necessary to duplicate the handle, so the
1300 Python code can close it on us */
1301 if (!DuplicateHandle(
1302 GetCurrentProcess(), /* source process handle */
1303 fh, /* handle to be duplicated */
1304 GetCurrentProcess(), /* target proc handle */
1305 (LPHANDLE)&m_obj->file_handle, /* result */
1306 0, /* access - ignored due to options value */
1307 FALSE, /* inherited by child processes? */
1308 DUPLICATE_SAME_ACCESS)) { /* options */
1309 dwErr = GetLastError();
1310 Py_DECREF(m_obj);
1311 PyErr_SetFromWindowsErr(dwErr);
1312 return NULL;
1313 }
1314 if (!map_size) {
1315 DWORD low,high;
1316 low = GetFileSize(fh, &high);
1317 /* low might just happen to have the value INVALID_FILE_SIZE;
1318 so we need to check the last error also. */
1319 if (low == INVALID_FILE_SIZE &&
1320 (dwErr = GetLastError()) != NO_ERROR) {
1321 Py_DECREF(m_obj);
1322 return PyErr_SetFromWindowsErr(dwErr);
1323 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001324
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001325 size = (((long long) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001326 if (size == 0) {
1327 PyErr_SetString(PyExc_ValueError,
1328 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001329 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001330 return NULL;
1331 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001332 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001333 PyErr_SetString(PyExc_ValueError,
1334 "mmap offset is greater than file size");
1335 Py_DECREF(m_obj);
1336 return NULL;
1337 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001338 if (size - offset > PY_SSIZE_T_MAX) {
1339 PyErr_SetString(PyExc_ValueError,
1340 "mmap length is too large");
1341 Py_DECREF(m_obj);
1342 return NULL;
1343 }
1344 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001345 } else {
1346 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001347 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001348 }
1349 }
1350 else {
1351 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001352 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001353 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001354
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001355 /* set the initial position */
1356 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001357
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001358 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001359 m_obj->exports = 0;
1360 /* set the tag name */
1361 if (tagname != NULL && *tagname != '\0') {
1362 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1363 if (m_obj->tagname == NULL) {
1364 PyErr_NoMemory();
1365 Py_DECREF(m_obj);
1366 return NULL;
1367 }
1368 strcpy(m_obj->tagname, tagname);
1369 }
1370 else
1371 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001372
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001373 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001374 size_hi = (DWORD)(size >> 32);
1375 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001376 off_hi = (DWORD)(offset >> 32);
1377 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001378 /* For files, it would be sufficient to pass 0 as size.
1379 For anonymous maps, we have to pass the size explicitly. */
1380 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1381 NULL,
1382 flProtect,
1383 size_hi,
1384 size_lo,
1385 m_obj->tagname);
1386 if (m_obj->map_handle != NULL) {
1387 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1388 dwDesiredAccess,
1389 off_hi,
1390 off_lo,
1391 m_obj->size);
1392 if (m_obj->data != NULL)
1393 return (PyObject *)m_obj;
1394 else {
1395 dwErr = GetLastError();
1396 CloseHandle(m_obj->map_handle);
1397 m_obj->map_handle = NULL;
1398 }
1399 } else
1400 dwErr = GetLastError();
1401 Py_DECREF(m_obj);
1402 PyErr_SetFromWindowsErr(dwErr);
1403 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001404}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001405#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001406
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001407static void
1408setint(PyObject *d, const char *name, long value)
1409{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001410 PyObject *o = PyLong_FromLong(value);
1411 if (o && PyDict_SetItemString(d, name, o) == 0) {
1412 Py_DECREF(o);
1413 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001414}
1415
Martin v. Löwis1a214512008-06-11 05:26:20 +00001416
1417static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001418 PyModuleDef_HEAD_INIT,
1419 "mmap",
1420 NULL,
1421 -1,
1422 NULL,
1423 NULL,
1424 NULL,
1425 NULL,
1426 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001427};
1428
Mark Hammond62b1ab12002-07-23 06:31:15 +00001429PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001430PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001432 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001433
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001434 if (PyType_Ready(&mmap_object_type) < 0)
1435 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001436
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001437 module = PyModule_Create(&mmapmodule);
1438 if (module == NULL)
1439 return NULL;
1440 dict = PyModule_GetDict(module);
1441 if (!dict)
1442 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001443 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001444 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001445#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001446 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001447#endif
1448#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001449 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001450#endif
1451#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001452 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001453#endif
1454
1455#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001456 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001457#endif
1458#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001459 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001460#endif
1461#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001462 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001463#endif
1464#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001465 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001466#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001467#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001468 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1469 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001470#endif
1471
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001472 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001473
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001474 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001475
Justus Schwabedal5a8a84b2017-11-07 15:51:43 -05001476 setint(dict, "ACCESS_DEFAULT", ACCESS_DEFAULT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001477 setint(dict, "ACCESS_READ", ACCESS_READ);
1478 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1479 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1480 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001481}