blob: b9c46cd919a0775c1f31bd2a4cb24f841a5adafb [file] [log] [blame]
Guido van Rossum09fdf072000-03-31 01:17:07 +00001/*
2 / Author: Sam Rushing <rushing@nightmare.com>
Andrew M. Kuchling10f9c072001-11-05 21:25:42 +00003 / Hacked for Unix by AMK
Guido van Rossum09fdf072000-03-31 01:17:07 +00004 / $Id$
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00005
Guido van Rossum8ce8a782007-11-01 19:42:39 +00006 / Modified to support mmap with offset - to map a 'window' of a file
7 / Author: Yotam Medini yotamm@mellanox.co.il
8 /
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00009 / mmapmodule.cpp -- map a view of a file into memory
10 /
11 / todo: need permission flags, perhaps a 'chsize' analog
12 / not all functions check range yet!!!
13 /
14 /
Mark Hammond071864a2000-07-30 02:46:26 +000015 / This version of mmapmodule.c has been changed significantly
16 / from the original mmapfile.c on which it was based.
17 / The original version of mmapfile is maintained by Sam at
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000018 / ftp://squirl.nightmare.com/pub/python/python-ext.
19*/
20
Martin v. Löwiscfe7e092006-02-17 06:59:14 +000021#define PY_SSIZE_T_CLEAN
Guido van Rossum09fdf072000-03-31 01:17:07 +000022#include <Python.h>
23
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000024#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000025#define UNIX
26#endif
27
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000028#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000030static int
31my_getpagesize(void)
32{
Tim Peters5ebfd362001-11-13 23:11:19 +000033 SYSTEM_INFO si;
34 GetSystemInfo(&si);
35 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000036}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000037
38static int
39my_getallocationgranularity (void)
40{
41
42 SYSTEM_INFO si;
43 GetSystemInfo(&si);
44 return si.dwAllocationGranularity;
45}
46
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000047#endif
48
49#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000051#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000052
Fred Drake145f96e2000-10-01 17:50:46 +000053#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
54static int
55my_getpagesize(void)
56{
Tim Peters5ebfd362001-11-13 23:11:19 +000057 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000058}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000059
60#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000061#else
62#define my_getpagesize getpagesize
63#endif
64
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000065#endif /* UNIX */
66
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000067#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000068
69#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000071#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000073/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000074#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
75# define MAP_ANONYMOUS MAP_ANON
76#endif
77
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000078static PyObject *mmap_module_error;
79
Tim Peters5ebfd362001-11-13 23:11:19 +000080typedef enum
81{
82 ACCESS_DEFAULT,
83 ACCESS_READ,
84 ACCESS_WRITE,
85 ACCESS_COPY
86} access_mode;
87
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000088typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000089 PyObject_HEAD
90 char * data;
91 size_t size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000092 size_t pos; /* relative to offset */
93 size_t offset;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000094 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000095
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000096#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +000097 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000098 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000099 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000100#endif
101
102#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000103 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000105
106 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107} mmap_object;
108
Tim Peters5ebfd362001-11-13 23:11:19 +0000109
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000111mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000112{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000113#ifdef MS_WINDOWS
Mark Hammond2cbed002000-07-30 02:22:43 +0000114 if (m_obj->data != NULL)
115 UnmapViewOfFile (m_obj->data);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000116 if (m_obj->map_handle != NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +0000117 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000118 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
119 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000120 if (m_obj->tagname)
121 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000122#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000123
124#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000125 if (m_obj->fd >= 0)
126 (void) close(m_obj->fd);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000127 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000128 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000129 munmap(m_obj->data, m_obj->size);
130 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000131#endif /* UNIX */
132
Christian Heimes1af737c2008-01-23 08:24:23 +0000133 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000134}
135
136static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000137mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000139 if (self->exports > 0) {
140 PyErr_SetString(PyExc_BufferError, "cannot close "\
141 "exported pointers exist");
142 return NULL;
143 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000144#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000145 /* For each resource we maintain, we need to check
Tim Petersec0a5f02006-02-16 23:47:20 +0000146 the value is valid, and if so, free the resource
Mark Hammond071864a2000-07-30 02:46:26 +0000147 and set the member value to an invalid value so
148 the dealloc does not attempt to resource clearing
149 again.
150 TODO - should we check for errors in the close operations???
151 */
152 if (self->data != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000153 UnmapViewOfFile(self->data);
Mark Hammond071864a2000-07-30 02:46:26 +0000154 self->data = NULL;
155 }
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000156 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000157 CloseHandle(self->map_handle);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000158 self->map_handle = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000159 }
160 if (self->file_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000161 CloseHandle(self->file_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000162 self->file_handle = INVALID_HANDLE_VALUE;
163 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000164#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000165
166#ifdef UNIX
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 { \
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000182 if (self->map_handle == NULL) { \
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);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000455 self->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000456 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000457 CloseHandle(self->map_handle);
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000458 self->map_handle = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000459 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000460#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000461 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
462 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
463 off_hi = (DWORD)(self->offset >> 32);
464 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000465#else
466 newSizeHigh = 0;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000467 newSizeLow = (DWORD)(self->offset + new_size);
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000468 off_hi = 0;
469 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000470#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000471 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000472 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000473 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000474 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000475 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000476 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000477 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000478 NULL,
479 PAGE_READWRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000480 0,
481 0,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000482 self->tagname);
483 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000484 self->data = (char *) MapViewOfFile(self->map_handle,
485 FILE_MAP_WRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000486 off_hi,
487 off_lo,
488 new_size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000489 if (self->data != NULL) {
490 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000491 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000492 return Py_None;
493 } else {
494 dwErrCode = GetLastError();
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000495 CloseHandle(self->map_handle);
496 self->map_handle = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000497 }
498 } else {
499 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000500 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000501 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000502 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000503#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000504
505#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000506#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000507 } else {
508 PyErr_SetString(PyExc_SystemError,
509 "mmap: resizing not available--no mremap()");
510 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000511#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000512 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000513 void *newmap;
514
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000515 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Georg Brandl38387b82005-08-24 07:17:40 +0000516 PyErr_SetFromErrno(mmap_module_error);
517 return NULL;
518 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000519
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000520#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000521 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000522#else
Jesse Noller32d68c22009-03-31 18:48:42 +0000523 #if defined(__NetBSD__)
524 newmap = mremap(self->data, self->size, self->data, new_size, 0);
525 #else
526 newmap = mremap(self->data, self->size, new_size, 0);
527 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000528#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000529 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000530 {
531 PyErr_SetFromErrno(mmap_module_error);
532 return NULL;
533 }
534 self->data = newmap;
535 self->size = new_size;
536 Py_INCREF(Py_None);
537 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000538#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000539#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000540 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000541}
542
543static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000544mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000545{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000546 CHECK_VALID(NULL);
Christian Heimes217cfd12007-12-02 14:31:20 +0000547 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000548}
549
550static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000551mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000553 Py_ssize_t offset = 0;
554 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000555 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000556 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000557 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000558 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000559 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000560 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000561 }
Christian Heimesaf98da12008-01-27 15:18:18 +0000562#ifdef MS_WINDOWS
563 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
564#elif defined(UNIX)
565 /* XXX semantics of return value? */
566 /* XXX flags for msync? */
567 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
568 PyErr_SetFromErrno(mmap_module_error);
569 return NULL;
570 }
571 return PyLong_FromLong(0);
572#else
573 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
574 return NULL;
575#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000576}
577
578static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000579mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000580{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000581 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000582 int how=0;
583 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000584 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000585 return NULL;
586 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000587 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000588 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000589 case 0: /* relative to start */
590 if (dist < 0)
591 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000592 where = dist;
593 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000594 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000595 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000596 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000597 where = self->pos + dist;
598 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000599 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000600 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000601 goto onoutofrange;
602 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000603 break;
604 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000605 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000606 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000607 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000608 if (where > self->size)
609 goto onoutofrange;
610 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000611 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000612 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000613 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000614
Tim Peters5ebfd362001-11-13 23:11:19 +0000615 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000616 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000617 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000618}
619
620static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000621mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000622{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000623 unsigned long dest, src, count;
624 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000625 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000626 !is_writable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000627 return NULL;
628 } else {
629 /* bounds check the values */
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000630 unsigned long pos = src > dest ? src : dest;
Hirokazu Yamamoto2ca15012009-03-31 20:43:56 +0000631 if (self->size < pos || count > self->size - pos) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000632 PyErr_SetString(PyExc_ValueError,
633 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000634 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000635 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000636 memmove(self->data+dest, self->data+src, count);
637 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000638 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000639 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000640 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000641}
642
643static struct PyMethodDef mmap_object_methods[] = {
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000644 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000645 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Georg Brandlfceab5a2008-01-19 20:08:23 +0000646 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000647 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
648 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
649 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000650 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
651 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000652 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
653 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000654 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
655 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000656 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
657 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000658 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000659};
660
661/* Functions for treating an mmap'ed file as a buffer */
662
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000663static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000664mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000665{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000666 CHECK_VALID(-1);
Martin v. Löwis423be952008-08-13 15:53:07 +0000667 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000668 (self->access == ACCESS_READ), flags) < 0)
669 return -1;
670 self->exports++;
671 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000672}
673
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000674static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000675mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000676{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000677 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000678}
679
Martin v. Löwis18e16552006-02-15 17:27:45 +0000680static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000681mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000682{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000683 CHECK_VALID(-1);
684 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000685}
686
687static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000688mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000689{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000690 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000691 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000692 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
693 return NULL;
694 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000695 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000696}
697
698static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000699mmap_subscript(mmap_object *self, PyObject *item)
700{
701 CHECK_VALID(NULL);
702 if (PyIndex_Check(item)) {
703 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
704 if (i == -1 && PyErr_Occurred())
705 return NULL;
706 if (i < 0)
707 i += self->size;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000708 if (i < 0 || (size_t)i >= self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000709 PyErr_SetString(PyExc_IndexError,
710 "mmap index out of range");
711 return NULL;
712 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000713 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
Thomas Woutersed03b412007-08-28 21:37:11 +0000714 }
715 else if (PySlice_Check(item)) {
716 Py_ssize_t start, stop, step, slicelen;
717
718 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
719 &start, &stop, &step, &slicelen) < 0) {
720 return NULL;
721 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000722
Thomas Woutersed03b412007-08-28 21:37:11 +0000723 if (slicelen <= 0)
Christian Heimes72b710a2008-05-26 13:28:38 +0000724 return PyBytes_FromStringAndSize("", 0);
Thomas Woutersed03b412007-08-28 21:37:11 +0000725 else if (step == 1)
Christian Heimes72b710a2008-05-26 13:28:38 +0000726 return PyBytes_FromStringAndSize(self->data + start,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000727 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000728 else {
729 char *result_buf = (char *)PyMem_Malloc(slicelen);
730 Py_ssize_t cur, i;
731 PyObject *result;
732
733 if (result_buf == NULL)
734 return PyErr_NoMemory();
735 for (cur = start, i = 0; i < slicelen;
736 cur += step, i++) {
737 result_buf[i] = self->data[cur];
738 }
Christian Heimes72b710a2008-05-26 13:28:38 +0000739 result = PyBytes_FromStringAndSize(result_buf,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000740 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000741 PyMem_Free(result_buf);
742 return result;
743 }
744 }
745 else {
746 PyErr_SetString(PyExc_TypeError,
747 "mmap indices must be integers");
748 return NULL;
749 }
750}
751
752static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000753mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000754{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000755 CHECK_VALID(NULL);
756 PyErr_SetString(PyExc_SystemError,
757 "mmaps don't support concatenation");
758 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000759}
760
761static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000762mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000763{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000764 CHECK_VALID(NULL);
765 PyErr_SetString(PyExc_SystemError,
766 "mmaps don't support repeat operation");
767 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000768}
769
770static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000771mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000772{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000773 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000774
Guido van Rossum09fdf072000-03-31 01:17:07 +0000775 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000776 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000777 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
778 return -1;
779 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000780 if (v == NULL) {
781 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000782 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000783 return -1;
784 }
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000785 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000786 PyErr_SetString(PyExc_IndexError,
Thomas Woutersed03b412007-08-28 21:37:11 +0000787 "mmap assignment must be length-1 bytes()");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000788 return -1;
789 }
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000790 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000791 return -1;
Gregory P. Smith0a608fd2008-09-06 21:34:51 +0000792 buf = PyBytes_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000793 self->data[i] = buf[0];
794 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000795}
796
Thomas Woutersed03b412007-08-28 21:37:11 +0000797static int
798mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
799{
800 CHECK_VALID(-1);
801
Guido van Rossum98297ee2007-11-06 21:34:58 +0000802 if (!is_writable(self))
803 return -1;
804
Thomas Woutersed03b412007-08-28 21:37:11 +0000805 if (PyIndex_Check(item)) {
806 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000807 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000808
809 if (i == -1 && PyErr_Occurred())
810 return -1;
811 if (i < 0)
812 i += self->size;
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000813 if (i < 0 || (size_t)i >= self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000814 PyErr_SetString(PyExc_IndexError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000815 "mmap index out of range");
Thomas Woutersed03b412007-08-28 21:37:11 +0000816 return -1;
817 }
818 if (value == NULL) {
819 PyErr_SetString(PyExc_TypeError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000820 "mmap doesn't support item deletion");
Thomas Woutersed03b412007-08-28 21:37:11 +0000821 return -1;
822 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000823 if (!PyIndex_Check(value)) {
824 PyErr_SetString(PyExc_TypeError,
825 "mmap item value must be an int");
Thomas Woutersed03b412007-08-28 21:37:11 +0000826 return -1;
827 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000828 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
829 if (v == -1 && PyErr_Occurred())
Thomas Woutersed03b412007-08-28 21:37:11 +0000830 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000831 if (v < 0 || v > 255) {
832 PyErr_SetString(PyExc_ValueError,
833 "mmap item value must be "
834 "in range(0, 256)");
835 return -1;
836 }
837 self->data[i] = v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000838 return 0;
839 }
840 else if (PySlice_Check(item)) {
841 Py_ssize_t start, stop, step, slicelen;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000842 Py_buffer vbuf;
843
Thomas Woutersed03b412007-08-28 21:37:11 +0000844 if (PySlice_GetIndicesEx((PySliceObject *)item,
845 self->size, &start, &stop,
846 &step, &slicelen) < 0) {
847 return -1;
848 }
849 if (value == NULL) {
850 PyErr_SetString(PyExc_TypeError,
851 "mmap object doesn't support slice deletion");
852 return -1;
853 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000854 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000855 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000856 if (vbuf.len != slicelen) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000857 PyErr_SetString(PyExc_IndexError,
858 "mmap slice assignment is wrong size");
Martin v. Löwis423be952008-08-13 15:53:07 +0000859 PyBuffer_Release(&vbuf);
Thomas Woutersed03b412007-08-28 21:37:11 +0000860 return -1;
861 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000862
Guido van Rossum98297ee2007-11-06 21:34:58 +0000863 if (slicelen == 0) {
864 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000865 else if (step == 1) {
Guido van Rossum98297ee2007-11-06 21:34:58 +0000866 memcpy(self->data + start, vbuf.buf, slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000867 }
868 else {
869 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000870
871 for (cur = start, i = 0;
872 i < slicelen;
873 cur += step, i++)
874 {
875 self->data[cur] = ((char *)vbuf.buf)[i];
Thomas Woutersed03b412007-08-28 21:37:11 +0000876 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000877 }
Martin v. Löwis423be952008-08-13 15:53:07 +0000878 PyBuffer_Release(&vbuf);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000879 return 0;
Thomas Woutersed03b412007-08-28 21:37:11 +0000880 }
881 else {
882 PyErr_SetString(PyExc_TypeError,
883 "mmap indices must be integer");
884 return -1;
885 }
886}
887
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000888static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000889 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000890 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000891 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
892 (ssizeargfunc)mmap_item, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000893 0, /*sq_slice*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000894 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000895 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000896};
897
Thomas Woutersed03b412007-08-28 21:37:11 +0000898static PyMappingMethods mmap_as_mapping = {
899 (lenfunc)mmap_length,
900 (binaryfunc)mmap_subscript,
901 (objobjargproc)mmap_ass_subscript,
902};
903
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000904static PyBufferProcs mmap_as_buffer = {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000905 (getbufferproc)mmap_buffer_getbuf,
906 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000907};
908
Georg Brandl86def6c2008-01-21 20:36:10 +0000909static PyObject *
910new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
911
Christian Heimese1c98112008-01-21 11:20:28 +0000912PyDoc_STRVAR(mmap_doc,
913"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
914\n\
915Maps length bytes from the file specified by the file handle fileno,\n\
916and returns a mmap object. If length is larger than the current size\n\
917of the file, the file is extended to contain length bytes. If length\n\
918is 0, the maximum length of the map is the current size of the file,\n\
919except that if the file is empty Windows raises an exception (you cannot\n\
920create an empty mapping on Windows).\n\
921\n\
922Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
923\n\
924Maps length bytes from the file specified by the file descriptor fileno,\n\
925and returns a mmap object. If length is 0, the maximum length of the map\n\
926will be the current size of the file when mmap is called.\n\
927flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
928private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000929object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000930that's shared with all other processes mapping the same areas of the file.\n\
931The default value is MAP_SHARED.\n\
932\n\
933To map anonymous memory, pass -1 as the fileno (both versions).");
934
935
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000936static PyTypeObject mmap_object_type = {
Georg Brandl86def6c2008-01-21 20:36:10 +0000937 PyVarObject_HEAD_INIT(NULL, 0)
Guido van Rossum14648392001-12-08 18:02:58 +0000938 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000939 sizeof(mmap_object), /* tp_size */
940 0, /* tp_itemsize */
941 /* methods */
942 (destructor) mmap_object_dealloc, /* tp_dealloc */
943 0, /* tp_print */
Christian Heimese1c98112008-01-21 11:20:28 +0000944 0, /* tp_getattr */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000945 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000946 0, /* tp_reserved */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000947 0, /* tp_repr */
948 0, /* tp_as_number */
949 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Woutersed03b412007-08-28 21:37:11 +0000950 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000951 0, /*tp_hash*/
952 0, /*tp_call*/
953 0, /*tp_str*/
Christian Heimese1c98112008-01-21 11:20:28 +0000954 PyObject_GenericGetAttr, /*tp_getattro*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000955 0, /*tp_setattro*/
956 &mmap_as_buffer, /*tp_as_buffer*/
Georg Brandl86def6c2008-01-21 20:36:10 +0000957 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Christian Heimese1c98112008-01-21 11:20:28 +0000958 mmap_doc, /*tp_doc*/
959 0, /* tp_traverse */
960 0, /* tp_clear */
961 0, /* tp_richcompare */
962 0, /* tp_weaklistoffset */
Georg Brandl86def6c2008-01-21 20:36:10 +0000963 0, /* tp_iter */
964 0, /* tp_iternext */
Christian Heimese1c98112008-01-21 11:20:28 +0000965 mmap_object_methods, /* tp_methods */
Georg Brandl86def6c2008-01-21 20:36:10 +0000966 0, /* tp_members */
967 0, /* tp_getset */
968 0, /* tp_base */
969 0, /* tp_dict */
970 0, /* tp_descr_get */
971 0, /* tp_descr_set */
972 0, /* tp_dictoffset */
973 0, /* tp_init */
974 PyType_GenericAlloc, /* tp_alloc */
975 new_mmap_object, /* tp_new */
976 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000977};
978
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000979
980/* extract the map size from the given PyObject
981
Thomas Wouters7e474022000-07-16 12:04:32 +0000982 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000983 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000984static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000985_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000986{
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000987 if (o == NULL)
988 return 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000989 if (PyIndex_Check(o)) {
990 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000991 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000992 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000993 if (i < 0) {
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000994 PyErr_Format(PyExc_OverflowError,
995 "memory mapped %s must be positive",
996 param);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000997 return -1;
998 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000999 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001000 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001001
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001002 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001003 return -1;
1004}
1005
Tim Petersec0a5f02006-02-16 23:47:20 +00001006#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001007static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001008new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001009{
Neal Norwitzb5673922002-09-05 21:48:07 +00001010#ifdef HAVE_FSTAT
1011 struct stat st;
1012#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001013 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001014 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1015 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001016 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001017 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001018 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001019 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001020 "flags", "prot",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001021 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001022
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001023 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001024 &fd, &map_size_obj, &flags, &prot,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001025 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001026 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001027 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001028 if (map_size < 0)
1029 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001030 offset = _GetMapSize(offset_obj, "offset");
1031 if (offset < 0)
1032 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001033
Tim Petersec0a5f02006-02-16 23:47:20 +00001034 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001035 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001036 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001037 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001038 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001039 case ACCESS_READ:
1040 flags = MAP_SHARED;
1041 prot = PROT_READ;
1042 break;
1043 case ACCESS_WRITE:
1044 flags = MAP_SHARED;
1045 prot = PROT_READ | PROT_WRITE;
1046 break;
1047 case ACCESS_COPY:
1048 flags = MAP_PRIVATE;
1049 prot = PROT_READ | PROT_WRITE;
1050 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001051 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001052 /* use the specified or default values of flags and prot */
1053 break;
1054 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001055 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001056 "mmap invalid access parameter.");
1057 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001058
Christian Heimesa156e092008-02-16 07:38:31 +00001059 if (prot == PROT_READ) {
1060 access = ACCESS_READ;
1061 }
1062
Neal Norwitzb5673922002-09-05 21:48:07 +00001063#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001064# ifdef __VMS
1065 /* on OpenVMS we must ensure that all bytes are written to the file */
Christian Heimes25bb7832008-01-11 16:17:00 +00001066 if (fd != -1) {
1067 fsync(fd);
1068 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001069# endif
Christian Heimes25bb7832008-01-11 16:17:00 +00001070 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001071 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001072 map_size = st.st_size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001073 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001074 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001075 "mmap length is greater than file size");
1076 return NULL;
1077 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001078 }
1079#endif
Georg Brandl86def6c2008-01-21 20:36:10 +00001080 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001081 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001082 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001083 m_obj->size = (size_t) map_size;
1084 m_obj->pos = (size_t) 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001085 m_obj->exports = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001086 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001087 if (fd == -1) {
1088 m_obj->fd = -1;
1089 /* Assume the caller wants to map anonymous memory.
1090 This is the same behaviour as Windows. mmap.mmap(-1, size)
1091 on both Windows and Unix map anonymous memory.
1092 */
1093#ifdef MAP_ANONYMOUS
1094 /* BSD way to map anonymous memory */
1095 flags |= MAP_ANONYMOUS;
1096#else
1097 /* SVR4 method to map anonymous memory is to open /dev/zero */
1098 fd = devzero = open("/dev/zero", O_RDWR);
1099 if (devzero == -1) {
1100 Py_DECREF(m_obj);
1101 PyErr_SetFromErrno(mmap_module_error);
1102 return NULL;
1103 }
1104#endif
1105 } else {
1106 m_obj->fd = dup(fd);
1107 if (m_obj->fd == -1) {
1108 Py_DECREF(m_obj);
1109 PyErr_SetFromErrno(mmap_module_error);
1110 return NULL;
1111 }
Georg Brandl38387b82005-08-24 07:17:40 +00001112 }
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001113
Tim Petersec0a5f02006-02-16 23:47:20 +00001114 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001115 prot, flags,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001116 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001117
1118 if (devzero != -1) {
1119 close(devzero);
1120 }
1121
Tim Peters5ebfd362001-11-13 23:11:19 +00001122 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001123 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001124 Py_DECREF(m_obj);
1125 PyErr_SetFromErrno(mmap_module_error);
1126 return NULL;
1127 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001128 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001129 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001130}
1131#endif /* UNIX */
1132
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001133#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001134static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001135new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001136{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001137 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001138 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1139 Py_ssize_t map_size, offset;
1140 DWORD off_hi; /* upper 32 bits of offset */
1141 DWORD off_lo; /* lower 32 bits of offset */
1142 DWORD size_hi; /* upper 32 bits of size */
1143 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001144 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001145 DWORD dwErr = 0;
1146 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001147 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001148 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001149 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001150 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001151 "tagname",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001152 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001153
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001154 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001155 &fileno, &map_size_obj,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001156 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001157 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001158 }
1159
Neal Norwitz8856fb72005-12-18 03:34:22 +00001160 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001161 case ACCESS_READ:
1162 flProtect = PAGE_READONLY;
1163 dwDesiredAccess = FILE_MAP_READ;
1164 break;
1165 case ACCESS_DEFAULT: case ACCESS_WRITE:
1166 flProtect = PAGE_READWRITE;
1167 dwDesiredAccess = FILE_MAP_WRITE;
1168 break;
1169 case ACCESS_COPY:
1170 flProtect = PAGE_WRITECOPY;
1171 dwDesiredAccess = FILE_MAP_COPY;
1172 break;
1173 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001174 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001175 "mmap invalid access parameter.");
1176 }
1177
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001178 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001179 if (map_size < 0)
1180 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001181 offset = _GetMapSize(offset_obj, "offset");
1182 if (offset < 0)
1183 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001184
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001185 /* assume -1 and 0 both mean invalid filedescriptor
1186 to 'anonymously' map memory.
1187 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1188 XXX: Should this code be added?
1189 if (fileno == 0)
Skip Montanaro46fc3372007-08-12 11:44:53 +00001190 PyErr_WarnEx(PyExc_DeprecationWarning,
1191 "don't use 0 for anonymous memory",
1192 1);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001193 */
1194 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001195 fh = (HANDLE)_get_osfhandle(fileno);
1196 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001197 PyErr_SetFromErrno(mmap_module_error);
1198 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001199 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001200 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001201 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001202 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001203
Georg Brandl86def6c2008-01-21 20:36:10 +00001204 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Tim Peters8f9cc292006-02-17 00:00:20 +00001205 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001206 return NULL;
1207 /* Set every field to an invalid marker, so we can safely
1208 destruct the object in the face of failure */
1209 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001210 m_obj->file_handle = INVALID_HANDLE_VALUE;
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +00001211 m_obj->map_handle = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001212 m_obj->tagname = NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001213 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001214
Guido van Rossum09fdf072000-03-31 01:17:07 +00001215 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001216 /* It is necessary to duplicate the handle, so the
1217 Python code can close it on us */
1218 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001219 GetCurrentProcess(), /* source process handle */
1220 fh, /* handle to be duplicated */
1221 GetCurrentProcess(), /* target proc handle */
1222 (LPHANDLE)&m_obj->file_handle, /* result */
1223 0, /* access - ignored due to options value */
1224 FALSE, /* inherited by child processes? */
1225 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001226 dwErr = GetLastError();
1227 Py_DECREF(m_obj);
1228 PyErr_SetFromWindowsErr(dwErr);
1229 return NULL;
1230 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001231 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001232 DWORD low,high;
1233 low = GetFileSize(fh, &high);
1234 /* low might just happen to have the value INVALID_FILE_SIZE;
1235 so we need to check the last error also. */
1236 if (low == INVALID_FILE_SIZE &&
1237 (dwErr = GetLastError()) != NO_ERROR) {
1238 Py_DECREF(m_obj);
1239 return PyErr_SetFromWindowsErr(dwErr);
Guido van Rossum98297ee2007-11-06 21:34:58 +00001240 }
1241
Martin v. Löwis15186072006-02-18 12:38:35 +00001242#if SIZEOF_SIZE_T > 4
1243 m_obj->size = (((size_t)high)<<32) + low;
1244#else
1245 if (high)
1246 /* File is too large to map completely */
1247 m_obj->size = (size_t)-1;
1248 else
1249 m_obj->size = low;
1250#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001251 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001252 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001253 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001254 }
1255 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001256 m_obj->size = map_size;
1257 }
1258
1259 /* set the initial position */
1260 m_obj->pos = (size_t) 0;
1261
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001262 m_obj->exports = 0;
Mark Hammond2cbed002000-07-30 02:22:43 +00001263 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001264 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001265 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1266 if (m_obj->tagname == NULL) {
1267 PyErr_NoMemory();
1268 Py_DECREF(m_obj);
1269 return NULL;
1270 }
1271 strcpy(m_obj->tagname, tagname);
1272 }
1273 else
1274 m_obj->tagname = NULL;
1275
Neal Norwitz8856fb72005-12-18 03:34:22 +00001276 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001277 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001278 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001279 * consumes 4 bytes), C doesn't define what happens if we shift
1280 * right by 32, so we need different code.
1281 */
1282#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001283 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1284 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1285 off_hi = (DWORD)(offset >> 32);
1286 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001287#else
1288 size_hi = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001289 size_lo = (DWORD)(offset + m_obj->size);
1290 off_hi = 0;
1291 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001292#endif
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001293 /* For files, it would be sufficient to pass 0 as size.
1294 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001295 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1296 NULL,
1297 flProtect,
1298 size_hi,
1299 size_lo,
1300 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001301 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001302 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1303 dwDesiredAccess,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001304 off_hi,
1305 off_lo,
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +00001306 m_obj->size);
Tim Peters23721ee2006-02-16 23:50:16 +00001307 if (m_obj->data != NULL)
1308 return (PyObject *)m_obj;
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +00001309 else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001310 dwErr = GetLastError();
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +00001311 CloseHandle(m_obj->map_handle);
1312 m_obj->map_handle = NULL;
1313 }
Tim Peters23721ee2006-02-16 23:50:16 +00001314 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001315 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001316 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001317 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001318 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001319}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001320#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001321
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001322static void
1323setint(PyObject *d, const char *name, long value)
1324{
Christian Heimes217cfd12007-12-02 14:31:20 +00001325 PyObject *o = PyLong_FromLong(value);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001326 if (o && PyDict_SetItemString(d, name, o) == 0) {
1327 Py_DECREF(o);
1328 }
1329}
1330
Martin v. Löwis1a214512008-06-11 05:26:20 +00001331
1332static struct PyModuleDef mmapmodule = {
1333 PyModuleDef_HEAD_INIT,
1334 "mmap",
1335 NULL,
1336 -1,
1337 NULL,
1338 NULL,
1339 NULL,
1340 NULL,
1341 NULL
1342};
1343
Mark Hammond62b1ab12002-07-23 06:31:15 +00001344PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001345PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001346{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001347 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001348
Georg Brandl86def6c2008-01-21 20:36:10 +00001349 if (PyType_Ready(&mmap_object_type) < 0)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001350 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001351
Martin v. Löwis1a214512008-06-11 05:26:20 +00001352 module = PyModule_Create(&mmapmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001353 if (module == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001354 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001355 dict = PyModule_GetDict(module);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001356 if (!dict)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001357 return NULL;
Christian Heimes7131fd92008-02-19 14:21:46 +00001358 mmap_module_error = PyErr_NewException("mmap.error",
1359 PyExc_EnvironmentError , NULL);
1360 if (mmap_module_error == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001361 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +00001362 PyDict_SetItemString(dict, "error", mmap_module_error);
Georg Brandl86def6c2008-01-21 20:36:10 +00001363 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001364#ifdef PROT_EXEC
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001365 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001366#endif
1367#ifdef PROT_READ
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001368 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001369#endif
1370#ifdef PROT_WRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001371 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001372#endif
1373
1374#ifdef MAP_SHARED
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001375 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001376#endif
1377#ifdef MAP_PRIVATE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001378 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001379#endif
1380#ifdef MAP_DENYWRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001381 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001382#endif
1383#ifdef MAP_EXECUTABLE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001384 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001385#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001386#ifdef MAP_ANONYMOUS
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001387 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1388 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001389#endif
1390
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001391 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001392
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001393 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1394
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001395 setint(dict, "ACCESS_READ", ACCESS_READ);
1396 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1397 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Martin v. Löwis1a214512008-06-11 05:26:20 +00001398 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001399}