blob: d214b62cc4fa2368d33842ff9496f1c3c7214729 [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;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000379
380 if (self->pos < self->size) {
381 *(self->data+self->pos) = value;
382 self->pos += 1;
383 Py_INCREF(Py_None);
384 return Py_None;
385 }
386 else {
387 PyErr_SetString(PyExc_ValueError, "write byte out of range");
388 return NULL;
389 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000390}
Tim Petersec0a5f02006-02-16 23:47:20 +0000391
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000392static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000393mmap_size_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000394 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000395{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000396 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000397
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000398#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000399 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000400 DWORD low,high;
401 PY_LONG_LONG size;
402 low = GetFileSize(self->file_handle, &high);
403 if (low == INVALID_FILE_SIZE) {
404 /* It might be that the function appears to have failed,
405 when indeed its size equals INVALID_FILE_SIZE */
406 DWORD error = GetLastError();
407 if (error != NO_ERROR)
408 return PyErr_SetFromWindowsErr(error);
409 }
410 if (!high && low < LONG_MAX)
Christian Heimes217cfd12007-12-02 14:31:20 +0000411 return PyLong_FromLong((long)low);
Martin v. Löwis15186072006-02-18 12:38:35 +0000412 size = (((PY_LONG_LONG)high)<<32) + low;
413 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000414 } else {
Christian Heimes217cfd12007-12-02 14:31:20 +0000415 return PyLong_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000416 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000417#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000418
419#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000420 {
421 struct stat buf;
422 if (-1 == fstat(self->fd, &buf)) {
423 PyErr_SetFromErrno(mmap_module_error);
424 return NULL;
425 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000426 return PyLong_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000427 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000428#endif /* UNIX */
429}
430
431/* This assumes that you want the entire file mapped,
432 / and when recreating the map will make the new file
433 / have the new size
434 /
435 / Is this really necessary? This could easily be done
436 / from python by just closing and re-opening with the
437 / new size?
438 */
439
440static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000441mmap_resize_method(mmap_object *self,
442 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000443{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000444 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000445 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000446 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000447 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000448 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000449#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000450 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000451 DWORD dwErrCode = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000452 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000453 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000454 UnmapViewOfFile(self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000455 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000456 CloseHandle(self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000457 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000458#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000459 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
460 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
461 off_hi = (DWORD)(self->offset >> 32);
462 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000463#else
464 newSizeHigh = 0;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000465 newSizeLow = (DWORD)(self->offset + new_size);
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000466 off_hi = 0;
467 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000468#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000469 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000470 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000471 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000472 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000473 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000474 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000475 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000476 NULL,
477 PAGE_READWRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000478 0,
479 0,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000480 self->tagname);
481 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000482 self->data = (char *) MapViewOfFile(self->map_handle,
483 FILE_MAP_WRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000484 off_hi,
485 off_lo,
486 new_size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000487 if (self->data != NULL) {
488 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000489 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000490 return Py_None;
491 } else {
492 dwErrCode = GetLastError();
493 }
494 } else {
495 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000496 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000497 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000498 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000499#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000500
501#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000502#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000503 } else {
504 PyErr_SetString(PyExc_SystemError,
505 "mmap: resizing not available--no mremap()");
506 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000507#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000508 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000509 void *newmap;
510
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000511 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Georg Brandl38387b82005-08-24 07:17:40 +0000512 PyErr_SetFromErrno(mmap_module_error);
513 return NULL;
514 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000516#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000517 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000518#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000519 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000520#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000521 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000522 {
523 PyErr_SetFromErrno(mmap_module_error);
524 return NULL;
525 }
526 self->data = newmap;
527 self->size = new_size;
528 Py_INCREF(Py_None);
529 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000530#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000531#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000532 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000533}
534
535static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000536mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000537{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000538 CHECK_VALID(NULL);
Christian Heimes217cfd12007-12-02 14:31:20 +0000539 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000540}
541
542static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000543mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000544{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000545 Py_ssize_t offset = 0;
546 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000547 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000548 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000549 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000550 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000551 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000552 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000553 }
Christian Heimesaf98da12008-01-27 15:18:18 +0000554#ifdef MS_WINDOWS
555 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
556#elif defined(UNIX)
557 /* XXX semantics of return value? */
558 /* XXX flags for msync? */
559 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
560 PyErr_SetFromErrno(mmap_module_error);
561 return NULL;
562 }
563 return PyLong_FromLong(0);
564#else
565 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
566 return NULL;
567#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000568}
569
570static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000571mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000572{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000573 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000574 int how=0;
575 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000576 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000577 return NULL;
578 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000579 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000580 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000581 case 0: /* relative to start */
582 if (dist < 0)
583 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000584 where = dist;
585 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000586 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000587 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000588 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000589 where = self->pos + dist;
590 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000591 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000592 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000593 goto onoutofrange;
594 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000595 break;
596 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000597 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000598 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000599 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000600 if (where > self->size)
601 goto onoutofrange;
602 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000603 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000604 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000605 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000606
Tim Peters5ebfd362001-11-13 23:11:19 +0000607 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000608 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000609 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000610}
611
612static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000613mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000614{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000615 unsigned long dest, src, count;
616 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000617 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000618 !is_writable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000619 return NULL;
620 } else {
621 /* bounds check the values */
622 if (/* end of source after end of data?? */
623 ((src+count) > self->size)
624 /* dest will fit? */
625 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000626 PyErr_SetString(PyExc_ValueError,
627 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000628 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000629 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000630 memmove(self->data+dest, self->data+src, count);
631 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000632 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000633 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000634 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000635}
636
637static struct PyMethodDef mmap_object_methods[] = {
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000638 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000639 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Georg Brandlfceab5a2008-01-19 20:08:23 +0000640 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000641 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
642 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
643 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000644 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
645 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000646 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
647 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000648 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
649 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000650 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
651 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000652 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000653};
654
655/* Functions for treating an mmap'ed file as a buffer */
656
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000657static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000658mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000659{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000660 CHECK_VALID(-1);
Martin v. Löwis423be952008-08-13 15:53:07 +0000661 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000662 (self->access == ACCESS_READ), flags) < 0)
663 return -1;
664 self->exports++;
665 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000666}
667
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000668static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000669mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000670{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000671 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000672}
673
Martin v. Löwis18e16552006-02-15 17:27:45 +0000674static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000675mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000676{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000677 CHECK_VALID(-1);
678 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679}
680
681static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000682mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000683{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000684 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000685 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000686 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
687 return NULL;
688 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000689 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690}
691
692static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000693mmap_subscript(mmap_object *self, PyObject *item)
694{
695 CHECK_VALID(NULL);
696 if (PyIndex_Check(item)) {
697 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
698 if (i == -1 && PyErr_Occurred())
699 return NULL;
700 if (i < 0)
701 i += self->size;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000702 if (i < 0 || (size_t)i >= self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000703 PyErr_SetString(PyExc_IndexError,
704 "mmap index out of range");
705 return NULL;
706 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000707 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
Thomas Woutersed03b412007-08-28 21:37:11 +0000708 }
709 else if (PySlice_Check(item)) {
710 Py_ssize_t start, stop, step, slicelen;
711
712 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
713 &start, &stop, &step, &slicelen) < 0) {
714 return NULL;
715 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000716
Thomas Woutersed03b412007-08-28 21:37:11 +0000717 if (slicelen <= 0)
Christian Heimes72b710a2008-05-26 13:28:38 +0000718 return PyBytes_FromStringAndSize("", 0);
Thomas Woutersed03b412007-08-28 21:37:11 +0000719 else if (step == 1)
Christian Heimes72b710a2008-05-26 13:28:38 +0000720 return PyBytes_FromStringAndSize(self->data + start,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000721 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000722 else {
723 char *result_buf = (char *)PyMem_Malloc(slicelen);
724 Py_ssize_t cur, i;
725 PyObject *result;
726
727 if (result_buf == NULL)
728 return PyErr_NoMemory();
729 for (cur = start, i = 0; i < slicelen;
730 cur += step, i++) {
731 result_buf[i] = self->data[cur];
732 }
Christian Heimes72b710a2008-05-26 13:28:38 +0000733 result = PyBytes_FromStringAndSize(result_buf,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000734 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000735 PyMem_Free(result_buf);
736 return result;
737 }
738 }
739 else {
740 PyErr_SetString(PyExc_TypeError,
741 "mmap indices must be integers");
742 return NULL;
743 }
744}
745
746static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000747mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000748{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000749 CHECK_VALID(NULL);
750 PyErr_SetString(PyExc_SystemError,
751 "mmaps don't support concatenation");
752 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000753}
754
755static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000756mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000757{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000758 CHECK_VALID(NULL);
759 PyErr_SetString(PyExc_SystemError,
760 "mmaps don't support repeat operation");
761 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000762}
763
764static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000765mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000766{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000767 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000768
Guido van Rossum09fdf072000-03-31 01:17:07 +0000769 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000770 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000771 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
772 return -1;
773 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000774 if (v == NULL) {
775 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000776 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000777 return -1;
778 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000779 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000780 PyErr_SetString(PyExc_IndexError,
Thomas Woutersed03b412007-08-28 21:37:11 +0000781 "mmap assignment must be length-1 bytes()");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000782 return -1;
783 }
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000784 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000785 return -1;
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000786 buf = PyBytes_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000787 self->data[i] = buf[0];
788 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000789}
790
Thomas Woutersed03b412007-08-28 21:37:11 +0000791static int
792mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
793{
794 CHECK_VALID(-1);
795
Guido van Rossum98297ee2007-11-06 21:34:58 +0000796 if (!is_writable(self))
797 return -1;
798
Thomas Woutersed03b412007-08-28 21:37:11 +0000799 if (PyIndex_Check(item)) {
800 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000801 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000802
803 if (i == -1 && PyErr_Occurred())
804 return -1;
805 if (i < 0)
806 i += self->size;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000807 if (i < 0 || (size_t)i >= self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000808 PyErr_SetString(PyExc_IndexError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000809 "mmap index out of range");
Thomas Woutersed03b412007-08-28 21:37:11 +0000810 return -1;
811 }
812 if (value == NULL) {
813 PyErr_SetString(PyExc_TypeError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000814 "mmap doesn't support item deletion");
Thomas Woutersed03b412007-08-28 21:37:11 +0000815 return -1;
816 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000817 if (!PyIndex_Check(value)) {
818 PyErr_SetString(PyExc_TypeError,
819 "mmap item value must be an int");
Thomas Woutersed03b412007-08-28 21:37:11 +0000820 return -1;
821 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000822 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
823 if (v == -1 && PyErr_Occurred())
Thomas Woutersed03b412007-08-28 21:37:11 +0000824 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000825 if (v < 0 || v > 255) {
826 PyErr_SetString(PyExc_ValueError,
827 "mmap item value must be "
828 "in range(0, 256)");
829 return -1;
830 }
831 self->data[i] = v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000832 return 0;
833 }
834 else if (PySlice_Check(item)) {
835 Py_ssize_t start, stop, step, slicelen;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000836 Py_buffer vbuf;
837
Thomas Woutersed03b412007-08-28 21:37:11 +0000838 if (PySlice_GetIndicesEx((PySliceObject *)item,
839 self->size, &start, &stop,
840 &step, &slicelen) < 0) {
841 return -1;
842 }
843 if (value == NULL) {
844 PyErr_SetString(PyExc_TypeError,
845 "mmap object doesn't support slice deletion");
846 return -1;
847 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000848 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000849 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000850 if (vbuf.len != slicelen) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000851 PyErr_SetString(PyExc_IndexError,
852 "mmap slice assignment is wrong size");
Martin v. Löwis423be952008-08-13 15:53:07 +0000853 PyBuffer_Release(&vbuf);
Thomas Woutersed03b412007-08-28 21:37:11 +0000854 return -1;
855 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000856
Guido van Rossum98297ee2007-11-06 21:34:58 +0000857 if (slicelen == 0) {
858 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000859 else if (step == 1) {
Guido van Rossum98297ee2007-11-06 21:34:58 +0000860 memcpy(self->data + start, vbuf.buf, slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000861 }
862 else {
863 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000864
865 for (cur = start, i = 0;
866 i < slicelen;
867 cur += step, i++)
868 {
869 self->data[cur] = ((char *)vbuf.buf)[i];
Thomas Woutersed03b412007-08-28 21:37:11 +0000870 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000871 }
Martin v. Löwis423be952008-08-13 15:53:07 +0000872 PyBuffer_Release(&vbuf);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000873 return 0;
Thomas Woutersed03b412007-08-28 21:37:11 +0000874 }
875 else {
876 PyErr_SetString(PyExc_TypeError,
877 "mmap indices must be integer");
878 return -1;
879 }
880}
881
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000882static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000883 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000884 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000885 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
886 (ssizeargfunc)mmap_item, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000887 0, /*sq_slice*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000888 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000889 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000890};
891
Thomas Woutersed03b412007-08-28 21:37:11 +0000892static PyMappingMethods mmap_as_mapping = {
893 (lenfunc)mmap_length,
894 (binaryfunc)mmap_subscript,
895 (objobjargproc)mmap_ass_subscript,
896};
897
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000898static PyBufferProcs mmap_as_buffer = {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000899 (getbufferproc)mmap_buffer_getbuf,
900 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000901};
902
Georg Brandl86def6c2008-01-21 20:36:10 +0000903static PyObject *
904new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
905
Christian Heimese1c98112008-01-21 11:20:28 +0000906PyDoc_STRVAR(mmap_doc,
907"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
908\n\
909Maps length bytes from the file specified by the file handle fileno,\n\
910and returns a mmap object. If length is larger than the current size\n\
911of the file, the file is extended to contain length bytes. If length\n\
912is 0, the maximum length of the map is the current size of the file,\n\
913except that if the file is empty Windows raises an exception (you cannot\n\
914create an empty mapping on Windows).\n\
915\n\
916Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
917\n\
918Maps length bytes from the file specified by the file descriptor fileno,\n\
919and returns a mmap object. If length is 0, the maximum length of the map\n\
920will be the current size of the file when mmap is called.\n\
921flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
922private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000923object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000924that's shared with all other processes mapping the same areas of the file.\n\
925The default value is MAP_SHARED.\n\
926\n\
927To map anonymous memory, pass -1 as the fileno (both versions).");
928
929
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000930static PyTypeObject mmap_object_type = {
Georg Brandl86def6c2008-01-21 20:36:10 +0000931 PyVarObject_HEAD_INIT(NULL, 0)
Guido van Rossum14648392001-12-08 18:02:58 +0000932 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000933 sizeof(mmap_object), /* tp_size */
934 0, /* tp_itemsize */
935 /* methods */
936 (destructor) mmap_object_dealloc, /* tp_dealloc */
937 0, /* tp_print */
Christian Heimese1c98112008-01-21 11:20:28 +0000938 0, /* tp_getattr */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000939 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000940 0, /* tp_reserved */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000941 0, /* tp_repr */
942 0, /* tp_as_number */
943 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Woutersed03b412007-08-28 21:37:11 +0000944 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000945 0, /*tp_hash*/
946 0, /*tp_call*/
947 0, /*tp_str*/
Christian Heimese1c98112008-01-21 11:20:28 +0000948 PyObject_GenericGetAttr, /*tp_getattro*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000949 0, /*tp_setattro*/
950 &mmap_as_buffer, /*tp_as_buffer*/
Georg Brandl86def6c2008-01-21 20:36:10 +0000951 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Christian Heimese1c98112008-01-21 11:20:28 +0000952 mmap_doc, /*tp_doc*/
953 0, /* tp_traverse */
954 0, /* tp_clear */
955 0, /* tp_richcompare */
956 0, /* tp_weaklistoffset */
Georg Brandl86def6c2008-01-21 20:36:10 +0000957 0, /* tp_iter */
958 0, /* tp_iternext */
Christian Heimese1c98112008-01-21 11:20:28 +0000959 mmap_object_methods, /* tp_methods */
Georg Brandl86def6c2008-01-21 20:36:10 +0000960 0, /* tp_members */
961 0, /* tp_getset */
962 0, /* tp_base */
963 0, /* tp_dict */
964 0, /* tp_descr_get */
965 0, /* tp_descr_set */
966 0, /* tp_dictoffset */
967 0, /* tp_init */
968 PyType_GenericAlloc, /* tp_alloc */
969 new_mmap_object, /* tp_new */
970 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000971};
972
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000973
974/* extract the map size from the given PyObject
975
Thomas Wouters7e474022000-07-16 12:04:32 +0000976 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000977 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000978static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000979_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000980{
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000981 if (o == NULL)
982 return 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000983 if (PyIndex_Check(o)) {
984 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000985 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000986 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000987 if (i < 0) {
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000988 PyErr_Format(PyExc_OverflowError,
989 "memory mapped %s must be positive",
990 param);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000991 return -1;
992 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000993 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000994 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000995
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000996 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000997 return -1;
998}
999
Tim Petersec0a5f02006-02-16 23:47:20 +00001000#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001001static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001002new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001003{
Neal Norwitzb5673922002-09-05 21:48:07 +00001004#ifdef HAVE_FSTAT
1005 struct stat st;
1006#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001007 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001008 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1009 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001010 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001011 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001012 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001013 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001014 "flags", "prot",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001015 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001016
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001017 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001018 &fd, &map_size_obj, &flags, &prot,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001019 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001020 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001021 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001022 if (map_size < 0)
1023 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001024 offset = _GetMapSize(offset_obj, "offset");
1025 if (offset < 0)
1026 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001027
Tim Petersec0a5f02006-02-16 23:47:20 +00001028 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001029 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001030 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001031 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001032 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001033 case ACCESS_READ:
1034 flags = MAP_SHARED;
1035 prot = PROT_READ;
1036 break;
1037 case ACCESS_WRITE:
1038 flags = MAP_SHARED;
1039 prot = PROT_READ | PROT_WRITE;
1040 break;
1041 case ACCESS_COPY:
1042 flags = MAP_PRIVATE;
1043 prot = PROT_READ | PROT_WRITE;
1044 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001045 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001046 /* use the specified or default values of flags and prot */
1047 break;
1048 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001049 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001050 "mmap invalid access parameter.");
1051 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001052
Christian Heimesa156e092008-02-16 07:38:31 +00001053 if (prot == PROT_READ) {
1054 access = ACCESS_READ;
1055 }
1056
Neal Norwitzb5673922002-09-05 21:48:07 +00001057#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001058# ifdef __VMS
1059 /* on OpenVMS we must ensure that all bytes are written to the file */
Christian Heimes25bb7832008-01-11 16:17:00 +00001060 if (fd != -1) {
1061 fsync(fd);
1062 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001063# endif
Christian Heimes25bb7832008-01-11 16:17:00 +00001064 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001065 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001066 map_size = st.st_size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001067 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001068 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001069 "mmap length is greater than file size");
1070 return NULL;
1071 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001072 }
1073#endif
Georg Brandl86def6c2008-01-21 20:36:10 +00001074 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001075 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001076 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001077 m_obj->size = (size_t) map_size;
1078 m_obj->pos = (size_t) 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001079 m_obj->exports = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001080 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001081 if (fd == -1) {
1082 m_obj->fd = -1;
1083 /* Assume the caller wants to map anonymous memory.
1084 This is the same behaviour as Windows. mmap.mmap(-1, size)
1085 on both Windows and Unix map anonymous memory.
1086 */
1087#ifdef MAP_ANONYMOUS
1088 /* BSD way to map anonymous memory */
1089 flags |= MAP_ANONYMOUS;
1090#else
1091 /* SVR4 method to map anonymous memory is to open /dev/zero */
1092 fd = devzero = open("/dev/zero", O_RDWR);
1093 if (devzero == -1) {
1094 Py_DECREF(m_obj);
1095 PyErr_SetFromErrno(mmap_module_error);
1096 return NULL;
1097 }
1098#endif
1099 } else {
1100 m_obj->fd = dup(fd);
1101 if (m_obj->fd == -1) {
1102 Py_DECREF(m_obj);
1103 PyErr_SetFromErrno(mmap_module_error);
1104 return NULL;
1105 }
Georg Brandl38387b82005-08-24 07:17:40 +00001106 }
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001107
Tim Petersec0a5f02006-02-16 23:47:20 +00001108 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001109 prot, flags,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001110 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001111
1112 if (devzero != -1) {
1113 close(devzero);
1114 }
1115
Tim Peters5ebfd362001-11-13 23:11:19 +00001116 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001117 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001118 Py_DECREF(m_obj);
1119 PyErr_SetFromErrno(mmap_module_error);
1120 return NULL;
1121 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001122 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001123 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001124}
1125#endif /* UNIX */
1126
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001127#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001128static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001129new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001130{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001131 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001132 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1133 Py_ssize_t map_size, offset;
1134 DWORD off_hi; /* upper 32 bits of offset */
1135 DWORD off_lo; /* lower 32 bits of offset */
1136 DWORD size_hi; /* upper 32 bits of size */
1137 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001138 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001139 DWORD dwErr = 0;
1140 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001141 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001142 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001143 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001144 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001145 "tagname",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001146 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001147
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001148 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001149 &fileno, &map_size_obj,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001150 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001151 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001152 }
1153
Neal Norwitz8856fb72005-12-18 03:34:22 +00001154 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001155 case ACCESS_READ:
1156 flProtect = PAGE_READONLY;
1157 dwDesiredAccess = FILE_MAP_READ;
1158 break;
1159 case ACCESS_DEFAULT: case ACCESS_WRITE:
1160 flProtect = PAGE_READWRITE;
1161 dwDesiredAccess = FILE_MAP_WRITE;
1162 break;
1163 case ACCESS_COPY:
1164 flProtect = PAGE_WRITECOPY;
1165 dwDesiredAccess = FILE_MAP_COPY;
1166 break;
1167 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001168 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001169 "mmap invalid access parameter.");
1170 }
1171
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001172 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001173 if (map_size < 0)
1174 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001175 offset = _GetMapSize(offset_obj, "offset");
1176 if (offset < 0)
1177 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001178
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001179 /* assume -1 and 0 both mean invalid filedescriptor
1180 to 'anonymously' map memory.
1181 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1182 XXX: Should this code be added?
1183 if (fileno == 0)
Skip Montanaro46fc3372007-08-12 11:44:53 +00001184 PyErr_WarnEx(PyExc_DeprecationWarning,
1185 "don't use 0 for anonymous memory",
1186 1);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001187 */
1188 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001189 fh = (HANDLE)_get_osfhandle(fileno);
1190 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001191 PyErr_SetFromErrno(mmap_module_error);
1192 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001193 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001194 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001195 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001196 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001197
Georg Brandl86def6c2008-01-21 20:36:10 +00001198 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Tim Peters8f9cc292006-02-17 00:00:20 +00001199 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001200 return NULL;
1201 /* Set every field to an invalid marker, so we can safely
1202 destruct the object in the face of failure */
1203 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001204 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001205 m_obj->map_handle = INVALID_HANDLE_VALUE;
1206 m_obj->tagname = NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001207 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001208
Guido van Rossum09fdf072000-03-31 01:17:07 +00001209 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001210 /* It is necessary to duplicate the handle, so the
1211 Python code can close it on us */
1212 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001213 GetCurrentProcess(), /* source process handle */
1214 fh, /* handle to be duplicated */
1215 GetCurrentProcess(), /* target proc handle */
1216 (LPHANDLE)&m_obj->file_handle, /* result */
1217 0, /* access - ignored due to options value */
1218 FALSE, /* inherited by child processes? */
1219 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001220 dwErr = GetLastError();
1221 Py_DECREF(m_obj);
1222 PyErr_SetFromWindowsErr(dwErr);
1223 return NULL;
1224 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001225 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001226 DWORD low,high;
1227 low = GetFileSize(fh, &high);
1228 /* low might just happen to have the value INVALID_FILE_SIZE;
1229 so we need to check the last error also. */
1230 if (low == INVALID_FILE_SIZE &&
1231 (dwErr = GetLastError()) != NO_ERROR) {
1232 Py_DECREF(m_obj);
1233 return PyErr_SetFromWindowsErr(dwErr);
Guido van Rossum98297ee2007-11-06 21:34:58 +00001234 }
1235
Martin v. Löwis15186072006-02-18 12:38:35 +00001236#if SIZEOF_SIZE_T > 4
1237 m_obj->size = (((size_t)high)<<32) + low;
1238#else
1239 if (high)
1240 /* File is too large to map completely */
1241 m_obj->size = (size_t)-1;
1242 else
1243 m_obj->size = low;
1244#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001245 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001246 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001247 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001248 }
1249 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001250 m_obj->size = map_size;
1251 }
1252
1253 /* set the initial position */
1254 m_obj->pos = (size_t) 0;
1255
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001256 m_obj->exports = 0;
Mark Hammond2cbed002000-07-30 02:22:43 +00001257 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001258 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001259 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1260 if (m_obj->tagname == NULL) {
1261 PyErr_NoMemory();
1262 Py_DECREF(m_obj);
1263 return NULL;
1264 }
1265 strcpy(m_obj->tagname, tagname);
1266 }
1267 else
1268 m_obj->tagname = NULL;
1269
Neal Norwitz8856fb72005-12-18 03:34:22 +00001270 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001271 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001272 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001273 * consumes 4 bytes), C doesn't define what happens if we shift
1274 * right by 32, so we need different code.
1275 */
1276#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001277 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1278 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1279 off_hi = (DWORD)(offset >> 32);
1280 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001281#else
1282 size_hi = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001283 size_lo = (DWORD)(offset + m_obj->size);
1284 off_hi = 0;
1285 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001286#endif
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001287 /* For files, it would be sufficient to pass 0 as size.
1288 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001289 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1290 NULL,
1291 flProtect,
1292 size_hi,
1293 size_lo,
1294 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001295 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001296 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1297 dwDesiredAccess,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001298 off_hi,
1299 off_lo,
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +00001300 m_obj->size);
Tim Peters23721ee2006-02-16 23:50:16 +00001301 if (m_obj->data != NULL)
1302 return (PyObject *)m_obj;
1303 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001304 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001305 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001306 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001307 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001308 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001309 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001310}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001311#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001312
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001313static void
1314setint(PyObject *d, const char *name, long value)
1315{
Christian Heimes217cfd12007-12-02 14:31:20 +00001316 PyObject *o = PyLong_FromLong(value);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001317 if (o && PyDict_SetItemString(d, name, o) == 0) {
1318 Py_DECREF(o);
1319 }
1320}
1321
Martin v. Löwis1a214512008-06-11 05:26:20 +00001322
1323static struct PyModuleDef mmapmodule = {
1324 PyModuleDef_HEAD_INIT,
1325 "mmap",
1326 NULL,
1327 -1,
1328 NULL,
1329 NULL,
1330 NULL,
1331 NULL,
1332 NULL
1333};
1334
Mark Hammond62b1ab12002-07-23 06:31:15 +00001335PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001336PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001337{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001338 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001339
Georg Brandl86def6c2008-01-21 20:36:10 +00001340 if (PyType_Ready(&mmap_object_type) < 0)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001341 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001342
Martin v. Löwis1a214512008-06-11 05:26:20 +00001343 module = PyModule_Create(&mmapmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001344 if (module == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001345 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001346 dict = PyModule_GetDict(module);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001347 if (!dict)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001348 return NULL;
Christian Heimes7131fd92008-02-19 14:21:46 +00001349 mmap_module_error = PyErr_NewException("mmap.error",
1350 PyExc_EnvironmentError , NULL);
1351 if (mmap_module_error == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001352 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001353 PyDict_SetItemString(dict, "error", mmap_module_error);
Georg Brandl86def6c2008-01-21 20:36:10 +00001354 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001355#ifdef PROT_EXEC
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001356 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001357#endif
1358#ifdef PROT_READ
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001359 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001360#endif
1361#ifdef PROT_WRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001362 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001363#endif
1364
1365#ifdef MAP_SHARED
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001366 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001367#endif
1368#ifdef MAP_PRIVATE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001369 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001370#endif
1371#ifdef MAP_DENYWRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001372 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001373#endif
1374#ifdef MAP_EXECUTABLE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001375 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001376#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001377#ifdef MAP_ANONYMOUS
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001378 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1379 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001380#endif
1381
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001382 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001383
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001384 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1385
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001386 setint(dict, "ACCESS_READ", ACCESS_READ);
1387 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1388 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Martin v. Löwis1a214512008-06-11 05:26:20 +00001389 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001390}