blob: 37584e222559f70eb46529d0839eaba7e2c5cf95 [file] [log] [blame]
Guido van Rossum09fdf072000-03-31 01:17:07 +00001/*
2 / Author: Sam Rushing <rushing@nightmare.com>
Andrew M. Kuchling10f9c072001-11-05 21:25:42 +00003 / Hacked for Unix by AMK
Guido van Rossum09fdf072000-03-31 01:17:07 +00004 / $Id$
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00005
Guido van Rossum8ce8a782007-11-01 19:42:39 +00006 / Modified to support mmap with offset - to map a 'window' of a file
7 / Author: Yotam Medini yotamm@mellanox.co.il
8 /
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00009 / mmapmodule.cpp -- map a view of a file into memory
10 /
11 / todo: need permission flags, perhaps a 'chsize' analog
12 / not all functions check range yet!!!
13 /
14 /
Mark Hammond071864a2000-07-30 02:46:26 +000015 / This version of mmapmodule.c has been changed significantly
16 / from the original mmapfile.c on which it was based.
17 / The original version of mmapfile is maintained by Sam at
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000018 / ftp://squirl.nightmare.com/pub/python/python-ext.
19*/
20
Martin v. Löwiscfe7e092006-02-17 06:59:14 +000021#define PY_SSIZE_T_CLEAN
Guido van Rossum09fdf072000-03-31 01:17:07 +000022#include <Python.h>
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
26#endif
27
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000028#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000030static int
31my_getpagesize(void)
32{
Tim Peters5ebfd362001-11-13 23:11:19 +000033 SYSTEM_INFO si;
34 GetSystemInfo(&si);
35 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000036}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000037
38static int
39my_getallocationgranularity (void)
40{
41
42 SYSTEM_INFO si;
43 GetSystemInfo(&si);
44 return si.dwAllocationGranularity;
45}
46
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000047#endif
48
49#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000051#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000052
Fred Drake145f96e2000-10-01 17:50:46 +000053#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
54static int
55my_getpagesize(void)
56{
Tim Peters5ebfd362001-11-13 23:11:19 +000057 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000058}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000059
60#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000061#else
62#define my_getpagesize getpagesize
63#endif
64
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000065#endif /* UNIX */
66
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000067#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000068
69#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000071#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000073/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000074#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
75# define MAP_ANONYMOUS MAP_ANON
76#endif
77
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000078static PyObject *mmap_module_error;
79
Tim Peters5ebfd362001-11-13 23:11:19 +000080typedef enum
81{
82 ACCESS_DEFAULT,
83 ACCESS_READ,
84 ACCESS_WRITE,
85 ACCESS_COPY
86} access_mode;
87
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000088typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000089 PyObject_HEAD
90 char * data;
91 size_t size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000092 size_t pos; /* relative to offset */
93 size_t offset;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000094 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000095
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000096#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +000097 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000098 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000099 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000100#endif
101
102#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000103 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000105
106 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107} mmap_object;
108
Tim Peters5ebfd362001-11-13 23:11:19 +0000109
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000111mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000112{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000113#ifdef MS_WINDOWS
Mark Hammond2cbed002000-07-30 02:22:43 +0000114 if (m_obj->data != NULL)
115 UnmapViewOfFile (m_obj->data);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000116 if (m_obj->map_handle != NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +0000117 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000118 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
119 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000120 if (m_obj->tagname)
121 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000122#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000123
124#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000125 if (m_obj->fd >= 0)
126 (void) close(m_obj->fd);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000127 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000128 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000129 munmap(m_obj->data, m_obj->size);
130 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000131#endif /* UNIX */
132
Christian Heimes1af737c2008-01-23 08:24:23 +0000133 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000134}
135
136static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000137mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000139 if (self->exports > 0) {
140 PyErr_SetString(PyExc_BufferError, "cannot close "\
141 "exported pointers exist");
142 return NULL;
143 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000144#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000145 /* For each resource we maintain, we need to check
Tim Petersec0a5f02006-02-16 23:47:20 +0000146 the value is valid, and if so, free the resource
Mark Hammond071864a2000-07-30 02:46:26 +0000147 and set the member value to an invalid value so
148 the dealloc does not attempt to resource clearing
149 again.
150 TODO - should we check for errors in the close operations???
151 */
152 if (self->data != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000153 UnmapViewOfFile(self->data);
Mark Hammond071864a2000-07-30 02:46:26 +0000154 self->data = NULL;
155 }
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000156 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000157 CloseHandle(self->map_handle);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000158 self->map_handle = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000159 }
160 if (self->file_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000161 CloseHandle(self->file_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000162 self->file_handle = INVALID_HANDLE_VALUE;
163 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000164#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000165
166#ifdef UNIX
Hirokazu Yamamoto3d8827d2009-06-14 04:58:16 +0000167 if (0 <= self->fd)
168 (void) close(self->fd);
Neal Norwitz6eac2002005-11-02 05:36:37 +0000169 self->fd = -1;
Neal Norwitze604c022003-01-10 20:52:16 +0000170 if (self->data != NULL) {
171 munmap(self->data, self->size);
172 self->data = NULL;
173 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000174#endif
175
Tim Peters8f9cc292006-02-17 00:00:20 +0000176 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000177 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000178}
179
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000180#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000181#define CHECK_VALID(err) \
182do { \
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000183 if (self->map_handle == NULL) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000184 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000185 return err; \
186 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000187} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000188#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000189
190#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000191#define CHECK_VALID(err) \
192do { \
193 if (self->data == NULL) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000194 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000195 return err; \
196 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000197} while (0)
198#endif /* UNIX */
199
200static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000201mmap_read_byte_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000202 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000203{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000204 CHECK_VALID(NULL);
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000205 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000206 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000207 self->pos += 1;
Benjamin Petersone099b372009-04-04 17:09:35 +0000208 return Py_BuildValue("b", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000209 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000210 PyErr_SetString(PyExc_ValueError, "read byte out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000211 return NULL;
212 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000213}
214
215static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000216mmap_read_line_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000217 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000219 char *start = self->data+self->pos;
220 char *eof = self->data+self->size;
221 char *eol;
222 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223
Guido van Rossum09fdf072000-03-31 01:17:07 +0000224 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000225
Fred Drake56a87a02000-04-04 18:17:35 +0000226 eol = memchr(start, '\n', self->size - self->pos);
227 if (!eol)
228 eol = eof;
229 else
230 ++eol; /* we're interested in the position after the
231 newline. */
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000232 result = PyBytes_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000233 self->pos += (eol - start);
Tim Peters23721ee2006-02-16 23:50:16 +0000234 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000235}
236
237static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000238mmap_read_method(mmap_object *self,
239 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000240{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000241 Py_ssize_t num_bytes;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000242 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000243
Guido van Rossum09fdf072000-03-31 01:17:07 +0000244 CHECK_VALID(NULL);
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000245 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000246 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000247
Guido van Rossum09fdf072000-03-31 01:17:07 +0000248 /* silently 'adjust' out-of-range requests */
Neal Norwitz3ce5d922008-08-24 07:08:55 +0000249 if (num_bytes > self->size - self->pos) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000250 num_bytes -= (self->pos+num_bytes) - self->size;
251 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000252 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
Tim Petersec0a5f02006-02-16 23:47:20 +0000253 self->pos += num_bytes;
Tim Peters23721ee2006-02-16 23:50:16 +0000254 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000255}
256
257static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000258mmap_gfind(mmap_object *self,
259 PyObject *args,
260 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000261{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000262 Py_ssize_t start = self->pos;
Christian Heimesaf98da12008-01-27 15:18:18 +0000263 Py_ssize_t end = self->size;
264 const char *needle;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000265 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266
Guido van Rossum09fdf072000-03-31 01:17:07 +0000267 CHECK_VALID(NULL);
Benjamin Petersone099b372009-04-04 17:09:35 +0000268 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
Georg Brandlfceab5a2008-01-19 20:08:23 +0000269 &needle, &len, &start, &end)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000270 return NULL;
271 } else {
Christian Heimesaf98da12008-01-27 15:18:18 +0000272 const char *p, *start_p, *end_p;
273 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000274
275 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000276 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000277 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000278 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000279 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000280 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000281
Georg Brandlfceab5a2008-01-19 20:08:23 +0000282 if (end < 0)
283 end += self->size;
284 if (end < 0)
285 end = 0;
286 else if ((size_t)end > self->size)
287 end = self->size;
288
Christian Heimesaf98da12008-01-27 15:18:18 +0000289 start_p = self->data + start;
290 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000291
Christian Heimesaf98da12008-01-27 15:18:18 +0000292 for (p = (reverse ? end_p - len : start_p);
293 (p >= start_p) && (p + len <= end_p); p += sign) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000294 Py_ssize_t i;
Tim Petersc9ffa062002-03-08 05:43:32 +0000295 for (i = 0; i < len && needle[i] == p[i]; ++i)
296 /* nothing */;
297 if (i == len) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000298 return PyLong_FromSsize_t(p - self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000299 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000300 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000301 return PyLong_FromLong(-1);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000302 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000303}
304
Georg Brandlfceab5a2008-01-19 20:08:23 +0000305static PyObject *
306mmap_find_method(mmap_object *self,
307 PyObject *args)
308{
309 return mmap_gfind(self, args, 0);
310}
311
312static PyObject *
313mmap_rfind_method(mmap_object *self,
314 PyObject *args)
315{
316 return mmap_gfind(self, args, 1);
317}
318
Tim Petersec0a5f02006-02-16 23:47:20 +0000319static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000320is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000321{
322 if (self->access != ACCESS_READ)
Tim Petersec0a5f02006-02-16 23:47:20 +0000323 return 1;
Tim Peters5ebfd362001-11-13 23:11:19 +0000324 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
325 return 0;
326}
327
Tim Petersec0a5f02006-02-16 23:47:20 +0000328static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000329is_resizeable(mmap_object *self)
330{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000331 if (self->exports > 0) {
332 PyErr_SetString(PyExc_BufferError,
333 "mmap can't resize with extant buffers exported.");
334 return 0;
335 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000336 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
Guido van Rossum98297ee2007-11-06 21:34:58 +0000337 return 1;
Tim Petersec0a5f02006-02-16 23:47:20 +0000338 PyErr_Format(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000339 "mmap can't resize a readonly or copy-on-write memory map.");
340 return 0;
341}
342
343
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000344static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000345mmap_write_method(mmap_object *self,
346 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000347{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000348 Py_ssize_t length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000349 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000350
Guido van Rossum09fdf072000-03-31 01:17:07 +0000351 CHECK_VALID(NULL);
Benjamin Petersone099b372009-04-04 17:09:35 +0000352 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000353 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000354
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000355 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000356 return NULL;
357
Guido van Rossum09fdf072000-03-31 01:17:07 +0000358 if ((self->pos + length) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000359 PyErr_SetString(PyExc_ValueError, "data out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000360 return NULL;
361 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000362 memcpy(self->data+self->pos, data, length);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000363 self->pos = self->pos+length;
Tim Peters8f9cc292006-02-17 00:00:20 +0000364 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000365 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000366}
367
368static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000369mmap_write_byte_method(mmap_object *self,
370 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000371{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000372 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000373
Guido van Rossum09fdf072000-03-31 01:17:07 +0000374 CHECK_VALID(NULL);
Benjamin Petersone099b372009-04-04 17:09:35 +0000375 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000376 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000377
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000378 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000379 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000380
381 if (self->pos < self->size) {
382 *(self->data+self->pos) = value;
383 self->pos += 1;
384 Py_INCREF(Py_None);
385 return Py_None;
386 }
387 else {
388 PyErr_SetString(PyExc_ValueError, "write byte out of range");
389 return NULL;
390 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000391}
Tim Petersec0a5f02006-02-16 23:47:20 +0000392
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000393static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000394mmap_size_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000395 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000396{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000397 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000398
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000399#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000400 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000401 DWORD low,high;
402 PY_LONG_LONG size;
403 low = GetFileSize(self->file_handle, &high);
404 if (low == INVALID_FILE_SIZE) {
405 /* It might be that the function appears to have failed,
406 when indeed its size equals INVALID_FILE_SIZE */
407 DWORD error = GetLastError();
408 if (error != NO_ERROR)
409 return PyErr_SetFromWindowsErr(error);
410 }
411 if (!high && low < LONG_MAX)
Christian Heimes217cfd12007-12-02 14:31:20 +0000412 return PyLong_FromLong((long)low);
Martin v. Löwis15186072006-02-18 12:38:35 +0000413 size = (((PY_LONG_LONG)high)<<32) + low;
414 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000415 } else {
Christian Heimes217cfd12007-12-02 14:31:20 +0000416 return PyLong_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000417 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000418#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000419
420#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000421 {
422 struct stat buf;
423 if (-1 == fstat(self->fd, &buf)) {
424 PyErr_SetFromErrno(mmap_module_error);
425 return NULL;
426 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000427 return PyLong_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000428 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429#endif /* UNIX */
430}
431
432/* This assumes that you want the entire file mapped,
433 / and when recreating the map will make the new file
434 / have the new size
435 /
436 / Is this really necessary? This could easily be done
437 / from python by just closing and re-opening with the
438 / new size?
439 */
440
441static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000442mmap_resize_method(mmap_object *self,
443 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000444{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000445 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000446 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000447 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000448 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000449 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000450#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000451 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000452 DWORD dwErrCode = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000453 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000454 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000455 UnmapViewOfFile(self->data);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000456 self->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000457 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000458 CloseHandle(self->map_handle);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000459 self->map_handle = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000460 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000461#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000462 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
463 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
464 off_hi = (DWORD)(self->offset >> 32);
465 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000466#else
467 newSizeHigh = 0;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000468 newSizeLow = (DWORD)(self->offset + new_size);
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000469 off_hi = 0;
470 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000471#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000472 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000473 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000474 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000475 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000476 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000477 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000478 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000479 NULL,
480 PAGE_READWRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000481 0,
482 0,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000483 self->tagname);
484 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000485 self->data = (char *) MapViewOfFile(self->map_handle,
486 FILE_MAP_WRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000487 off_hi,
488 off_lo,
489 new_size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000490 if (self->data != NULL) {
491 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000492 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000493 return Py_None;
494 } else {
495 dwErrCode = GetLastError();
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000496 CloseHandle(self->map_handle);
497 self->map_handle = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000498 }
499 } else {
500 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000501 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000502 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000503 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000504#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000505
506#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000507#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000508 } else {
509 PyErr_SetString(PyExc_SystemError,
510 "mmap: resizing not available--no mremap()");
511 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000512#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000513 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000514 void *newmap;
515
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000516 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Georg Brandl38387b82005-08-24 07:17:40 +0000517 PyErr_SetFromErrno(mmap_module_error);
518 return NULL;
519 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000520
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000521#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000522 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000523#else
Jesse Noller32d68c22009-03-31 18:48:42 +0000524 #if defined(__NetBSD__)
525 newmap = mremap(self->data, self->size, self->data, new_size, 0);
526 #else
527 newmap = mremap(self->data, self->size, new_size, 0);
528 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000529#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000530 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000531 {
532 PyErr_SetFromErrno(mmap_module_error);
533 return NULL;
534 }
535 self->data = newmap;
536 self->size = new_size;
537 Py_INCREF(Py_None);
538 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000539#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000540#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000541 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000542}
543
544static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000545mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000546{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000547 CHECK_VALID(NULL);
Christian Heimes217cfd12007-12-02 14:31:20 +0000548 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000549}
550
551static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000552mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000554 Py_ssize_t offset = 0;
555 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000556 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000557 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000558 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000559 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000560 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000561 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000562 }
Christian Heimesaf98da12008-01-27 15:18:18 +0000563#ifdef MS_WINDOWS
564 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
565#elif defined(UNIX)
566 /* 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 PyLong_FromLong(0);
573#else
574 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
575 return NULL;
576#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{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000582 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000583 int how=0;
584 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000585 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000586 return NULL;
587 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000588 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000589 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000590 case 0: /* relative to start */
591 if (dist < 0)
592 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000593 where = dist;
594 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000595 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000596 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000597 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000598 where = self->pos + dist;
599 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000600 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000601 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000602 goto onoutofrange;
603 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000604 break;
605 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000606 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000607 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000608 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000609 if (where > self->size)
610 goto onoutofrange;
611 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000612 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000613 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000614 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000615
Tim Peters5ebfd362001-11-13 23:11:19 +0000616 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000617 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000618 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 Petersonef3e4c22009-04-11 19:48:14 +0000624 unsigned long dest, src, cnt;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000625 CHECK_VALID(NULL);
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000626 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000627 !is_writable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000628 return NULL;
629 } else {
630 /* bounds check the values */
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000631 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
632 src < 0 || src > self->size || (src + cnt) > self->size ||
633 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000634 PyErr_SetString(PyExc_ValueError,
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000635 "source, destination, or count out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000636 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000637 }
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000638 memmove(self->data+dest, self->data+src, cnt);
639 Py_INCREF(Py_None);
640 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000641 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000642}
643
644static struct PyMethodDef mmap_object_methods[] = {
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000645 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000646 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Georg Brandlfceab5a2008-01-19 20:08:23 +0000647 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000648 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
649 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
650 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000651 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
652 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000653 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
654 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000655 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
656 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000657 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
658 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000659 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000660};
661
662/* Functions for treating an mmap'ed file as a buffer */
663
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000664static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000665mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000666{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000667 CHECK_VALID(-1);
Martin v. Löwis423be952008-08-13 15:53:07 +0000668 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000669 (self->access == ACCESS_READ), flags) < 0)
670 return -1;
671 self->exports++;
672 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000673}
674
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000675static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000676mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000677{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000678 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679}
680
Martin v. Löwis18e16552006-02-15 17:27:45 +0000681static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000682mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000683{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000684 CHECK_VALID(-1);
685 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000686}
687
688static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000689mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000691 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000692 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000693 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
694 return NULL;
695 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000696 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000697}
698
699static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000700mmap_subscript(mmap_object *self, PyObject *item)
701{
702 CHECK_VALID(NULL);
703 if (PyIndex_Check(item)) {
704 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
705 if (i == -1 && PyErr_Occurred())
706 return NULL;
707 if (i < 0)
708 i += self->size;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000709 if (i < 0 || (size_t)i >= self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000710 PyErr_SetString(PyExc_IndexError,
711 "mmap index out of range");
712 return NULL;
713 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000714 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
Thomas Woutersed03b412007-08-28 21:37:11 +0000715 }
716 else if (PySlice_Check(item)) {
717 Py_ssize_t start, stop, step, slicelen;
718
719 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
720 &start, &stop, &step, &slicelen) < 0) {
721 return NULL;
722 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000723
Thomas Woutersed03b412007-08-28 21:37:11 +0000724 if (slicelen <= 0)
Christian Heimes72b710a2008-05-26 13:28:38 +0000725 return PyBytes_FromStringAndSize("", 0);
Thomas Woutersed03b412007-08-28 21:37:11 +0000726 else if (step == 1)
Christian Heimes72b710a2008-05-26 13:28:38 +0000727 return PyBytes_FromStringAndSize(self->data + start,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000728 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000729 else {
730 char *result_buf = (char *)PyMem_Malloc(slicelen);
731 Py_ssize_t cur, i;
732 PyObject *result;
733
734 if (result_buf == NULL)
735 return PyErr_NoMemory();
736 for (cur = start, i = 0; i < slicelen;
737 cur += step, i++) {
738 result_buf[i] = self->data[cur];
739 }
Christian Heimes72b710a2008-05-26 13:28:38 +0000740 result = PyBytes_FromStringAndSize(result_buf,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000741 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000742 PyMem_Free(result_buf);
743 return result;
744 }
745 }
746 else {
747 PyErr_SetString(PyExc_TypeError,
748 "mmap indices must be integers");
749 return NULL;
750 }
751}
752
753static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000754mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000756 CHECK_VALID(NULL);
757 PyErr_SetString(PyExc_SystemError,
758 "mmaps don't support concatenation");
759 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000760}
761
762static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000763mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000764{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000765 CHECK_VALID(NULL);
766 PyErr_SetString(PyExc_SystemError,
767 "mmaps don't support repeat operation");
768 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000769}
770
771static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000772mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000773{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000774 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000775
Guido van Rossum09fdf072000-03-31 01:17:07 +0000776 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000777 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000778 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
779 return -1;
780 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000781 if (v == NULL) {
782 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000783 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000784 return -1;
785 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000786 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000787 PyErr_SetString(PyExc_IndexError,
Thomas Woutersed03b412007-08-28 21:37:11 +0000788 "mmap assignment must be length-1 bytes()");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000789 return -1;
790 }
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000791 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000792 return -1;
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000793 buf = PyBytes_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000794 self->data[i] = buf[0];
795 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000796}
797
Thomas Woutersed03b412007-08-28 21:37:11 +0000798static int
799mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
800{
801 CHECK_VALID(-1);
802
Guido van Rossum98297ee2007-11-06 21:34:58 +0000803 if (!is_writable(self))
804 return -1;
805
Thomas Woutersed03b412007-08-28 21:37:11 +0000806 if (PyIndex_Check(item)) {
807 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000808 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000809
810 if (i == -1 && PyErr_Occurred())
811 return -1;
812 if (i < 0)
813 i += self->size;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000814 if (i < 0 || (size_t)i >= self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000815 PyErr_SetString(PyExc_IndexError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000816 "mmap index out of range");
Thomas Woutersed03b412007-08-28 21:37:11 +0000817 return -1;
818 }
819 if (value == NULL) {
820 PyErr_SetString(PyExc_TypeError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000821 "mmap doesn't support item deletion");
Thomas Woutersed03b412007-08-28 21:37:11 +0000822 return -1;
823 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000824 if (!PyIndex_Check(value)) {
825 PyErr_SetString(PyExc_TypeError,
826 "mmap item value must be an int");
Thomas Woutersed03b412007-08-28 21:37:11 +0000827 return -1;
828 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000829 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
830 if (v == -1 && PyErr_Occurred())
Thomas Woutersed03b412007-08-28 21:37:11 +0000831 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000832 if (v < 0 || v > 255) {
833 PyErr_SetString(PyExc_ValueError,
834 "mmap item value must be "
835 "in range(0, 256)");
836 return -1;
837 }
838 self->data[i] = v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000839 return 0;
840 }
841 else if (PySlice_Check(item)) {
842 Py_ssize_t start, stop, step, slicelen;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000843 Py_buffer vbuf;
844
Thomas Woutersed03b412007-08-28 21:37:11 +0000845 if (PySlice_GetIndicesEx((PySliceObject *)item,
846 self->size, &start, &stop,
847 &step, &slicelen) < 0) {
848 return -1;
849 }
850 if (value == NULL) {
851 PyErr_SetString(PyExc_TypeError,
852 "mmap object doesn't support slice deletion");
853 return -1;
854 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000855 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000856 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000857 if (vbuf.len != slicelen) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000858 PyErr_SetString(PyExc_IndexError,
859 "mmap slice assignment is wrong size");
Martin v. Löwis423be952008-08-13 15:53:07 +0000860 PyBuffer_Release(&vbuf);
Thomas Woutersed03b412007-08-28 21:37:11 +0000861 return -1;
862 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000863
Guido van Rossum98297ee2007-11-06 21:34:58 +0000864 if (slicelen == 0) {
865 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000866 else if (step == 1) {
Guido van Rossum98297ee2007-11-06 21:34:58 +0000867 memcpy(self->data + start, vbuf.buf, slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000868 }
869 else {
870 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000871
872 for (cur = start, i = 0;
873 i < slicelen;
874 cur += step, i++)
875 {
876 self->data[cur] = ((char *)vbuf.buf)[i];
Thomas Woutersed03b412007-08-28 21:37:11 +0000877 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000878 }
Martin v. Löwis423be952008-08-13 15:53:07 +0000879 PyBuffer_Release(&vbuf);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000880 return 0;
Thomas Woutersed03b412007-08-28 21:37:11 +0000881 }
882 else {
883 PyErr_SetString(PyExc_TypeError,
884 "mmap indices must be integer");
885 return -1;
886 }
887}
888
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000889static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000890 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000891 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000892 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
893 (ssizeargfunc)mmap_item, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000894 0, /*sq_slice*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000895 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000896 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000897};
898
Thomas Woutersed03b412007-08-28 21:37:11 +0000899static PyMappingMethods mmap_as_mapping = {
900 (lenfunc)mmap_length,
901 (binaryfunc)mmap_subscript,
902 (objobjargproc)mmap_ass_subscript,
903};
904
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000905static PyBufferProcs mmap_as_buffer = {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000906 (getbufferproc)mmap_buffer_getbuf,
907 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000908};
909
Georg Brandl86def6c2008-01-21 20:36:10 +0000910static PyObject *
911new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
912
Christian Heimese1c98112008-01-21 11:20:28 +0000913PyDoc_STRVAR(mmap_doc,
914"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
915\n\
916Maps length bytes from the file specified by the file handle fileno,\n\
917and returns a mmap object. If length is larger than the current size\n\
918of the file, the file is extended to contain length bytes. If length\n\
919is 0, the maximum length of the map is the current size of the file,\n\
920except that if the file is empty Windows raises an exception (you cannot\n\
921create an empty mapping on Windows).\n\
922\n\
923Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
924\n\
925Maps length bytes from the file specified by the file descriptor fileno,\n\
926and returns a mmap object. If length is 0, the maximum length of the map\n\
927will be the current size of the file when mmap is called.\n\
928flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
929private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000930object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000931that's shared with all other processes mapping the same areas of the file.\n\
932The default value is MAP_SHARED.\n\
933\n\
934To map anonymous memory, pass -1 as the fileno (both versions).");
935
936
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000937static PyTypeObject mmap_object_type = {
Georg Brandl86def6c2008-01-21 20:36:10 +0000938 PyVarObject_HEAD_INIT(NULL, 0)
Guido van Rossum14648392001-12-08 18:02:58 +0000939 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000940 sizeof(mmap_object), /* tp_size */
941 0, /* tp_itemsize */
942 /* methods */
943 (destructor) mmap_object_dealloc, /* tp_dealloc */
944 0, /* tp_print */
Christian Heimese1c98112008-01-21 11:20:28 +0000945 0, /* tp_getattr */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000946 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000947 0, /* tp_reserved */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000948 0, /* tp_repr */
949 0, /* tp_as_number */
950 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Woutersed03b412007-08-28 21:37:11 +0000951 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000952 0, /*tp_hash*/
953 0, /*tp_call*/
954 0, /*tp_str*/
Christian Heimese1c98112008-01-21 11:20:28 +0000955 PyObject_GenericGetAttr, /*tp_getattro*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000956 0, /*tp_setattro*/
957 &mmap_as_buffer, /*tp_as_buffer*/
Georg Brandl86def6c2008-01-21 20:36:10 +0000958 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Christian Heimese1c98112008-01-21 11:20:28 +0000959 mmap_doc, /*tp_doc*/
960 0, /* tp_traverse */
961 0, /* tp_clear */
962 0, /* tp_richcompare */
963 0, /* tp_weaklistoffset */
Georg Brandl86def6c2008-01-21 20:36:10 +0000964 0, /* tp_iter */
965 0, /* tp_iternext */
Christian Heimese1c98112008-01-21 11:20:28 +0000966 mmap_object_methods, /* tp_methods */
Georg Brandl86def6c2008-01-21 20:36:10 +0000967 0, /* tp_members */
968 0, /* tp_getset */
969 0, /* tp_base */
970 0, /* tp_dict */
971 0, /* tp_descr_get */
972 0, /* tp_descr_set */
973 0, /* tp_dictoffset */
974 0, /* tp_init */
975 PyType_GenericAlloc, /* tp_alloc */
976 new_mmap_object, /* tp_new */
977 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000978};
979
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000980
981/* extract the map size from the given PyObject
982
Thomas Wouters7e474022000-07-16 12:04:32 +0000983 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000984 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000985static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000986_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000987{
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000988 if (o == NULL)
989 return 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000990 if (PyIndex_Check(o)) {
991 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000992 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000993 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000994 if (i < 0) {
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000995 PyErr_Format(PyExc_OverflowError,
996 "memory mapped %s must be positive",
997 param);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000998 return -1;
999 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001000 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001001 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001002
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001003 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001004 return -1;
1005}
1006
Tim Petersec0a5f02006-02-16 23:47:20 +00001007#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001008static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001009new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001010{
Neal Norwitzb5673922002-09-05 21:48:07 +00001011#ifdef HAVE_FSTAT
1012 struct stat st;
1013#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001014 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001015 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1016 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001017 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001018 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001019 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001020 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001021 "flags", "prot",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001022 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001023
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001024 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001025 &fd, &map_size_obj, &flags, &prot,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001026 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001027 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001028 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001029 if (map_size < 0)
1030 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001031 offset = _GetMapSize(offset_obj, "offset");
1032 if (offset < 0)
1033 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001034
Tim Petersec0a5f02006-02-16 23:47:20 +00001035 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001036 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001037 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001038 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001039 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001040 case ACCESS_READ:
1041 flags = MAP_SHARED;
1042 prot = PROT_READ;
1043 break;
1044 case ACCESS_WRITE:
1045 flags = MAP_SHARED;
1046 prot = PROT_READ | PROT_WRITE;
1047 break;
1048 case ACCESS_COPY:
1049 flags = MAP_PRIVATE;
1050 prot = PROT_READ | PROT_WRITE;
1051 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001052 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001053 /* use the specified or default values of flags and prot */
1054 break;
1055 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001056 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001057 "mmap invalid access parameter.");
1058 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001059
Christian Heimesa156e092008-02-16 07:38:31 +00001060 if (prot == PROT_READ) {
1061 access = ACCESS_READ;
1062 }
1063
Neal Norwitzb5673922002-09-05 21:48:07 +00001064#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001065# ifdef __VMS
1066 /* on OpenVMS we must ensure that all bytes are written to the file */
Christian Heimes25bb7832008-01-11 16:17:00 +00001067 if (fd != -1) {
1068 fsync(fd);
1069 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001070# endif
Christian Heimes25bb7832008-01-11 16:17:00 +00001071 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001072 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001073 map_size = st.st_size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001074 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001075 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001076 "mmap length is greater than file size");
1077 return NULL;
1078 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001079 }
1080#endif
Georg Brandl86def6c2008-01-21 20:36:10 +00001081 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001082 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001083 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001084 m_obj->size = (size_t) map_size;
1085 m_obj->pos = (size_t) 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001086 m_obj->exports = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001087 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001088 if (fd == -1) {
1089 m_obj->fd = -1;
1090 /* Assume the caller wants to map anonymous memory.
1091 This is the same behaviour as Windows. mmap.mmap(-1, size)
1092 on both Windows and Unix map anonymous memory.
1093 */
1094#ifdef MAP_ANONYMOUS
1095 /* BSD way to map anonymous memory */
1096 flags |= MAP_ANONYMOUS;
1097#else
1098 /* SVR4 method to map anonymous memory is to open /dev/zero */
1099 fd = devzero = open("/dev/zero", O_RDWR);
1100 if (devzero == -1) {
1101 Py_DECREF(m_obj);
1102 PyErr_SetFromErrno(mmap_module_error);
1103 return NULL;
1104 }
1105#endif
1106 } else {
1107 m_obj->fd = dup(fd);
1108 if (m_obj->fd == -1) {
1109 Py_DECREF(m_obj);
1110 PyErr_SetFromErrno(mmap_module_error);
1111 return NULL;
1112 }
Georg Brandl38387b82005-08-24 07:17:40 +00001113 }
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001114
Tim Petersec0a5f02006-02-16 23:47:20 +00001115 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001116 prot, flags,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001117 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001118
1119 if (devzero != -1) {
1120 close(devzero);
1121 }
1122
Tim Peters5ebfd362001-11-13 23:11:19 +00001123 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001124 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001125 Py_DECREF(m_obj);
1126 PyErr_SetFromErrno(mmap_module_error);
1127 return NULL;
1128 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001129 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001130 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001131}
1132#endif /* UNIX */
1133
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001134#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001135static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001136new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001137{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001138 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001139 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1140 Py_ssize_t map_size, offset;
1141 DWORD off_hi; /* upper 32 bits of offset */
1142 DWORD off_lo; /* lower 32 bits of offset */
1143 DWORD size_hi; /* upper 32 bits of size */
1144 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001145 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001146 DWORD dwErr = 0;
1147 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001148 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001149 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001150 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001151 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001152 "tagname",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001153 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001154
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001155 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001156 &fileno, &map_size_obj,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001157 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001158 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001159 }
1160
Neal Norwitz8856fb72005-12-18 03:34:22 +00001161 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001162 case ACCESS_READ:
1163 flProtect = PAGE_READONLY;
1164 dwDesiredAccess = FILE_MAP_READ;
1165 break;
1166 case ACCESS_DEFAULT: case ACCESS_WRITE:
1167 flProtect = PAGE_READWRITE;
1168 dwDesiredAccess = FILE_MAP_WRITE;
1169 break;
1170 case ACCESS_COPY:
1171 flProtect = PAGE_WRITECOPY;
1172 dwDesiredAccess = FILE_MAP_COPY;
1173 break;
1174 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001175 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001176 "mmap invalid access parameter.");
1177 }
1178
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001179 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001180 if (map_size < 0)
1181 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001182 offset = _GetMapSize(offset_obj, "offset");
1183 if (offset < 0)
1184 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001185
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001186 /* assume -1 and 0 both mean invalid filedescriptor
1187 to 'anonymously' map memory.
1188 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1189 XXX: Should this code be added?
1190 if (fileno == 0)
Skip Montanaro46fc3372007-08-12 11:44:53 +00001191 PyErr_WarnEx(PyExc_DeprecationWarning,
1192 "don't use 0 for anonymous memory",
1193 1);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001194 */
1195 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001196 fh = (HANDLE)_get_osfhandle(fileno);
1197 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001198 PyErr_SetFromErrno(mmap_module_error);
1199 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001200 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001201 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001202 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001203 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001204
Georg Brandl86def6c2008-01-21 20:36:10 +00001205 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Tim Peters8f9cc292006-02-17 00:00:20 +00001206 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001207 return NULL;
1208 /* Set every field to an invalid marker, so we can safely
1209 destruct the object in the face of failure */
1210 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001211 m_obj->file_handle = INVALID_HANDLE_VALUE;
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +00001212 m_obj->map_handle = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001213 m_obj->tagname = NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001214 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001215
Guido van Rossum09fdf072000-03-31 01:17:07 +00001216 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001217 /* It is necessary to duplicate the handle, so the
1218 Python code can close it on us */
1219 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001220 GetCurrentProcess(), /* source process handle */
1221 fh, /* handle to be duplicated */
1222 GetCurrentProcess(), /* target proc handle */
1223 (LPHANDLE)&m_obj->file_handle, /* result */
1224 0, /* access - ignored due to options value */
1225 FALSE, /* inherited by child processes? */
1226 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001227 dwErr = GetLastError();
1228 Py_DECREF(m_obj);
1229 PyErr_SetFromWindowsErr(dwErr);
1230 return NULL;
1231 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001232 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001233 DWORD low,high;
1234 low = GetFileSize(fh, &high);
1235 /* low might just happen to have the value INVALID_FILE_SIZE;
1236 so we need to check the last error also. */
1237 if (low == INVALID_FILE_SIZE &&
1238 (dwErr = GetLastError()) != NO_ERROR) {
1239 Py_DECREF(m_obj);
1240 return PyErr_SetFromWindowsErr(dwErr);
Guido van Rossum98297ee2007-11-06 21:34:58 +00001241 }
1242
Martin v. Löwis15186072006-02-18 12:38:35 +00001243#if SIZEOF_SIZE_T > 4
1244 m_obj->size = (((size_t)high)<<32) + low;
1245#else
1246 if (high)
1247 /* File is too large to map completely */
1248 m_obj->size = (size_t)-1;
1249 else
1250 m_obj->size = low;
1251#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001252 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001253 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001254 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001255 }
1256 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001257 m_obj->size = map_size;
1258 }
1259
1260 /* set the initial position */
1261 m_obj->pos = (size_t) 0;
1262
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001263 m_obj->exports = 0;
Mark Hammond2cbed002000-07-30 02:22:43 +00001264 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001265 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001266 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1267 if (m_obj->tagname == NULL) {
1268 PyErr_NoMemory();
1269 Py_DECREF(m_obj);
1270 return NULL;
1271 }
1272 strcpy(m_obj->tagname, tagname);
1273 }
1274 else
1275 m_obj->tagname = NULL;
1276
Neal Norwitz8856fb72005-12-18 03:34:22 +00001277 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001278 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001279 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001280 * consumes 4 bytes), C doesn't define what happens if we shift
1281 * right by 32, so we need different code.
1282 */
1283#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001284 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1285 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1286 off_hi = (DWORD)(offset >> 32);
1287 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001288#else
1289 size_hi = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001290 size_lo = (DWORD)(offset + m_obj->size);
1291 off_hi = 0;
1292 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001293#endif
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001294 /* For files, it would be sufficient to pass 0 as size.
1295 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001296 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1297 NULL,
1298 flProtect,
1299 size_hi,
1300 size_lo,
1301 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001302 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001303 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1304 dwDesiredAccess,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001305 off_hi,
1306 off_lo,
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +00001307 m_obj->size);
Tim Peters23721ee2006-02-16 23:50:16 +00001308 if (m_obj->data != NULL)
1309 return (PyObject *)m_obj;
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +00001310 else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001311 dwErr = GetLastError();
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +00001312 CloseHandle(m_obj->map_handle);
1313 m_obj->map_handle = NULL;
1314 }
Tim Peters23721ee2006-02-16 23:50:16 +00001315 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001316 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001317 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001318 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001319 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001320}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001321#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001322
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001323static void
1324setint(PyObject *d, const char *name, long value)
1325{
Christian Heimes217cfd12007-12-02 14:31:20 +00001326 PyObject *o = PyLong_FromLong(value);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001327 if (o && PyDict_SetItemString(d, name, o) == 0) {
1328 Py_DECREF(o);
1329 }
1330}
1331
Martin v. Löwis1a214512008-06-11 05:26:20 +00001332
1333static struct PyModuleDef mmapmodule = {
1334 PyModuleDef_HEAD_INIT,
1335 "mmap",
1336 NULL,
1337 -1,
1338 NULL,
1339 NULL,
1340 NULL,
1341 NULL,
1342 NULL
1343};
1344
Mark Hammond62b1ab12002-07-23 06:31:15 +00001345PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001346PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001347{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001348 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001349
Georg Brandl86def6c2008-01-21 20:36:10 +00001350 if (PyType_Ready(&mmap_object_type) < 0)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001351 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001352
Martin v. Löwis1a214512008-06-11 05:26:20 +00001353 module = PyModule_Create(&mmapmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001354 if (module == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001355 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001356 dict = PyModule_GetDict(module);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001357 if (!dict)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001358 return NULL;
Christian Heimes7131fd92008-02-19 14:21:46 +00001359 mmap_module_error = PyErr_NewException("mmap.error",
1360 PyExc_EnvironmentError , NULL);
1361 if (mmap_module_error == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001362 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001363 PyDict_SetItemString(dict, "error", mmap_module_error);
Georg Brandl86def6c2008-01-21 20:36:10 +00001364 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001365#ifdef PROT_EXEC
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001366 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001367#endif
1368#ifdef PROT_READ
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001369 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001370#endif
1371#ifdef PROT_WRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001372 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001373#endif
1374
1375#ifdef MAP_SHARED
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001376 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001377#endif
1378#ifdef MAP_PRIVATE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001379 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001380#endif
1381#ifdef MAP_DENYWRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001382 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001383#endif
1384#ifdef MAP_EXECUTABLE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001385 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001386#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001387#ifdef MAP_ANONYMOUS
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001388 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1389 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001390#endif
1391
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001392 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001393
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001394 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1395
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001396 setint(dict, "ACCESS_READ", ACCESS_READ);
1397 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1398 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Martin v. Löwis1a214512008-06-11 05:26:20 +00001399 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001400}