blob: 88da4a0ac647033a56f0636a2deded0e10539c4c [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 Pitrou7f14f0d2010-05-09 16:14:21 +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 Pitrou7f14f0d2010-05-09 16:14:21 +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 Pitrou7f14f0d2010-05-09 16:14:21 +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 Pitrou7f14f0d2010-05-09 16:14:21 +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 Pitrou7f14f0d2010-05-09 16:14:21 +000092 PyObject_HEAD
93 char * data;
94 size_t size;
95 size_t pos; /* relative to offset */
Antoine Pitrou9e719b62011-02-28 23:48:16 +000096#ifdef MS_WINDOWS
97 PY_LONG_LONG offset;
98#else
99 off_t offset;
100#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +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 Pitrou7f14f0d2010-05-09 16:14:21 +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 Pitrou7f14f0d2010-05-09 16:14:21 +0000110 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000112
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +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 Pitrou7f14f0d2010-05-09 16:14:21 +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 Pitrou7f14f0d2010-05-09 16:14:21 +0000132 if (m_obj->fd >= 0)
133 (void) close(m_obj->fd);
134 if (m_obj->data!=NULL) {
R. David Murray07c1bd72010-12-11 02:05:32 +0000135 if (m_obj->access != ACCESS_READ && m_obj->access != ACCESS_COPY)
136 msync(m_obj->data, m_obj->size, MS_SYNC);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000137 munmap(m_obj->data, m_obj->size);
138 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000139#endif /* UNIX */
140
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000141 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142}
143
144static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000145mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000146{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000147 if (self->exports > 0) {
148 PyErr_SetString(PyExc_BufferError, "cannot close "\
149 "exported pointers exist");
150 return NULL;
151 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000152#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000153 /* For each resource we maintain, we need to check
154 the value is valid, and if so, free the resource
155 and set the member value to an invalid value so
156 the dealloc does not attempt to resource clearing
157 again.
158 TODO - should we check for errors in the close operations???
159 */
160 if (self->data != NULL) {
161 UnmapViewOfFile(self->data);
162 self->data = NULL;
163 }
164 if (self->map_handle != NULL) {
165 CloseHandle(self->map_handle);
166 self->map_handle = NULL;
167 }
168 if (self->file_handle != INVALID_HANDLE_VALUE) {
169 CloseHandle(self->file_handle);
170 self->file_handle = INVALID_HANDLE_VALUE;
171 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000172#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000173
174#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000175 if (0 <= self->fd)
176 (void) close(self->fd);
177 self->fd = -1;
178 if (self->data != NULL) {
179 munmap(self->data, self->size);
180 self->data = NULL;
181 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000182#endif
183
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000184 Py_INCREF(Py_None);
185 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000186}
187
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000188#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000189#define CHECK_VALID(err) \
190do { \
191 if (self->map_handle == NULL) { \
192 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
193 return err; \
194 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000195} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000196#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000197
198#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000199#define CHECK_VALID(err) \
200do { \
201 if (self->data == NULL) { \
202 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
203 return err; \
204 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000205} while (0)
206#endif /* UNIX */
207
208static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000209mmap_read_byte_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000210 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000211{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000212 CHECK_VALID(NULL);
213 if (self->pos < self->size) {
214 char value = self->data[self->pos];
215 self->pos += 1;
Hirokazu Yamamoto09ea7922010-11-04 12:35:21 +0000216 return Py_BuildValue("B", (unsigned char)value);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000217 } else {
218 PyErr_SetString(PyExc_ValueError, "read byte out of range");
219 return NULL;
220 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000221}
222
223static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000224mmap_read_line_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000225 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000226{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000227 char *start = self->data+self->pos;
228 char *eof = self->data+self->size;
229 char *eol;
230 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000231
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000232 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000233
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000234 eol = memchr(start, '\n', self->size - self->pos);
235 if (!eol)
236 eol = eof;
237 else
238 ++eol; /* we're interested in the position after the
239 newline. */
240 result = PyBytes_FromStringAndSize(start, (eol - start));
241 self->pos += (eol - start);
242 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000243}
244
245static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000246mmap_read_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000247 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000248{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000249 Py_ssize_t num_bytes, n;
250 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000251
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000252 CHECK_VALID(NULL);
253 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
254 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000255
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000256 /* silently 'adjust' out-of-range requests */
257 assert(self->size >= self->pos);
258 n = self->size - self->pos;
259 /* The difference can overflow, only if self->size is greater than
260 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
261 * because the mapped area and the returned string each need more
262 * than half of the addressable memory. So we clip the size, and let
263 * the code below raise MemoryError.
264 */
265 if (n < 0)
266 n = PY_SSIZE_T_MAX;
267 if (num_bytes < 0 || num_bytes > n) {
268 num_bytes = n;
269 }
270 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
271 self->pos += num_bytes;
272 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000273}
274
275static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000276mmap_gfind(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000277 PyObject *args,
278 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000279{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000280 Py_ssize_t start = self->pos;
281 Py_ssize_t end = self->size;
282 const char *needle;
283 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000284
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000285 CHECK_VALID(NULL);
286 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
287 &needle, &len, &start, &end)) {
288 return NULL;
289 } else {
290 const char *p, *start_p, *end_p;
291 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000292
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000293 if (start < 0)
294 start += self->size;
295 if (start < 0)
296 start = 0;
297 else if ((size_t)start > self->size)
298 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000299
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000300 if (end < 0)
301 end += self->size;
302 if (end < 0)
303 end = 0;
304 else if ((size_t)end > self->size)
305 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000306
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000307 start_p = self->data + start;
308 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000309
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000310 for (p = (reverse ? end_p - len : start_p);
311 (p >= start_p) && (p + len <= end_p); p += sign) {
312 Py_ssize_t i;
313 for (i = 0; i < len && needle[i] == p[i]; ++i)
314 /* nothing */;
315 if (i == len) {
316 return PyLong_FromSsize_t(p - self->data);
317 }
318 }
319 return PyLong_FromLong(-1);
320 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000321}
322
Georg Brandlfceab5a2008-01-19 20:08:23 +0000323static PyObject *
324mmap_find_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000325 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000326{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000327 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000328}
329
330static PyObject *
331mmap_rfind_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000332 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000333{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000334 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000335}
336
Tim Petersec0a5f02006-02-16 23:47:20 +0000337static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000338is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000339{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000340 if (self->access != ACCESS_READ)
341 return 1;
342 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
343 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000344}
345
Tim Petersec0a5f02006-02-16 23:47:20 +0000346static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000347is_resizeable(mmap_object *self)
348{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000349 if (self->exports > 0) {
350 PyErr_SetString(PyExc_BufferError,
351 "mmap can't resize with extant buffers exported.");
352 return 0;
353 }
354 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
355 return 1;
356 PyErr_Format(PyExc_TypeError,
357 "mmap can't resize a readonly or copy-on-write memory map.");
358 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000359}
360
361
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000362static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000363mmap_write_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000364 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000365{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000366 Py_ssize_t length;
367 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000368
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000369 CHECK_VALID(NULL);
370 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
371 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000372
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000373 if (!is_writable(self))
374 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000375
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000376 if ((self->pos + length) > self->size) {
377 PyErr_SetString(PyExc_ValueError, "data out of range");
378 return NULL;
379 }
380 memcpy(self->data+self->pos, data, length);
381 self->pos = self->pos+length;
382 Py_INCREF(Py_None);
383 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000384}
385
386static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000387mmap_write_byte_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000388 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000389{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000390 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000391
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000392 CHECK_VALID(NULL);
393 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
394 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000395
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000396 if (!is_writable(self))
397 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000398
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000399 if (self->pos < self->size) {
400 *(self->data+self->pos) = value;
401 self->pos += 1;
402 Py_INCREF(Py_None);
403 return Py_None;
404 }
405 else {
406 PyErr_SetString(PyExc_ValueError, "write byte out of range");
407 return NULL;
408 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000409}
Tim Petersec0a5f02006-02-16 23:47:20 +0000410
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000411static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000412mmap_size_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000413 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000414{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000415 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000416
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000417#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000418 if (self->file_handle != INVALID_HANDLE_VALUE) {
419 DWORD low,high;
420 PY_LONG_LONG size;
421 low = GetFileSize(self->file_handle, &high);
422 if (low == INVALID_FILE_SIZE) {
423 /* It might be that the function appears to have failed,
424 when indeed its size equals INVALID_FILE_SIZE */
425 DWORD error = GetLastError();
426 if (error != NO_ERROR)
427 return PyErr_SetFromWindowsErr(error);
428 }
429 if (!high && low < LONG_MAX)
430 return PyLong_FromLong((long)low);
431 size = (((PY_LONG_LONG)high)<<32) + low;
432 return PyLong_FromLongLong(size);
433 } else {
434 return PyLong_FromSsize_t(self->size);
435 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000436#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000437
438#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000439 {
440 struct stat buf;
441 if (-1 == fstat(self->fd, &buf)) {
442 PyErr_SetFromErrno(mmap_module_error);
443 return NULL;
444 }
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000445#ifdef HAVE_LARGEFILE_SUPPORT
446 return PyLong_FromLongLong(buf.st_size);
447#else
448 return PyLong_FromLong(buf.st_size);
449#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000450 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000451#endif /* UNIX */
452}
453
454/* This assumes that you want the entire file mapped,
455 / and when recreating the map will make the new file
456 / have the new size
457 /
458 / Is this really necessary? This could easily be done
459 / from python by just closing and re-opening with the
460 / new size?
461 */
462
463static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000464mmap_resize_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000465 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000466{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000467 Py_ssize_t new_size;
468 CHECK_VALID(NULL);
469 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
470 !is_resizeable(self)) {
471 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000472#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000473 } else {
474 DWORD dwErrCode = 0;
475 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
476 /* First, unmap the file view */
477 UnmapViewOfFile(self->data);
478 self->data = NULL;
479 /* Close the mapping object */
480 CloseHandle(self->map_handle);
481 self->map_handle = NULL;
482 /* Move to the desired EOF position */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000483 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
484 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
485 off_hi = (DWORD)(self->offset >> 32);
486 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000487 SetFilePointer(self->file_handle,
488 newSizeLow, &newSizeHigh, FILE_BEGIN);
489 /* Change the size of the file */
490 SetEndOfFile(self->file_handle);
491 /* Create another mapping object and remap the file view */
492 self->map_handle = CreateFileMapping(
493 self->file_handle,
494 NULL,
495 PAGE_READWRITE,
496 0,
497 0,
498 self->tagname);
499 if (self->map_handle != NULL) {
500 self->data = (char *) MapViewOfFile(self->map_handle,
501 FILE_MAP_WRITE,
502 off_hi,
503 off_lo,
504 new_size);
505 if (self->data != NULL) {
506 self->size = new_size;
507 Py_INCREF(Py_None);
508 return Py_None;
509 } else {
510 dwErrCode = GetLastError();
511 CloseHandle(self->map_handle);
512 self->map_handle = NULL;
513 }
514 } else {
515 dwErrCode = GetLastError();
516 }
517 PyErr_SetFromWindowsErr(dwErrCode);
518 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000519#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000520
521#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000522#ifndef HAVE_MREMAP
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000523 } else {
524 PyErr_SetString(PyExc_SystemError,
525 "mmap: resizing not available--no mremap()");
526 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000527#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000528 } else {
529 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000530
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000531 if (ftruncate(self->fd, self->offset + new_size) == -1) {
532 PyErr_SetFromErrno(mmap_module_error);
533 return NULL;
534 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000535
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000536#ifdef MREMAP_MAYMOVE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000537 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000538#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000539 #if defined(__NetBSD__)
540 newmap = mremap(self->data, self->size, self->data, new_size, 0);
541 #else
542 newmap = mremap(self->data, self->size, new_size, 0);
543 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000544#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000545 if (newmap == (void *)-1)
546 {
547 PyErr_SetFromErrno(mmap_module_error);
548 return NULL;
549 }
550 self->data = newmap;
551 self->size = new_size;
552 Py_INCREF(Py_None);
553 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000554#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000555#endif /* UNIX */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000556 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557}
558
559static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000560mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000561{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000562 CHECK_VALID(NULL);
563 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000564}
565
566static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000567mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000568{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000569 Py_ssize_t offset = 0;
570 Py_ssize_t size = self->size;
571 CHECK_VALID(NULL);
572 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
573 return NULL;
574 if ((size_t)(offset + size) > self->size) {
575 PyErr_SetString(PyExc_ValueError, "flush values out of range");
576 return NULL;
577 }
R. David Murray07c1bd72010-12-11 02:05:32 +0000578
579 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
580 return PyLong_FromLong(0);
581
Christian Heimesaf98da12008-01-27 15:18:18 +0000582#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000583 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000584#elif defined(UNIX)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000585 /* XXX semantics of return value? */
586 /* XXX flags for msync? */
587 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
588 PyErr_SetFromErrno(mmap_module_error);
589 return NULL;
590 }
591 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000592#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000593 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
594 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000595#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000596}
597
598static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000599mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000600{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000601 Py_ssize_t dist;
602 int how=0;
603 CHECK_VALID(NULL);
604 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
605 return NULL;
606 else {
607 size_t where;
608 switch (how) {
609 case 0: /* relative to start */
610 if (dist < 0)
611 goto onoutofrange;
612 where = dist;
613 break;
614 case 1: /* relative to current position */
615 if ((Py_ssize_t)self->pos + dist < 0)
616 goto onoutofrange;
617 where = self->pos + dist;
618 break;
619 case 2: /* relative to end */
620 if ((Py_ssize_t)self->size + dist < 0)
621 goto onoutofrange;
622 where = self->size + dist;
623 break;
624 default:
625 PyErr_SetString(PyExc_ValueError, "unknown seek type");
626 return NULL;
627 }
628 if (where > self->size)
629 goto onoutofrange;
630 self->pos = where;
631 Py_INCREF(Py_None);
632 return Py_None;
633 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000634
Tim Peters5ebfd362001-11-13 23:11:19 +0000635 onoutofrange:
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000636 PyErr_SetString(PyExc_ValueError, "seek out of range");
637 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000638}
639
640static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000641mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000642{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000643 unsigned long dest, src, cnt;
644 CHECK_VALID(NULL);
645 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
646 !is_writable(self)) {
647 return NULL;
648 } else {
649 /* bounds check the values */
650 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
651 src < 0 || src > self->size || (src + cnt) > self->size ||
652 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
653 PyErr_SetString(PyExc_ValueError,
654 "source, destination, or count out of range");
655 return NULL;
656 }
657 memmove(self->data+dest, self->data+src, cnt);
658 Py_INCREF(Py_None);
659 return Py_None;
660 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000661}
662
663static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000664 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
665 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
666 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
667 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
668 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
669 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
670 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
671 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
672 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
673 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
674 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
675 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
676 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
677 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
678 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679};
680
681/* Functions for treating an mmap'ed file as a buffer */
682
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000683static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000684mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000685{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000686 CHECK_VALID(-1);
687 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
688 (self->access == ACCESS_READ), flags) < 0)
689 return -1;
690 self->exports++;
691 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000692}
693
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000694static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000695mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000696{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000697 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000698}
699
Martin v. Löwis18e16552006-02-15 17:27:45 +0000700static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000701mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000702{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000703 CHECK_VALID(-1);
704 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000705}
706
707static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000708mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000709{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000710 CHECK_VALID(NULL);
711 if (i < 0 || (size_t)i >= self->size) {
712 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
713 return NULL;
714 }
715 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000716}
717
718static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000719mmap_subscript(mmap_object *self, PyObject *item)
720{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000721 CHECK_VALID(NULL);
722 if (PyIndex_Check(item)) {
723 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
724 if (i == -1 && PyErr_Occurred())
725 return NULL;
726 if (i < 0)
727 i += self->size;
728 if (i < 0 || (size_t)i >= self->size) {
729 PyErr_SetString(PyExc_IndexError,
730 "mmap index out of range");
731 return NULL;
732 }
733 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
734 }
735 else if (PySlice_Check(item)) {
736 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000737
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000738 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
739 &start, &stop, &step, &slicelen) < 0) {
740 return NULL;
741 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000742
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000743 if (slicelen <= 0)
744 return PyBytes_FromStringAndSize("", 0);
745 else if (step == 1)
746 return PyBytes_FromStringAndSize(self->data + start,
747 slicelen);
748 else {
749 char *result_buf = (char *)PyMem_Malloc(slicelen);
750 Py_ssize_t cur, i;
751 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000752
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000753 if (result_buf == NULL)
754 return PyErr_NoMemory();
755 for (cur = start, i = 0; i < slicelen;
756 cur += step, i++) {
757 result_buf[i] = self->data[cur];
758 }
759 result = PyBytes_FromStringAndSize(result_buf,
760 slicelen);
761 PyMem_Free(result_buf);
762 return result;
763 }
764 }
765 else {
766 PyErr_SetString(PyExc_TypeError,
767 "mmap indices must be integers");
768 return NULL;
769 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000770}
771
772static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000773mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000774{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000775 CHECK_VALID(NULL);
776 PyErr_SetString(PyExc_SystemError,
777 "mmaps don't support concatenation");
778 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000779}
780
781static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000782mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000783{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000784 CHECK_VALID(NULL);
785 PyErr_SetString(PyExc_SystemError,
786 "mmaps don't support repeat operation");
787 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000788}
789
790static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000791mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000792{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000793 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000794
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000795 CHECK_VALID(-1);
796 if (i < 0 || (size_t)i >= self->size) {
797 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
798 return -1;
799 }
800 if (v == NULL) {
801 PyErr_SetString(PyExc_TypeError,
802 "mmap object doesn't support item deletion");
803 return -1;
804 }
805 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
806 PyErr_SetString(PyExc_IndexError,
807 "mmap assignment must be length-1 bytes()");
808 return -1;
809 }
810 if (!is_writable(self))
811 return -1;
812 buf = PyBytes_AsString(v);
813 self->data[i] = buf[0];
814 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000815}
816
Thomas Woutersed03b412007-08-28 21:37:11 +0000817static int
818mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
819{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000820 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000821
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000822 if (!is_writable(self))
823 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000824
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000825 if (PyIndex_Check(item)) {
826 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
827 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000828
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000829 if (i == -1 && PyErr_Occurred())
830 return -1;
831 if (i < 0)
832 i += self->size;
833 if (i < 0 || (size_t)i >= self->size) {
834 PyErr_SetString(PyExc_IndexError,
835 "mmap index out of range");
836 return -1;
837 }
838 if (value == NULL) {
839 PyErr_SetString(PyExc_TypeError,
840 "mmap doesn't support item deletion");
841 return -1;
842 }
843 if (!PyIndex_Check(value)) {
844 PyErr_SetString(PyExc_TypeError,
845 "mmap item value must be an int");
846 return -1;
847 }
848 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
849 if (v == -1 && PyErr_Occurred())
850 return -1;
851 if (v < 0 || v > 255) {
852 PyErr_SetString(PyExc_ValueError,
853 "mmap item value must be "
854 "in range(0, 256)");
855 return -1;
856 }
Antoine Pitrou835b4452010-08-15 18:32:16 +0000857 self->data[i] = (char) v;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000858 return 0;
859 }
860 else if (PySlice_Check(item)) {
861 Py_ssize_t start, stop, step, slicelen;
862 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000863
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000864 if (PySlice_GetIndicesEx((PySliceObject *)item,
865 self->size, &start, &stop,
866 &step, &slicelen) < 0) {
867 return -1;
868 }
869 if (value == NULL) {
870 PyErr_SetString(PyExc_TypeError,
871 "mmap object doesn't support slice deletion");
872 return -1;
873 }
874 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
875 return -1;
876 if (vbuf.len != slicelen) {
877 PyErr_SetString(PyExc_IndexError,
878 "mmap slice assignment is wrong size");
879 PyBuffer_Release(&vbuf);
880 return -1;
881 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000882
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000883 if (slicelen == 0) {
884 }
885 else if (step == 1) {
886 memcpy(self->data + start, vbuf.buf, slicelen);
887 }
888 else {
889 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000890
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000891 for (cur = start, i = 0;
892 i < slicelen;
893 cur += step, i++)
894 {
895 self->data[cur] = ((char *)vbuf.buf)[i];
896 }
897 }
898 PyBuffer_Release(&vbuf);
899 return 0;
900 }
901 else {
902 PyErr_SetString(PyExc_TypeError,
903 "mmap indices must be integer");
904 return -1;
905 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000906}
907
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000908static PySequenceMethods mmap_as_sequence = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000909 (lenfunc)mmap_length, /*sq_length*/
910 (binaryfunc)mmap_concat, /*sq_concat*/
911 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
912 (ssizeargfunc)mmap_item, /*sq_item*/
913 0, /*sq_slice*/
914 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
915 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000916};
917
Thomas Woutersed03b412007-08-28 21:37:11 +0000918static PyMappingMethods mmap_as_mapping = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000919 (lenfunc)mmap_length,
920 (binaryfunc)mmap_subscript,
921 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000922};
923
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000924static PyBufferProcs mmap_as_buffer = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000925 (getbufferproc)mmap_buffer_getbuf,
926 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000927};
928
Georg Brandl86def6c2008-01-21 20:36:10 +0000929static PyObject *
930new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
931
Christian Heimese1c98112008-01-21 11:20:28 +0000932PyDoc_STRVAR(mmap_doc,
933"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
934\n\
935Maps length bytes from the file specified by the file handle fileno,\n\
936and returns a mmap object. If length is larger than the current size\n\
937of the file, the file is extended to contain length bytes. If length\n\
938is 0, the maximum length of the map is the current size of the file,\n\
939except that if the file is empty Windows raises an exception (you cannot\n\
940create an empty mapping on Windows).\n\
941\n\
942Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
943\n\
944Maps length bytes from the file specified by the file descriptor fileno,\n\
945and returns a mmap object. If length is 0, the maximum length of the map\n\
946will be the current size of the file when mmap is called.\n\
947flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
948private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000949object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000950that's shared with all other processes mapping the same areas of the file.\n\
951The default value is MAP_SHARED.\n\
952\n\
953To map anonymous memory, pass -1 as the fileno (both versions).");
954
955
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000956static PyTypeObject mmap_object_type = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000957 PyVarObject_HEAD_INIT(NULL, 0)
958 "mmap.mmap", /* tp_name */
959 sizeof(mmap_object), /* tp_size */
960 0, /* tp_itemsize */
961 /* methods */
962 (destructor) mmap_object_dealloc, /* tp_dealloc */
963 0, /* tp_print */
964 0, /* tp_getattr */
965 0, /* tp_setattr */
966 0, /* tp_reserved */
967 0, /* tp_repr */
968 0, /* tp_as_number */
969 &mmap_as_sequence, /*tp_as_sequence*/
970 &mmap_as_mapping, /*tp_as_mapping*/
971 0, /*tp_hash*/
972 0, /*tp_call*/
973 0, /*tp_str*/
974 PyObject_GenericGetAttr, /*tp_getattro*/
975 0, /*tp_setattro*/
976 &mmap_as_buffer, /*tp_as_buffer*/
977 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
978 mmap_doc, /*tp_doc*/
979 0, /* tp_traverse */
980 0, /* tp_clear */
981 0, /* tp_richcompare */
982 0, /* tp_weaklistoffset */
983 0, /* tp_iter */
984 0, /* tp_iternext */
985 mmap_object_methods, /* tp_methods */
986 0, /* tp_members */
987 0, /* tp_getset */
988 0, /* tp_base */
989 0, /* tp_dict */
990 0, /* tp_descr_get */
991 0, /* tp_descr_set */
992 0, /* tp_dictoffset */
993 0, /* tp_init */
994 PyType_GenericAlloc, /* tp_alloc */
995 new_mmap_object, /* tp_new */
996 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000997};
998
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000999
1000/* extract the map size from the given PyObject
1001
Thomas Wouters7e474022000-07-16 12:04:32 +00001002 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001003 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001004static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001005_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001006{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001007 if (o == NULL)
1008 return 0;
1009 if (PyIndex_Check(o)) {
1010 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1011 if (i==-1 && PyErr_Occurred())
1012 return -1;
1013 if (i < 0) {
1014 PyErr_Format(PyExc_OverflowError,
1015 "memory mapped %s must be positive",
1016 param);
1017 return -1;
1018 }
1019 return i;
1020 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001021
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001022 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1023 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001024}
1025
Tim Petersec0a5f02006-02-16 23:47:20 +00001026#ifdef UNIX
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001027#ifdef HAVE_LARGEFILE_SUPPORT
1028#define _Py_PARSE_OFF_T "L"
1029#else
1030#define _Py_PARSE_OFF_T "l"
1031#endif
1032
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001033static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001034new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001035{
Neal Norwitzb5673922002-09-05 21:48:07 +00001036#ifdef HAVE_FSTAT
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001037 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001038#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001039 mmap_object *m_obj;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001040 PyObject *map_size_obj = NULL;
1041 Py_ssize_t map_size;
1042 off_t offset = 0;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001043 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1044 int devzero = -1;
1045 int access = (int)ACCESS_DEFAULT;
1046 static char *keywords[] = {"fileno", "length",
1047 "flags", "prot",
1048 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001049
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001050 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001051 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001052 &access, &offset))
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001053 return NULL;
1054 map_size = _GetMapSize(map_size_obj, "size");
1055 if (map_size < 0)
1056 return NULL;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001057 if (offset < 0) {
1058 PyErr_SetString(PyExc_OverflowError,
1059 "memory mapped offset must be positive");
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001060 return NULL;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001061 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001062
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001063 if ((access != (int)ACCESS_DEFAULT) &&
1064 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1065 return PyErr_Format(PyExc_ValueError,
1066 "mmap can't specify both access and flags, prot.");
1067 switch ((access_mode)access) {
1068 case ACCESS_READ:
1069 flags = MAP_SHARED;
1070 prot = PROT_READ;
1071 break;
1072 case ACCESS_WRITE:
1073 flags = MAP_SHARED;
1074 prot = PROT_READ | PROT_WRITE;
1075 break;
1076 case ACCESS_COPY:
1077 flags = MAP_PRIVATE;
1078 prot = PROT_READ | PROT_WRITE;
1079 break;
1080 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001081 /* map prot to access type */
1082 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1083 /* ACCESS_DEFAULT */
1084 }
1085 else if (prot & PROT_WRITE) {
1086 access = ACCESS_WRITE;
1087 }
1088 else {
1089 access = ACCESS_READ;
1090 }
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001091 break;
1092 default:
1093 return PyErr_Format(PyExc_ValueError,
1094 "mmap invalid access parameter.");
1095 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001096
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001097#ifdef __APPLE__
1098 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1099 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1100 if (fd != -1)
1101 (void)fcntl(fd, F_FULLFSYNC);
1102#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001103#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001104# ifdef __VMS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001105 /* on OpenVMS we must ensure that all bytes are written to the file */
1106 if (fd != -1) {
1107 fsync(fd);
1108 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001109# endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001110 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1111 if (map_size == 0) {
Antoine Pitrou6107a4e2011-01-20 21:11:13 +00001112 if (offset >= st.st_size) {
1113 PyErr_SetString(PyExc_ValueError,
1114 "mmap offset is greater than file size");
1115 return NULL;
1116 }
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001117 off_t calc_size = st.st_size - offset;
1118 map_size = calc_size;
1119 if (map_size != calc_size) {
1120 PyErr_SetString(PyExc_ValueError,
1121 "mmap length is too large");
1122 return NULL;
1123 }
1124 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001125 PyErr_SetString(PyExc_ValueError,
1126 "mmap length is greater than file size");
1127 return NULL;
1128 }
1129 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001130#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001131 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1132 if (m_obj == NULL) {return NULL;}
1133 m_obj->data = NULL;
1134 m_obj->size = (size_t) map_size;
1135 m_obj->pos = (size_t) 0;
1136 m_obj->exports = 0;
1137 m_obj->offset = offset;
1138 if (fd == -1) {
1139 m_obj->fd = -1;
1140 /* Assume the caller wants to map anonymous memory.
1141 This is the same behaviour as Windows. mmap.mmap(-1, size)
1142 on both Windows and Unix map anonymous memory.
1143 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001144#ifdef MAP_ANONYMOUS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001145 /* BSD way to map anonymous memory */
1146 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001147#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001148 /* SVR4 method to map anonymous memory is to open /dev/zero */
1149 fd = devzero = open("/dev/zero", O_RDWR);
1150 if (devzero == -1) {
1151 Py_DECREF(m_obj);
1152 PyErr_SetFromErrno(mmap_module_error);
1153 return NULL;
1154 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001155#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001156 } else {
1157 m_obj->fd = dup(fd);
1158 if (m_obj->fd == -1) {
1159 Py_DECREF(m_obj);
1160 PyErr_SetFromErrno(mmap_module_error);
1161 return NULL;
1162 }
1163 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001164
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001165 m_obj->data = mmap(NULL, map_size,
1166 prot, flags,
1167 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001168
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001169 if (devzero != -1) {
1170 close(devzero);
1171 }
1172
1173 if (m_obj->data == (char *)-1) {
1174 m_obj->data = NULL;
1175 Py_DECREF(m_obj);
1176 PyErr_SetFromErrno(mmap_module_error);
1177 return NULL;
1178 }
1179 m_obj->access = (access_mode)access;
1180 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001181}
1182#endif /* UNIX */
1183
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001184#ifdef MS_WINDOWS
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001185
1186/* A note on sizes and offsets: while the actual map size must hold in a
1187 Py_ssize_t, both the total file size and the start offset can be longer
1188 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1189*/
1190
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001191static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001192new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001193{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001194 mmap_object *m_obj;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001195 PyObject *map_size_obj = NULL;
1196 Py_ssize_t map_size;
1197 PY_LONG_LONG offset = 0, size;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001198 DWORD off_hi; /* upper 32 bits of offset */
1199 DWORD off_lo; /* lower 32 bits of offset */
1200 DWORD size_hi; /* upper 32 bits of size */
1201 DWORD size_lo; /* lower 32 bits of size */
1202 char *tagname = "";
1203 DWORD dwErr = 0;
1204 int fileno;
1205 HANDLE fh = 0;
1206 int access = (access_mode)ACCESS_DEFAULT;
1207 DWORD flProtect, dwDesiredAccess;
1208 static char *keywords[] = { "fileno", "length",
1209 "tagname",
1210 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001211
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001212 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001213 &fileno, &map_size_obj,
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001214 &tagname, &access, &offset)) {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001215 return NULL;
1216 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001217
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001218 switch((access_mode)access) {
1219 case ACCESS_READ:
1220 flProtect = PAGE_READONLY;
1221 dwDesiredAccess = FILE_MAP_READ;
1222 break;
1223 case ACCESS_DEFAULT: case ACCESS_WRITE:
1224 flProtect = PAGE_READWRITE;
1225 dwDesiredAccess = FILE_MAP_WRITE;
1226 break;
1227 case ACCESS_COPY:
1228 flProtect = PAGE_WRITECOPY;
1229 dwDesiredAccess = FILE_MAP_COPY;
1230 break;
1231 default:
1232 return PyErr_Format(PyExc_ValueError,
1233 "mmap invalid access parameter.");
1234 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001235
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001236 map_size = _GetMapSize(map_size_obj, "size");
1237 if (map_size < 0)
1238 return NULL;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001239 if (offset < 0) {
1240 PyErr_SetString(PyExc_OverflowError,
1241 "memory mapped offset must be positive");
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001242 return NULL;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001243 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001244
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001245 /* assume -1 and 0 both mean invalid filedescriptor
1246 to 'anonymously' map memory.
1247 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1248 XXX: Should this code be added?
1249 if (fileno == 0)
1250 PyErr_WarnEx(PyExc_DeprecationWarning,
1251 "don't use 0 for anonymous memory",
1252 1);
1253 */
1254 if (fileno != -1 && fileno != 0) {
Brian Curtin686ee4f2010-08-01 15:44:11 +00001255 /* Ensure that fileno is within the CRT's valid range */
1256 if (_PyVerify_fd(fileno) == 0) {
1257 PyErr_SetFromErrno(mmap_module_error);
1258 return NULL;
1259 }
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001260 fh = (HANDLE)_get_osfhandle(fileno);
1261 if (fh==(HANDLE)-1) {
1262 PyErr_SetFromErrno(mmap_module_error);
1263 return NULL;
1264 }
1265 /* Win9x appears to need us seeked to zero */
1266 lseek(fileno, 0, SEEK_SET);
1267 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001268
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001269 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1270 if (m_obj == NULL)
1271 return NULL;
1272 /* Set every field to an invalid marker, so we can safely
1273 destruct the object in the face of failure */
1274 m_obj->data = NULL;
1275 m_obj->file_handle = INVALID_HANDLE_VALUE;
1276 m_obj->map_handle = NULL;
1277 m_obj->tagname = NULL;
1278 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001279
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001280 if (fh) {
1281 /* It is necessary to duplicate the handle, so the
1282 Python code can close it on us */
1283 if (!DuplicateHandle(
1284 GetCurrentProcess(), /* source process handle */
1285 fh, /* handle to be duplicated */
1286 GetCurrentProcess(), /* target proc handle */
1287 (LPHANDLE)&m_obj->file_handle, /* result */
1288 0, /* access - ignored due to options value */
1289 FALSE, /* inherited by child processes? */
1290 DUPLICATE_SAME_ACCESS)) { /* options */
1291 dwErr = GetLastError();
1292 Py_DECREF(m_obj);
1293 PyErr_SetFromWindowsErr(dwErr);
1294 return NULL;
1295 }
1296 if (!map_size) {
1297 DWORD low,high;
1298 low = GetFileSize(fh, &high);
1299 /* low might just happen to have the value INVALID_FILE_SIZE;
1300 so we need to check the last error also. */
1301 if (low == INVALID_FILE_SIZE &&
1302 (dwErr = GetLastError()) != NO_ERROR) {
1303 Py_DECREF(m_obj);
1304 return PyErr_SetFromWindowsErr(dwErr);
1305 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001306
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001307 size = (((PY_LONG_LONG) high) << 32) + low;
1308 if (offset >= size) {
Antoine Pitrou6107a4e2011-01-20 21:11:13 +00001309 PyErr_SetString(PyExc_ValueError,
1310 "mmap offset is greater than file size");
1311 Py_DECREF(m_obj);
1312 return NULL;
1313 }
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001314 if (offset - size > PY_SSIZE_T_MAX)
1315 /* Map area too large to fit in memory */
1316 m_obj->size = (Py_ssize_t) -1;
1317 else
1318 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001319 } else {
1320 m_obj->size = map_size;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001321 size = offset + map_size;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001322 }
1323 }
1324 else {
1325 m_obj->size = map_size;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001326 size = offset + map_size;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001327 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001328
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001329 /* set the initial position */
1330 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001331
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001332 m_obj->exports = 0;
1333 /* set the tag name */
1334 if (tagname != NULL && *tagname != '\0') {
1335 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1336 if (m_obj->tagname == NULL) {
1337 PyErr_NoMemory();
1338 Py_DECREF(m_obj);
1339 return NULL;
1340 }
1341 strcpy(m_obj->tagname, tagname);
1342 }
1343 else
1344 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001345
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001346 m_obj->access = (access_mode)access;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001347 size_hi = (DWORD)(size >> 32);
1348 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001349 off_hi = (DWORD)(offset >> 32);
1350 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001351 /* For files, it would be sufficient to pass 0 as size.
1352 For anonymous maps, we have to pass the size explicitly. */
1353 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1354 NULL,
1355 flProtect,
1356 size_hi,
1357 size_lo,
1358 m_obj->tagname);
1359 if (m_obj->map_handle != NULL) {
1360 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1361 dwDesiredAccess,
1362 off_hi,
1363 off_lo,
1364 m_obj->size);
1365 if (m_obj->data != NULL)
1366 return (PyObject *)m_obj;
1367 else {
1368 dwErr = GetLastError();
1369 CloseHandle(m_obj->map_handle);
1370 m_obj->map_handle = NULL;
1371 }
1372 } else
1373 dwErr = GetLastError();
1374 Py_DECREF(m_obj);
1375 PyErr_SetFromWindowsErr(dwErr);
1376 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001377}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001378#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001379
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001380static void
1381setint(PyObject *d, const char *name, long value)
1382{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001383 PyObject *o = PyLong_FromLong(value);
1384 if (o && PyDict_SetItemString(d, name, o) == 0) {
1385 Py_DECREF(o);
1386 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001387}
1388
Martin v. Löwis1a214512008-06-11 05:26:20 +00001389
1390static struct PyModuleDef mmapmodule = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001391 PyModuleDef_HEAD_INIT,
1392 "mmap",
1393 NULL,
1394 -1,
1395 NULL,
1396 NULL,
1397 NULL,
1398 NULL,
1399 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001400};
1401
Mark Hammond62b1ab12002-07-23 06:31:15 +00001402PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001403PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001404{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001405 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001406
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001407 if (PyType_Ready(&mmap_object_type) < 0)
1408 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001409
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001410 module = PyModule_Create(&mmapmodule);
1411 if (module == NULL)
1412 return NULL;
1413 dict = PyModule_GetDict(module);
1414 if (!dict)
1415 return NULL;
1416 mmap_module_error = PyErr_NewException("mmap.error",
1417 PyExc_EnvironmentError , NULL);
1418 if (mmap_module_error == NULL)
1419 return NULL;
1420 PyDict_SetItemString(dict, "error", mmap_module_error);
1421 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001422#ifdef PROT_EXEC
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001423 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001424#endif
1425#ifdef PROT_READ
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001426 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001427#endif
1428#ifdef PROT_WRITE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001429 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001430#endif
1431
1432#ifdef MAP_SHARED
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001433 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001434#endif
1435#ifdef MAP_PRIVATE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001436 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001437#endif
1438#ifdef MAP_DENYWRITE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001439 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001440#endif
1441#ifdef MAP_EXECUTABLE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001442 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001443#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001444#ifdef MAP_ANONYMOUS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001445 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1446 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001447#endif
1448
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001449 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001450
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001451 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001452
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001453 setint(dict, "ACCESS_READ", ACCESS_READ);
1454 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1455 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1456 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001457}