blob: 9d6d6af89ce7b4611fcf224c3278bbca4172a41f [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{
Hirokazu Yamamoto7a9e1bd2009-06-29 14:54:12 +0000241 Py_ssize_t num_bytes, n;
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 */
Hirokazu Yamamoto7a9e1bd2009-06-29 14:54:12 +0000249 assert(self->size >= self->pos);
250 n = self->size - self->pos;
251 /* The difference can overflow, only if self->size is greater than
252 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
253 * because the mapped area and the returned string each need more
254 * than half of the addressable memory. So we clip the size, and let
255 * the code below raise MemoryError.
256 */
257 if (n < 0)
258 n = PY_SSIZE_T_MAX;
259 if (num_bytes < 0 || num_bytes > n) {
260 num_bytes = n;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000261 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000262 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
Tim Petersec0a5f02006-02-16 23:47:20 +0000263 self->pos += num_bytes;
Tim Peters23721ee2006-02-16 23:50:16 +0000264 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000265}
266
267static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000268mmap_gfind(mmap_object *self,
269 PyObject *args,
270 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000271{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000272 Py_ssize_t start = self->pos;
Christian Heimesaf98da12008-01-27 15:18:18 +0000273 Py_ssize_t end = self->size;
274 const char *needle;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000275 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000276
Guido van Rossum09fdf072000-03-31 01:17:07 +0000277 CHECK_VALID(NULL);
Benjamin Petersone099b372009-04-04 17:09:35 +0000278 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
Georg Brandlfceab5a2008-01-19 20:08:23 +0000279 &needle, &len, &start, &end)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000280 return NULL;
281 } else {
Christian Heimesaf98da12008-01-27 15:18:18 +0000282 const char *p, *start_p, *end_p;
283 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000284
285 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000286 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000287 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000288 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000289 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000290 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000291
Georg Brandlfceab5a2008-01-19 20:08:23 +0000292 if (end < 0)
293 end += self->size;
294 if (end < 0)
295 end = 0;
296 else if ((size_t)end > self->size)
297 end = self->size;
298
Christian Heimesaf98da12008-01-27 15:18:18 +0000299 start_p = self->data + start;
300 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000301
Christian Heimesaf98da12008-01-27 15:18:18 +0000302 for (p = (reverse ? end_p - len : start_p);
303 (p >= start_p) && (p + len <= end_p); p += sign) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000304 Py_ssize_t i;
Tim Petersc9ffa062002-03-08 05:43:32 +0000305 for (i = 0; i < len && needle[i] == p[i]; ++i)
306 /* nothing */;
307 if (i == len) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000308 return PyLong_FromSsize_t(p - self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000309 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000310 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000311 return PyLong_FromLong(-1);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000312 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000313}
314
Georg Brandlfceab5a2008-01-19 20:08:23 +0000315static PyObject *
316mmap_find_method(mmap_object *self,
317 PyObject *args)
318{
319 return mmap_gfind(self, args, 0);
320}
321
322static PyObject *
323mmap_rfind_method(mmap_object *self,
324 PyObject *args)
325{
326 return mmap_gfind(self, args, 1);
327}
328
Tim Petersec0a5f02006-02-16 23:47:20 +0000329static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000330is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000331{
332 if (self->access != ACCESS_READ)
Tim Petersec0a5f02006-02-16 23:47:20 +0000333 return 1;
Tim Peters5ebfd362001-11-13 23:11:19 +0000334 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
335 return 0;
336}
337
Tim Petersec0a5f02006-02-16 23:47:20 +0000338static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000339is_resizeable(mmap_object *self)
340{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000341 if (self->exports > 0) {
342 PyErr_SetString(PyExc_BufferError,
343 "mmap can't resize with extant buffers exported.");
344 return 0;
345 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000346 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
Guido van Rossum98297ee2007-11-06 21:34:58 +0000347 return 1;
Tim Petersec0a5f02006-02-16 23:47:20 +0000348 PyErr_Format(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000349 "mmap can't resize a readonly or copy-on-write memory map.");
350 return 0;
351}
352
353
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000354static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000355mmap_write_method(mmap_object *self,
356 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000357{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000358 Py_ssize_t length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000359 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000360
Guido van Rossum09fdf072000-03-31 01:17:07 +0000361 CHECK_VALID(NULL);
Benjamin Petersone099b372009-04-04 17:09:35 +0000362 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000363 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000364
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000365 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000366 return NULL;
367
Guido van Rossum09fdf072000-03-31 01:17:07 +0000368 if ((self->pos + length) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000369 PyErr_SetString(PyExc_ValueError, "data out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000370 return NULL;
371 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000372 memcpy(self->data+self->pos, data, length);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000373 self->pos = self->pos+length;
Tim Peters8f9cc292006-02-17 00:00:20 +0000374 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000375 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000376}
377
378static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000379mmap_write_byte_method(mmap_object *self,
380 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000381{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000382 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000383
Guido van Rossum09fdf072000-03-31 01:17:07 +0000384 CHECK_VALID(NULL);
Benjamin Petersone099b372009-04-04 17:09:35 +0000385 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000386 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000387
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000388 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000389 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000390
391 if (self->pos < self->size) {
392 *(self->data+self->pos) = value;
393 self->pos += 1;
394 Py_INCREF(Py_None);
395 return Py_None;
396 }
397 else {
398 PyErr_SetString(PyExc_ValueError, "write byte out of range");
399 return NULL;
400 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000401}
Tim Petersec0a5f02006-02-16 23:47:20 +0000402
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000403static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000404mmap_size_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000405 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000406{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000407 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000408
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000409#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000410 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000411 DWORD low,high;
412 PY_LONG_LONG size;
413 low = GetFileSize(self->file_handle, &high);
414 if (low == INVALID_FILE_SIZE) {
415 /* It might be that the function appears to have failed,
416 when indeed its size equals INVALID_FILE_SIZE */
417 DWORD error = GetLastError();
418 if (error != NO_ERROR)
419 return PyErr_SetFromWindowsErr(error);
420 }
421 if (!high && low < LONG_MAX)
Christian Heimes217cfd12007-12-02 14:31:20 +0000422 return PyLong_FromLong((long)low);
Martin v. Löwis15186072006-02-18 12:38:35 +0000423 size = (((PY_LONG_LONG)high)<<32) + low;
424 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000425 } else {
Christian Heimes217cfd12007-12-02 14:31:20 +0000426 return PyLong_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000427 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000428#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429
430#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000431 {
432 struct stat buf;
433 if (-1 == fstat(self->fd, &buf)) {
434 PyErr_SetFromErrno(mmap_module_error);
435 return NULL;
436 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000437 return PyLong_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000438 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000439#endif /* UNIX */
440}
441
442/* This assumes that you want the entire file mapped,
443 / and when recreating the map will make the new file
444 / have the new size
445 /
446 / Is this really necessary? This could easily be done
447 / from python by just closing and re-opening with the
448 / new size?
449 */
450
451static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000452mmap_resize_method(mmap_object *self,
453 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000454{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000455 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000456 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000457 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000458 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000459 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000460#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000461 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000462 DWORD dwErrCode = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000463 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000464 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000465 UnmapViewOfFile(self->data);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000466 self->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000467 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000468 CloseHandle(self->map_handle);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000469 self->map_handle = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000470 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000471#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000472 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
473 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
474 off_hi = (DWORD)(self->offset >> 32);
475 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000476#else
477 newSizeHigh = 0;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000478 newSizeLow = (DWORD)(self->offset + new_size);
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000479 off_hi = 0;
480 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000481#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000482 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000483 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000484 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000485 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000486 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000487 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000488 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000489 NULL,
490 PAGE_READWRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000491 0,
492 0,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000493 self->tagname);
494 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000495 self->data = (char *) MapViewOfFile(self->map_handle,
496 FILE_MAP_WRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000497 off_hi,
498 off_lo,
499 new_size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000500 if (self->data != NULL) {
501 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000502 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000503 return Py_None;
504 } else {
505 dwErrCode = GetLastError();
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000506 CloseHandle(self->map_handle);
507 self->map_handle = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000508 }
509 } else {
510 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000511 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000512 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000513 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000514#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515
516#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000517#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000518 } else {
519 PyErr_SetString(PyExc_SystemError,
520 "mmap: resizing not available--no mremap()");
521 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000522#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000523 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000524 void *newmap;
525
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000526 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Georg Brandl38387b82005-08-24 07:17:40 +0000527 PyErr_SetFromErrno(mmap_module_error);
528 return NULL;
529 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000530
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000531#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000532 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000533#else
Jesse Noller32d68c22009-03-31 18:48:42 +0000534 #if defined(__NetBSD__)
535 newmap = mremap(self->data, self->size, self->data, new_size, 0);
536 #else
537 newmap = mremap(self->data, self->size, new_size, 0);
538 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000539#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000540 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000541 {
542 PyErr_SetFromErrno(mmap_module_error);
543 return NULL;
544 }
545 self->data = newmap;
546 self->size = new_size;
547 Py_INCREF(Py_None);
548 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000549#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000551 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552}
553
554static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000555mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000556{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000557 CHECK_VALID(NULL);
Christian Heimes217cfd12007-12-02 14:31:20 +0000558 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000559}
560
561static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000562mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000563{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000564 Py_ssize_t offset = 0;
565 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000566 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000567 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000568 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000569 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000570 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000571 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000572 }
Christian Heimesaf98da12008-01-27 15:18:18 +0000573#ifdef MS_WINDOWS
574 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
575#elif defined(UNIX)
576 /* XXX semantics of return value? */
577 /* XXX flags for msync? */
578 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
579 PyErr_SetFromErrno(mmap_module_error);
580 return NULL;
581 }
582 return PyLong_FromLong(0);
583#else
584 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
585 return NULL;
586#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000587}
588
589static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000590mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000591{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000592 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000593 int how=0;
594 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000595 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000596 return NULL;
597 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000598 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000599 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000600 case 0: /* relative to start */
601 if (dist < 0)
602 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000603 where = dist;
604 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000605 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000606 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000607 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000608 where = self->pos + dist;
609 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000610 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000611 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000612 goto onoutofrange;
613 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000614 break;
615 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000616 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000617 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000618 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000619 if (where > self->size)
620 goto onoutofrange;
621 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000622 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000623 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000624 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000625
Tim Peters5ebfd362001-11-13 23:11:19 +0000626 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000627 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000628 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000629}
630
631static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000632mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000633{
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000634 unsigned long dest, src, cnt;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000635 CHECK_VALID(NULL);
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000636 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000637 !is_writable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000638 return NULL;
639 } else {
640 /* bounds check the values */
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000641 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
642 src < 0 || src > self->size || (src + cnt) > self->size ||
643 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000644 PyErr_SetString(PyExc_ValueError,
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000645 "source, destination, or count out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000646 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000647 }
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000648 memmove(self->data+dest, self->data+src, cnt);
649 Py_INCREF(Py_None);
650 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000651 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652}
653
654static struct PyMethodDef mmap_object_methods[] = {
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000655 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000656 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Georg Brandlfceab5a2008-01-19 20:08:23 +0000657 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000658 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
659 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
660 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000661 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
662 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000663 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
664 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000665 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
666 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000667 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
668 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000669 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000670};
671
672/* Functions for treating an mmap'ed file as a buffer */
673
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000674static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000675mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000676{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000677 CHECK_VALID(-1);
Martin v. Löwis423be952008-08-13 15:53:07 +0000678 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000679 (self->access == ACCESS_READ), flags) < 0)
680 return -1;
681 self->exports++;
682 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000683}
684
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000685static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000686mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000687{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000688 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000689}
690
Martin v. Löwis18e16552006-02-15 17:27:45 +0000691static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000692mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000693{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000694 CHECK_VALID(-1);
695 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000696}
697
698static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000699mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000700{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000701 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000702 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000703 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
704 return NULL;
705 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000706 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000707}
708
709static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000710mmap_subscript(mmap_object *self, PyObject *item)
711{
712 CHECK_VALID(NULL);
713 if (PyIndex_Check(item)) {
714 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
715 if (i == -1 && PyErr_Occurred())
716 return NULL;
717 if (i < 0)
718 i += self->size;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000719 if (i < 0 || (size_t)i >= self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000720 PyErr_SetString(PyExc_IndexError,
721 "mmap index out of range");
722 return NULL;
723 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000724 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
Thomas Woutersed03b412007-08-28 21:37:11 +0000725 }
726 else if (PySlice_Check(item)) {
727 Py_ssize_t start, stop, step, slicelen;
728
729 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
730 &start, &stop, &step, &slicelen) < 0) {
731 return NULL;
732 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000733
Thomas Woutersed03b412007-08-28 21:37:11 +0000734 if (slicelen <= 0)
Christian Heimes72b710a2008-05-26 13:28:38 +0000735 return PyBytes_FromStringAndSize("", 0);
Thomas Woutersed03b412007-08-28 21:37:11 +0000736 else if (step == 1)
Christian Heimes72b710a2008-05-26 13:28:38 +0000737 return PyBytes_FromStringAndSize(self->data + start,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000738 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000739 else {
740 char *result_buf = (char *)PyMem_Malloc(slicelen);
741 Py_ssize_t cur, i;
742 PyObject *result;
743
744 if (result_buf == NULL)
745 return PyErr_NoMemory();
746 for (cur = start, i = 0; i < slicelen;
747 cur += step, i++) {
748 result_buf[i] = self->data[cur];
749 }
Christian Heimes72b710a2008-05-26 13:28:38 +0000750 result = PyBytes_FromStringAndSize(result_buf,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000751 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000752 PyMem_Free(result_buf);
753 return result;
754 }
755 }
756 else {
757 PyErr_SetString(PyExc_TypeError,
758 "mmap indices must be integers");
759 return NULL;
760 }
761}
762
763static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000764mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000765{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000766 CHECK_VALID(NULL);
767 PyErr_SetString(PyExc_SystemError,
768 "mmaps don't support concatenation");
769 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000770}
771
772static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000773mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000774{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000775 CHECK_VALID(NULL);
776 PyErr_SetString(PyExc_SystemError,
777 "mmaps don't support repeat operation");
778 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000779}
780
781static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000782mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000783{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000784 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000785
Guido van Rossum09fdf072000-03-31 01:17:07 +0000786 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000787 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000788 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
789 return -1;
790 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000791 if (v == NULL) {
792 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000793 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000794 return -1;
795 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000796 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000797 PyErr_SetString(PyExc_IndexError,
Thomas Woutersed03b412007-08-28 21:37:11 +0000798 "mmap assignment must be length-1 bytes()");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000799 return -1;
800 }
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000801 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000802 return -1;
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000803 buf = PyBytes_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000804 self->data[i] = buf[0];
805 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000806}
807
Thomas Woutersed03b412007-08-28 21:37:11 +0000808static int
809mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
810{
811 CHECK_VALID(-1);
812
Guido van Rossum98297ee2007-11-06 21:34:58 +0000813 if (!is_writable(self))
814 return -1;
815
Thomas Woutersed03b412007-08-28 21:37:11 +0000816 if (PyIndex_Check(item)) {
817 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000818 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000819
820 if (i == -1 && PyErr_Occurred())
821 return -1;
822 if (i < 0)
823 i += self->size;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000824 if (i < 0 || (size_t)i >= self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000825 PyErr_SetString(PyExc_IndexError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000826 "mmap index out of range");
Thomas Woutersed03b412007-08-28 21:37:11 +0000827 return -1;
828 }
829 if (value == NULL) {
830 PyErr_SetString(PyExc_TypeError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000831 "mmap doesn't support item deletion");
Thomas Woutersed03b412007-08-28 21:37:11 +0000832 return -1;
833 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000834 if (!PyIndex_Check(value)) {
835 PyErr_SetString(PyExc_TypeError,
836 "mmap item value must be an int");
Thomas Woutersed03b412007-08-28 21:37:11 +0000837 return -1;
838 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000839 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
840 if (v == -1 && PyErr_Occurred())
Thomas Woutersed03b412007-08-28 21:37:11 +0000841 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000842 if (v < 0 || v > 255) {
843 PyErr_SetString(PyExc_ValueError,
844 "mmap item value must be "
845 "in range(0, 256)");
846 return -1;
847 }
848 self->data[i] = v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000849 return 0;
850 }
851 else if (PySlice_Check(item)) {
852 Py_ssize_t start, stop, step, slicelen;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000853 Py_buffer vbuf;
854
Thomas Woutersed03b412007-08-28 21:37:11 +0000855 if (PySlice_GetIndicesEx((PySliceObject *)item,
856 self->size, &start, &stop,
857 &step, &slicelen) < 0) {
858 return -1;
859 }
860 if (value == NULL) {
861 PyErr_SetString(PyExc_TypeError,
862 "mmap object doesn't support slice deletion");
863 return -1;
864 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000865 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000866 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000867 if (vbuf.len != slicelen) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000868 PyErr_SetString(PyExc_IndexError,
869 "mmap slice assignment is wrong size");
Martin v. Löwis423be952008-08-13 15:53:07 +0000870 PyBuffer_Release(&vbuf);
Thomas Woutersed03b412007-08-28 21:37:11 +0000871 return -1;
872 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000873
Guido van Rossum98297ee2007-11-06 21:34:58 +0000874 if (slicelen == 0) {
875 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000876 else if (step == 1) {
Guido van Rossum98297ee2007-11-06 21:34:58 +0000877 memcpy(self->data + start, vbuf.buf, slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000878 }
879 else {
880 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000881
882 for (cur = start, i = 0;
883 i < slicelen;
884 cur += step, i++)
885 {
886 self->data[cur] = ((char *)vbuf.buf)[i];
Thomas Woutersed03b412007-08-28 21:37:11 +0000887 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000888 }
Martin v. Löwis423be952008-08-13 15:53:07 +0000889 PyBuffer_Release(&vbuf);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000890 return 0;
Thomas Woutersed03b412007-08-28 21:37:11 +0000891 }
892 else {
893 PyErr_SetString(PyExc_TypeError,
894 "mmap indices must be integer");
895 return -1;
896 }
897}
898
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000899static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000900 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000901 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000902 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
903 (ssizeargfunc)mmap_item, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000904 0, /*sq_slice*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000905 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000906 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000907};
908
Thomas Woutersed03b412007-08-28 21:37:11 +0000909static PyMappingMethods mmap_as_mapping = {
910 (lenfunc)mmap_length,
911 (binaryfunc)mmap_subscript,
912 (objobjargproc)mmap_ass_subscript,
913};
914
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000915static PyBufferProcs mmap_as_buffer = {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000916 (getbufferproc)mmap_buffer_getbuf,
917 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000918};
919
Georg Brandl86def6c2008-01-21 20:36:10 +0000920static PyObject *
921new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
922
Christian Heimese1c98112008-01-21 11:20:28 +0000923PyDoc_STRVAR(mmap_doc,
924"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
925\n\
926Maps length bytes from the file specified by the file handle fileno,\n\
927and returns a mmap object. If length is larger than the current size\n\
928of the file, the file is extended to contain length bytes. If length\n\
929is 0, the maximum length of the map is the current size of the file,\n\
930except that if the file is empty Windows raises an exception (you cannot\n\
931create an empty mapping on Windows).\n\
932\n\
933Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
934\n\
935Maps length bytes from the file specified by the file descriptor fileno,\n\
936and returns a mmap object. If length is 0, the maximum length of the map\n\
937will be the current size of the file when mmap is called.\n\
938flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
939private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000940object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000941that's shared with all other processes mapping the same areas of the file.\n\
942The default value is MAP_SHARED.\n\
943\n\
944To map anonymous memory, pass -1 as the fileno (both versions).");
945
946
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000947static PyTypeObject mmap_object_type = {
Georg Brandl86def6c2008-01-21 20:36:10 +0000948 PyVarObject_HEAD_INIT(NULL, 0)
Guido van Rossum14648392001-12-08 18:02:58 +0000949 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000950 sizeof(mmap_object), /* tp_size */
951 0, /* tp_itemsize */
952 /* methods */
953 (destructor) mmap_object_dealloc, /* tp_dealloc */
954 0, /* tp_print */
Christian Heimese1c98112008-01-21 11:20:28 +0000955 0, /* tp_getattr */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000956 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000957 0, /* tp_reserved */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000958 0, /* tp_repr */
959 0, /* tp_as_number */
960 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Woutersed03b412007-08-28 21:37:11 +0000961 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000962 0, /*tp_hash*/
963 0, /*tp_call*/
964 0, /*tp_str*/
Christian Heimese1c98112008-01-21 11:20:28 +0000965 PyObject_GenericGetAttr, /*tp_getattro*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000966 0, /*tp_setattro*/
967 &mmap_as_buffer, /*tp_as_buffer*/
Georg Brandl86def6c2008-01-21 20:36:10 +0000968 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Christian Heimese1c98112008-01-21 11:20:28 +0000969 mmap_doc, /*tp_doc*/
970 0, /* tp_traverse */
971 0, /* tp_clear */
972 0, /* tp_richcompare */
973 0, /* tp_weaklistoffset */
Georg Brandl86def6c2008-01-21 20:36:10 +0000974 0, /* tp_iter */
975 0, /* tp_iternext */
Christian Heimese1c98112008-01-21 11:20:28 +0000976 mmap_object_methods, /* tp_methods */
Georg Brandl86def6c2008-01-21 20:36:10 +0000977 0, /* tp_members */
978 0, /* tp_getset */
979 0, /* tp_base */
980 0, /* tp_dict */
981 0, /* tp_descr_get */
982 0, /* tp_descr_set */
983 0, /* tp_dictoffset */
984 0, /* tp_init */
985 PyType_GenericAlloc, /* tp_alloc */
986 new_mmap_object, /* tp_new */
987 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000988};
989
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000990
991/* extract the map size from the given PyObject
992
Thomas Wouters7e474022000-07-16 12:04:32 +0000993 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000994 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000995static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000996_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000997{
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000998 if (o == NULL)
999 return 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001000 if (PyIndex_Check(o)) {
1001 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum98297ee2007-11-06 21:34:58 +00001002 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001003 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +00001004 if (i < 0) {
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001005 PyErr_Format(PyExc_OverflowError,
1006 "memory mapped %s must be positive",
1007 param);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001008 return -1;
1009 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001010 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001011 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001012
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001013 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001014 return -1;
1015}
1016
Tim Petersec0a5f02006-02-16 23:47:20 +00001017#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001018static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001019new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001020{
Neal Norwitzb5673922002-09-05 21:48:07 +00001021#ifdef HAVE_FSTAT
1022 struct stat st;
1023#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001024 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001025 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1026 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001027 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001028 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001029 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001030 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001031 "flags", "prot",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001032 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001033
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001034 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001035 &fd, &map_size_obj, &flags, &prot,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001036 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001037 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001038 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001039 if (map_size < 0)
1040 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001041 offset = _GetMapSize(offset_obj, "offset");
1042 if (offset < 0)
1043 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001044
Tim Petersec0a5f02006-02-16 23:47:20 +00001045 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001046 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001047 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001048 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001049 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001050 case ACCESS_READ:
1051 flags = MAP_SHARED;
1052 prot = PROT_READ;
1053 break;
1054 case ACCESS_WRITE:
1055 flags = MAP_SHARED;
1056 prot = PROT_READ | PROT_WRITE;
1057 break;
1058 case ACCESS_COPY:
1059 flags = MAP_PRIVATE;
1060 prot = PROT_READ | PROT_WRITE;
1061 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001062 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001063 /* use the specified or default values of flags and prot */
1064 break;
1065 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001066 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001067 "mmap invalid access parameter.");
1068 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001069
Christian Heimesa156e092008-02-16 07:38:31 +00001070 if (prot == PROT_READ) {
1071 access = ACCESS_READ;
1072 }
1073
Neal Norwitzb5673922002-09-05 21:48:07 +00001074#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001075# ifdef __VMS
1076 /* on OpenVMS we must ensure that all bytes are written to the file */
Christian Heimes25bb7832008-01-11 16:17:00 +00001077 if (fd != -1) {
1078 fsync(fd);
1079 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001080# endif
Christian Heimes25bb7832008-01-11 16:17:00 +00001081 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001082 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001083 map_size = st.st_size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001084 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001085 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001086 "mmap length is greater than file size");
1087 return NULL;
1088 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001089 }
1090#endif
Georg Brandl86def6c2008-01-21 20:36:10 +00001091 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001092 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001093 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001094 m_obj->size = (size_t) map_size;
1095 m_obj->pos = (size_t) 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001096 m_obj->exports = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001097 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001098 if (fd == -1) {
1099 m_obj->fd = -1;
1100 /* Assume the caller wants to map anonymous memory.
1101 This is the same behaviour as Windows. mmap.mmap(-1, size)
1102 on both Windows and Unix map anonymous memory.
1103 */
1104#ifdef MAP_ANONYMOUS
1105 /* BSD way to map anonymous memory */
1106 flags |= MAP_ANONYMOUS;
1107#else
1108 /* SVR4 method to map anonymous memory is to open /dev/zero */
1109 fd = devzero = open("/dev/zero", O_RDWR);
1110 if (devzero == -1) {
1111 Py_DECREF(m_obj);
1112 PyErr_SetFromErrno(mmap_module_error);
1113 return NULL;
1114 }
1115#endif
1116 } else {
1117 m_obj->fd = dup(fd);
1118 if (m_obj->fd == -1) {
1119 Py_DECREF(m_obj);
1120 PyErr_SetFromErrno(mmap_module_error);
1121 return NULL;
1122 }
Georg Brandl38387b82005-08-24 07:17:40 +00001123 }
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001124
Tim Petersec0a5f02006-02-16 23:47:20 +00001125 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001126 prot, flags,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001127 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001128
1129 if (devzero != -1) {
1130 close(devzero);
1131 }
1132
Tim Peters5ebfd362001-11-13 23:11:19 +00001133 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001134 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001135 Py_DECREF(m_obj);
1136 PyErr_SetFromErrno(mmap_module_error);
1137 return NULL;
1138 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001139 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001140 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001141}
1142#endif /* UNIX */
1143
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001144#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001145static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001146new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001147{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001148 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001149 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1150 Py_ssize_t map_size, offset;
1151 DWORD off_hi; /* upper 32 bits of offset */
1152 DWORD off_lo; /* lower 32 bits of offset */
1153 DWORD size_hi; /* upper 32 bits of size */
1154 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001155 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001156 DWORD dwErr = 0;
1157 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001158 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001159 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001160 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001161 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001162 "tagname",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001163 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001164
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001165 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001166 &fileno, &map_size_obj,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001167 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001168 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001169 }
1170
Neal Norwitz8856fb72005-12-18 03:34:22 +00001171 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001172 case ACCESS_READ:
1173 flProtect = PAGE_READONLY;
1174 dwDesiredAccess = FILE_MAP_READ;
1175 break;
1176 case ACCESS_DEFAULT: case ACCESS_WRITE:
1177 flProtect = PAGE_READWRITE;
1178 dwDesiredAccess = FILE_MAP_WRITE;
1179 break;
1180 case ACCESS_COPY:
1181 flProtect = PAGE_WRITECOPY;
1182 dwDesiredAccess = FILE_MAP_COPY;
1183 break;
1184 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001185 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001186 "mmap invalid access parameter.");
1187 }
1188
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001189 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001190 if (map_size < 0)
1191 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001192 offset = _GetMapSize(offset_obj, "offset");
1193 if (offset < 0)
1194 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001195
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001196 /* assume -1 and 0 both mean invalid filedescriptor
1197 to 'anonymously' map memory.
1198 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1199 XXX: Should this code be added?
1200 if (fileno == 0)
Skip Montanaro46fc3372007-08-12 11:44:53 +00001201 PyErr_WarnEx(PyExc_DeprecationWarning,
1202 "don't use 0 for anonymous memory",
1203 1);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001204 */
1205 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001206 fh = (HANDLE)_get_osfhandle(fileno);
1207 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001208 PyErr_SetFromErrno(mmap_module_error);
1209 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001210 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001211 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001212 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001213 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001214
Georg Brandl86def6c2008-01-21 20:36:10 +00001215 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Tim Peters8f9cc292006-02-17 00:00:20 +00001216 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001217 return NULL;
1218 /* Set every field to an invalid marker, so we can safely
1219 destruct the object in the face of failure */
1220 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001221 m_obj->file_handle = INVALID_HANDLE_VALUE;
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +00001222 m_obj->map_handle = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001223 m_obj->tagname = NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001224 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001225
Guido van Rossum09fdf072000-03-31 01:17:07 +00001226 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001227 /* It is necessary to duplicate the handle, so the
1228 Python code can close it on us */
1229 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001230 GetCurrentProcess(), /* source process handle */
1231 fh, /* handle to be duplicated */
1232 GetCurrentProcess(), /* target proc handle */
1233 (LPHANDLE)&m_obj->file_handle, /* result */
1234 0, /* access - ignored due to options value */
1235 FALSE, /* inherited by child processes? */
1236 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001237 dwErr = GetLastError();
1238 Py_DECREF(m_obj);
1239 PyErr_SetFromWindowsErr(dwErr);
1240 return NULL;
1241 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001242 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001243 DWORD low,high;
1244 low = GetFileSize(fh, &high);
1245 /* low might just happen to have the value INVALID_FILE_SIZE;
1246 so we need to check the last error also. */
1247 if (low == INVALID_FILE_SIZE &&
1248 (dwErr = GetLastError()) != NO_ERROR) {
1249 Py_DECREF(m_obj);
1250 return PyErr_SetFromWindowsErr(dwErr);
Guido van Rossum98297ee2007-11-06 21:34:58 +00001251 }
1252
Martin v. Löwis15186072006-02-18 12:38:35 +00001253#if SIZEOF_SIZE_T > 4
1254 m_obj->size = (((size_t)high)<<32) + low;
1255#else
1256 if (high)
1257 /* File is too large to map completely */
1258 m_obj->size = (size_t)-1;
1259 else
1260 m_obj->size = low;
1261#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001262 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001263 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001264 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001265 }
1266 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001267 m_obj->size = map_size;
1268 }
1269
1270 /* set the initial position */
1271 m_obj->pos = (size_t) 0;
1272
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001273 m_obj->exports = 0;
Mark Hammond2cbed002000-07-30 02:22:43 +00001274 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001275 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001276 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1277 if (m_obj->tagname == NULL) {
1278 PyErr_NoMemory();
1279 Py_DECREF(m_obj);
1280 return NULL;
1281 }
1282 strcpy(m_obj->tagname, tagname);
1283 }
1284 else
1285 m_obj->tagname = NULL;
1286
Neal Norwitz8856fb72005-12-18 03:34:22 +00001287 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001288 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001289 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001290 * consumes 4 bytes), C doesn't define what happens if we shift
1291 * right by 32, so we need different code.
1292 */
1293#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001294 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1295 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1296 off_hi = (DWORD)(offset >> 32);
1297 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001298#else
1299 size_hi = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001300 size_lo = (DWORD)(offset + m_obj->size);
1301 off_hi = 0;
1302 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001303#endif
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001304 /* For files, it would be sufficient to pass 0 as size.
1305 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001306 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1307 NULL,
1308 flProtect,
1309 size_hi,
1310 size_lo,
1311 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001312 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001313 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1314 dwDesiredAccess,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001315 off_hi,
1316 off_lo,
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +00001317 m_obj->size);
Tim Peters23721ee2006-02-16 23:50:16 +00001318 if (m_obj->data != NULL)
1319 return (PyObject *)m_obj;
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +00001320 else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001321 dwErr = GetLastError();
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +00001322 CloseHandle(m_obj->map_handle);
1323 m_obj->map_handle = NULL;
1324 }
Tim Peters23721ee2006-02-16 23:50:16 +00001325 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001326 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001327 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001328 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001329 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001330}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001331#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001332
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001333static void
1334setint(PyObject *d, const char *name, long value)
1335{
Christian Heimes217cfd12007-12-02 14:31:20 +00001336 PyObject *o = PyLong_FromLong(value);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001337 if (o && PyDict_SetItemString(d, name, o) == 0) {
1338 Py_DECREF(o);
1339 }
1340}
1341
Martin v. Löwis1a214512008-06-11 05:26:20 +00001342
1343static struct PyModuleDef mmapmodule = {
1344 PyModuleDef_HEAD_INIT,
1345 "mmap",
1346 NULL,
1347 -1,
1348 NULL,
1349 NULL,
1350 NULL,
1351 NULL,
1352 NULL
1353};
1354
Mark Hammond62b1ab12002-07-23 06:31:15 +00001355PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001356PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001357{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001358 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001359
Georg Brandl86def6c2008-01-21 20:36:10 +00001360 if (PyType_Ready(&mmap_object_type) < 0)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001361 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001362
Martin v. Löwis1a214512008-06-11 05:26:20 +00001363 module = PyModule_Create(&mmapmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001364 if (module == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001365 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001366 dict = PyModule_GetDict(module);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001367 if (!dict)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001368 return NULL;
Christian Heimes7131fd92008-02-19 14:21:46 +00001369 mmap_module_error = PyErr_NewException("mmap.error",
1370 PyExc_EnvironmentError , NULL);
1371 if (mmap_module_error == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001372 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001373 PyDict_SetItemString(dict, "error", mmap_module_error);
Georg Brandl86def6c2008-01-21 20:36:10 +00001374 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001375#ifdef PROT_EXEC
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001376 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001377#endif
1378#ifdef PROT_READ
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001379 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001380#endif
1381#ifdef PROT_WRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001382 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001383#endif
1384
1385#ifdef MAP_SHARED
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001386 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001387#endif
1388#ifdef MAP_PRIVATE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001389 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001390#endif
1391#ifdef MAP_DENYWRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001392 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001393#endif
1394#ifdef MAP_EXECUTABLE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001395 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001396#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001397#ifdef MAP_ANONYMOUS
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001398 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1399 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001400#endif
1401
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001402 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001403
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001404 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1405
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001406 setint(dict, "ACCESS_READ", ACCESS_READ);
1407 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1408 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Martin v. Löwis1a214512008-06-11 05:26:20 +00001409 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001410}