blob: f4a80c237929449a44a65fb0fc569e4926b6f0e6 [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
Victor Stinnera6cd0cf2011-05-02 01:05:37 +020026# ifdef __APPLE__
27# include <fcntl.h>
28# endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#endif
30
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000031#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000032#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000033static int
34my_getpagesize(void)
35{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000036 SYSTEM_INFO si;
37 GetSystemInfo(&si);
38 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000039}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000040
41static int
42my_getallocationgranularity (void)
43{
44
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000045 SYSTEM_INFO si;
46 GetSystemInfo(&si);
47 return si.dwAllocationGranularity;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000048}
49
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#endif
51
52#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000053#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000054#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000055
Fred Drake145f96e2000-10-01 17:50:46 +000056#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
57static int
58my_getpagesize(void)
59{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000060 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000061}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000062
63#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000064#else
65#define my_getpagesize getpagesize
66#endif
67
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000068#endif /* UNIX */
69
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000071
72#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000073#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000074#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000075
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000076/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000077#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
78# define MAP_ANONYMOUS MAP_ANON
79#endif
80
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000081static PyObject *mmap_module_error;
82
Tim Peters5ebfd362001-11-13 23:11:19 +000083typedef enum
84{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000085 ACCESS_DEFAULT,
86 ACCESS_READ,
87 ACCESS_WRITE,
88 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000089} access_mode;
90
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000091typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000092 PyObject_HEAD
93 char * data;
94 size_t size;
95 size_t pos; /* relative to offset */
Antoine Pitrou97696cb2011-02-21 23:46:27 +000096#ifdef MS_WINDOWS
97 PY_LONG_LONG offset;
98#else
99 off_t offset;
100#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000101 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000102
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000103#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 HANDLE map_handle;
105 HANDLE file_handle;
106 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107#endif
108
109#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000112
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000114} mmap_object;
115
Tim Peters5ebfd362001-11-13 23:11:19 +0000116
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000117static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000118mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000119{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000120#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000121 if (m_obj->data != NULL)
122 UnmapViewOfFile (m_obj->data);
123 if (m_obj->map_handle != NULL)
124 CloseHandle (m_obj->map_handle);
125 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
126 CloseHandle (m_obj->file_handle);
127 if (m_obj->tagname)
128 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000129#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000130
131#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 if (m_obj->fd >= 0)
133 (void) close(m_obj->fd);
134 if (m_obj->data!=NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000135 munmap(m_obj->data, m_obj->size);
136 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000137#endif /* UNIX */
138
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000140}
141
142static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000143mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000144{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 if (self->exports > 0) {
146 PyErr_SetString(PyExc_BufferError, "cannot close "\
147 "exported pointers exist");
148 return NULL;
149 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000150#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 /* For each resource we maintain, we need to check
152 the value is valid, and if so, free the resource
153 and set the member value to an invalid value so
154 the dealloc does not attempt to resource clearing
155 again.
156 TODO - should we check for errors in the close operations???
157 */
158 if (self->data != NULL) {
159 UnmapViewOfFile(self->data);
160 self->data = NULL;
161 }
162 if (self->map_handle != NULL) {
163 CloseHandle(self->map_handle);
164 self->map_handle = NULL;
165 }
166 if (self->file_handle != INVALID_HANDLE_VALUE) {
167 CloseHandle(self->file_handle);
168 self->file_handle = INVALID_HANDLE_VALUE;
169 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000170#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000171
172#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000173 if (0 <= self->fd)
174 (void) close(self->fd);
175 self->fd = -1;
176 if (self->data != NULL) {
177 munmap(self->data, self->size);
178 self->data = NULL;
179 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180#endif
181
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000182 Py_INCREF(Py_None);
183 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000184}
185
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000186#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187#define CHECK_VALID(err) \
188do { \
189 if (self->map_handle == NULL) { \
190 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
191 return err; \
192 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000193} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000194#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000195
196#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000197#define CHECK_VALID(err) \
198do { \
199 if (self->data == NULL) { \
200 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
201 return err; \
202 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000203} while (0)
204#endif /* UNIX */
205
206static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000207mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000209{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 CHECK_VALID(NULL);
211 if (self->pos < self->size) {
212 char value = self->data[self->pos];
213 self->pos += 1;
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000214 return Py_BuildValue("B", (unsigned char)value);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000215 } else {
216 PyErr_SetString(PyExc_ValueError, "read byte out of range");
217 return NULL;
218 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000219}
220
221static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000222mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 char *start = self->data+self->pos;
226 char *eof = self->data+self->size;
227 char *eol;
228 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000229
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000230 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000231
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000232 eol = memchr(start, '\n', self->size - self->pos);
233 if (!eol)
234 eol = eof;
235 else
236 ++eol; /* we're interested in the position after the
237 newline. */
238 result = PyBytes_FromStringAndSize(start, (eol - start));
239 self->pos += (eol - start);
240 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241}
242
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200243/* Basically the "n" format code with the ability to turn None into -1. */
244static int
245mmap_convert_ssize_t(PyObject *obj, void *result) {
246 Py_ssize_t limit;
247 if (obj == Py_None) {
248 limit = -1;
249 }
250 else if (PyNumber_Check(obj)) {
251 limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError);
252 if (limit == -1 && PyErr_Occurred())
253 return 0;
254 }
255 else {
256 PyErr_Format(PyExc_TypeError,
257 "integer argument expected, got '%.200s'",
258 Py_TYPE(obj)->tp_name);
259 return 0;
260 }
261 *((Py_ssize_t *)result) = limit;
262 return 1;
263}
264
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000265static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000266mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000267 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000268{
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200269 Py_ssize_t num_bytes = -1, n;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000271
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 CHECK_VALID(NULL);
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200273 if (!PyArg_ParseTuple(args, "|O&:read", mmap_convert_ssize_t, &num_bytes))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000275
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000276 /* silently 'adjust' out-of-range requests */
277 assert(self->size >= self->pos);
278 n = self->size - self->pos;
279 /* The difference can overflow, only if self->size is greater than
280 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
281 * because the mapped area and the returned string each need more
282 * than half of the addressable memory. So we clip the size, and let
283 * the code below raise MemoryError.
284 */
285 if (n < 0)
286 n = PY_SSIZE_T_MAX;
287 if (num_bytes < 0 || num_bytes > n) {
288 num_bytes = n;
289 }
290 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
291 self->pos += num_bytes;
292 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000293}
294
295static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000296mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000297 PyObject *args,
298 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000299{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000300 Py_ssize_t start = self->pos;
301 Py_ssize_t end = self->size;
302 const char *needle;
303 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000304
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000305 CHECK_VALID(NULL);
306 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
307 &needle, &len, &start, &end)) {
308 return NULL;
309 } else {
310 const char *p, *start_p, *end_p;
311 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000312
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000313 if (start < 0)
314 start += self->size;
315 if (start < 0)
316 start = 0;
317 else if ((size_t)start > self->size)
318 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000319
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 if (end < 0)
321 end += self->size;
322 if (end < 0)
323 end = 0;
324 else if ((size_t)end > self->size)
325 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000326
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 start_p = self->data + start;
328 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000329
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000330 for (p = (reverse ? end_p - len : start_p);
331 (p >= start_p) && (p + len <= end_p); p += sign) {
332 Py_ssize_t i;
333 for (i = 0; i < len && needle[i] == p[i]; ++i)
334 /* nothing */;
335 if (i == len) {
336 return PyLong_FromSsize_t(p - self->data);
337 }
338 }
339 return PyLong_FromLong(-1);
340 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000341}
342
Georg Brandlfceab5a2008-01-19 20:08:23 +0000343static PyObject *
344mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000345 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000346{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000347 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000348}
349
350static PyObject *
351mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000353{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000354 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000355}
356
Tim Petersec0a5f02006-02-16 23:47:20 +0000357static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000358is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000359{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000360 if (self->access != ACCESS_READ)
361 return 1;
362 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
363 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000364}
365
Tim Petersec0a5f02006-02-16 23:47:20 +0000366static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000367is_resizeable(mmap_object *self)
368{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000369 if (self->exports > 0) {
370 PyErr_SetString(PyExc_BufferError,
371 "mmap can't resize with extant buffers exported.");
372 return 0;
373 }
374 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
375 return 1;
376 PyErr_Format(PyExc_TypeError,
377 "mmap can't resize a readonly or copy-on-write memory map.");
378 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000379}
380
381
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000382static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000383mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000385{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 Py_ssize_t length;
387 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000388
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000389 CHECK_VALID(NULL);
390 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
391 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000392
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000393 if (!is_writable(self))
394 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000395
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000396 if ((self->pos + length) > self->size) {
397 PyErr_SetString(PyExc_ValueError, "data out of range");
398 return NULL;
399 }
400 memcpy(self->data+self->pos, data, length);
401 self->pos = self->pos+length;
402 Py_INCREF(Py_None);
403 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000404}
405
406static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000407mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000409{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000410 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000411
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000412 CHECK_VALID(NULL);
413 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
414 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000415
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000416 if (!is_writable(self))
417 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000418
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 if (self->pos < self->size) {
420 *(self->data+self->pos) = value;
421 self->pos += 1;
422 Py_INCREF(Py_None);
423 return Py_None;
424 }
425 else {
426 PyErr_SetString(PyExc_ValueError, "write byte out of range");
427 return NULL;
428 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429}
Tim Petersec0a5f02006-02-16 23:47:20 +0000430
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000431static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000432mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000433 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000434{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000435 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000436
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000437#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000438 if (self->file_handle != INVALID_HANDLE_VALUE) {
439 DWORD low,high;
440 PY_LONG_LONG size;
441 low = GetFileSize(self->file_handle, &high);
442 if (low == INVALID_FILE_SIZE) {
443 /* It might be that the function appears to have failed,
444 when indeed its size equals INVALID_FILE_SIZE */
445 DWORD error = GetLastError();
446 if (error != NO_ERROR)
447 return PyErr_SetFromWindowsErr(error);
448 }
449 if (!high && low < LONG_MAX)
450 return PyLong_FromLong((long)low);
451 size = (((PY_LONG_LONG)high)<<32) + low;
452 return PyLong_FromLongLong(size);
453 } else {
454 return PyLong_FromSsize_t(self->size);
455 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000456#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000457
458#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000459 {
460 struct stat buf;
461 if (-1 == fstat(self->fd, &buf)) {
462 PyErr_SetFromErrno(mmap_module_error);
463 return NULL;
464 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000465#ifdef HAVE_LARGEFILE_SUPPORT
466 return PyLong_FromLongLong(buf.st_size);
467#else
468 return PyLong_FromLong(buf.st_size);
469#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000471#endif /* UNIX */
472}
473
474/* This assumes that you want the entire file mapped,
475 / and when recreating the map will make the new file
476 / have the new size
477 /
478 / Is this really necessary? This could easily be done
479 / from python by just closing and re-opening with the
480 / new size?
481 */
482
483static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000484mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000485 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000486{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000487 Py_ssize_t new_size;
488 CHECK_VALID(NULL);
489 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
490 !is_resizeable(self)) {
491 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000492#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000493 } else {
494 DWORD dwErrCode = 0;
495 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
496 /* First, unmap the file view */
497 UnmapViewOfFile(self->data);
498 self->data = NULL;
499 /* Close the mapping object */
500 CloseHandle(self->map_handle);
501 self->map_handle = NULL;
502 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000503 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
504 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
505 off_hi = (DWORD)(self->offset >> 32);
506 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000507 SetFilePointer(self->file_handle,
508 newSizeLow, &newSizeHigh, FILE_BEGIN);
509 /* Change the size of the file */
510 SetEndOfFile(self->file_handle);
511 /* Create another mapping object and remap the file view */
512 self->map_handle = CreateFileMapping(
513 self->file_handle,
514 NULL,
515 PAGE_READWRITE,
516 0,
517 0,
518 self->tagname);
519 if (self->map_handle != NULL) {
520 self->data = (char *) MapViewOfFile(self->map_handle,
521 FILE_MAP_WRITE,
522 off_hi,
523 off_lo,
524 new_size);
525 if (self->data != NULL) {
526 self->size = new_size;
527 Py_INCREF(Py_None);
528 return Py_None;
529 } else {
530 dwErrCode = GetLastError();
531 CloseHandle(self->map_handle);
532 self->map_handle = NULL;
533 }
534 } else {
535 dwErrCode = GetLastError();
536 }
537 PyErr_SetFromWindowsErr(dwErrCode);
538 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000539#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000540
541#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000542#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000543 } else {
544 PyErr_SetString(PyExc_SystemError,
545 "mmap: resizing not available--no mremap()");
546 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000547#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000548 } else {
549 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000550
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000551 if (ftruncate(self->fd, self->offset + new_size) == -1) {
552 PyErr_SetFromErrno(mmap_module_error);
553 return NULL;
554 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000555
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000556#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000557 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000558#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000559 #if defined(__NetBSD__)
560 newmap = mremap(self->data, self->size, self->data, new_size, 0);
561 #else
562 newmap = mremap(self->data, self->size, new_size, 0);
563 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000564#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000565 if (newmap == (void *)-1)
566 {
567 PyErr_SetFromErrno(mmap_module_error);
568 return NULL;
569 }
570 self->data = newmap;
571 self->size = new_size;
572 Py_INCREF(Py_None);
573 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000574#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000575#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000576 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000577}
578
579static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000580mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000581{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000582 CHECK_VALID(NULL);
583 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000584}
585
586static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000587mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000589 Py_ssize_t offset = 0;
590 Py_ssize_t size = self->size;
591 CHECK_VALID(NULL);
592 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
593 return NULL;
594 if ((size_t)(offset + size) > self->size) {
595 PyErr_SetString(PyExc_ValueError, "flush values out of range");
596 return NULL;
597 }
R. David Murraye194dd62010-10-18 01:14:06 +0000598
599 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
600 return PyLong_FromLong(0);
601
Christian Heimesaf98da12008-01-27 15:18:18 +0000602#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000603 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000604#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000605 /* XXX semantics of return value? */
606 /* XXX flags for msync? */
607 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
608 PyErr_SetFromErrno(mmap_module_error);
609 return NULL;
610 }
611 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000612#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000613 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
614 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000615#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000616}
617
618static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000619mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000620{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000621 Py_ssize_t dist;
622 int how=0;
623 CHECK_VALID(NULL);
624 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
625 return NULL;
626 else {
627 size_t where;
628 switch (how) {
629 case 0: /* relative to start */
630 if (dist < 0)
631 goto onoutofrange;
632 where = dist;
633 break;
634 case 1: /* relative to current position */
635 if ((Py_ssize_t)self->pos + dist < 0)
636 goto onoutofrange;
637 where = self->pos + dist;
638 break;
639 case 2: /* relative to end */
640 if ((Py_ssize_t)self->size + dist < 0)
641 goto onoutofrange;
642 where = self->size + dist;
643 break;
644 default:
645 PyErr_SetString(PyExc_ValueError, "unknown seek type");
646 return NULL;
647 }
648 if (where > self->size)
649 goto onoutofrange;
650 self->pos = where;
651 Py_INCREF(Py_None);
652 return Py_None;
653 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000654
Tim Peters5ebfd362001-11-13 23:11:19 +0000655 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000656 PyErr_SetString(PyExc_ValueError, "seek out of range");
657 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000658}
659
660static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000661mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000662{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000663 unsigned long dest, src, cnt;
664 CHECK_VALID(NULL);
665 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
666 !is_writable(self)) {
667 return NULL;
668 } else {
669 /* bounds check the values */
Brett Cannon5fac8af2011-06-06 20:22:56 -0700670 if ((cnt + dest) < cnt || (cnt + src) < cnt ||
671 src > self->size || (src + cnt) > self->size ||
672 dest > self->size || (dest + cnt) > self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000673 PyErr_SetString(PyExc_ValueError,
674 "source, destination, or count out of range");
675 return NULL;
676 }
677 memmove(self->data+dest, self->data+src, cnt);
678 Py_INCREF(Py_None);
679 return Py_None;
680 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000681}
682
Georg Brandl0bccc182010-08-01 14:50:00 +0000683static PyObject *
684mmap_closed_get(mmap_object *self)
685{
686#ifdef MS_WINDOWS
687 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
688#elif defined(UNIX)
689 return PyBool_FromLong(self->data == NULL ? 1 : 0);
690#endif
691}
692
693static PyObject *
694mmap__enter__method(mmap_object *self, PyObject *args)
695{
696 CHECK_VALID(NULL);
697
698 Py_INCREF(self);
699 return (PyObject *)self;
700}
701
702static PyObject *
703mmap__exit__method(PyObject *self, PyObject *args)
704{
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200705 _Py_identifier(close);
706
707 return _PyObject_CallMethodId(self, &PyId_close, NULL);
Georg Brandl0bccc182010-08-01 14:50:00 +0000708}
709
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000710static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000711 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
712 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
713 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
714 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
715 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
716 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
717 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
718 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
719 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
720 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
721 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
722 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
723 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
724 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000725 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
726 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000727 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000728};
729
Georg Brandl0bccc182010-08-01 14:50:00 +0000730static PyGetSetDef mmap_object_getset[] = {
731 {"closed", (getter) mmap_closed_get, NULL, NULL},
732 {NULL}
733};
734
735
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000736/* Functions for treating an mmap'ed file as a buffer */
737
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000738static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000739mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000740{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000741 CHECK_VALID(-1);
742 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
743 (self->access == ACCESS_READ), flags) < 0)
744 return -1;
745 self->exports++;
746 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000747}
748
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000749static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000750mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000751{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000752 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000753}
754
Martin v. Löwis18e16552006-02-15 17:27:45 +0000755static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000756mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000757{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000758 CHECK_VALID(-1);
759 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000760}
761
762static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000763mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000764{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000765 CHECK_VALID(NULL);
766 if (i < 0 || (size_t)i >= self->size) {
767 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
768 return NULL;
769 }
770 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000771}
772
773static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000774mmap_subscript(mmap_object *self, PyObject *item)
775{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000776 CHECK_VALID(NULL);
777 if (PyIndex_Check(item)) {
778 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
779 if (i == -1 && PyErr_Occurred())
780 return NULL;
781 if (i < 0)
782 i += self->size;
783 if (i < 0 || (size_t)i >= self->size) {
784 PyErr_SetString(PyExc_IndexError,
785 "mmap index out of range");
786 return NULL;
787 }
788 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
789 }
790 else if (PySlice_Check(item)) {
791 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000792
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000793 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000794 &start, &stop, &step, &slicelen) < 0) {
795 return NULL;
796 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000797
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000798 if (slicelen <= 0)
799 return PyBytes_FromStringAndSize("", 0);
800 else if (step == 1)
801 return PyBytes_FromStringAndSize(self->data + start,
802 slicelen);
803 else {
804 char *result_buf = (char *)PyMem_Malloc(slicelen);
805 Py_ssize_t cur, i;
806 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000807
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000808 if (result_buf == NULL)
809 return PyErr_NoMemory();
810 for (cur = start, i = 0; i < slicelen;
811 cur += step, i++) {
812 result_buf[i] = self->data[cur];
813 }
814 result = PyBytes_FromStringAndSize(result_buf,
815 slicelen);
816 PyMem_Free(result_buf);
817 return result;
818 }
819 }
820 else {
821 PyErr_SetString(PyExc_TypeError,
822 "mmap indices must be integers");
823 return NULL;
824 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000825}
826
827static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000828mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000829{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000830 CHECK_VALID(NULL);
831 PyErr_SetString(PyExc_SystemError,
832 "mmaps don't support concatenation");
833 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000834}
835
836static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000837mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000838{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000839 CHECK_VALID(NULL);
840 PyErr_SetString(PyExc_SystemError,
841 "mmaps don't support repeat operation");
842 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000843}
844
845static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000846mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000847{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000848 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000849
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000850 CHECK_VALID(-1);
851 if (i < 0 || (size_t)i >= self->size) {
852 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
853 return -1;
854 }
855 if (v == NULL) {
856 PyErr_SetString(PyExc_TypeError,
857 "mmap object doesn't support item deletion");
858 return -1;
859 }
860 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
861 PyErr_SetString(PyExc_IndexError,
862 "mmap assignment must be length-1 bytes()");
863 return -1;
864 }
865 if (!is_writable(self))
866 return -1;
867 buf = PyBytes_AsString(v);
868 self->data[i] = buf[0];
869 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000870}
871
Thomas Woutersed03b412007-08-28 21:37:11 +0000872static int
873mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
874{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000875 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000876
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000877 if (!is_writable(self))
878 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000879
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000880 if (PyIndex_Check(item)) {
881 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
882 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000883
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000884 if (i == -1 && PyErr_Occurred())
885 return -1;
886 if (i < 0)
887 i += self->size;
888 if (i < 0 || (size_t)i >= self->size) {
889 PyErr_SetString(PyExc_IndexError,
890 "mmap index out of range");
891 return -1;
892 }
893 if (value == NULL) {
894 PyErr_SetString(PyExc_TypeError,
895 "mmap doesn't support item deletion");
896 return -1;
897 }
898 if (!PyIndex_Check(value)) {
899 PyErr_SetString(PyExc_TypeError,
900 "mmap item value must be an int");
901 return -1;
902 }
903 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
904 if (v == -1 && PyErr_Occurred())
905 return -1;
906 if (v < 0 || v > 255) {
907 PyErr_SetString(PyExc_ValueError,
908 "mmap item value must be "
909 "in range(0, 256)");
910 return -1;
911 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000912 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000913 return 0;
914 }
915 else if (PySlice_Check(item)) {
916 Py_ssize_t start, stop, step, slicelen;
917 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000918
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000919 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000920 self->size, &start, &stop,
921 &step, &slicelen) < 0) {
922 return -1;
923 }
924 if (value == NULL) {
925 PyErr_SetString(PyExc_TypeError,
926 "mmap object doesn't support slice deletion");
927 return -1;
928 }
929 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
930 return -1;
931 if (vbuf.len != slicelen) {
932 PyErr_SetString(PyExc_IndexError,
933 "mmap slice assignment is wrong size");
934 PyBuffer_Release(&vbuf);
935 return -1;
936 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000937
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000938 if (slicelen == 0) {
939 }
940 else if (step == 1) {
941 memcpy(self->data + start, vbuf.buf, slicelen);
942 }
943 else {
944 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000945
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000946 for (cur = start, i = 0;
947 i < slicelen;
948 cur += step, i++)
949 {
950 self->data[cur] = ((char *)vbuf.buf)[i];
951 }
952 }
953 PyBuffer_Release(&vbuf);
954 return 0;
955 }
956 else {
957 PyErr_SetString(PyExc_TypeError,
958 "mmap indices must be integer");
959 return -1;
960 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000961}
962
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000963static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000964 (lenfunc)mmap_length, /*sq_length*/
965 (binaryfunc)mmap_concat, /*sq_concat*/
966 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
967 (ssizeargfunc)mmap_item, /*sq_item*/
968 0, /*sq_slice*/
969 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
970 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000971};
972
Thomas Woutersed03b412007-08-28 21:37:11 +0000973static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000974 (lenfunc)mmap_length,
975 (binaryfunc)mmap_subscript,
976 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000977};
978
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000979static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000980 (getbufferproc)mmap_buffer_getbuf,
981 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000982};
983
Georg Brandl86def6c2008-01-21 20:36:10 +0000984static PyObject *
985new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
986
Christian Heimese1c98112008-01-21 11:20:28 +0000987PyDoc_STRVAR(mmap_doc,
988"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
989\n\
990Maps length bytes from the file specified by the file handle fileno,\n\
991and returns a mmap object. If length is larger than the current size\n\
992of the file, the file is extended to contain length bytes. If length\n\
993is 0, the maximum length of the map is the current size of the file,\n\
994except that if the file is empty Windows raises an exception (you cannot\n\
995create an empty mapping on Windows).\n\
996\n\
997Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
998\n\
999Maps length bytes from the file specified by the file descriptor fileno,\n\
1000and returns a mmap object. If length is 0, the maximum length of the map\n\
1001will be the current size of the file when mmap is called.\n\
1002flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1003private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001004object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001005that's shared with all other processes mapping the same areas of the file.\n\
1006The default value is MAP_SHARED.\n\
1007\n\
1008To map anonymous memory, pass -1 as the fileno (both versions).");
1009
1010
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001011static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001012 PyVarObject_HEAD_INIT(NULL, 0)
1013 "mmap.mmap", /* tp_name */
1014 sizeof(mmap_object), /* tp_size */
1015 0, /* tp_itemsize */
1016 /* methods */
1017 (destructor) mmap_object_dealloc, /* tp_dealloc */
1018 0, /* tp_print */
1019 0, /* tp_getattr */
1020 0, /* tp_setattr */
1021 0, /* tp_reserved */
1022 0, /* tp_repr */
1023 0, /* tp_as_number */
1024 &mmap_as_sequence, /*tp_as_sequence*/
1025 &mmap_as_mapping, /*tp_as_mapping*/
1026 0, /*tp_hash*/
1027 0, /*tp_call*/
1028 0, /*tp_str*/
1029 PyObject_GenericGetAttr, /*tp_getattro*/
1030 0, /*tp_setattro*/
1031 &mmap_as_buffer, /*tp_as_buffer*/
1032 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1033 mmap_doc, /*tp_doc*/
1034 0, /* tp_traverse */
1035 0, /* tp_clear */
1036 0, /* tp_richcompare */
1037 0, /* tp_weaklistoffset */
1038 0, /* tp_iter */
1039 0, /* tp_iternext */
1040 mmap_object_methods, /* tp_methods */
1041 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001042 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001043 0, /* tp_base */
1044 0, /* tp_dict */
1045 0, /* tp_descr_get */
1046 0, /* tp_descr_set */
1047 0, /* tp_dictoffset */
1048 0, /* tp_init */
1049 PyType_GenericAlloc, /* tp_alloc */
1050 new_mmap_object, /* tp_new */
1051 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001052};
1053
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001054
1055/* extract the map size from the given PyObject
1056
Thomas Wouters7e474022000-07-16 12:04:32 +00001057 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001058 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001059static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001060_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001061{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001062 if (o == NULL)
1063 return 0;
1064 if (PyIndex_Check(o)) {
1065 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1066 if (i==-1 && PyErr_Occurred())
1067 return -1;
1068 if (i < 0) {
1069 PyErr_Format(PyExc_OverflowError,
1070 "memory mapped %s must be positive",
1071 param);
1072 return -1;
1073 }
1074 return i;
1075 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001076
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001077 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1078 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001079}
1080
Tim Petersec0a5f02006-02-16 23:47:20 +00001081#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001082#ifdef HAVE_LARGEFILE_SUPPORT
1083#define _Py_PARSE_OFF_T "L"
1084#else
1085#define _Py_PARSE_OFF_T "l"
1086#endif
1087
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001089new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001090{
Neal Norwitzb5673922002-09-05 21:48:07 +00001091#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001092 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001093#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001094 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001095 PyObject *map_size_obj = NULL;
1096 Py_ssize_t map_size;
1097 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001098 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1099 int devzero = -1;
1100 int access = (int)ACCESS_DEFAULT;
1101 static char *keywords[] = {"fileno", "length",
1102 "flags", "prot",
1103 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001104
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001105 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001106 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001107 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001108 return NULL;
1109 map_size = _GetMapSize(map_size_obj, "size");
1110 if (map_size < 0)
1111 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001112 if (offset < 0) {
1113 PyErr_SetString(PyExc_OverflowError,
1114 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001115 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001116 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001117
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001118 if ((access != (int)ACCESS_DEFAULT) &&
1119 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1120 return PyErr_Format(PyExc_ValueError,
1121 "mmap can't specify both access and flags, prot.");
1122 switch ((access_mode)access) {
1123 case ACCESS_READ:
1124 flags = MAP_SHARED;
1125 prot = PROT_READ;
1126 break;
1127 case ACCESS_WRITE:
1128 flags = MAP_SHARED;
1129 prot = PROT_READ | PROT_WRITE;
1130 break;
1131 case ACCESS_COPY:
1132 flags = MAP_PRIVATE;
1133 prot = PROT_READ | PROT_WRITE;
1134 break;
1135 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001136 /* map prot to access type */
1137 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1138 /* ACCESS_DEFAULT */
1139 }
1140 else if (prot & PROT_WRITE) {
1141 access = ACCESS_WRITE;
1142 }
1143 else {
1144 access = ACCESS_READ;
1145 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001146 break;
1147 default:
1148 return PyErr_Format(PyExc_ValueError,
1149 "mmap invalid access parameter.");
1150 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001151
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001152#ifdef __APPLE__
1153 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1154 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1155 if (fd != -1)
1156 (void)fcntl(fd, F_FULLFSYNC);
1157#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001158#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001159# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001160 /* on OpenVMS we must ensure that all bytes are written to the file */
1161 if (fd != -1) {
1162 fsync(fd);
1163 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001164# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001165 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1166 if (map_size == 0) {
Ross Lagerwalldbfb9b82011-06-25 10:02:37 +02001167 off_t calc_size;
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001168 if (offset >= st.st_size) {
1169 PyErr_SetString(PyExc_ValueError,
1170 "mmap offset is greater than file size");
1171 return NULL;
1172 }
Ross Lagerwalldbfb9b82011-06-25 10:02:37 +02001173 calc_size = st.st_size - offset;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001174 map_size = calc_size;
1175 if (map_size != calc_size) {
1176 PyErr_SetString(PyExc_ValueError,
1177 "mmap length is too large");
1178 return NULL;
1179 }
1180 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001181 PyErr_SetString(PyExc_ValueError,
1182 "mmap length is greater than file size");
1183 return NULL;
1184 }
1185 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001186#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001187 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1188 if (m_obj == NULL) {return NULL;}
1189 m_obj->data = NULL;
1190 m_obj->size = (size_t) map_size;
1191 m_obj->pos = (size_t) 0;
1192 m_obj->exports = 0;
1193 m_obj->offset = offset;
1194 if (fd == -1) {
1195 m_obj->fd = -1;
1196 /* Assume the caller wants to map anonymous memory.
1197 This is the same behaviour as Windows. mmap.mmap(-1, size)
1198 on both Windows and Unix map anonymous memory.
1199 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001200#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001201 /* BSD way to map anonymous memory */
1202 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001203#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001204 /* SVR4 method to map anonymous memory is to open /dev/zero */
1205 fd = devzero = open("/dev/zero", O_RDWR);
1206 if (devzero == -1) {
1207 Py_DECREF(m_obj);
1208 PyErr_SetFromErrno(mmap_module_error);
1209 return NULL;
1210 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001211#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001212 } else {
1213 m_obj->fd = dup(fd);
1214 if (m_obj->fd == -1) {
1215 Py_DECREF(m_obj);
1216 PyErr_SetFromErrno(mmap_module_error);
1217 return NULL;
1218 }
1219 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001220
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001221 m_obj->data = mmap(NULL, map_size,
1222 prot, flags,
1223 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001224
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001225 if (devzero != -1) {
1226 close(devzero);
1227 }
1228
1229 if (m_obj->data == (char *)-1) {
1230 m_obj->data = NULL;
1231 Py_DECREF(m_obj);
1232 PyErr_SetFromErrno(mmap_module_error);
1233 return NULL;
1234 }
1235 m_obj->access = (access_mode)access;
1236 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001237}
1238#endif /* UNIX */
1239
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001240#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001241
1242/* A note on sizes and offsets: while the actual map size must hold in a
1243 Py_ssize_t, both the total file size and the start offset can be longer
1244 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1245*/
1246
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001247static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001248new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001249{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001250 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001251 PyObject *map_size_obj = NULL;
1252 Py_ssize_t map_size;
1253 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001254 DWORD off_hi; /* upper 32 bits of offset */
1255 DWORD off_lo; /* lower 32 bits of offset */
1256 DWORD size_hi; /* upper 32 bits of size */
1257 DWORD size_lo; /* lower 32 bits of size */
1258 char *tagname = "";
1259 DWORD dwErr = 0;
1260 int fileno;
1261 HANDLE fh = 0;
1262 int access = (access_mode)ACCESS_DEFAULT;
1263 DWORD flProtect, dwDesiredAccess;
1264 static char *keywords[] = { "fileno", "length",
1265 "tagname",
1266 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001267
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001268 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001269 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001270 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001271 return NULL;
1272 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001273
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001274 switch((access_mode)access) {
1275 case ACCESS_READ:
1276 flProtect = PAGE_READONLY;
1277 dwDesiredAccess = FILE_MAP_READ;
1278 break;
1279 case ACCESS_DEFAULT: case ACCESS_WRITE:
1280 flProtect = PAGE_READWRITE;
1281 dwDesiredAccess = FILE_MAP_WRITE;
1282 break;
1283 case ACCESS_COPY:
1284 flProtect = PAGE_WRITECOPY;
1285 dwDesiredAccess = FILE_MAP_COPY;
1286 break;
1287 default:
1288 return PyErr_Format(PyExc_ValueError,
1289 "mmap invalid access parameter.");
1290 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001291
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001292 map_size = _GetMapSize(map_size_obj, "size");
1293 if (map_size < 0)
1294 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001295 if (offset < 0) {
1296 PyErr_SetString(PyExc_OverflowError,
1297 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001298 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001299 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001300
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001301 /* assume -1 and 0 both mean invalid filedescriptor
1302 to 'anonymously' map memory.
1303 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1304 XXX: Should this code be added?
1305 if (fileno == 0)
1306 PyErr_WarnEx(PyExc_DeprecationWarning,
1307 "don't use 0 for anonymous memory",
1308 1);
1309 */
1310 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001311 /* Ensure that fileno is within the CRT's valid range */
1312 if (_PyVerify_fd(fileno) == 0) {
1313 PyErr_SetFromErrno(mmap_module_error);
1314 return NULL;
1315 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001316 fh = (HANDLE)_get_osfhandle(fileno);
1317 if (fh==(HANDLE)-1) {
1318 PyErr_SetFromErrno(mmap_module_error);
1319 return NULL;
1320 }
1321 /* Win9x appears to need us seeked to zero */
1322 lseek(fileno, 0, SEEK_SET);
1323 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001325 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1326 if (m_obj == NULL)
1327 return NULL;
1328 /* Set every field to an invalid marker, so we can safely
1329 destruct the object in the face of failure */
1330 m_obj->data = NULL;
1331 m_obj->file_handle = INVALID_HANDLE_VALUE;
1332 m_obj->map_handle = NULL;
1333 m_obj->tagname = NULL;
1334 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001335
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001336 if (fh) {
1337 /* It is necessary to duplicate the handle, so the
1338 Python code can close it on us */
1339 if (!DuplicateHandle(
1340 GetCurrentProcess(), /* source process handle */
1341 fh, /* handle to be duplicated */
1342 GetCurrentProcess(), /* target proc handle */
1343 (LPHANDLE)&m_obj->file_handle, /* result */
1344 0, /* access - ignored due to options value */
1345 FALSE, /* inherited by child processes? */
1346 DUPLICATE_SAME_ACCESS)) { /* options */
1347 dwErr = GetLastError();
1348 Py_DECREF(m_obj);
1349 PyErr_SetFromWindowsErr(dwErr);
1350 return NULL;
1351 }
1352 if (!map_size) {
1353 DWORD low,high;
1354 low = GetFileSize(fh, &high);
1355 /* low might just happen to have the value INVALID_FILE_SIZE;
1356 so we need to check the last error also. */
1357 if (low == INVALID_FILE_SIZE &&
1358 (dwErr = GetLastError()) != NO_ERROR) {
1359 Py_DECREF(m_obj);
1360 return PyErr_SetFromWindowsErr(dwErr);
1361 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001362
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001363 size = (((PY_LONG_LONG) high) << 32) + low;
1364 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001365 PyErr_SetString(PyExc_ValueError,
1366 "mmap offset is greater than file size");
1367 Py_DECREF(m_obj);
1368 return NULL;
1369 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001370 if (offset - size > PY_SSIZE_T_MAX)
1371 /* Map area too large to fit in memory */
1372 m_obj->size = (Py_ssize_t) -1;
1373 else
1374 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001375 } else {
1376 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001377 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001378 }
1379 }
1380 else {
1381 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001382 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001383 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001384
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001385 /* set the initial position */
1386 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001387
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001388 m_obj->exports = 0;
1389 /* set the tag name */
1390 if (tagname != NULL && *tagname != '\0') {
1391 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1392 if (m_obj->tagname == NULL) {
1393 PyErr_NoMemory();
1394 Py_DECREF(m_obj);
1395 return NULL;
1396 }
1397 strcpy(m_obj->tagname, tagname);
1398 }
1399 else
1400 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001401
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001402 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001403 size_hi = (DWORD)(size >> 32);
1404 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001405 off_hi = (DWORD)(offset >> 32);
1406 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001407 /* For files, it would be sufficient to pass 0 as size.
1408 For anonymous maps, we have to pass the size explicitly. */
1409 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1410 NULL,
1411 flProtect,
1412 size_hi,
1413 size_lo,
1414 m_obj->tagname);
1415 if (m_obj->map_handle != NULL) {
1416 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1417 dwDesiredAccess,
1418 off_hi,
1419 off_lo,
1420 m_obj->size);
1421 if (m_obj->data != NULL)
1422 return (PyObject *)m_obj;
1423 else {
1424 dwErr = GetLastError();
1425 CloseHandle(m_obj->map_handle);
1426 m_obj->map_handle = NULL;
1427 }
1428 } else
1429 dwErr = GetLastError();
1430 Py_DECREF(m_obj);
1431 PyErr_SetFromWindowsErr(dwErr);
1432 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001433}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001434#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001435
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001436static void
1437setint(PyObject *d, const char *name, long value)
1438{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001439 PyObject *o = PyLong_FromLong(value);
1440 if (o && PyDict_SetItemString(d, name, o) == 0) {
1441 Py_DECREF(o);
1442 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001443}
1444
Martin v. Löwis1a214512008-06-11 05:26:20 +00001445
1446static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001447 PyModuleDef_HEAD_INIT,
1448 "mmap",
1449 NULL,
1450 -1,
1451 NULL,
1452 NULL,
1453 NULL,
1454 NULL,
1455 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001456};
1457
Mark Hammond62b1ab12002-07-23 06:31:15 +00001458PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001459PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001460{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001461 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001462
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001463 if (PyType_Ready(&mmap_object_type) < 0)
1464 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001465
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001466 module = PyModule_Create(&mmapmodule);
1467 if (module == NULL)
1468 return NULL;
1469 dict = PyModule_GetDict(module);
1470 if (!dict)
1471 return NULL;
1472 mmap_module_error = PyErr_NewException("mmap.error",
1473 PyExc_EnvironmentError , NULL);
1474 if (mmap_module_error == NULL)
1475 return NULL;
1476 PyDict_SetItemString(dict, "error", mmap_module_error);
1477 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001478#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001479 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001480#endif
1481#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001482 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001483#endif
1484#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001485 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001486#endif
1487
1488#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001489 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001490#endif
1491#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001492 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001493#endif
1494#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001495 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001496#endif
1497#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001498 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001499#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001500#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001501 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1502 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001503#endif
1504
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001505 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001506
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001507 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001508
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001509 setint(dict, "ACCESS_READ", ACCESS_READ);
1510 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1511 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1512 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001513}