blob: bafdce3b1f84282a51c203aa319be1455862e57d [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
Travis E. Oliphant8feafab2007-10-23 02:40:56 +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>
23
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000024#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000025#define UNIX
Benjamin Petersond7a4f9e2015-08-02 12:15:30 -070026# ifdef HAVE_FCNTL_H
Victor Stinner112d48a2011-05-03 14:36:36 +020027# include <fcntl.h>
Benjamin Petersond7a4f9e2015-08-02 12:15:30 -070028# endif /* HAVE_FCNTL_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#endif
30
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000031#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000032#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000033static int
34my_getpagesize(void)
35{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000036 SYSTEM_INFO si;
37 GetSystemInfo(&si);
38 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000039}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000040
41static int
42my_getallocationgranularity (void)
43{
44
Antoine Pitrouc83ea132010-05-09 14:46:46 +000045 SYSTEM_INFO si;
46 GetSystemInfo(&si);
47 return si.dwAllocationGranularity;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000048}
49
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#endif
51
52#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000053#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000054#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000055
Fred Drake145f96e2000-10-01 17:50:46 +000056#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
57static int
58my_getpagesize(void)
59{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000060 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000061}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000062
63#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000064#else
65#define my_getpagesize getpagesize
66#endif
67
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000068#endif /* UNIX */
69
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <string.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000071
72#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000073#include <sys/types.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000074#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000075
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000076/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000077#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
78# define MAP_ANONYMOUS MAP_ANON
79#endif
80
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000081static PyObject *mmap_module_error;
82
Tim Peters5ebfd362001-11-13 23:11:19 +000083typedef enum
84{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000085 ACCESS_DEFAULT,
86 ACCESS_READ,
87 ACCESS_WRITE,
88 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000089} access_mode;
90
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000091typedef struct {
Antoine Pitrouc83ea132010-05-09 14:46:46 +000092 PyObject_HEAD
93 char * data;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -070094 Py_ssize_t size;
95 Py_ssize_t pos; /* relative to offset */
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +000096#ifdef MS_WINDOWS
97 PY_LONG_LONG offset;
98#else
99 off_t offset;
100#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000101
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000102#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +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 Pitrouc83ea132010-05-09 14:46:46 +0000109 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000111
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000112 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000113} mmap_object;
114
Tim Peters5ebfd362001-11-13 23:11:19 +0000115
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000116static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000117mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000118{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000119#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000120 if (m_obj->data != NULL)
121 UnmapViewOfFile (m_obj->data);
122 if (m_obj->map_handle != NULL)
123 CloseHandle (m_obj->map_handle);
124 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
125 CloseHandle (m_obj->file_handle);
126 if (m_obj->tagname)
127 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000128#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000129
130#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000131 if (m_obj->fd >= 0)
132 (void) close(m_obj->fd);
133 if (m_obj->data!=NULL) {
R. David Murray2a4b3fc2010-12-11 02:13:04 +0000134 if (m_obj->access != ACCESS_READ && m_obj->access != ACCESS_COPY)
135 msync(m_obj->data, m_obj->size, MS_SYNC);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000136 munmap(m_obj->data, m_obj->size);
137 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138#endif /* UNIX */
139
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000140 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000141}
142
143static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000144mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000145{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000146#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000147 /* For each resource we maintain, we need to check
148 the value is valid, and if so, free the resource
149 and set the member value to an invalid value so
150 the dealloc does not attempt to resource clearing
151 again.
152 TODO - should we check for errors in the close operations???
153 */
154 if (self->data != NULL) {
155 UnmapViewOfFile(self->data);
156 self->data = NULL;
157 }
158 if (self->map_handle != NULL) {
159 CloseHandle(self->map_handle);
160 self->map_handle = NULL;
161 }
162 if (self->file_handle != INVALID_HANDLE_VALUE) {
163 CloseHandle(self->file_handle);
164 self->file_handle = INVALID_HANDLE_VALUE;
165 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000166#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000167
168#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000169 if (0 <= self->fd)
170 (void) close(self->fd);
171 self->fd = -1;
172 if (self->data != NULL) {
173 munmap(self->data, self->size);
174 self->data = NULL;
175 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000176#endif
177
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000178 Py_INCREF(Py_None);
179 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180}
181
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000182#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000183#define CHECK_VALID(err) \
184do { \
185 if (self->map_handle == NULL) { \
186 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
187 return err; \
188 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000189} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000190#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000191
192#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000193#define CHECK_VALID(err) \
194do { \
195 if (self->data == NULL) { \
196 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
197 return err; \
198 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000199} while (0)
200#endif /* UNIX */
201
202static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000203mmap_read_byte_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000204 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000205{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000206 CHECK_VALID(NULL);
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700207 if (self->pos >= self->size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000208 PyErr_SetString(PyExc_ValueError, "read byte out of range");
209 return NULL;
210 }
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700211 return PyString_FromStringAndSize(&self->data[self->pos++], 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000212}
213
214static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000215mmap_read_line_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000216 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217{
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700218 Py_ssize_t remaining;
219 char *start, *eol;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000220 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000221
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000222 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700224 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
225 if (!remaining)
226 return PyString_FromString("");
227 start = self->data + self->pos;
228 eol = memchr(start, '\n', remaining);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000229 if (!eol)
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700230 eol = self->data + self->size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000231 else
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700232 ++eol; /* advance past newline */
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000233 result = PyString_FromStringAndSize(start, (eol - start));
234 self->pos += (eol - start);
235 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000236}
237
238static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000239mmap_read_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000240 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241{
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700242 Py_ssize_t num_bytes, remaining;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000243 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000244
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000245 CHECK_VALID(NULL);
246 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700247 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000248
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000249 /* silently 'adjust' out-of-range requests */
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700250 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
251 if (num_bytes < 0 || num_bytes > remaining)
252 num_bytes = remaining;
253 result = PyString_FromStringAndSize(&self->data[self->pos], num_bytes);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000254 self->pos += num_bytes;
255 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000256}
257
258static PyObject *
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000259mmap_gfind(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000260 PyObject *args,
261 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000262{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000263 Py_ssize_t start = self->pos;
264 Py_ssize_t end = self->size;
265 const char *needle;
266 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000267
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000268 CHECK_VALID(NULL);
269 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
270 &needle, &len, &start, &end)) {
271 return NULL;
272 } else {
273 const char *p, *start_p, *end_p;
274 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000275
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000276 if (start < 0)
277 start += self->size;
278 if (start < 0)
279 start = 0;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700280 else if (start > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000281 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000282
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000283 if (end < 0)
284 end += self->size;
285 if (end < 0)
286 end = 0;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700287 else if (end > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000288 end = self->size;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000289
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000290 start_p = self->data + start;
291 end_p = self->data + end;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000292
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000293 for (p = (reverse ? end_p - len : start_p);
294 (p >= start_p) && (p + len <= end_p); p += sign) {
295 Py_ssize_t i;
296 for (i = 0; i < len && needle[i] == p[i]; ++i)
297 /* nothing */;
298 if (i == len) {
299 return PyInt_FromSsize_t(p - self->data);
300 }
301 }
302 return PyInt_FromLong(-1);
303 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000304}
305
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000306static PyObject *
307mmap_find_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000308 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000309{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000310 return mmap_gfind(self, args, 0);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000311}
312
313static PyObject *
314mmap_rfind_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000315 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000316{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000317 return mmap_gfind(self, args, 1);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000318}
319
Tim Petersec0a5f02006-02-16 23:47:20 +0000320static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000321is_writeable(mmap_object *self)
322{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000323 if (self->access != ACCESS_READ)
324 return 1;
325 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
326 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000327}
328
Tim Petersec0a5f02006-02-16 23:47:20 +0000329static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000330is_resizeable(mmap_object *self)
331{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000332 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
333 return 1;
334 PyErr_Format(PyExc_TypeError,
335 "mmap can't resize a readonly or copy-on-write memory map.");
336 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000337}
338
339
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000340static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000341mmap_write_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000342 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000343{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000344 Py_ssize_t length;
345 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000346
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000347 CHECK_VALID(NULL);
348 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
349 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000350
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000351 if (!is_writeable(self))
352 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000353
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700354 if (self->pos > self->size || self->size - self->pos < length) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000355 PyErr_SetString(PyExc_ValueError, "data out of range");
356 return NULL;
357 }
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700358 memcpy(&self->data[self->pos], data, length);
359 self->pos += length;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000360 Py_INCREF(Py_None);
361 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000362}
363
364static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000365mmap_write_byte_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000366 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000367{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000368 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000369
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000370 CHECK_VALID(NULL);
371 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
372 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000373
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000374 if (!is_writeable(self))
375 return NULL;
Hirokazu Yamamotof2dc8852009-02-28 10:31:54 +0000376
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000377 if (self->pos < self->size) {
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700378 self->data[self->pos++] = value;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000379 Py_INCREF(Py_None);
380 return Py_None;
381 }
382 else {
383 PyErr_SetString(PyExc_ValueError, "write byte out of range");
384 return NULL;
385 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000386}
Tim Petersec0a5f02006-02-16 23:47:20 +0000387
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000388static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000389mmap_size_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000390 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000391{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000392 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000393
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000394#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000395 if (self->file_handle != INVALID_HANDLE_VALUE) {
396 DWORD low,high;
397 PY_LONG_LONG size;
398 low = GetFileSize(self->file_handle, &high);
399 if (low == INVALID_FILE_SIZE) {
400 /* It might be that the function appears to have failed,
401 when indeed its size equals INVALID_FILE_SIZE */
402 DWORD error = GetLastError();
403 if (error != NO_ERROR)
404 return PyErr_SetFromWindowsErr(error);
405 }
406 if (!high && low < LONG_MAX)
407 return PyInt_FromLong((long)low);
408 size = (((PY_LONG_LONG)high)<<32) + low;
409 return PyLong_FromLongLong(size);
410 } else {
411 return PyInt_FromSsize_t(self->size);
412 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000413#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000414
415#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000416 {
417 struct stat buf;
418 if (-1 == fstat(self->fd, &buf)) {
419 PyErr_SetFromErrno(mmap_module_error);
420 return NULL;
421 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +0000422#ifdef HAVE_LARGEFILE_SUPPORT
423 return PyLong_FromLongLong(buf.st_size);
424#else
425 return PyInt_FromLong(buf.st_size);
426#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000427 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000428#endif /* UNIX */
429}
430
431/* This assumes that you want the entire file mapped,
432 / and when recreating the map will make the new file
433 / have the new size
434 /
435 / Is this really necessary? This could easily be done
436 / from python by just closing and re-opening with the
437 / new size?
438 */
439
440static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000441mmap_resize_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000442 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000443{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000444 Py_ssize_t new_size;
445 CHECK_VALID(NULL);
446 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
447 !is_resizeable(self)) {
448 return NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700449 }
450 if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) {
451 PyErr_SetString(PyExc_ValueError, "new size out of range");
452 return NULL;
453 }
454
455 {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000456#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000457 DWORD dwErrCode = 0;
458 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
459 /* First, unmap the file view */
460 UnmapViewOfFile(self->data);
461 self->data = NULL;
462 /* Close the mapping object */
463 CloseHandle(self->map_handle);
464 self->map_handle = NULL;
465 /* Move to the desired EOF position */
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000466 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
467 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
468 off_hi = (DWORD)(self->offset >> 32);
469 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000470 SetFilePointer(self->file_handle,
471 newSizeLow, &newSizeHigh, FILE_BEGIN);
472 /* Change the size of the file */
473 SetEndOfFile(self->file_handle);
474 /* Create another mapping object and remap the file view */
475 self->map_handle = CreateFileMapping(
476 self->file_handle,
477 NULL,
478 PAGE_READWRITE,
479 0,
480 0,
481 self->tagname);
482 if (self->map_handle != NULL) {
483 self->data = (char *) MapViewOfFile(self->map_handle,
484 FILE_MAP_WRITE,
485 off_hi,
486 off_lo,
487 new_size);
488 if (self->data != NULL) {
489 self->size = new_size;
490 Py_INCREF(Py_None);
491 return Py_None;
492 } else {
493 dwErrCode = GetLastError();
494 CloseHandle(self->map_handle);
495 self->map_handle = NULL;
496 }
497 } else {
498 dwErrCode = GetLastError();
499 }
500 PyErr_SetFromWindowsErr(dwErrCode);
501 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000502#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000503
504#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000505#ifndef HAVE_MREMAP
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000506 PyErr_SetString(PyExc_SystemError,
507 "mmap: resizing not available--no mremap()");
508 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000509#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000510 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000511
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700512 if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000513 PyErr_SetFromErrno(mmap_module_error);
514 return NULL;
515 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000516
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000517#ifdef MREMAP_MAYMOVE
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000518 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000519#else
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700520#if defined(__NetBSD__)
521 newmap = mremap(self->data, self->size, self->data, new_size, 0);
522#else
523 newmap = mremap(self->data, self->size, new_size, 0);
524#endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000525#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000526 if (newmap == (void *)-1)
527 {
528 PyErr_SetFromErrno(mmap_module_error);
529 return NULL;
530 }
531 self->data = newmap;
532 self->size = new_size;
533 Py_INCREF(Py_None);
534 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000535#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000536#endif /* UNIX */
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000537 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000538}
539
540static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000541mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000542{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000543 CHECK_VALID(NULL);
544 return PyInt_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000545}
546
547static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000548mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000549{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000550 Py_ssize_t offset = 0;
551 Py_ssize_t size = self->size;
552 CHECK_VALID(NULL);
553 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
554 return NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700555 if (size < 0 || offset < 0 || self->size - offset < size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000556 PyErr_SetString(PyExc_ValueError, "flush values out of range");
557 return NULL;
558 }
R. David Murray2a4b3fc2010-12-11 02:13:04 +0000559
560 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
561 return PyLong_FromLong(0);
562
Neal Norwitz448654f2008-01-27 07:36:03 +0000563#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000564 return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
Neal Norwitz448654f2008-01-27 07:36:03 +0000565#elif defined(UNIX)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000566 /* XXX semantics of return value? */
567 /* XXX flags for msync? */
568 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
569 PyErr_SetFromErrno(mmap_module_error);
570 return NULL;
571 }
572 return PyInt_FromLong(0);
Neal Norwitz448654f2008-01-27 07:36:03 +0000573#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000574 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
575 return NULL;
Neal Norwitz448654f2008-01-27 07:36:03 +0000576#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000577}
578
579static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000580mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000581{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000582 Py_ssize_t dist;
583 int how=0;
584 CHECK_VALID(NULL);
585 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
586 return NULL;
587 else {
Benjamin Petersonbc4bdbd2016-10-05 23:26:24 -0700588 Py_ssize_t where;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000589 switch (how) {
590 case 0: /* relative to start */
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000591 where = dist;
592 break;
593 case 1: /* relative to current position */
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700594 if (PY_SSIZE_T_MAX - self->pos < dist)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000595 goto onoutofrange;
596 where = self->pos + dist;
597 break;
598 case 2: /* relative to end */
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700599 if (PY_SSIZE_T_MAX - self->size < dist)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000600 goto onoutofrange;
601 where = self->size + dist;
602 break;
603 default:
604 PyErr_SetString(PyExc_ValueError, "unknown seek type");
605 return NULL;
606 }
Benjamin Petersonbc4bdbd2016-10-05 23:26:24 -0700607 if (where > self->size || where < 0)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000608 goto onoutofrange;
609 self->pos = where;
610 Py_INCREF(Py_None);
611 return Py_None;
612 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000613
Tim Peters5ebfd362001-11-13 23:11:19 +0000614 onoutofrange:
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000615 PyErr_SetString(PyExc_ValueError, "seek out of range");
616 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000617}
618
619static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000620mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000621{
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700622 Py_ssize_t dest, src, cnt;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000623 CHECK_VALID(NULL);
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700624 if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000625 !is_writeable(self)) {
626 return NULL;
627 } else {
628 /* bounds check the values */
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700629 if (dest < 0 || src < 0 || cnt < 0)
630 goto bounds;
631 if (self->size - dest < cnt || self->size - src < cnt)
632 goto bounds;
633
634 memmove(&self->data[dest], &self->data[src], cnt);
635
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000636 Py_INCREF(Py_None);
637 return Py_None;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700638
639 bounds:
640 PyErr_SetString(PyExc_ValueError,
641 "source, destination, or count out of range");
642 return NULL;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000643 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000644}
645
Serhiy Storchakacbee9722014-08-19 17:03:42 +0300646#ifdef MS_WINDOWS
647static PyObject *
648mmap__sizeof__method(mmap_object *self, void *unused)
649{
650 Py_ssize_t res;
651
Serhiy Storchakac06a6d02015-12-19 20:07:48 +0200652 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchakacbee9722014-08-19 17:03:42 +0300653 if (self->tagname)
654 res += strlen(self->tagname) + 1;
655 return PyLong_FromSsize_t(res);
656}
657#endif
658
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000659static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000660 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
661 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
662 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
663 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
664 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
665 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
666 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
667 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
668 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
669 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
670 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
671 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
672 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
673 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Serhiy Storchakacbee9722014-08-19 17:03:42 +0300674#ifdef MS_WINDOWS
675 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
676#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000677 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000678};
679
680/* Functions for treating an mmap'ed file as a buffer */
681
Martin v. Löwis18e16552006-02-15 17:27:45 +0000682static Py_ssize_t
683mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000684{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000685 CHECK_VALID(-1);
686 if (index != 0) {
687 PyErr_SetString(PyExc_SystemError,
688 "Accessing non-existent mmap segment");
689 return -1;
690 }
691 *ptr = self->data;
692 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000693}
694
Martin v. Löwis18e16552006-02-15 17:27:45 +0000695static Py_ssize_t
696mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000697{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000698 CHECK_VALID(-1);
699 if (index != 0) {
700 PyErr_SetString(PyExc_SystemError,
701 "Accessing non-existent mmap segment");
702 return -1;
703 }
704 if (!is_writeable(self))
705 return -1;
706 *ptr = self->data;
707 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000708}
709
Martin v. Löwis18e16552006-02-15 17:27:45 +0000710static Py_ssize_t
711mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000712{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000713 CHECK_VALID(-1);
714 if (lenp)
715 *lenp = self->size;
716 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000717}
718
Martin v. Löwis18e16552006-02-15 17:27:45 +0000719static Py_ssize_t
720mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000721{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000722 if (index != 0) {
723 PyErr_SetString(PyExc_SystemError,
724 "accessing non-existent buffer segment");
725 return -1;
726 }
727 *ptr = (const char *)self->data;
728 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000729}
730
Martin v. Löwis18e16552006-02-15 17:27:45 +0000731static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000732mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000733{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000734 CHECK_VALID(-1);
735 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000736}
737
738static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000739mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000740{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000741 CHECK_VALID(NULL);
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700742 if (i < 0 || i >= self->size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000743 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
744 return NULL;
745 }
746 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000747}
748
749static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000750mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000751{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000752 CHECK_VALID(NULL);
753 if (ilow < 0)
754 ilow = 0;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700755 else if (ilow > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000756 ilow = self->size;
757 if (ihigh < 0)
758 ihigh = 0;
759 if (ihigh < ilow)
760 ihigh = ilow;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700761 else if (ihigh > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000762 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000763
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000764 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000765}
766
767static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000768mmap_subscript(mmap_object *self, PyObject *item)
769{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000770 CHECK_VALID(NULL);
771 if (PyIndex_Check(item)) {
772 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
773 if (i == -1 && PyErr_Occurred())
774 return NULL;
775 if (i < 0)
776 i += self->size;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700777 if (i < 0 || i >= self->size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000778 PyErr_SetString(PyExc_IndexError,
779 "mmap index out of range");
780 return NULL;
781 }
782 return PyString_FromStringAndSize(self->data + i, 1);
783 }
784 else if (PySlice_Check(item)) {
785 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000786
Serhiy Storchaka5e793212017-04-15 20:11:12 +0300787 if (_PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000788 return NULL;
789 }
Serhiy Storchakae41390a2017-04-08 11:48:57 +0300790 slicelen = _PySlice_AdjustIndices(self->size, &start, &stop, step);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000791
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000792 if (slicelen <= 0)
793 return PyString_FromStringAndSize("", 0);
794 else if (step == 1)
795 return PyString_FromStringAndSize(self->data + start,
796 slicelen);
797 else {
798 char *result_buf = (char *)PyMem_Malloc(slicelen);
799 Py_ssize_t cur, i;
800 PyObject *result;
801
802 if (result_buf == NULL)
803 return PyErr_NoMemory();
804 for (cur = start, i = 0; i < slicelen;
805 cur += step, i++) {
806 result_buf[i] = self->data[cur];
807 }
808 result = PyString_FromStringAndSize(result_buf,
809 slicelen);
810 PyMem_Free(result_buf);
811 return result;
812 }
813 }
814 else {
815 PyErr_SetString(PyExc_TypeError,
816 "mmap indices must be integers");
817 return NULL;
818 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000819}
820
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000821static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000822mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000823{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000824 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000825
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000826 CHECK_VALID(-1);
827 if (ilow < 0)
828 ilow = 0;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700829 else if (ilow > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000830 ilow = self->size;
831 if (ihigh < 0)
832 ihigh = 0;
833 if (ihigh < ilow)
834 ihigh = ilow;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700835 else if (ihigh > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000836 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000837
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000838 if (v == NULL) {
839 PyErr_SetString(PyExc_TypeError,
840 "mmap object doesn't support slice deletion");
841 return -1;
842 }
843 if (! (PyString_Check(v)) ) {
844 PyErr_SetString(PyExc_IndexError,
845 "mmap slice assignment must be a string");
846 return -1;
847 }
848 if (PyString_Size(v) != (ihigh - ilow)) {
849 PyErr_SetString(PyExc_IndexError,
850 "mmap slice assignment is wrong size");
851 return -1;
852 }
853 if (!is_writeable(self))
854 return -1;
855 buf = PyString_AsString(v);
856 memcpy(self->data + ilow, buf, ihigh-ilow);
857 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000858}
859
860static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000861mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000862{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000863 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000864
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000865 CHECK_VALID(-1);
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700866 if (i < 0 || i >= self->size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000867 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
868 return -1;
869 }
870 if (v == NULL) {
871 PyErr_SetString(PyExc_TypeError,
872 "mmap object doesn't support item deletion");
873 return -1;
874 }
875 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
876 PyErr_SetString(PyExc_IndexError,
877 "mmap assignment must be single-character string");
878 return -1;
879 }
880 if (!is_writeable(self))
881 return -1;
882 buf = PyString_AsString(v);
883 self->data[i] = buf[0];
884 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000885}
886
Thomas Wouters3ccec682007-08-28 15:28:19 +0000887static int
888mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
889{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000890 CHECK_VALID(-1);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000891
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000892 if (PyIndex_Check(item)) {
893 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
894 const char *buf;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000895
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000896 if (i == -1 && PyErr_Occurred())
897 return -1;
898 if (i < 0)
899 i += self->size;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700900 if (i < 0 || i >= self->size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000901 PyErr_SetString(PyExc_IndexError,
902 "mmap index out of range");
903 return -1;
904 }
905 if (value == NULL) {
906 PyErr_SetString(PyExc_TypeError,
907 "mmap object doesn't support item deletion");
908 return -1;
909 }
910 if (!PyString_Check(value) || PyString_Size(value) != 1) {
911 PyErr_SetString(PyExc_IndexError,
912 "mmap assignment must be single-character string");
913 return -1;
914 }
915 if (!is_writeable(self))
916 return -1;
917 buf = PyString_AsString(value);
918 self->data[i] = buf[0];
919 return 0;
920 }
921 else if (PySlice_Check(item)) {
922 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000923
Serhiy Storchaka5e793212017-04-15 20:11:12 +0300924 if (_PySlice_Unpack(item, &start, &stop, &step) < 0) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000925 return -1;
926 }
Serhiy Storchakae41390a2017-04-08 11:48:57 +0300927 slicelen = _PySlice_AdjustIndices(self->size, &start, &stop, step);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000928 if (value == NULL) {
929 PyErr_SetString(PyExc_TypeError,
930 "mmap object doesn't support slice deletion");
931 return -1;
932 }
933 if (!PyString_Check(value)) {
934 PyErr_SetString(PyExc_IndexError,
935 "mmap slice assignment must be a string");
936 return -1;
937 }
938 if (PyString_Size(value) != slicelen) {
939 PyErr_SetString(PyExc_IndexError,
940 "mmap slice assignment is wrong size");
941 return -1;
942 }
943 if (!is_writeable(self))
944 return -1;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000945
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000946 if (slicelen == 0)
947 return 0;
948 else if (step == 1) {
949 const char *buf = PyString_AsString(value);
950
951 if (buf == NULL)
952 return -1;
953 memcpy(self->data + start, buf, slicelen);
954 return 0;
955 }
956 else {
957 Py_ssize_t cur, i;
958 const char *buf = PyString_AsString(value);
959
960 if (buf == NULL)
961 return -1;
962 for (cur = start, i = 0; i < slicelen;
963 cur += step, i++) {
964 self->data[cur] = buf[i];
965 }
966 return 0;
967 }
968 }
969 else {
970 PyErr_SetString(PyExc_TypeError,
971 "mmap indices must be integer");
972 return -1;
973 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000974}
975
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000976static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000977 (lenfunc)mmap_length, /*sq_length*/
Serhiy Storchaka3014d6e2018-06-05 19:51:37 +0300978 0, /*sq_concat*/
979 0, /*sq_repeat*/
980 (ssizeargfunc)mmap_item, /*sq_item*/
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000981 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
982 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
983 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000984};
985
Thomas Wouters3ccec682007-08-28 15:28:19 +0000986static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000987 (lenfunc)mmap_length,
988 (binaryfunc)mmap_subscript,
989 (objobjargproc)mmap_ass_subscript,
Thomas Wouters3ccec682007-08-28 15:28:19 +0000990};
991
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000992static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000993 (readbufferproc)mmap_buffer_getreadbuf,
994 (writebufferproc)mmap_buffer_getwritebuf,
995 (segcountproc)mmap_buffer_getsegcount,
996 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000997};
998
Georg Brandl845c4032008-01-21 14:16:46 +0000999static PyObject *
1000new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1001
Georg Brandlef928022008-01-20 14:50:05 +00001002PyDoc_STRVAR(mmap_doc,
1003"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1004\n\
1005Maps length bytes from the file specified by the file handle fileno,\n\
1006and returns a mmap object. If length is larger than the current size\n\
1007of the file, the file is extended to contain length bytes. If length\n\
1008is 0, the maximum length of the map is the current size of the file,\n\
1009except that if the file is empty Windows raises an exception (you cannot\n\
1010create an empty mapping on Windows).\n\
1011\n\
1012Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1013\n\
1014Maps length bytes from the file specified by the file descriptor fileno,\n\
1015and returns a mmap object. If length is 0, the maximum length of the map\n\
1016will be the current size of the file when mmap is called.\n\
1017flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1018private copy-on-write mapping, so changes to the contents of the mmap\n\
Thomas Heller66260992008-08-19 17:47:13 +00001019object will be private to this process, and MAP_SHARED creates a mapping\n\
Georg Brandlef928022008-01-20 14:50:05 +00001020that's shared with all other processes mapping the same areas of the file.\n\
1021The default value is MAP_SHARED.\n\
1022\n\
1023To map anonymous memory, pass -1 as the fileno (both versions).");
1024
1025
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001026static PyTypeObject mmap_object_type = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001027 PyVarObject_HEAD_INIT(NULL, 0)
1028 "mmap.mmap", /* tp_name */
1029 sizeof(mmap_object), /* tp_size */
1030 0, /* tp_itemsize */
1031 /* methods */
1032 (destructor) mmap_object_dealloc, /* tp_dealloc */
1033 0, /* tp_print */
1034 0, /* tp_getattr */
1035 0, /* tp_setattr */
1036 0, /* tp_compare */
1037 0, /* tp_repr */
1038 0, /* tp_as_number */
1039 &mmap_as_sequence, /*tp_as_sequence*/
1040 &mmap_as_mapping, /*tp_as_mapping*/
1041 0, /*tp_hash*/
1042 0, /*tp_call*/
1043 0, /*tp_str*/
1044 PyObject_GenericGetAttr, /*tp_getattro*/
1045 0, /*tp_setattro*/
1046 &mmap_as_buffer, /*tp_as_buffer*/
1047 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
1048 mmap_doc, /*tp_doc*/
1049 0, /* tp_traverse */
1050 0, /* tp_clear */
1051 0, /* tp_richcompare */
1052 0, /* tp_weaklistoffset */
1053 0, /* tp_iter */
1054 0, /* tp_iternext */
1055 mmap_object_methods, /* tp_methods */
1056 0, /* tp_members */
1057 0, /* tp_getset */
1058 0, /* tp_base */
1059 0, /* tp_dict */
1060 0, /* tp_descr_get */
1061 0, /* tp_descr_set */
1062 0, /* tp_dictoffset */
1063 0, /* tp_init */
1064 PyType_GenericAlloc, /* tp_alloc */
1065 new_mmap_object, /* tp_new */
1066 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001067};
1068
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001069
Tim Petersec0a5f02006-02-16 23:47:20 +00001070#ifdef UNIX
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001071#ifdef HAVE_LARGEFILE_SUPPORT
1072#define _Py_PARSE_OFF_T "L"
1073#else
1074#define _Py_PARSE_OFF_T "l"
1075#endif
1076
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001077static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001078new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001079{
Neal Norwitzb5673922002-09-05 21:48:07 +00001080#ifdef HAVE_FSTAT
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001081 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001082#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001083 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001084 Py_ssize_t map_size;
1085 off_t offset = 0;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001086 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1087 int devzero = -1;
1088 int access = (int)ACCESS_DEFAULT;
1089 static char *keywords[] = {"fileno", "length",
1090 "flags", "prot",
1091 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001092
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001093 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1094 &fd, &map_size, &flags, &prot,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001095 &access, &offset))
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001096 return NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001097 if (map_size < 0) {
1098 PyErr_SetString(PyExc_OverflowError,
Miss Islington (bot)7ee09362018-03-20 23:55:44 -07001099 "memory mapped length must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001100 return NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001101 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001102 if (offset < 0) {
1103 PyErr_SetString(PyExc_OverflowError,
1104 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001105 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001106 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001107
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001108 if ((access != (int)ACCESS_DEFAULT) &&
1109 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1110 return PyErr_Format(PyExc_ValueError,
1111 "mmap can't specify both access and flags, prot.");
1112 switch ((access_mode)access) {
1113 case ACCESS_READ:
1114 flags = MAP_SHARED;
1115 prot = PROT_READ;
1116 break;
1117 case ACCESS_WRITE:
1118 flags = MAP_SHARED;
1119 prot = PROT_READ | PROT_WRITE;
1120 break;
1121 case ACCESS_COPY:
1122 flags = MAP_PRIVATE;
1123 prot = PROT_READ | PROT_WRITE;
1124 break;
1125 case ACCESS_DEFAULT:
Antoine Pitroud6f3a3e2011-03-06 02:03:34 +01001126 /* map prot to access type */
1127 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1128 /* ACCESS_DEFAULT */
1129 }
1130 else if (prot & PROT_WRITE) {
1131 access = ACCESS_WRITE;
1132 }
1133 else {
1134 access = ACCESS_READ;
1135 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001136 break;
1137 default:
1138 return PyErr_Format(PyExc_ValueError,
1139 "mmap invalid access parameter.");
1140 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001141
Victor Stinner112d48a2011-05-03 14:36:36 +02001142#ifdef __APPLE__
1143 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1144 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1145 if (fd != -1)
1146 (void)fcntl(fd, F_FULLFSYNC);
1147#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001148#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001149# ifdef __VMS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001150 /* on OpenVMS we must ensure that all bytes are written to the file */
1151 if (fd != -1) {
1152 fsync(fd);
1153 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001154# endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001155 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1156 if (map_size == 0) {
Jesus Cea8b54d6d2012-09-10 00:22:39 +02001157 if (st.st_size == 0) {
1158 PyErr_SetString(PyExc_ValueError,
1159 "cannot mmap an empty file");
1160 return NULL;
1161 }
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001162 if (offset >= st.st_size) {
1163 PyErr_SetString(PyExc_ValueError,
1164 "mmap offset is greater than file size");
1165 return NULL;
1166 }
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001167 if (st.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001168 PyErr_SetString(PyExc_ValueError,
1169 "mmap length is too large");
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001170 return NULL;
1171 }
1172 map_size = (Py_ssize_t) (st.st_size - offset);
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001173 } else if (offset > st.st_size || st.st_size - offset < map_size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001174 PyErr_SetString(PyExc_ValueError,
1175 "mmap length is greater than file size");
1176 return NULL;
1177 }
1178 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001179#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001180 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1181 if (m_obj == NULL) {return NULL;}
1182 m_obj->data = NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001183 m_obj->size = map_size;
1184 m_obj->pos = 0;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001185 m_obj->offset = offset;
1186 if (fd == -1) {
1187 m_obj->fd = -1;
1188 /* Assume the caller wants to map anonymous memory.
1189 This is the same behaviour as Windows. mmap.mmap(-1, size)
1190 on both Windows and Unix map anonymous memory.
1191 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001192#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001193 /* BSD way to map anonymous memory */
1194 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001195#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001196 /* SVR4 method to map anonymous memory is to open /dev/zero */
1197 fd = devzero = open("/dev/zero", O_RDWR);
1198 if (devzero == -1) {
1199 Py_DECREF(m_obj);
1200 PyErr_SetFromErrno(mmap_module_error);
1201 return NULL;
1202 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001203#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001204 } else {
1205 m_obj->fd = dup(fd);
1206 if (m_obj->fd == -1) {
1207 Py_DECREF(m_obj);
1208 PyErr_SetFromErrno(mmap_module_error);
1209 return NULL;
1210 }
1211 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001212
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001213 m_obj->data = mmap(NULL, map_size,
1214 prot, flags,
1215 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001216
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001217 if (devzero != -1) {
1218 close(devzero);
1219 }
1220
1221 if (m_obj->data == (char *)-1) {
1222 m_obj->data = NULL;
1223 Py_DECREF(m_obj);
1224 PyErr_SetFromErrno(mmap_module_error);
1225 return NULL;
1226 }
1227 m_obj->access = (access_mode)access;
1228 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001229}
1230#endif /* UNIX */
1231
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001232#ifdef MS_WINDOWS
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001233
1234/* A note on sizes and offsets: while the actual map size must hold in a
1235 Py_ssize_t, both the total file size and the start offset can be longer
1236 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1237*/
1238
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001239static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001240new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001241{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001242 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001243 Py_ssize_t map_size;
1244 PY_LONG_LONG offset = 0, size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001245 DWORD off_hi; /* upper 32 bits of offset */
1246 DWORD off_lo; /* lower 32 bits of offset */
1247 DWORD size_hi; /* upper 32 bits of size */
1248 DWORD size_lo; /* lower 32 bits of size */
1249 char *tagname = "";
1250 DWORD dwErr = 0;
1251 int fileno;
1252 HANDLE fh = 0;
1253 int access = (access_mode)ACCESS_DEFAULT;
1254 DWORD flProtect, dwDesiredAccess;
1255 static char *keywords[] = { "fileno", "length",
1256 "tagname",
1257 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001258
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001259 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1260 &fileno, &map_size,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001261 &tagname, &access, &offset)) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001262 return NULL;
1263 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001264
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001265 switch((access_mode)access) {
1266 case ACCESS_READ:
1267 flProtect = PAGE_READONLY;
1268 dwDesiredAccess = FILE_MAP_READ;
1269 break;
1270 case ACCESS_DEFAULT: case ACCESS_WRITE:
1271 flProtect = PAGE_READWRITE;
1272 dwDesiredAccess = FILE_MAP_WRITE;
1273 break;
1274 case ACCESS_COPY:
1275 flProtect = PAGE_WRITECOPY;
1276 dwDesiredAccess = FILE_MAP_COPY;
1277 break;
1278 default:
1279 return PyErr_Format(PyExc_ValueError,
1280 "mmap invalid access parameter.");
1281 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001282
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001283 if (map_size < 0) {
1284 PyErr_SetString(PyExc_OverflowError,
Miss Islington (bot)7ee09362018-03-20 23:55:44 -07001285 "memory mapped length must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001286 return NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001287 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001288 if (offset < 0) {
1289 PyErr_SetString(PyExc_OverflowError,
1290 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001291 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001292 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001293
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001294 /* assume -1 and 0 both mean invalid filedescriptor
1295 to 'anonymously' map memory.
1296 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1297 XXX: Should this code be added?
1298 if (fileno == 0)
1299 PyErr_Warn(PyExc_DeprecationWarning,
1300 "don't use 0 for anonymous memory");
1301 */
1302 if (fileno != -1 && fileno != 0) {
Brian Curtinba6c08e2010-08-01 15:47:53 +00001303 /* Ensure that fileno is within the CRT's valid range */
1304 if (_PyVerify_fd(fileno) == 0) {
1305 PyErr_SetFromErrno(mmap_module_error);
1306 return NULL;
1307 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001308 fh = (HANDLE)_get_osfhandle(fileno);
1309 if (fh==(HANDLE)-1) {
1310 PyErr_SetFromErrno(mmap_module_error);
1311 return NULL;
1312 }
1313 /* Win9x appears to need us seeked to zero */
1314 lseek(fileno, 0, SEEK_SET);
1315 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001316
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001317 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1318 if (m_obj == NULL)
1319 return NULL;
1320 /* Set every field to an invalid marker, so we can safely
1321 destruct the object in the face of failure */
1322 m_obj->data = NULL;
1323 m_obj->file_handle = INVALID_HANDLE_VALUE;
1324 m_obj->map_handle = NULL;
1325 m_obj->tagname = NULL;
1326 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001327
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001328 if (fh) {
1329 /* It is necessary to duplicate the handle, so the
1330 Python code can close it on us */
1331 if (!DuplicateHandle(
1332 GetCurrentProcess(), /* source process handle */
1333 fh, /* handle to be duplicated */
1334 GetCurrentProcess(), /* target proc handle */
1335 (LPHANDLE)&m_obj->file_handle, /* result */
1336 0, /* access - ignored due to options value */
1337 FALSE, /* inherited by child processes? */
1338 DUPLICATE_SAME_ACCESS)) { /* options */
1339 dwErr = GetLastError();
1340 Py_DECREF(m_obj);
1341 PyErr_SetFromWindowsErr(dwErr);
1342 return NULL;
1343 }
1344 if (!map_size) {
1345 DWORD low,high;
1346 low = GetFileSize(fh, &high);
1347 /* low might just happen to have the value INVALID_FILE_SIZE;
1348 so we need to check the last error also. */
1349 if (low == INVALID_FILE_SIZE &&
1350 (dwErr = GetLastError()) != NO_ERROR) {
1351 Py_DECREF(m_obj);
1352 return PyErr_SetFromWindowsErr(dwErr);
1353 }
1354
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001355 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea20f0ea12012-09-10 22:45:47 +02001356 if (size == 0) {
1357 PyErr_SetString(PyExc_ValueError,
1358 "cannot mmap an empty file");
Jesus Cea8e03b4c2012-09-10 22:57:34 +02001359 Py_DECREF(m_obj);
Jesus Cea20f0ea12012-09-10 22:45:47 +02001360 return NULL;
1361 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001362 if (offset >= size) {
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001363 PyErr_SetString(PyExc_ValueError,
1364 "mmap offset is greater than file size");
1365 Py_DECREF(m_obj);
1366 return NULL;
1367 }
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001368 if (size - offset > PY_SSIZE_T_MAX) {
1369 PyErr_SetString(PyExc_ValueError,
1370 "mmap length is too large");
1371 Py_DECREF(m_obj);
1372 return NULL;
1373 }
1374 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001375 } else {
1376 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001377 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001378 }
1379 }
1380 else {
1381 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001382 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001383 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001384
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001385 /* set the initial position */
1386 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001387
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001388 /* set the tag name */
1389 if (tagname != NULL && *tagname != '\0') {
1390 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1391 if (m_obj->tagname == NULL) {
1392 PyErr_NoMemory();
1393 Py_DECREF(m_obj);
1394 return NULL;
1395 }
1396 strcpy(m_obj->tagname, tagname);
1397 }
1398 else
1399 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001400
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001401 m_obj->access = (access_mode)access;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001402 size_hi = (DWORD)(size >> 32);
1403 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001404 off_hi = (DWORD)(offset >> 32);
1405 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001406 /* For files, it would be sufficient to pass 0 as size.
1407 For anonymous maps, we have to pass the size explicitly. */
1408 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1409 NULL,
1410 flProtect,
1411 size_hi,
1412 size_lo,
1413 m_obj->tagname);
1414 if (m_obj->map_handle != NULL) {
1415 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1416 dwDesiredAccess,
1417 off_hi,
1418 off_lo,
1419 m_obj->size);
1420 if (m_obj->data != NULL)
1421 return (PyObject *)m_obj;
1422 else {
1423 dwErr = GetLastError();
1424 CloseHandle(m_obj->map_handle);
1425 m_obj->map_handle = NULL;
1426 }
1427 } else
1428 dwErr = GetLastError();
1429 Py_DECREF(m_obj);
1430 PyErr_SetFromWindowsErr(dwErr);
1431 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001432}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001433#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001434
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001435static void
1436setint(PyObject *d, const char *name, long value)
1437{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001438 PyObject *o = PyInt_FromLong(value);
1439 if (o && PyDict_SetItemString(d, name, o) == 0) {
1440 Py_DECREF(o);
1441 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001442}
1443
Mark Hammond62b1ab12002-07-23 06:31:15 +00001444PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001445initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001446{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001447 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001448
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001449 if (PyType_Ready(&mmap_object_type) < 0)
1450 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001451
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001452 module = Py_InitModule("mmap", NULL);
1453 if (module == NULL)
1454 return;
1455 dict = PyModule_GetDict(module);
1456 if (!dict)
1457 return;
1458 mmap_module_error = PyErr_NewException("mmap.error",
1459 PyExc_EnvironmentError , NULL);
1460 if (mmap_module_error == NULL)
1461 return;
1462 PyDict_SetItemString(dict, "error", mmap_module_error);
1463 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001464#ifdef PROT_EXEC
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001465 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001466#endif
1467#ifdef PROT_READ
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001468 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001469#endif
1470#ifdef PROT_WRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001471 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001472#endif
1473
1474#ifdef MAP_SHARED
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001475 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001476#endif
1477#ifdef MAP_PRIVATE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001478 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001479#endif
1480#ifdef MAP_DENYWRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001481 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001482#endif
1483#ifdef MAP_EXECUTABLE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001484 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001485#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001486#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001487 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1488 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001489#endif
1490
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001491 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001492
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001493 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001494
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001495 setint(dict, "ACCESS_READ", ACCESS_READ);
1496 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1497 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001498}