blob: 5d086a7386a73a299db15f7f2f6d18463c391fc5 [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{
705 return PyObject_CallMethod(self, "close", NULL);
706}
707
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000708static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000709 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
710 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
711 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
712 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
713 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
714 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
715 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
716 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
717 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
718 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
719 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
720 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
721 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
722 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000723 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
724 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000725 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000726};
727
Georg Brandl0bccc182010-08-01 14:50:00 +0000728static PyGetSetDef mmap_object_getset[] = {
729 {"closed", (getter) mmap_closed_get, NULL, NULL},
730 {NULL}
731};
732
733
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000734/* Functions for treating an mmap'ed file as a buffer */
735
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000736static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000737mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000738{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000739 CHECK_VALID(-1);
740 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
741 (self->access == ACCESS_READ), flags) < 0)
742 return -1;
743 self->exports++;
744 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000745}
746
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000747static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000748mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000749{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000750 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000751}
752
Martin v. Löwis18e16552006-02-15 17:27:45 +0000753static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000754mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000756 CHECK_VALID(-1);
757 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000758}
759
760static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000761mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000762{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000763 CHECK_VALID(NULL);
764 if (i < 0 || (size_t)i >= self->size) {
765 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
766 return NULL;
767 }
768 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000769}
770
771static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000772mmap_subscript(mmap_object *self, PyObject *item)
773{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000774 CHECK_VALID(NULL);
775 if (PyIndex_Check(item)) {
776 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
777 if (i == -1 && PyErr_Occurred())
778 return NULL;
779 if (i < 0)
780 i += self->size;
781 if (i < 0 || (size_t)i >= self->size) {
782 PyErr_SetString(PyExc_IndexError,
783 "mmap index out of range");
784 return NULL;
785 }
786 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
787 }
788 else if (PySlice_Check(item)) {
789 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000790
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000791 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000792 &start, &stop, &step, &slicelen) < 0) {
793 return NULL;
794 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000795
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000796 if (slicelen <= 0)
797 return PyBytes_FromStringAndSize("", 0);
798 else if (step == 1)
799 return PyBytes_FromStringAndSize(self->data + start,
800 slicelen);
801 else {
802 char *result_buf = (char *)PyMem_Malloc(slicelen);
803 Py_ssize_t cur, i;
804 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000805
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000806 if (result_buf == NULL)
807 return PyErr_NoMemory();
808 for (cur = start, i = 0; i < slicelen;
809 cur += step, i++) {
810 result_buf[i] = self->data[cur];
811 }
812 result = PyBytes_FromStringAndSize(result_buf,
813 slicelen);
814 PyMem_Free(result_buf);
815 return result;
816 }
817 }
818 else {
819 PyErr_SetString(PyExc_TypeError,
820 "mmap indices must be integers");
821 return NULL;
822 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000823}
824
825static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000826mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000827{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000828 CHECK_VALID(NULL);
829 PyErr_SetString(PyExc_SystemError,
830 "mmaps don't support concatenation");
831 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000832}
833
834static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000835mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000836{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000837 CHECK_VALID(NULL);
838 PyErr_SetString(PyExc_SystemError,
839 "mmaps don't support repeat operation");
840 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000841}
842
843static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000844mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000845{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000846 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000847
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000848 CHECK_VALID(-1);
849 if (i < 0 || (size_t)i >= self->size) {
850 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
851 return -1;
852 }
853 if (v == NULL) {
854 PyErr_SetString(PyExc_TypeError,
855 "mmap object doesn't support item deletion");
856 return -1;
857 }
858 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
859 PyErr_SetString(PyExc_IndexError,
860 "mmap assignment must be length-1 bytes()");
861 return -1;
862 }
863 if (!is_writable(self))
864 return -1;
865 buf = PyBytes_AsString(v);
866 self->data[i] = buf[0];
867 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000868}
869
Thomas Woutersed03b412007-08-28 21:37:11 +0000870static int
871mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
872{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000873 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000874
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000875 if (!is_writable(self))
876 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000877
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000878 if (PyIndex_Check(item)) {
879 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
880 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000881
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000882 if (i == -1 && PyErr_Occurred())
883 return -1;
884 if (i < 0)
885 i += self->size;
886 if (i < 0 || (size_t)i >= self->size) {
887 PyErr_SetString(PyExc_IndexError,
888 "mmap index out of range");
889 return -1;
890 }
891 if (value == NULL) {
892 PyErr_SetString(PyExc_TypeError,
893 "mmap doesn't support item deletion");
894 return -1;
895 }
896 if (!PyIndex_Check(value)) {
897 PyErr_SetString(PyExc_TypeError,
898 "mmap item value must be an int");
899 return -1;
900 }
901 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
902 if (v == -1 && PyErr_Occurred())
903 return -1;
904 if (v < 0 || v > 255) {
905 PyErr_SetString(PyExc_ValueError,
906 "mmap item value must be "
907 "in range(0, 256)");
908 return -1;
909 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000910 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000911 return 0;
912 }
913 else if (PySlice_Check(item)) {
914 Py_ssize_t start, stop, step, slicelen;
915 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000916
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000917 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000918 self->size, &start, &stop,
919 &step, &slicelen) < 0) {
920 return -1;
921 }
922 if (value == NULL) {
923 PyErr_SetString(PyExc_TypeError,
924 "mmap object doesn't support slice deletion");
925 return -1;
926 }
927 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
928 return -1;
929 if (vbuf.len != slicelen) {
930 PyErr_SetString(PyExc_IndexError,
931 "mmap slice assignment is wrong size");
932 PyBuffer_Release(&vbuf);
933 return -1;
934 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000935
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000936 if (slicelen == 0) {
937 }
938 else if (step == 1) {
939 memcpy(self->data + start, vbuf.buf, slicelen);
940 }
941 else {
942 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000943
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000944 for (cur = start, i = 0;
945 i < slicelen;
946 cur += step, i++)
947 {
948 self->data[cur] = ((char *)vbuf.buf)[i];
949 }
950 }
951 PyBuffer_Release(&vbuf);
952 return 0;
953 }
954 else {
955 PyErr_SetString(PyExc_TypeError,
956 "mmap indices must be integer");
957 return -1;
958 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000959}
960
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000961static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000962 (lenfunc)mmap_length, /*sq_length*/
963 (binaryfunc)mmap_concat, /*sq_concat*/
964 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
965 (ssizeargfunc)mmap_item, /*sq_item*/
966 0, /*sq_slice*/
967 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
968 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000969};
970
Thomas Woutersed03b412007-08-28 21:37:11 +0000971static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000972 (lenfunc)mmap_length,
973 (binaryfunc)mmap_subscript,
974 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000975};
976
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000977static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000978 (getbufferproc)mmap_buffer_getbuf,
979 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000980};
981
Georg Brandl86def6c2008-01-21 20:36:10 +0000982static PyObject *
983new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
984
Christian Heimese1c98112008-01-21 11:20:28 +0000985PyDoc_STRVAR(mmap_doc,
986"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
987\n\
988Maps length bytes from the file specified by the file handle fileno,\n\
989and returns a mmap object. If length is larger than the current size\n\
990of the file, the file is extended to contain length bytes. If length\n\
991is 0, the maximum length of the map is the current size of the file,\n\
992except that if the file is empty Windows raises an exception (you cannot\n\
993create an empty mapping on Windows).\n\
994\n\
995Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
996\n\
997Maps length bytes from the file specified by the file descriptor fileno,\n\
998and returns a mmap object. If length is 0, the maximum length of the map\n\
999will be the current size of the file when mmap is called.\n\
1000flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1001private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001002object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001003that's shared with all other processes mapping the same areas of the file.\n\
1004The default value is MAP_SHARED.\n\
1005\n\
1006To map anonymous memory, pass -1 as the fileno (both versions).");
1007
1008
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001009static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001010 PyVarObject_HEAD_INIT(NULL, 0)
1011 "mmap.mmap", /* tp_name */
1012 sizeof(mmap_object), /* tp_size */
1013 0, /* tp_itemsize */
1014 /* methods */
1015 (destructor) mmap_object_dealloc, /* tp_dealloc */
1016 0, /* tp_print */
1017 0, /* tp_getattr */
1018 0, /* tp_setattr */
1019 0, /* tp_reserved */
1020 0, /* tp_repr */
1021 0, /* tp_as_number */
1022 &mmap_as_sequence, /*tp_as_sequence*/
1023 &mmap_as_mapping, /*tp_as_mapping*/
1024 0, /*tp_hash*/
1025 0, /*tp_call*/
1026 0, /*tp_str*/
1027 PyObject_GenericGetAttr, /*tp_getattro*/
1028 0, /*tp_setattro*/
1029 &mmap_as_buffer, /*tp_as_buffer*/
1030 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1031 mmap_doc, /*tp_doc*/
1032 0, /* tp_traverse */
1033 0, /* tp_clear */
1034 0, /* tp_richcompare */
1035 0, /* tp_weaklistoffset */
1036 0, /* tp_iter */
1037 0, /* tp_iternext */
1038 mmap_object_methods, /* tp_methods */
1039 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001040 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001041 0, /* tp_base */
1042 0, /* tp_dict */
1043 0, /* tp_descr_get */
1044 0, /* tp_descr_set */
1045 0, /* tp_dictoffset */
1046 0, /* tp_init */
1047 PyType_GenericAlloc, /* tp_alloc */
1048 new_mmap_object, /* tp_new */
1049 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001050};
1051
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001052
1053/* extract the map size from the given PyObject
1054
Thomas Wouters7e474022000-07-16 12:04:32 +00001055 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001056 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001057static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001058_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001059{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001060 if (o == NULL)
1061 return 0;
1062 if (PyIndex_Check(o)) {
1063 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1064 if (i==-1 && PyErr_Occurred())
1065 return -1;
1066 if (i < 0) {
1067 PyErr_Format(PyExc_OverflowError,
1068 "memory mapped %s must be positive",
1069 param);
1070 return -1;
1071 }
1072 return i;
1073 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001074
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001075 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1076 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001077}
1078
Tim Petersec0a5f02006-02-16 23:47:20 +00001079#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001080#ifdef HAVE_LARGEFILE_SUPPORT
1081#define _Py_PARSE_OFF_T "L"
1082#else
1083#define _Py_PARSE_OFF_T "l"
1084#endif
1085
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001086static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001087new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088{
Neal Norwitzb5673922002-09-05 21:48:07 +00001089#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001090 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001091#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001092 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001093 PyObject *map_size_obj = NULL;
1094 Py_ssize_t map_size;
1095 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001096 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1097 int devzero = -1;
1098 int access = (int)ACCESS_DEFAULT;
1099 static char *keywords[] = {"fileno", "length",
1100 "flags", "prot",
1101 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001102
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001103 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001104 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001105 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001106 return NULL;
1107 map_size = _GetMapSize(map_size_obj, "size");
1108 if (map_size < 0)
1109 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001110 if (offset < 0) {
1111 PyErr_SetString(PyExc_OverflowError,
1112 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001113 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001114 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001115
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001116 if ((access != (int)ACCESS_DEFAULT) &&
1117 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1118 return PyErr_Format(PyExc_ValueError,
1119 "mmap can't specify both access and flags, prot.");
1120 switch ((access_mode)access) {
1121 case ACCESS_READ:
1122 flags = MAP_SHARED;
1123 prot = PROT_READ;
1124 break;
1125 case ACCESS_WRITE:
1126 flags = MAP_SHARED;
1127 prot = PROT_READ | PROT_WRITE;
1128 break;
1129 case ACCESS_COPY:
1130 flags = MAP_PRIVATE;
1131 prot = PROT_READ | PROT_WRITE;
1132 break;
1133 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001134 /* map prot to access type */
1135 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1136 /* ACCESS_DEFAULT */
1137 }
1138 else if (prot & PROT_WRITE) {
1139 access = ACCESS_WRITE;
1140 }
1141 else {
1142 access = ACCESS_READ;
1143 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001144 break;
1145 default:
1146 return PyErr_Format(PyExc_ValueError,
1147 "mmap invalid access parameter.");
1148 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001149
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001150#ifdef __APPLE__
1151 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1152 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1153 if (fd != -1)
1154 (void)fcntl(fd, F_FULLFSYNC);
1155#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001156#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001157# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001158 /* on OpenVMS we must ensure that all bytes are written to the file */
1159 if (fd != -1) {
1160 fsync(fd);
1161 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001162# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001163 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1164 if (map_size == 0) {
Ross Lagerwalldbfb9b82011-06-25 10:02:37 +02001165 off_t calc_size;
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001166 if (offset >= st.st_size) {
1167 PyErr_SetString(PyExc_ValueError,
1168 "mmap offset is greater than file size");
1169 return NULL;
1170 }
Ross Lagerwalldbfb9b82011-06-25 10:02:37 +02001171 calc_size = st.st_size - offset;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001172 map_size = calc_size;
1173 if (map_size != calc_size) {
1174 PyErr_SetString(PyExc_ValueError,
1175 "mmap length is too large");
1176 return NULL;
1177 }
1178 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001179 PyErr_SetString(PyExc_ValueError,
1180 "mmap length is greater than file size");
1181 return NULL;
1182 }
1183 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001184#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001185 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1186 if (m_obj == NULL) {return NULL;}
1187 m_obj->data = NULL;
1188 m_obj->size = (size_t) map_size;
1189 m_obj->pos = (size_t) 0;
1190 m_obj->exports = 0;
1191 m_obj->offset = offset;
1192 if (fd == -1) {
1193 m_obj->fd = -1;
1194 /* Assume the caller wants to map anonymous memory.
1195 This is the same behaviour as Windows. mmap.mmap(-1, size)
1196 on both Windows and Unix map anonymous memory.
1197 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001198#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001199 /* BSD way to map anonymous memory */
1200 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001201#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001202 /* SVR4 method to map anonymous memory is to open /dev/zero */
1203 fd = devzero = open("/dev/zero", O_RDWR);
1204 if (devzero == -1) {
1205 Py_DECREF(m_obj);
1206 PyErr_SetFromErrno(mmap_module_error);
1207 return NULL;
1208 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001209#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001210 } else {
1211 m_obj->fd = dup(fd);
1212 if (m_obj->fd == -1) {
1213 Py_DECREF(m_obj);
1214 PyErr_SetFromErrno(mmap_module_error);
1215 return NULL;
1216 }
1217 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001218
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001219 m_obj->data = mmap(NULL, map_size,
1220 prot, flags,
1221 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001222
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001223 if (devzero != -1) {
1224 close(devzero);
1225 }
1226
1227 if (m_obj->data == (char *)-1) {
1228 m_obj->data = NULL;
1229 Py_DECREF(m_obj);
1230 PyErr_SetFromErrno(mmap_module_error);
1231 return NULL;
1232 }
1233 m_obj->access = (access_mode)access;
1234 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001235}
1236#endif /* UNIX */
1237
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001238#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001239
1240/* A note on sizes and offsets: while the actual map size must hold in a
1241 Py_ssize_t, both the total file size and the start offset can be longer
1242 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1243*/
1244
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001245static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001246new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001247{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001248 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001249 PyObject *map_size_obj = NULL;
1250 Py_ssize_t map_size;
1251 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001252 DWORD off_hi; /* upper 32 bits of offset */
1253 DWORD off_lo; /* lower 32 bits of offset */
1254 DWORD size_hi; /* upper 32 bits of size */
1255 DWORD size_lo; /* lower 32 bits of size */
1256 char *tagname = "";
1257 DWORD dwErr = 0;
1258 int fileno;
1259 HANDLE fh = 0;
1260 int access = (access_mode)ACCESS_DEFAULT;
1261 DWORD flProtect, dwDesiredAccess;
1262 static char *keywords[] = { "fileno", "length",
1263 "tagname",
1264 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001265
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001266 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001267 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001268 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001269 return NULL;
1270 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001271
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001272 switch((access_mode)access) {
1273 case ACCESS_READ:
1274 flProtect = PAGE_READONLY;
1275 dwDesiredAccess = FILE_MAP_READ;
1276 break;
1277 case ACCESS_DEFAULT: case ACCESS_WRITE:
1278 flProtect = PAGE_READWRITE;
1279 dwDesiredAccess = FILE_MAP_WRITE;
1280 break;
1281 case ACCESS_COPY:
1282 flProtect = PAGE_WRITECOPY;
1283 dwDesiredAccess = FILE_MAP_COPY;
1284 break;
1285 default:
1286 return PyErr_Format(PyExc_ValueError,
1287 "mmap invalid access parameter.");
1288 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001289
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001290 map_size = _GetMapSize(map_size_obj, "size");
1291 if (map_size < 0)
1292 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001293 if (offset < 0) {
1294 PyErr_SetString(PyExc_OverflowError,
1295 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001296 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001297 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001298
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001299 /* assume -1 and 0 both mean invalid filedescriptor
1300 to 'anonymously' map memory.
1301 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1302 XXX: Should this code be added?
1303 if (fileno == 0)
1304 PyErr_WarnEx(PyExc_DeprecationWarning,
1305 "don't use 0 for anonymous memory",
1306 1);
1307 */
1308 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001309 /* Ensure that fileno is within the CRT's valid range */
1310 if (_PyVerify_fd(fileno) == 0) {
1311 PyErr_SetFromErrno(mmap_module_error);
1312 return NULL;
1313 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001314 fh = (HANDLE)_get_osfhandle(fileno);
1315 if (fh==(HANDLE)-1) {
1316 PyErr_SetFromErrno(mmap_module_error);
1317 return NULL;
1318 }
1319 /* Win9x appears to need us seeked to zero */
1320 lseek(fileno, 0, SEEK_SET);
1321 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001322
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001323 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1324 if (m_obj == NULL)
1325 return NULL;
1326 /* Set every field to an invalid marker, so we can safely
1327 destruct the object in the face of failure */
1328 m_obj->data = NULL;
1329 m_obj->file_handle = INVALID_HANDLE_VALUE;
1330 m_obj->map_handle = NULL;
1331 m_obj->tagname = NULL;
1332 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001333
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001334 if (fh) {
1335 /* It is necessary to duplicate the handle, so the
1336 Python code can close it on us */
1337 if (!DuplicateHandle(
1338 GetCurrentProcess(), /* source process handle */
1339 fh, /* handle to be duplicated */
1340 GetCurrentProcess(), /* target proc handle */
1341 (LPHANDLE)&m_obj->file_handle, /* result */
1342 0, /* access - ignored due to options value */
1343 FALSE, /* inherited by child processes? */
1344 DUPLICATE_SAME_ACCESS)) { /* options */
1345 dwErr = GetLastError();
1346 Py_DECREF(m_obj);
1347 PyErr_SetFromWindowsErr(dwErr);
1348 return NULL;
1349 }
1350 if (!map_size) {
1351 DWORD low,high;
1352 low = GetFileSize(fh, &high);
1353 /* low might just happen to have the value INVALID_FILE_SIZE;
1354 so we need to check the last error also. */
1355 if (low == INVALID_FILE_SIZE &&
1356 (dwErr = GetLastError()) != NO_ERROR) {
1357 Py_DECREF(m_obj);
1358 return PyErr_SetFromWindowsErr(dwErr);
1359 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001360
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001361 size = (((PY_LONG_LONG) high) << 32) + low;
1362 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001363 PyErr_SetString(PyExc_ValueError,
1364 "mmap offset is greater than file size");
1365 Py_DECREF(m_obj);
1366 return NULL;
1367 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001368 if (offset - size > PY_SSIZE_T_MAX)
1369 /* Map area too large to fit in memory */
1370 m_obj->size = (Py_ssize_t) -1;
1371 else
1372 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001373 } else {
1374 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001375 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001376 }
1377 }
1378 else {
1379 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001380 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001381 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001382
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001383 /* set the initial position */
1384 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001385
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001386 m_obj->exports = 0;
1387 /* set the tag name */
1388 if (tagname != NULL && *tagname != '\0') {
1389 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1390 if (m_obj->tagname == NULL) {
1391 PyErr_NoMemory();
1392 Py_DECREF(m_obj);
1393 return NULL;
1394 }
1395 strcpy(m_obj->tagname, tagname);
1396 }
1397 else
1398 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001399
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001400 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001401 size_hi = (DWORD)(size >> 32);
1402 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001403 off_hi = (DWORD)(offset >> 32);
1404 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001405 /* For files, it would be sufficient to pass 0 as size.
1406 For anonymous maps, we have to pass the size explicitly. */
1407 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1408 NULL,
1409 flProtect,
1410 size_hi,
1411 size_lo,
1412 m_obj->tagname);
1413 if (m_obj->map_handle != NULL) {
1414 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1415 dwDesiredAccess,
1416 off_hi,
1417 off_lo,
1418 m_obj->size);
1419 if (m_obj->data != NULL)
1420 return (PyObject *)m_obj;
1421 else {
1422 dwErr = GetLastError();
1423 CloseHandle(m_obj->map_handle);
1424 m_obj->map_handle = NULL;
1425 }
1426 } else
1427 dwErr = GetLastError();
1428 Py_DECREF(m_obj);
1429 PyErr_SetFromWindowsErr(dwErr);
1430 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001432#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001433
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001434static void
1435setint(PyObject *d, const char *name, long value)
1436{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001437 PyObject *o = PyLong_FromLong(value);
1438 if (o && PyDict_SetItemString(d, name, o) == 0) {
1439 Py_DECREF(o);
1440 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001441}
1442
Martin v. Löwis1a214512008-06-11 05:26:20 +00001443
1444static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001445 PyModuleDef_HEAD_INIT,
1446 "mmap",
1447 NULL,
1448 -1,
1449 NULL,
1450 NULL,
1451 NULL,
1452 NULL,
1453 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001454};
1455
Mark Hammond62b1ab12002-07-23 06:31:15 +00001456PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001457PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001458{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001459 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001460
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001461 if (PyType_Ready(&mmap_object_type) < 0)
1462 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001463
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001464 module = PyModule_Create(&mmapmodule);
1465 if (module == NULL)
1466 return NULL;
1467 dict = PyModule_GetDict(module);
1468 if (!dict)
1469 return NULL;
1470 mmap_module_error = PyErr_NewException("mmap.error",
1471 PyExc_EnvironmentError , NULL);
1472 if (mmap_module_error == NULL)
1473 return NULL;
1474 PyDict_SetItemString(dict, "error", mmap_module_error);
1475 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001476#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001477 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001478#endif
1479#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001480 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001481#endif
1482#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001483 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001484#endif
1485
1486#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001487 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001488#endif
1489#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001490 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001491#endif
1492#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001493 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001494#endif
1495#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001496 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001497#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001498#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001499 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1500 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001501#endif
1502
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001503 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001504
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001505 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001506
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001507 setint(dict, "ACCESS_READ", ACCESS_READ);
1508 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1509 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1510 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001511}