blob: 297bb074ce6aed4e81519cfc41757ad5b19e1a47 [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 {
588 size_t where;
589 switch (how) {
590 case 0: /* relative to start */
591 if (dist < 0)
592 goto onoutofrange;
593 where = dist;
594 break;
595 case 1: /* relative to current position */
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700596 if (PY_SSIZE_T_MAX - self->pos < dist)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000597 goto onoutofrange;
598 where = self->pos + dist;
599 break;
600 case 2: /* relative to end */
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700601 if (PY_SSIZE_T_MAX - self->size < dist)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000602 goto onoutofrange;
603 where = self->size + dist;
604 break;
605 default:
606 PyErr_SetString(PyExc_ValueError, "unknown seek type");
607 return NULL;
608 }
609 if (where > self->size)
610 goto onoutofrange;
611 self->pos = where;
612 Py_INCREF(Py_None);
613 return Py_None;
614 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000615
Tim Peters5ebfd362001-11-13 23:11:19 +0000616 onoutofrange:
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000617 PyErr_SetString(PyExc_ValueError, "seek out of range");
618 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000619}
620
621static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000622mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000623{
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700624 Py_ssize_t dest, src, cnt;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000625 CHECK_VALID(NULL);
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700626 if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000627 !is_writeable(self)) {
628 return NULL;
629 } else {
630 /* bounds check the values */
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700631 if (dest < 0 || src < 0 || cnt < 0)
632 goto bounds;
633 if (self->size - dest < cnt || self->size - src < cnt)
634 goto bounds;
635
636 memmove(&self->data[dest], &self->data[src], cnt);
637
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000638 Py_INCREF(Py_None);
639 return Py_None;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700640
641 bounds:
642 PyErr_SetString(PyExc_ValueError,
643 "source, destination, or count out of range");
644 return NULL;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000645 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000646}
647
Serhiy Storchakacbee9722014-08-19 17:03:42 +0300648#ifdef MS_WINDOWS
649static PyObject *
650mmap__sizeof__method(mmap_object *self, void *unused)
651{
652 Py_ssize_t res;
653
Serhiy Storchakac06a6d02015-12-19 20:07:48 +0200654 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchakacbee9722014-08-19 17:03:42 +0300655 if (self->tagname)
656 res += strlen(self->tagname) + 1;
657 return PyLong_FromSsize_t(res);
658}
659#endif
660
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000661static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000662 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
663 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
664 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
665 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
666 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
667 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
668 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
669 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
670 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
671 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
672 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
673 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
674 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
675 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Serhiy Storchakacbee9722014-08-19 17:03:42 +0300676#ifdef MS_WINDOWS
677 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
678#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000679 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000680};
681
682/* Functions for treating an mmap'ed file as a buffer */
683
Martin v. Löwis18e16552006-02-15 17:27:45 +0000684static Py_ssize_t
685mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000686{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000687 CHECK_VALID(-1);
688 if (index != 0) {
689 PyErr_SetString(PyExc_SystemError,
690 "Accessing non-existent mmap segment");
691 return -1;
692 }
693 *ptr = self->data;
694 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000695}
696
Martin v. Löwis18e16552006-02-15 17:27:45 +0000697static Py_ssize_t
698mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000699{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000700 CHECK_VALID(-1);
701 if (index != 0) {
702 PyErr_SetString(PyExc_SystemError,
703 "Accessing non-existent mmap segment");
704 return -1;
705 }
706 if (!is_writeable(self))
707 return -1;
708 *ptr = self->data;
709 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000710}
711
Martin v. Löwis18e16552006-02-15 17:27:45 +0000712static Py_ssize_t
713mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000714{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000715 CHECK_VALID(-1);
716 if (lenp)
717 *lenp = self->size;
718 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000719}
720
Martin v. Löwis18e16552006-02-15 17:27:45 +0000721static Py_ssize_t
722mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000723{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000724 if (index != 0) {
725 PyErr_SetString(PyExc_SystemError,
726 "accessing non-existent buffer segment");
727 return -1;
728 }
729 *ptr = (const char *)self->data;
730 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000731}
732
Martin v. Löwis18e16552006-02-15 17:27:45 +0000733static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000734mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000735{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000736 CHECK_VALID(-1);
737 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000738}
739
740static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000741mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000742{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000743 CHECK_VALID(NULL);
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700744 if (i < 0 || i >= self->size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000745 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
746 return NULL;
747 }
748 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000749}
750
751static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000752mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000753{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000754 CHECK_VALID(NULL);
755 if (ilow < 0)
756 ilow = 0;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700757 else if (ilow > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000758 ilow = self->size;
759 if (ihigh < 0)
760 ihigh = 0;
761 if (ihigh < ilow)
762 ihigh = ilow;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700763 else if (ihigh > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000764 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000765
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000766 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000767}
768
769static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000770mmap_subscript(mmap_object *self, PyObject *item)
771{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000772 CHECK_VALID(NULL);
773 if (PyIndex_Check(item)) {
774 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
775 if (i == -1 && PyErr_Occurred())
776 return NULL;
777 if (i < 0)
778 i += self->size;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700779 if (i < 0 || i >= self->size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000780 PyErr_SetString(PyExc_IndexError,
781 "mmap index out of range");
782 return NULL;
783 }
784 return PyString_FromStringAndSize(self->data + i, 1);
785 }
786 else if (PySlice_Check(item)) {
787 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000788
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000789 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
790 &start, &stop, &step, &slicelen) < 0) {
791 return NULL;
792 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000793
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000794 if (slicelen <= 0)
795 return PyString_FromStringAndSize("", 0);
796 else if (step == 1)
797 return PyString_FromStringAndSize(self->data + start,
798 slicelen);
799 else {
800 char *result_buf = (char *)PyMem_Malloc(slicelen);
801 Py_ssize_t cur, i;
802 PyObject *result;
803
804 if (result_buf == NULL)
805 return PyErr_NoMemory();
806 for (cur = start, i = 0; i < slicelen;
807 cur += step, i++) {
808 result_buf[i] = self->data[cur];
809 }
810 result = PyString_FromStringAndSize(result_buf,
811 slicelen);
812 PyMem_Free(result_buf);
813 return result;
814 }
815 }
816 else {
817 PyErr_SetString(PyExc_TypeError,
818 "mmap indices must be integers");
819 return NULL;
820 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000821}
822
823static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000824mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000825{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000826 CHECK_VALID(NULL);
827 PyErr_SetString(PyExc_SystemError,
828 "mmaps don't support concatenation");
829 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000830}
831
832static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000833mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000834{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000835 CHECK_VALID(NULL);
836 PyErr_SetString(PyExc_SystemError,
837 "mmaps don't support repeat operation");
838 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000839}
840
841static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000842mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000843{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000844 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000845
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000846 CHECK_VALID(-1);
847 if (ilow < 0)
848 ilow = 0;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700849 else if (ilow > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000850 ilow = self->size;
851 if (ihigh < 0)
852 ihigh = 0;
853 if (ihigh < ilow)
854 ihigh = ilow;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700855 else if (ihigh > self->size)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000856 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000857
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000858 if (v == NULL) {
859 PyErr_SetString(PyExc_TypeError,
860 "mmap object doesn't support slice deletion");
861 return -1;
862 }
863 if (! (PyString_Check(v)) ) {
864 PyErr_SetString(PyExc_IndexError,
865 "mmap slice assignment must be a string");
866 return -1;
867 }
868 if (PyString_Size(v) != (ihigh - ilow)) {
869 PyErr_SetString(PyExc_IndexError,
870 "mmap slice assignment is wrong size");
871 return -1;
872 }
873 if (!is_writeable(self))
874 return -1;
875 buf = PyString_AsString(v);
876 memcpy(self->data + ilow, buf, ihigh-ilow);
877 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000878}
879
880static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000881mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000882{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000883 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000884
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000885 CHECK_VALID(-1);
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700886 if (i < 0 || i >= self->size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000887 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
888 return -1;
889 }
890 if (v == NULL) {
891 PyErr_SetString(PyExc_TypeError,
892 "mmap object doesn't support item deletion");
893 return -1;
894 }
895 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
896 PyErr_SetString(PyExc_IndexError,
897 "mmap assignment must be single-character string");
898 return -1;
899 }
900 if (!is_writeable(self))
901 return -1;
902 buf = PyString_AsString(v);
903 self->data[i] = buf[0];
904 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000905}
906
Thomas Wouters3ccec682007-08-28 15:28:19 +0000907static int
908mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
909{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000910 CHECK_VALID(-1);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000911
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000912 if (PyIndex_Check(item)) {
913 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
914 const char *buf;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000915
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000916 if (i == -1 && PyErr_Occurred())
917 return -1;
918 if (i < 0)
919 i += self->size;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -0700920 if (i < 0 || i >= self->size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000921 PyErr_SetString(PyExc_IndexError,
922 "mmap index out of range");
923 return -1;
924 }
925 if (value == NULL) {
926 PyErr_SetString(PyExc_TypeError,
927 "mmap object doesn't support item deletion");
928 return -1;
929 }
930 if (!PyString_Check(value) || PyString_Size(value) != 1) {
931 PyErr_SetString(PyExc_IndexError,
932 "mmap assignment must be single-character string");
933 return -1;
934 }
935 if (!is_writeable(self))
936 return -1;
937 buf = PyString_AsString(value);
938 self->data[i] = buf[0];
939 return 0;
940 }
941 else if (PySlice_Check(item)) {
942 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000943
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000944 if (PySlice_GetIndicesEx((PySliceObject *)item,
945 self->size, &start, &stop,
946 &step, &slicelen) < 0) {
947 return -1;
948 }
949 if (value == NULL) {
950 PyErr_SetString(PyExc_TypeError,
951 "mmap object doesn't support slice deletion");
952 return -1;
953 }
954 if (!PyString_Check(value)) {
955 PyErr_SetString(PyExc_IndexError,
956 "mmap slice assignment must be a string");
957 return -1;
958 }
959 if (PyString_Size(value) != slicelen) {
960 PyErr_SetString(PyExc_IndexError,
961 "mmap slice assignment is wrong size");
962 return -1;
963 }
964 if (!is_writeable(self))
965 return -1;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000966
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000967 if (slicelen == 0)
968 return 0;
969 else if (step == 1) {
970 const char *buf = PyString_AsString(value);
971
972 if (buf == NULL)
973 return -1;
974 memcpy(self->data + start, buf, slicelen);
975 return 0;
976 }
977 else {
978 Py_ssize_t cur, i;
979 const char *buf = PyString_AsString(value);
980
981 if (buf == NULL)
982 return -1;
983 for (cur = start, i = 0; i < slicelen;
984 cur += step, i++) {
985 self->data[cur] = buf[i];
986 }
987 return 0;
988 }
989 }
990 else {
991 PyErr_SetString(PyExc_TypeError,
992 "mmap indices must be integer");
993 return -1;
994 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000995}
996
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000997static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000998 (lenfunc)mmap_length, /*sq_length*/
999 (binaryfunc)mmap_concat, /*sq_concat*/
1000 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
1001 (ssizeargfunc)mmap_item, /*sq_item*/
1002 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
1003 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
1004 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001005};
1006
Thomas Wouters3ccec682007-08-28 15:28:19 +00001007static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001008 (lenfunc)mmap_length,
1009 (binaryfunc)mmap_subscript,
1010 (objobjargproc)mmap_ass_subscript,
Thomas Wouters3ccec682007-08-28 15:28:19 +00001011};
1012
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001013static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001014 (readbufferproc)mmap_buffer_getreadbuf,
1015 (writebufferproc)mmap_buffer_getwritebuf,
1016 (segcountproc)mmap_buffer_getsegcount,
1017 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001018};
1019
Georg Brandl845c4032008-01-21 14:16:46 +00001020static PyObject *
1021new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1022
Georg Brandlef928022008-01-20 14:50:05 +00001023PyDoc_STRVAR(mmap_doc,
1024"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1025\n\
1026Maps length bytes from the file specified by the file handle fileno,\n\
1027and returns a mmap object. If length is larger than the current size\n\
1028of the file, the file is extended to contain length bytes. If length\n\
1029is 0, the maximum length of the map is the current size of the file,\n\
1030except that if the file is empty Windows raises an exception (you cannot\n\
1031create an empty mapping on Windows).\n\
1032\n\
1033Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1034\n\
1035Maps length bytes from the file specified by the file descriptor fileno,\n\
1036and returns a mmap object. If length is 0, the maximum length of the map\n\
1037will be the current size of the file when mmap is called.\n\
1038flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1039private copy-on-write mapping, so changes to the contents of the mmap\n\
Thomas Heller66260992008-08-19 17:47:13 +00001040object will be private to this process, and MAP_SHARED creates a mapping\n\
Georg Brandlef928022008-01-20 14:50:05 +00001041that's shared with all other processes mapping the same areas of the file.\n\
1042The default value is MAP_SHARED.\n\
1043\n\
1044To map anonymous memory, pass -1 as the fileno (both versions).");
1045
1046
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001047static PyTypeObject mmap_object_type = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001048 PyVarObject_HEAD_INIT(NULL, 0)
1049 "mmap.mmap", /* tp_name */
1050 sizeof(mmap_object), /* tp_size */
1051 0, /* tp_itemsize */
1052 /* methods */
1053 (destructor) mmap_object_dealloc, /* tp_dealloc */
1054 0, /* tp_print */
1055 0, /* tp_getattr */
1056 0, /* tp_setattr */
1057 0, /* tp_compare */
1058 0, /* tp_repr */
1059 0, /* tp_as_number */
1060 &mmap_as_sequence, /*tp_as_sequence*/
1061 &mmap_as_mapping, /*tp_as_mapping*/
1062 0, /*tp_hash*/
1063 0, /*tp_call*/
1064 0, /*tp_str*/
1065 PyObject_GenericGetAttr, /*tp_getattro*/
1066 0, /*tp_setattro*/
1067 &mmap_as_buffer, /*tp_as_buffer*/
1068 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
1069 mmap_doc, /*tp_doc*/
1070 0, /* tp_traverse */
1071 0, /* tp_clear */
1072 0, /* tp_richcompare */
1073 0, /* tp_weaklistoffset */
1074 0, /* tp_iter */
1075 0, /* tp_iternext */
1076 mmap_object_methods, /* tp_methods */
1077 0, /* tp_members */
1078 0, /* tp_getset */
1079 0, /* tp_base */
1080 0, /* tp_dict */
1081 0, /* tp_descr_get */
1082 0, /* tp_descr_set */
1083 0, /* tp_dictoffset */
1084 0, /* tp_init */
1085 PyType_GenericAlloc, /* tp_alloc */
1086 new_mmap_object, /* tp_new */
1087 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088};
1089
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001090
Tim Petersec0a5f02006-02-16 23:47:20 +00001091#ifdef UNIX
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001092#ifdef HAVE_LARGEFILE_SUPPORT
1093#define _Py_PARSE_OFF_T "L"
1094#else
1095#define _Py_PARSE_OFF_T "l"
1096#endif
1097
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001098static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001099new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001100{
Neal Norwitzb5673922002-09-05 21:48:07 +00001101#ifdef HAVE_FSTAT
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001102 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001103#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001104 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001105 Py_ssize_t map_size;
1106 off_t offset = 0;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001107 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1108 int devzero = -1;
1109 int access = (int)ACCESS_DEFAULT;
1110 static char *keywords[] = {"fileno", "length",
1111 "flags", "prot",
1112 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001113
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001114 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1115 &fd, &map_size, &flags, &prot,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001116 &access, &offset))
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001117 return NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001118 if (map_size < 0) {
1119 PyErr_SetString(PyExc_OverflowError,
1120 "memory mapped length must be postiive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001121 return NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001122 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001123 if (offset < 0) {
1124 PyErr_SetString(PyExc_OverflowError,
1125 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001126 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001127 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001128
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001129 if ((access != (int)ACCESS_DEFAULT) &&
1130 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1131 return PyErr_Format(PyExc_ValueError,
1132 "mmap can't specify both access and flags, prot.");
1133 switch ((access_mode)access) {
1134 case ACCESS_READ:
1135 flags = MAP_SHARED;
1136 prot = PROT_READ;
1137 break;
1138 case ACCESS_WRITE:
1139 flags = MAP_SHARED;
1140 prot = PROT_READ | PROT_WRITE;
1141 break;
1142 case ACCESS_COPY:
1143 flags = MAP_PRIVATE;
1144 prot = PROT_READ | PROT_WRITE;
1145 break;
1146 case ACCESS_DEFAULT:
Antoine Pitroud6f3a3e2011-03-06 02:03:34 +01001147 /* map prot to access type */
1148 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1149 /* ACCESS_DEFAULT */
1150 }
1151 else if (prot & PROT_WRITE) {
1152 access = ACCESS_WRITE;
1153 }
1154 else {
1155 access = ACCESS_READ;
1156 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001157 break;
1158 default:
1159 return PyErr_Format(PyExc_ValueError,
1160 "mmap invalid access parameter.");
1161 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001162
Victor Stinner112d48a2011-05-03 14:36:36 +02001163#ifdef __APPLE__
1164 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1165 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1166 if (fd != -1)
1167 (void)fcntl(fd, F_FULLFSYNC);
1168#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001169#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001170# ifdef __VMS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001171 /* on OpenVMS we must ensure that all bytes are written to the file */
1172 if (fd != -1) {
1173 fsync(fd);
1174 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001175# endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001176 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1177 if (map_size == 0) {
Jesus Cea8b54d6d2012-09-10 00:22:39 +02001178 if (st.st_size == 0) {
1179 PyErr_SetString(PyExc_ValueError,
1180 "cannot mmap an empty file");
1181 return NULL;
1182 }
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001183 if (offset >= st.st_size) {
1184 PyErr_SetString(PyExc_ValueError,
1185 "mmap offset is greater than file size");
1186 return NULL;
1187 }
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001188 if (st.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001189 PyErr_SetString(PyExc_ValueError,
1190 "mmap length is too large");
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001191 return NULL;
1192 }
1193 map_size = (Py_ssize_t) (st.st_size - offset);
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001194 } else if (offset > st.st_size || st.st_size - offset < map_size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001195 PyErr_SetString(PyExc_ValueError,
1196 "mmap length is greater than file size");
1197 return NULL;
1198 }
1199 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001200#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001201 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1202 if (m_obj == NULL) {return NULL;}
1203 m_obj->data = NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001204 m_obj->size = map_size;
1205 m_obj->pos = 0;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001206 m_obj->offset = offset;
1207 if (fd == -1) {
1208 m_obj->fd = -1;
1209 /* Assume the caller wants to map anonymous memory.
1210 This is the same behaviour as Windows. mmap.mmap(-1, size)
1211 on both Windows and Unix map anonymous memory.
1212 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001213#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001214 /* BSD way to map anonymous memory */
1215 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001216#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001217 /* SVR4 method to map anonymous memory is to open /dev/zero */
1218 fd = devzero = open("/dev/zero", O_RDWR);
1219 if (devzero == -1) {
1220 Py_DECREF(m_obj);
1221 PyErr_SetFromErrno(mmap_module_error);
1222 return NULL;
1223 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001224#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001225 } else {
1226 m_obj->fd = dup(fd);
1227 if (m_obj->fd == -1) {
1228 Py_DECREF(m_obj);
1229 PyErr_SetFromErrno(mmap_module_error);
1230 return NULL;
1231 }
1232 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001233
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001234 m_obj->data = mmap(NULL, map_size,
1235 prot, flags,
1236 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001237
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001238 if (devzero != -1) {
1239 close(devzero);
1240 }
1241
1242 if (m_obj->data == (char *)-1) {
1243 m_obj->data = NULL;
1244 Py_DECREF(m_obj);
1245 PyErr_SetFromErrno(mmap_module_error);
1246 return NULL;
1247 }
1248 m_obj->access = (access_mode)access;
1249 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001250}
1251#endif /* UNIX */
1252
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001253#ifdef MS_WINDOWS
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001254
1255/* A note on sizes and offsets: while the actual map size must hold in a
1256 Py_ssize_t, both the total file size and the start offset can be longer
1257 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1258*/
1259
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001260static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001261new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001262{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001263 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001264 Py_ssize_t map_size;
1265 PY_LONG_LONG offset = 0, size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001266 DWORD off_hi; /* upper 32 bits of offset */
1267 DWORD off_lo; /* lower 32 bits of offset */
1268 DWORD size_hi; /* upper 32 bits of size */
1269 DWORD size_lo; /* lower 32 bits of size */
1270 char *tagname = "";
1271 DWORD dwErr = 0;
1272 int fileno;
1273 HANDLE fh = 0;
1274 int access = (access_mode)ACCESS_DEFAULT;
1275 DWORD flProtect, dwDesiredAccess;
1276 static char *keywords[] = { "fileno", "length",
1277 "tagname",
1278 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001279
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001280 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1281 &fileno, &map_size,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001282 &tagname, &access, &offset)) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001283 return NULL;
1284 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001285
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001286 switch((access_mode)access) {
1287 case ACCESS_READ:
1288 flProtect = PAGE_READONLY;
1289 dwDesiredAccess = FILE_MAP_READ;
1290 break;
1291 case ACCESS_DEFAULT: case ACCESS_WRITE:
1292 flProtect = PAGE_READWRITE;
1293 dwDesiredAccess = FILE_MAP_WRITE;
1294 break;
1295 case ACCESS_COPY:
1296 flProtect = PAGE_WRITECOPY;
1297 dwDesiredAccess = FILE_MAP_COPY;
1298 break;
1299 default:
1300 return PyErr_Format(PyExc_ValueError,
1301 "mmap invalid access parameter.");
1302 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001303
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001304 if (map_size < 0) {
1305 PyErr_SetString(PyExc_OverflowError,
1306 "memory mapped length must be postiive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001307 return NULL;
Benjamin Peterson1df2cbe2016-10-05 21:45:48 -07001308 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001309 if (offset < 0) {
1310 PyErr_SetString(PyExc_OverflowError,
1311 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001312 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001313 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001314
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001315 /* assume -1 and 0 both mean invalid filedescriptor
1316 to 'anonymously' map memory.
1317 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1318 XXX: Should this code be added?
1319 if (fileno == 0)
1320 PyErr_Warn(PyExc_DeprecationWarning,
1321 "don't use 0 for anonymous memory");
1322 */
1323 if (fileno != -1 && fileno != 0) {
Brian Curtinba6c08e2010-08-01 15:47:53 +00001324 /* Ensure that fileno is within the CRT's valid range */
1325 if (_PyVerify_fd(fileno) == 0) {
1326 PyErr_SetFromErrno(mmap_module_error);
1327 return NULL;
1328 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001329 fh = (HANDLE)_get_osfhandle(fileno);
1330 if (fh==(HANDLE)-1) {
1331 PyErr_SetFromErrno(mmap_module_error);
1332 return NULL;
1333 }
1334 /* Win9x appears to need us seeked to zero */
1335 lseek(fileno, 0, SEEK_SET);
1336 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001337
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001338 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1339 if (m_obj == NULL)
1340 return NULL;
1341 /* Set every field to an invalid marker, so we can safely
1342 destruct the object in the face of failure */
1343 m_obj->data = NULL;
1344 m_obj->file_handle = INVALID_HANDLE_VALUE;
1345 m_obj->map_handle = NULL;
1346 m_obj->tagname = NULL;
1347 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001348
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001349 if (fh) {
1350 /* It is necessary to duplicate the handle, so the
1351 Python code can close it on us */
1352 if (!DuplicateHandle(
1353 GetCurrentProcess(), /* source process handle */
1354 fh, /* handle to be duplicated */
1355 GetCurrentProcess(), /* target proc handle */
1356 (LPHANDLE)&m_obj->file_handle, /* result */
1357 0, /* access - ignored due to options value */
1358 FALSE, /* inherited by child processes? */
1359 DUPLICATE_SAME_ACCESS)) { /* options */
1360 dwErr = GetLastError();
1361 Py_DECREF(m_obj);
1362 PyErr_SetFromWindowsErr(dwErr);
1363 return NULL;
1364 }
1365 if (!map_size) {
1366 DWORD low,high;
1367 low = GetFileSize(fh, &high);
1368 /* low might just happen to have the value INVALID_FILE_SIZE;
1369 so we need to check the last error also. */
1370 if (low == INVALID_FILE_SIZE &&
1371 (dwErr = GetLastError()) != NO_ERROR) {
1372 Py_DECREF(m_obj);
1373 return PyErr_SetFromWindowsErr(dwErr);
1374 }
1375
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001376 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea20f0ea12012-09-10 22:45:47 +02001377 if (size == 0) {
1378 PyErr_SetString(PyExc_ValueError,
1379 "cannot mmap an empty file");
Jesus Cea8e03b4c2012-09-10 22:57:34 +02001380 Py_DECREF(m_obj);
Jesus Cea20f0ea12012-09-10 22:45:47 +02001381 return NULL;
1382 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001383 if (offset >= size) {
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001384 PyErr_SetString(PyExc_ValueError,
1385 "mmap offset is greater than file size");
1386 Py_DECREF(m_obj);
1387 return NULL;
1388 }
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001389 if (size - offset > PY_SSIZE_T_MAX) {
1390 PyErr_SetString(PyExc_ValueError,
1391 "mmap length is too large");
1392 Py_DECREF(m_obj);
1393 return NULL;
1394 }
1395 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001396 } else {
1397 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001398 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001399 }
1400 }
1401 else {
1402 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001403 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001404 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001405
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001406 /* set the initial position */
1407 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001408
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001409 /* set the tag name */
1410 if (tagname != NULL && *tagname != '\0') {
1411 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1412 if (m_obj->tagname == NULL) {
1413 PyErr_NoMemory();
1414 Py_DECREF(m_obj);
1415 return NULL;
1416 }
1417 strcpy(m_obj->tagname, tagname);
1418 }
1419 else
1420 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001421
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001422 m_obj->access = (access_mode)access;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001423 size_hi = (DWORD)(size >> 32);
1424 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001425 off_hi = (DWORD)(offset >> 32);
1426 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001427 /* For files, it would be sufficient to pass 0 as size.
1428 For anonymous maps, we have to pass the size explicitly. */
1429 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1430 NULL,
1431 flProtect,
1432 size_hi,
1433 size_lo,
1434 m_obj->tagname);
1435 if (m_obj->map_handle != NULL) {
1436 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1437 dwDesiredAccess,
1438 off_hi,
1439 off_lo,
1440 m_obj->size);
1441 if (m_obj->data != NULL)
1442 return (PyObject *)m_obj;
1443 else {
1444 dwErr = GetLastError();
1445 CloseHandle(m_obj->map_handle);
1446 m_obj->map_handle = NULL;
1447 }
1448 } else
1449 dwErr = GetLastError();
1450 Py_DECREF(m_obj);
1451 PyErr_SetFromWindowsErr(dwErr);
1452 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001453}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001454#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001455
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001456static void
1457setint(PyObject *d, const char *name, long value)
1458{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001459 PyObject *o = PyInt_FromLong(value);
1460 if (o && PyDict_SetItemString(d, name, o) == 0) {
1461 Py_DECREF(o);
1462 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001463}
1464
Mark Hammond62b1ab12002-07-23 06:31:15 +00001465PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001466initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001467{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001468 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001469
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001470 if (PyType_Ready(&mmap_object_type) < 0)
1471 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001472
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001473 module = Py_InitModule("mmap", NULL);
1474 if (module == NULL)
1475 return;
1476 dict = PyModule_GetDict(module);
1477 if (!dict)
1478 return;
1479 mmap_module_error = PyErr_NewException("mmap.error",
1480 PyExc_EnvironmentError , NULL);
1481 if (mmap_module_error == NULL)
1482 return;
1483 PyDict_SetItemString(dict, "error", mmap_module_error);
1484 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001485#ifdef PROT_EXEC
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001486 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001487#endif
1488#ifdef PROT_READ
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001489 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001490#endif
1491#ifdef PROT_WRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001492 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001493#endif
1494
1495#ifdef MAP_SHARED
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001496 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001497#endif
1498#ifdef MAP_PRIVATE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001499 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001500#endif
1501#ifdef MAP_DENYWRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001502 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001503#endif
1504#ifdef MAP_EXECUTABLE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001505 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001506#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001507#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001508 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1509 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001510#endif
1511
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001512 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001513
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001514 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001515
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001516 setint(dict, "ACCESS_READ", ACCESS_READ);
1517 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1518 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001519}