blob: 6a2ebfd45da7549054d4449eda448368e0f0f810 [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);
116 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
117 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 }
156 if (self->map_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000157 CloseHandle(self->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000158 self->map_handle = INVALID_HANDLE_VALUE;
159 }
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
Neal Norwitz6eac2002005-11-02 05:36:37 +0000167 (void) close(self->fd);
168 self->fd = -1;
Neal Norwitze604c022003-01-10 20:52:16 +0000169 if (self->data != NULL) {
170 munmap(self->data, self->size);
171 self->data = NULL;
172 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000173#endif
174
Tim Peters8f9cc292006-02-17 00:00:20 +0000175 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000176 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000177}
178
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000179#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000180#define CHECK_VALID(err) \
181do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000182 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000183 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000184 return err; \
185 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000186} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000187#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000188
189#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000190#define CHECK_VALID(err) \
191do { \
192 if (self->data == NULL) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000193 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000194 return err; \
195 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000196} while (0)
197#endif /* UNIX */
198
199static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000200mmap_read_byte_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000201 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000202{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000203 CHECK_VALID(NULL);
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000204 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000205 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000206 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000207 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000208 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000209 PyErr_SetString(PyExc_ValueError, "read byte out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000210 return NULL;
211 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000212}
213
214static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000215mmap_read_line_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000216 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000218 char *start = self->data+self->pos;
219 char *eof = self->data+self->size;
220 char *eol;
221 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000222
Guido van Rossum09fdf072000-03-31 01:17:07 +0000223 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224
Fred Drake56a87a02000-04-04 18:17:35 +0000225 eol = memchr(start, '\n', self->size - self->pos);
226 if (!eol)
227 eol = eof;
228 else
229 ++eol; /* we're interested in the position after the
230 newline. */
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000231 result = PyBytes_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000232 self->pos += (eol - start);
Tim Peters23721ee2006-02-16 23:50:16 +0000233 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000234}
235
236static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000237mmap_read_method(mmap_object *self,
238 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000239{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000240 Py_ssize_t num_bytes;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000241 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000242
Guido van Rossum09fdf072000-03-31 01:17:07 +0000243 CHECK_VALID(NULL);
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000244 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000245 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246
Guido van Rossum09fdf072000-03-31 01:17:07 +0000247 /* silently 'adjust' out-of-range requests */
Neal Norwitz3ce5d922008-08-24 07:08:55 +0000248 if (num_bytes > self->size - self->pos) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000249 num_bytes -= (self->pos+num_bytes) - self->size;
250 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000251 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
Tim Petersec0a5f02006-02-16 23:47:20 +0000252 self->pos += num_bytes;
Tim Peters23721ee2006-02-16 23:50:16 +0000253 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000254}
255
256static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000257mmap_gfind(mmap_object *self,
258 PyObject *args,
259 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000260{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000261 Py_ssize_t start = self->pos;
Christian Heimesaf98da12008-01-27 15:18:18 +0000262 Py_ssize_t end = self->size;
263 const char *needle;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000264 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000265
Guido van Rossum09fdf072000-03-31 01:17:07 +0000266 CHECK_VALID(NULL);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000267 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
268 &needle, &len, &start, &end)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000269 return NULL;
270 } else {
Christian Heimesaf98da12008-01-27 15:18:18 +0000271 const char *p, *start_p, *end_p;
272 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000273
274 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000275 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000276 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000277 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000278 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000279 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000280
Georg Brandlfceab5a2008-01-19 20:08:23 +0000281 if (end < 0)
282 end += self->size;
283 if (end < 0)
284 end = 0;
285 else if ((size_t)end > self->size)
286 end = self->size;
287
Christian Heimesaf98da12008-01-27 15:18:18 +0000288 start_p = self->data + start;
289 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000290
Christian Heimesaf98da12008-01-27 15:18:18 +0000291 for (p = (reverse ? end_p - len : start_p);
292 (p >= start_p) && (p + len <= end_p); p += sign) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000293 Py_ssize_t i;
Tim Petersc9ffa062002-03-08 05:43:32 +0000294 for (i = 0; i < len && needle[i] == p[i]; ++i)
295 /* nothing */;
296 if (i == len) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000297 return PyLong_FromSsize_t(p - self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000298 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000299 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000300 return PyLong_FromLong(-1);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000301 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000302}
303
Georg Brandlfceab5a2008-01-19 20:08:23 +0000304static PyObject *
305mmap_find_method(mmap_object *self,
306 PyObject *args)
307{
308 return mmap_gfind(self, args, 0);
309}
310
311static PyObject *
312mmap_rfind_method(mmap_object *self,
313 PyObject *args)
314{
315 return mmap_gfind(self, args, 1);
316}
317
Tim Petersec0a5f02006-02-16 23:47:20 +0000318static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000319is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000320{
321 if (self->access != ACCESS_READ)
Tim Petersec0a5f02006-02-16 23:47:20 +0000322 return 1;
Tim Peters5ebfd362001-11-13 23:11:19 +0000323 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
324 return 0;
325}
326
Tim Petersec0a5f02006-02-16 23:47:20 +0000327static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000328is_resizeable(mmap_object *self)
329{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000330 if (self->exports > 0) {
331 PyErr_SetString(PyExc_BufferError,
332 "mmap can't resize with extant buffers exported.");
333 return 0;
334 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000335 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
Guido van Rossum98297ee2007-11-06 21:34:58 +0000336 return 1;
Tim Petersec0a5f02006-02-16 23:47:20 +0000337 PyErr_Format(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000338 "mmap can't resize a readonly or copy-on-write memory map.");
339 return 0;
340}
341
342
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000343static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000344mmap_write_method(mmap_object *self,
345 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000346{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000347 Py_ssize_t length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000348 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000349
Guido van Rossum09fdf072000-03-31 01:17:07 +0000350 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000351 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000352 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000353
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000354 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000355 return NULL;
356
Guido van Rossum09fdf072000-03-31 01:17:07 +0000357 if ((self->pos + length) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000358 PyErr_SetString(PyExc_ValueError, "data out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000359 return NULL;
360 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000361 memcpy(self->data+self->pos, data, length);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000362 self->pos = self->pos+length;
Tim Peters8f9cc292006-02-17 00:00:20 +0000363 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000364 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000365}
366
367static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000368mmap_write_byte_method(mmap_object *self,
369 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000370{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000371 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000372
Guido van Rossum09fdf072000-03-31 01:17:07 +0000373 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000374 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000375 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000376
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000377 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000378 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000379 *(self->data+self->pos) = value;
380 self->pos += 1;
Tim Peters8f9cc292006-02-17 00:00:20 +0000381 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000382 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000383}
Tim Petersec0a5f02006-02-16 23:47:20 +0000384
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000385static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000386mmap_size_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000387 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000388{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000389 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000390
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000391#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000392 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000393 DWORD low,high;
394 PY_LONG_LONG size;
395 low = GetFileSize(self->file_handle, &high);
396 if (low == INVALID_FILE_SIZE) {
397 /* It might be that the function appears to have failed,
398 when indeed its size equals INVALID_FILE_SIZE */
399 DWORD error = GetLastError();
400 if (error != NO_ERROR)
401 return PyErr_SetFromWindowsErr(error);
402 }
403 if (!high && low < LONG_MAX)
Christian Heimes217cfd12007-12-02 14:31:20 +0000404 return PyLong_FromLong((long)low);
Martin v. Löwis15186072006-02-18 12:38:35 +0000405 size = (((PY_LONG_LONG)high)<<32) + low;
406 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000407 } else {
Christian Heimes217cfd12007-12-02 14:31:20 +0000408 return PyLong_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000409 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000410#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000411
412#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000413 {
414 struct stat buf;
415 if (-1 == fstat(self->fd, &buf)) {
416 PyErr_SetFromErrno(mmap_module_error);
417 return NULL;
418 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000419 return PyLong_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000420 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000421#endif /* UNIX */
422}
423
424/* This assumes that you want the entire file mapped,
425 / and when recreating the map will make the new file
426 / have the new size
427 /
428 / Is this really necessary? This could easily be done
429 / from python by just closing and re-opening with the
430 / new size?
431 */
432
433static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000434mmap_resize_method(mmap_object *self,
435 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000436{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000437 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000438 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000439 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000440 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000441 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000442#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000443 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000444 DWORD dwErrCode = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000445 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000446 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000447 UnmapViewOfFile(self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000448 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000449 CloseHandle(self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000450 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000451#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000452 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
453 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
454 off_hi = (DWORD)(self->offset >> 32);
455 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000456#else
457 newSizeHigh = 0;
Martin v. Löwis5bb8a152006-02-18 12:49:49 +0000458 newSizeLow = (DWORD)new_size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000459 off_hi = 0;
460 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000461#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000462 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000463 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000464 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000465 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000466 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000467 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000468 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000469 NULL,
470 PAGE_READWRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000471 0,
472 0,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000473 self->tagname);
474 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000475 self->data = (char *) MapViewOfFile(self->map_handle,
476 FILE_MAP_WRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000477 off_hi,
478 off_lo,
479 new_size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000480 if (self->data != NULL) {
481 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000482 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000483 return Py_None;
484 } else {
485 dwErrCode = GetLastError();
486 }
487 } else {
488 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000489 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000490 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000491 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000492#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000493
494#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000495#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000496 } else {
497 PyErr_SetString(PyExc_SystemError,
498 "mmap: resizing not available--no mremap()");
499 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000500#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000501 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000502 void *newmap;
503
Georg Brandl38387b82005-08-24 07:17:40 +0000504 if (ftruncate(self->fd, new_size) == -1) {
505 PyErr_SetFromErrno(mmap_module_error);
506 return NULL;
507 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000508
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000509#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000510 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000511#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000512 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000513#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000514 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000515 {
516 PyErr_SetFromErrno(mmap_module_error);
517 return NULL;
518 }
519 self->data = newmap;
520 self->size = new_size;
521 Py_INCREF(Py_None);
522 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000523#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000524#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000525 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000526}
527
528static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000529mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000530{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000531 CHECK_VALID(NULL);
Christian Heimes217cfd12007-12-02 14:31:20 +0000532 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000533}
534
535static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000536mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000537{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000538 Py_ssize_t offset = 0;
539 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000540 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000541 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000542 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000543 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000544 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000545 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000546 }
Christian Heimesaf98da12008-01-27 15:18:18 +0000547#ifdef MS_WINDOWS
548 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
549#elif defined(UNIX)
550 /* XXX semantics of return value? */
551 /* XXX flags for msync? */
552 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
553 PyErr_SetFromErrno(mmap_module_error);
554 return NULL;
555 }
556 return PyLong_FromLong(0);
557#else
558 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
559 return NULL;
560#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000561}
562
563static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000564mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000565{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000566 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000567 int how=0;
568 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000569 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000570 return NULL;
571 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000572 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000573 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000574 case 0: /* relative to start */
575 if (dist < 0)
576 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000577 where = dist;
578 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000579 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000580 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000581 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000582 where = self->pos + dist;
583 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000584 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000585 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000586 goto onoutofrange;
587 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000588 break;
589 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000590 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000591 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000592 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000593 if (where > self->size)
594 goto onoutofrange;
595 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000596 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000597 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000598 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000599
Tim Peters5ebfd362001-11-13 23:11:19 +0000600 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000601 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000602 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000603}
604
605static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000606mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000607{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000608 unsigned long dest, src, count;
609 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000610 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000611 !is_writable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000612 return NULL;
613 } else {
614 /* bounds check the values */
615 if (/* end of source after end of data?? */
616 ((src+count) > self->size)
617 /* dest will fit? */
618 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000619 PyErr_SetString(PyExc_ValueError,
620 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000621 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000622 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000623 memmove(self->data+dest, self->data+src, count);
624 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000625 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000626 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000627 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628}
629
630static struct PyMethodDef mmap_object_methods[] = {
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000631 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000632 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Georg Brandlfceab5a2008-01-19 20:08:23 +0000633 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000634 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
635 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
636 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000637 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
638 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000639 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
640 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000641 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
642 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000643 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
644 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000645 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000646};
647
648/* Functions for treating an mmap'ed file as a buffer */
649
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000650static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000651mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000653 CHECK_VALID(-1);
Martin v. Löwis423be952008-08-13 15:53:07 +0000654 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000655 (self->access == ACCESS_READ), flags) < 0)
656 return -1;
657 self->exports++;
658 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000659}
660
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000661static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000662mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000663{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000664 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000665}
666
Martin v. Löwis18e16552006-02-15 17:27:45 +0000667static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000668mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000669{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000670 CHECK_VALID(-1);
671 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000672}
673
674static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000675mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000676{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000677 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000678 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000679 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
680 return NULL;
681 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000682 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000683}
684
685static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000686mmap_subscript(mmap_object *self, PyObject *item)
687{
688 CHECK_VALID(NULL);
689 if (PyIndex_Check(item)) {
690 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
691 if (i == -1 && PyErr_Occurred())
692 return NULL;
693 if (i < 0)
694 i += self->size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000695 if (i < 0 || (size_t)i > self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000696 PyErr_SetString(PyExc_IndexError,
697 "mmap index out of range");
698 return NULL;
699 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000700 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
Thomas Woutersed03b412007-08-28 21:37:11 +0000701 }
702 else if (PySlice_Check(item)) {
703 Py_ssize_t start, stop, step, slicelen;
704
705 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
706 &start, &stop, &step, &slicelen) < 0) {
707 return NULL;
708 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000709
Thomas Woutersed03b412007-08-28 21:37:11 +0000710 if (slicelen <= 0)
Christian Heimes72b710a2008-05-26 13:28:38 +0000711 return PyBytes_FromStringAndSize("", 0);
Thomas Woutersed03b412007-08-28 21:37:11 +0000712 else if (step == 1)
Christian Heimes72b710a2008-05-26 13:28:38 +0000713 return PyBytes_FromStringAndSize(self->data + start,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000714 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000715 else {
716 char *result_buf = (char *)PyMem_Malloc(slicelen);
717 Py_ssize_t cur, i;
718 PyObject *result;
719
720 if (result_buf == NULL)
721 return PyErr_NoMemory();
722 for (cur = start, i = 0; i < slicelen;
723 cur += step, i++) {
724 result_buf[i] = self->data[cur];
725 }
Christian Heimes72b710a2008-05-26 13:28:38 +0000726 result = PyBytes_FromStringAndSize(result_buf,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000727 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000728 PyMem_Free(result_buf);
729 return result;
730 }
731 }
732 else {
733 PyErr_SetString(PyExc_TypeError,
734 "mmap indices must be integers");
735 return NULL;
736 }
737}
738
739static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000740mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000741{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000742 CHECK_VALID(NULL);
743 PyErr_SetString(PyExc_SystemError,
744 "mmaps don't support concatenation");
745 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000746}
747
748static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000749mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000750{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000751 CHECK_VALID(NULL);
752 PyErr_SetString(PyExc_SystemError,
753 "mmaps don't support repeat operation");
754 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755}
756
757static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000758mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000759{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000760 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000761
Guido van Rossum09fdf072000-03-31 01:17:07 +0000762 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000763 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000764 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
765 return -1;
766 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000767 if (v == NULL) {
768 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000769 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000770 return -1;
771 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000772 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000773 PyErr_SetString(PyExc_IndexError,
Thomas Woutersed03b412007-08-28 21:37:11 +0000774 "mmap assignment must be length-1 bytes()");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000775 return -1;
776 }
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000777 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000778 return -1;
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000779 buf = PyBytes_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000780 self->data[i] = buf[0];
781 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000782}
783
Thomas Woutersed03b412007-08-28 21:37:11 +0000784static int
785mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
786{
787 CHECK_VALID(-1);
788
Guido van Rossum98297ee2007-11-06 21:34:58 +0000789 if (!is_writable(self))
790 return -1;
791
Thomas Woutersed03b412007-08-28 21:37:11 +0000792 if (PyIndex_Check(item)) {
793 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000794 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000795
796 if (i == -1 && PyErr_Occurred())
797 return -1;
798 if (i < 0)
799 i += self->size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000800 if (i < 0 || (size_t)i > self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000801 PyErr_SetString(PyExc_IndexError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000802 "mmap index out of range");
Thomas Woutersed03b412007-08-28 21:37:11 +0000803 return -1;
804 }
805 if (value == NULL) {
806 PyErr_SetString(PyExc_TypeError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000807 "mmap doesn't support item deletion");
Thomas Woutersed03b412007-08-28 21:37:11 +0000808 return -1;
809 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000810 if (!PyIndex_Check(value)) {
811 PyErr_SetString(PyExc_TypeError,
812 "mmap item value must be an int");
Thomas Woutersed03b412007-08-28 21:37:11 +0000813 return -1;
814 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000815 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
816 if (v == -1 && PyErr_Occurred())
Thomas Woutersed03b412007-08-28 21:37:11 +0000817 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000818 if (v < 0 || v > 255) {
819 PyErr_SetString(PyExc_ValueError,
820 "mmap item value must be "
821 "in range(0, 256)");
822 return -1;
823 }
824 self->data[i] = v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000825 return 0;
826 }
827 else if (PySlice_Check(item)) {
828 Py_ssize_t start, stop, step, slicelen;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000829 Py_buffer vbuf;
830
Thomas Woutersed03b412007-08-28 21:37:11 +0000831 if (PySlice_GetIndicesEx((PySliceObject *)item,
832 self->size, &start, &stop,
833 &step, &slicelen) < 0) {
834 return -1;
835 }
836 if (value == NULL) {
837 PyErr_SetString(PyExc_TypeError,
838 "mmap object doesn't support slice deletion");
839 return -1;
840 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000841 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000842 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000843 if (vbuf.len != slicelen) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000844 PyErr_SetString(PyExc_IndexError,
845 "mmap slice assignment is wrong size");
Martin v. Löwis423be952008-08-13 15:53:07 +0000846 PyBuffer_Release(&vbuf);
Thomas Woutersed03b412007-08-28 21:37:11 +0000847 return -1;
848 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000849
Guido van Rossum98297ee2007-11-06 21:34:58 +0000850 if (slicelen == 0) {
851 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000852 else if (step == 1) {
Guido van Rossum98297ee2007-11-06 21:34:58 +0000853 memcpy(self->data + start, vbuf.buf, slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000854 }
855 else {
856 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000857
858 for (cur = start, i = 0;
859 i < slicelen;
860 cur += step, i++)
861 {
862 self->data[cur] = ((char *)vbuf.buf)[i];
Thomas Woutersed03b412007-08-28 21:37:11 +0000863 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000864 }
Martin v. Löwis423be952008-08-13 15:53:07 +0000865 PyBuffer_Release(&vbuf);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000866 return 0;
Thomas Woutersed03b412007-08-28 21:37:11 +0000867 }
868 else {
869 PyErr_SetString(PyExc_TypeError,
870 "mmap indices must be integer");
871 return -1;
872 }
873}
874
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000875static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000876 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000877 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000878 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
879 (ssizeargfunc)mmap_item, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000880 0, /*sq_slice*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000881 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000882 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000883};
884
Thomas Woutersed03b412007-08-28 21:37:11 +0000885static PyMappingMethods mmap_as_mapping = {
886 (lenfunc)mmap_length,
887 (binaryfunc)mmap_subscript,
888 (objobjargproc)mmap_ass_subscript,
889};
890
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000891static PyBufferProcs mmap_as_buffer = {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000892 (getbufferproc)mmap_buffer_getbuf,
893 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000894};
895
Georg Brandl86def6c2008-01-21 20:36:10 +0000896static PyObject *
897new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
898
Christian Heimese1c98112008-01-21 11:20:28 +0000899PyDoc_STRVAR(mmap_doc,
900"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
901\n\
902Maps length bytes from the file specified by the file handle fileno,\n\
903and returns a mmap object. If length is larger than the current size\n\
904of the file, the file is extended to contain length bytes. If length\n\
905is 0, the maximum length of the map is the current size of the file,\n\
906except that if the file is empty Windows raises an exception (you cannot\n\
907create an empty mapping on Windows).\n\
908\n\
909Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
910\n\
911Maps length bytes from the file specified by the file descriptor fileno,\n\
912and returns a mmap object. If length is 0, the maximum length of the map\n\
913will be the current size of the file when mmap is called.\n\
914flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
915private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000916object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000917that's shared with all other processes mapping the same areas of the file.\n\
918The default value is MAP_SHARED.\n\
919\n\
920To map anonymous memory, pass -1 as the fileno (both versions).");
921
922
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000923static PyTypeObject mmap_object_type = {
Georg Brandl86def6c2008-01-21 20:36:10 +0000924 PyVarObject_HEAD_INIT(NULL, 0)
Guido van Rossum14648392001-12-08 18:02:58 +0000925 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000926 sizeof(mmap_object), /* tp_size */
927 0, /* tp_itemsize */
928 /* methods */
929 (destructor) mmap_object_dealloc, /* tp_dealloc */
930 0, /* tp_print */
Christian Heimese1c98112008-01-21 11:20:28 +0000931 0, /* tp_getattr */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000932 0, /* tp_setattr */
933 0, /* tp_compare */
934 0, /* tp_repr */
935 0, /* tp_as_number */
936 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Woutersed03b412007-08-28 21:37:11 +0000937 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000938 0, /*tp_hash*/
939 0, /*tp_call*/
940 0, /*tp_str*/
Christian Heimese1c98112008-01-21 11:20:28 +0000941 PyObject_GenericGetAttr, /*tp_getattro*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000942 0, /*tp_setattro*/
943 &mmap_as_buffer, /*tp_as_buffer*/
Georg Brandl86def6c2008-01-21 20:36:10 +0000944 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Christian Heimese1c98112008-01-21 11:20:28 +0000945 mmap_doc, /*tp_doc*/
946 0, /* tp_traverse */
947 0, /* tp_clear */
948 0, /* tp_richcompare */
949 0, /* tp_weaklistoffset */
Georg Brandl86def6c2008-01-21 20:36:10 +0000950 0, /* tp_iter */
951 0, /* tp_iternext */
Christian Heimese1c98112008-01-21 11:20:28 +0000952 mmap_object_methods, /* tp_methods */
Georg Brandl86def6c2008-01-21 20:36:10 +0000953 0, /* tp_members */
954 0, /* tp_getset */
955 0, /* tp_base */
956 0, /* tp_dict */
957 0, /* tp_descr_get */
958 0, /* tp_descr_set */
959 0, /* tp_dictoffset */
960 0, /* tp_init */
961 PyType_GenericAlloc, /* tp_alloc */
962 new_mmap_object, /* tp_new */
963 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000964};
965
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000966
967/* extract the map size from the given PyObject
968
Thomas Wouters7e474022000-07-16 12:04:32 +0000969 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000970 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000971static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000972_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000973{
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000974 if (o == NULL)
975 return 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000976 if (PyIndex_Check(o)) {
977 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000978 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000979 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000980 if (i < 0) {
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000981 PyErr_Format(PyExc_OverflowError,
982 "memory mapped %s must be positive",
983 param);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000984 return -1;
985 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000986 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000987 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000988
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000989 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000990 return -1;
991}
992
Tim Petersec0a5f02006-02-16 23:47:20 +0000993#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000994static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +0000995new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000996{
Neal Norwitzb5673922002-09-05 21:48:07 +0000997#ifdef HAVE_FSTAT
998 struct stat st;
999#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001000 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001001 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1002 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001003 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001004 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001005 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001006 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001007 "flags", "prot",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001008 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001009
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001010 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001011 &fd, &map_size_obj, &flags, &prot,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001012 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001013 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001014 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001015 if (map_size < 0)
1016 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001017 offset = _GetMapSize(offset_obj, "offset");
1018 if (offset < 0)
1019 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001020
Tim Petersec0a5f02006-02-16 23:47:20 +00001021 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001022 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001023 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001024 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001025 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001026 case ACCESS_READ:
1027 flags = MAP_SHARED;
1028 prot = PROT_READ;
1029 break;
1030 case ACCESS_WRITE:
1031 flags = MAP_SHARED;
1032 prot = PROT_READ | PROT_WRITE;
1033 break;
1034 case ACCESS_COPY:
1035 flags = MAP_PRIVATE;
1036 prot = PROT_READ | PROT_WRITE;
1037 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001038 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001039 /* use the specified or default values of flags and prot */
1040 break;
1041 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001042 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001043 "mmap invalid access parameter.");
1044 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001045
Christian Heimesa156e092008-02-16 07:38:31 +00001046 if (prot == PROT_READ) {
1047 access = ACCESS_READ;
1048 }
1049
Neal Norwitzb5673922002-09-05 21:48:07 +00001050#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001051# ifdef __VMS
1052 /* on OpenVMS we must ensure that all bytes are written to the file */
Christian Heimes25bb7832008-01-11 16:17:00 +00001053 if (fd != -1) {
1054 fsync(fd);
1055 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001056# endif
Christian Heimes25bb7832008-01-11 16:17:00 +00001057 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001058 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001059 map_size = st.st_size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001060 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001061 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001062 "mmap length is greater than file size");
1063 return NULL;
1064 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001065 }
1066#endif
Georg Brandl86def6c2008-01-21 20:36:10 +00001067 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001068 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001069 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001070 m_obj->size = (size_t) map_size;
1071 m_obj->pos = (size_t) 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001072 m_obj->exports = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001073 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001074 if (fd == -1) {
1075 m_obj->fd = -1;
1076 /* Assume the caller wants to map anonymous memory.
1077 This is the same behaviour as Windows. mmap.mmap(-1, size)
1078 on both Windows and Unix map anonymous memory.
1079 */
1080#ifdef MAP_ANONYMOUS
1081 /* BSD way to map anonymous memory */
1082 flags |= MAP_ANONYMOUS;
1083#else
1084 /* SVR4 method to map anonymous memory is to open /dev/zero */
1085 fd = devzero = open("/dev/zero", O_RDWR);
1086 if (devzero == -1) {
1087 Py_DECREF(m_obj);
1088 PyErr_SetFromErrno(mmap_module_error);
1089 return NULL;
1090 }
1091#endif
1092 } else {
1093 m_obj->fd = dup(fd);
1094 if (m_obj->fd == -1) {
1095 Py_DECREF(m_obj);
1096 PyErr_SetFromErrno(mmap_module_error);
1097 return NULL;
1098 }
Georg Brandl38387b82005-08-24 07:17:40 +00001099 }
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001100
Tim Petersec0a5f02006-02-16 23:47:20 +00001101 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001102 prot, flags,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001103 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001104
1105 if (devzero != -1) {
1106 close(devzero);
1107 }
1108
Tim Peters5ebfd362001-11-13 23:11:19 +00001109 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001110 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001111 Py_DECREF(m_obj);
1112 PyErr_SetFromErrno(mmap_module_error);
1113 return NULL;
1114 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001115 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001116 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001117}
1118#endif /* UNIX */
1119
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001120#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001121static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001122new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001123{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001124 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001125 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1126 Py_ssize_t map_size, offset;
1127 DWORD off_hi; /* upper 32 bits of offset */
1128 DWORD off_lo; /* lower 32 bits of offset */
1129 DWORD size_hi; /* upper 32 bits of size */
1130 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001131 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001132 DWORD dwErr = 0;
1133 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001134 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001135 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001136 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001137 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001138 "tagname",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001139 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001140
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001141 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001142 &fileno, &map_size_obj,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001143 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001144 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001145 }
1146
Neal Norwitz8856fb72005-12-18 03:34:22 +00001147 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001148 case ACCESS_READ:
1149 flProtect = PAGE_READONLY;
1150 dwDesiredAccess = FILE_MAP_READ;
1151 break;
1152 case ACCESS_DEFAULT: case ACCESS_WRITE:
1153 flProtect = PAGE_READWRITE;
1154 dwDesiredAccess = FILE_MAP_WRITE;
1155 break;
1156 case ACCESS_COPY:
1157 flProtect = PAGE_WRITECOPY;
1158 dwDesiredAccess = FILE_MAP_COPY;
1159 break;
1160 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001161 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001162 "mmap invalid access parameter.");
1163 }
1164
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001165 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001166 if (map_size < 0)
1167 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001168 offset = _GetMapSize(offset_obj, "offset");
1169 if (offset < 0)
1170 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001171
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001172 /* assume -1 and 0 both mean invalid filedescriptor
1173 to 'anonymously' map memory.
1174 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1175 XXX: Should this code be added?
1176 if (fileno == 0)
Skip Montanaro46fc3372007-08-12 11:44:53 +00001177 PyErr_WarnEx(PyExc_DeprecationWarning,
1178 "don't use 0 for anonymous memory",
1179 1);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001180 */
1181 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001182 fh = (HANDLE)_get_osfhandle(fileno);
1183 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001184 PyErr_SetFromErrno(mmap_module_error);
1185 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001186 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001187 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001188 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001189 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001190
Georg Brandl86def6c2008-01-21 20:36:10 +00001191 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Tim Peters8f9cc292006-02-17 00:00:20 +00001192 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001193 return NULL;
1194 /* Set every field to an invalid marker, so we can safely
1195 destruct the object in the face of failure */
1196 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001197 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001198 m_obj->map_handle = INVALID_HANDLE_VALUE;
1199 m_obj->tagname = NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001200 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001201
Guido van Rossum09fdf072000-03-31 01:17:07 +00001202 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001203 /* It is necessary to duplicate the handle, so the
1204 Python code can close it on us */
1205 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001206 GetCurrentProcess(), /* source process handle */
1207 fh, /* handle to be duplicated */
1208 GetCurrentProcess(), /* target proc handle */
1209 (LPHANDLE)&m_obj->file_handle, /* result */
1210 0, /* access - ignored due to options value */
1211 FALSE, /* inherited by child processes? */
1212 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001213 dwErr = GetLastError();
1214 Py_DECREF(m_obj);
1215 PyErr_SetFromWindowsErr(dwErr);
1216 return NULL;
1217 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001218 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001219 DWORD low,high;
1220 low = GetFileSize(fh, &high);
1221 /* low might just happen to have the value INVALID_FILE_SIZE;
1222 so we need to check the last error also. */
1223 if (low == INVALID_FILE_SIZE &&
1224 (dwErr = GetLastError()) != NO_ERROR) {
1225 Py_DECREF(m_obj);
1226 return PyErr_SetFromWindowsErr(dwErr);
Guido van Rossum98297ee2007-11-06 21:34:58 +00001227 }
1228
Martin v. Löwis15186072006-02-18 12:38:35 +00001229#if SIZEOF_SIZE_T > 4
1230 m_obj->size = (((size_t)high)<<32) + low;
1231#else
1232 if (high)
1233 /* File is too large to map completely */
1234 m_obj->size = (size_t)-1;
1235 else
1236 m_obj->size = low;
1237#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001238 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001239 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001240 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001241 }
1242 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001243 m_obj->size = map_size;
1244 }
1245
1246 /* set the initial position */
1247 m_obj->pos = (size_t) 0;
1248
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001249 m_obj->exports = 0;
Mark Hammond2cbed002000-07-30 02:22:43 +00001250 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001251 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001252 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1253 if (m_obj->tagname == NULL) {
1254 PyErr_NoMemory();
1255 Py_DECREF(m_obj);
1256 return NULL;
1257 }
1258 strcpy(m_obj->tagname, tagname);
1259 }
1260 else
1261 m_obj->tagname = NULL;
1262
Neal Norwitz8856fb72005-12-18 03:34:22 +00001263 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001264 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001265 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001266 * consumes 4 bytes), C doesn't define what happens if we shift
1267 * right by 32, so we need different code.
1268 */
1269#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001270 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1271 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1272 off_hi = (DWORD)(offset >> 32);
1273 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001274#else
1275 size_hi = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001276 size_lo = (DWORD)(offset + m_obj->size);
1277 off_hi = 0;
1278 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001279#endif
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001280 /* For files, it would be sufficient to pass 0 as size.
1281 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001282 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1283 NULL,
1284 flProtect,
1285 size_hi,
1286 size_lo,
1287 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001288 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001289 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1290 dwDesiredAccess,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001291 off_hi,
1292 off_lo,
Tim Peters8f9cc292006-02-17 00:00:20 +00001293 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001294 if (m_obj->data != NULL)
1295 return (PyObject *)m_obj;
1296 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001297 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001298 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001299 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001300 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001301 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001302 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001303}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001304#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001305
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001306static void
1307setint(PyObject *d, const char *name, long value)
1308{
Christian Heimes217cfd12007-12-02 14:31:20 +00001309 PyObject *o = PyLong_FromLong(value);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001310 if (o && PyDict_SetItemString(d, name, o) == 0) {
1311 Py_DECREF(o);
1312 }
1313}
1314
Martin v. Löwis1a214512008-06-11 05:26:20 +00001315
1316static struct PyModuleDef mmapmodule = {
1317 PyModuleDef_HEAD_INIT,
1318 "mmap",
1319 NULL,
1320 -1,
1321 NULL,
1322 NULL,
1323 NULL,
1324 NULL,
1325 NULL
1326};
1327
Mark Hammond62b1ab12002-07-23 06:31:15 +00001328PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001329PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001330{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001331 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001332
Georg Brandl86def6c2008-01-21 20:36:10 +00001333 if (PyType_Ready(&mmap_object_type) < 0)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001334 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001335
Martin v. Löwis1a214512008-06-11 05:26:20 +00001336 module = PyModule_Create(&mmapmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001337 if (module == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001338 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001339 dict = PyModule_GetDict(module);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001340 if (!dict)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001341 return NULL;
Christian Heimes7131fd92008-02-19 14:21:46 +00001342 mmap_module_error = PyErr_NewException("mmap.error",
1343 PyExc_EnvironmentError , NULL);
1344 if (mmap_module_error == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001345 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001346 PyDict_SetItemString(dict, "error", mmap_module_error);
Georg Brandl86def6c2008-01-21 20:36:10 +00001347 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001348#ifdef PROT_EXEC
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001349 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001350#endif
1351#ifdef PROT_READ
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001352 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001353#endif
1354#ifdef PROT_WRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001355 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001356#endif
1357
1358#ifdef MAP_SHARED
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001359 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001360#endif
1361#ifdef MAP_PRIVATE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001362 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001363#endif
1364#ifdef MAP_DENYWRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001365 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001366#endif
1367#ifdef MAP_EXECUTABLE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001368 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001369#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001370#ifdef MAP_ANONYMOUS
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001371 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1372 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001373#endif
1374
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001375 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001376
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001377 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1378
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001379 setint(dict, "ACCESS_READ", ACCESS_READ);
1380 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1381 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Martin v. Löwis1a214512008-06-11 05:26:20 +00001382 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001383}