blob: 3413f17ebd3cdb766e10532197e7bee1bd5f55c5 [file] [log] [blame]
Guido van Rossum09fdf072000-03-31 01:17:07 +00001/*
2 / Author: Sam Rushing <rushing@nightmare.com>
Andrew M. Kuchling10f9c072001-11-05 21:25:42 +00003 / Hacked for Unix by AMK
Guido van Rossum09fdf072000-03-31 01:17:07 +00004 / $Id$
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00005
Guido van Rossum8ce8a782007-11-01 19:42:39 +00006 / Modified to support mmap with offset - to map a 'window' of a file
7 / Author: Yotam Medini yotamm@mellanox.co.il
8 /
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00009 / mmapmodule.cpp -- map a view of a file into memory
10 /
11 / todo: need permission flags, perhaps a 'chsize' analog
12 / not all functions check range yet!!!
13 /
14 /
Mark Hammond071864a2000-07-30 02:46:26 +000015 / This version of mmapmodule.c has been changed significantly
16 / from the original mmapfile.c on which it was based.
17 / The original version of mmapfile is maintained by Sam at
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000018 / ftp://squirl.nightmare.com/pub/python/python-ext.
19*/
20
Martin v. Löwiscfe7e092006-02-17 06:59:14 +000021#define PY_SSIZE_T_CLEAN
Guido van Rossum09fdf072000-03-31 01:17:07 +000022#include <Python.h>
23
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000024#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000025#define UNIX
26#endif
27
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000028#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000030static int
31my_getpagesize(void)
32{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000033 SYSTEM_INFO si;
34 GetSystemInfo(&si);
35 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000036}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000037
38static int
39my_getallocationgranularity (void)
40{
41
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000042 SYSTEM_INFO si;
43 GetSystemInfo(&si);
44 return si.dwAllocationGranularity;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000045}
46
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000047#endif
48
49#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000051#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000052
Fred Drake145f96e2000-10-01 17:50:46 +000053#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
54static int
55my_getpagesize(void)
56{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000057 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000058}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000059
60#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000061#else
62#define my_getpagesize getpagesize
63#endif
64
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000065#endif /* UNIX */
66
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000067#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000068
69#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000071#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000073/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000074#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
75# define MAP_ANONYMOUS MAP_ANON
76#endif
77
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000078static PyObject *mmap_module_error;
79
Tim Peters5ebfd362001-11-13 23:11:19 +000080typedef enum
81{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000082 ACCESS_DEFAULT,
83 ACCESS_READ,
84 ACCESS_WRITE,
85 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000086} access_mode;
87
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000088typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000089 PyObject_HEAD
90 char * data;
91 size_t size;
92 size_t pos; /* relative to offset */
93 size_t offset;
94 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000095
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000096#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000097 HANDLE map_handle;
98 HANDLE file_handle;
99 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000100#endif
101
102#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000103 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000105
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000106 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107} mmap_object;
108
Tim Peters5ebfd362001-11-13 23:11:19 +0000109
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000111mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000112{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000113#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000114 if (m_obj->data != NULL)
115 UnmapViewOfFile (m_obj->data);
116 if (m_obj->map_handle != NULL)
117 CloseHandle (m_obj->map_handle);
118 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
119 CloseHandle (m_obj->file_handle);
120 if (m_obj->tagname)
121 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000122#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000123
124#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000125 if (m_obj->fd >= 0)
126 (void) close(m_obj->fd);
127 if (m_obj->data!=NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000128 munmap(m_obj->data, m_obj->size);
129 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000130#endif /* UNIX */
131
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000133}
134
135static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000136mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000137{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000138 if (self->exports > 0) {
139 PyErr_SetString(PyExc_BufferError, "cannot close "\
140 "exported pointers exist");
141 return NULL;
142 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000143#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000144 /* For each resource we maintain, we need to check
145 the value is valid, and if so, free the resource
146 and set the member value to an invalid value so
147 the dealloc does not attempt to resource clearing
148 again.
149 TODO - should we check for errors in the close operations???
150 */
151 if (self->data != NULL) {
152 UnmapViewOfFile(self->data);
153 self->data = NULL;
154 }
155 if (self->map_handle != NULL) {
156 CloseHandle(self->map_handle);
157 self->map_handle = NULL;
158 }
159 if (self->file_handle != INVALID_HANDLE_VALUE) {
160 CloseHandle(self->file_handle);
161 self->file_handle = INVALID_HANDLE_VALUE;
162 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000163#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000164
165#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000166 if (0 <= self->fd)
167 (void) close(self->fd);
168 self->fd = -1;
169 if (self->data != NULL) {
170 munmap(self->data, self->size);
171 self->data = NULL;
172 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000173#endif
174
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 Py_INCREF(Py_None);
176 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000177}
178
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000179#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000180#define CHECK_VALID(err) \
181do { \
182 if (self->map_handle == NULL) { \
183 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
184 return err; \
185 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000186} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000187#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000188
189#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190#define CHECK_VALID(err) \
191do { \
192 if (self->data == NULL) { \
193 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
194 return err; \
195 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000196} while (0)
197#endif /* UNIX */
198
199static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000200mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000202{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 CHECK_VALID(NULL);
204 if (self->pos < self->size) {
205 char value = self->data[self->pos];
206 self->pos += 1;
207 return Py_BuildValue("b", value);
208 } else {
209 PyErr_SetString(PyExc_ValueError, "read byte out of range");
210 return NULL;
211 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000212}
213
214static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000215mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000216 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000218 char *start = self->data+self->pos;
219 char *eof = self->data+self->size;
220 char *eol;
221 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000222
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 eol = memchr(start, '\n', self->size - self->pos);
226 if (!eol)
227 eol = eof;
228 else
229 ++eol; /* we're interested in the position after the
230 newline. */
231 result = PyBytes_FromStringAndSize(start, (eol - start));
232 self->pos += (eol - start);
233 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000234}
235
236static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000237mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000238 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000239{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000240 Py_ssize_t num_bytes, n;
241 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000242
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000243 CHECK_VALID(NULL);
244 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
245 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 /* silently 'adjust' out-of-range requests */
248 assert(self->size >= self->pos);
249 n = self->size - self->pos;
250 /* The difference can overflow, only if self->size is greater than
251 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
252 * because the mapped area and the returned string each need more
253 * than half of the addressable memory. So we clip the size, and let
254 * the code below raise MemoryError.
255 */
256 if (n < 0)
257 n = PY_SSIZE_T_MAX;
258 if (num_bytes < 0 || num_bytes > n) {
259 num_bytes = n;
260 }
261 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
262 self->pos += num_bytes;
263 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000264}
265
266static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000267mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 PyObject *args,
269 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000270{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000271 Py_ssize_t start = self->pos;
272 Py_ssize_t end = self->size;
273 const char *needle;
274 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000275
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000276 CHECK_VALID(NULL);
277 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
278 &needle, &len, &start, &end)) {
279 return NULL;
280 } else {
281 const char *p, *start_p, *end_p;
282 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000283
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000284 if (start < 0)
285 start += self->size;
286 if (start < 0)
287 start = 0;
288 else if ((size_t)start > self->size)
289 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 if (end < 0)
292 end += self->size;
293 if (end < 0)
294 end = 0;
295 else if ((size_t)end > self->size)
296 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000297
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 start_p = self->data + start;
299 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000300
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000301 for (p = (reverse ? end_p - len : start_p);
302 (p >= start_p) && (p + len <= end_p); p += sign) {
303 Py_ssize_t i;
304 for (i = 0; i < len && needle[i] == p[i]; ++i)
305 /* nothing */;
306 if (i == len) {
307 return PyLong_FromSsize_t(p - self->data);
308 }
309 }
310 return PyLong_FromLong(-1);
311 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000312}
313
Georg Brandlfceab5a2008-01-19 20:08:23 +0000314static PyObject *
315mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000316 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000317{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000318 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000319}
320
321static PyObject *
322mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000324{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000326}
327
Tim Petersec0a5f02006-02-16 23:47:20 +0000328static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000329is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000330{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 if (self->access != ACCESS_READ)
332 return 1;
333 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
334 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000335}
336
Tim Petersec0a5f02006-02-16 23:47:20 +0000337static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000338is_resizeable(mmap_object *self)
339{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 if (self->exports > 0) {
341 PyErr_SetString(PyExc_BufferError,
342 "mmap can't resize with extant buffers exported.");
343 return 0;
344 }
345 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
346 return 1;
347 PyErr_Format(PyExc_TypeError,
348 "mmap can't resize a readonly or copy-on-write memory map.");
349 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000350}
351
352
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000353static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000354mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000355 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000356{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000357 Py_ssize_t length;
358 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000359
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000360 CHECK_VALID(NULL);
361 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
362 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000363
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000364 if (!is_writable(self))
365 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000366
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 if ((self->pos + length) > self->size) {
368 PyErr_SetString(PyExc_ValueError, "data out of range");
369 return NULL;
370 }
371 memcpy(self->data+self->pos, data, length);
372 self->pos = self->pos+length;
373 Py_INCREF(Py_None);
374 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000375}
376
377static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000378mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000379 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000380{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000381 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000382
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000383 CHECK_VALID(NULL);
384 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
385 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000386
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000387 if (!is_writable(self))
388 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000389
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000390 if (self->pos < self->size) {
391 *(self->data+self->pos) = value;
392 self->pos += 1;
393 Py_INCREF(Py_None);
394 return Py_None;
395 }
396 else {
397 PyErr_SetString(PyExc_ValueError, "write byte out of range");
398 return NULL;
399 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000400}
Tim Petersec0a5f02006-02-16 23:47:20 +0000401
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000402static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000403mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000404 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000405{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000407
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000408#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000409 if (self->file_handle != INVALID_HANDLE_VALUE) {
410 DWORD low,high;
411 PY_LONG_LONG size;
412 low = GetFileSize(self->file_handle, &high);
413 if (low == INVALID_FILE_SIZE) {
414 /* It might be that the function appears to have failed,
415 when indeed its size equals INVALID_FILE_SIZE */
416 DWORD error = GetLastError();
417 if (error != NO_ERROR)
418 return PyErr_SetFromWindowsErr(error);
419 }
420 if (!high && low < LONG_MAX)
421 return PyLong_FromLong((long)low);
422 size = (((PY_LONG_LONG)high)<<32) + low;
423 return PyLong_FromLongLong(size);
424 } else {
425 return PyLong_FromSsize_t(self->size);
426 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000427#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000428
429#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000430 {
431 struct stat buf;
432 if (-1 == fstat(self->fd, &buf)) {
433 PyErr_SetFromErrno(mmap_module_error);
434 return NULL;
435 }
436 return PyLong_FromSsize_t(buf.st_size);
437 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000438#endif /* UNIX */
439}
440
441/* This assumes that you want the entire file mapped,
442 / and when recreating the map will make the new file
443 / have the new size
444 /
445 / Is this really necessary? This could easily be done
446 / from python by just closing and re-opening with the
447 / new size?
448 */
449
450static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000451mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000452 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000453{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000454 Py_ssize_t new_size;
455 CHECK_VALID(NULL);
456 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
457 !is_resizeable(self)) {
458 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000459#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000460 } else {
461 DWORD dwErrCode = 0;
462 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
463 /* First, unmap the file view */
464 UnmapViewOfFile(self->data);
465 self->data = NULL;
466 /* Close the mapping object */
467 CloseHandle(self->map_handle);
468 self->map_handle = NULL;
469 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000470#if SIZEOF_SIZE_T > 4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000471 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
472 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
473 off_hi = (DWORD)(self->offset >> 32);
474 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000475#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000476 newSizeHigh = 0;
477 newSizeLow = (DWORD)(self->offset + new_size);
478 off_hi = 0;
479 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000480#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000481 SetFilePointer(self->file_handle,
482 newSizeLow, &newSizeHigh, FILE_BEGIN);
483 /* Change the size of the file */
484 SetEndOfFile(self->file_handle);
485 /* Create another mapping object and remap the file view */
486 self->map_handle = CreateFileMapping(
487 self->file_handle,
488 NULL,
489 PAGE_READWRITE,
490 0,
491 0,
492 self->tagname);
493 if (self->map_handle != NULL) {
494 self->data = (char *) MapViewOfFile(self->map_handle,
495 FILE_MAP_WRITE,
496 off_hi,
497 off_lo,
498 new_size);
499 if (self->data != NULL) {
500 self->size = new_size;
501 Py_INCREF(Py_None);
502 return Py_None;
503 } else {
504 dwErrCode = GetLastError();
505 CloseHandle(self->map_handle);
506 self->map_handle = NULL;
507 }
508 } else {
509 dwErrCode = GetLastError();
510 }
511 PyErr_SetFromWindowsErr(dwErrCode);
512 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000513#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000514
515#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000516#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000517 } else {
518 PyErr_SetString(PyExc_SystemError,
519 "mmap: resizing not available--no mremap()");
520 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000521#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000522 } else {
523 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000524
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000525 if (ftruncate(self->fd, self->offset + new_size) == -1) {
526 PyErr_SetFromErrno(mmap_module_error);
527 return NULL;
528 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000529
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000530#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000531 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000532#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000533 #if defined(__NetBSD__)
534 newmap = mremap(self->data, self->size, self->data, new_size, 0);
535 #else
536 newmap = mremap(self->data, self->size, new_size, 0);
537 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000538#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000539 if (newmap == (void *)-1)
540 {
541 PyErr_SetFromErrno(mmap_module_error);
542 return NULL;
543 }
544 self->data = newmap;
545 self->size = new_size;
546 Py_INCREF(Py_None);
547 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000548#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000549#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000550 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000551}
552
553static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000554mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000555{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000556 CHECK_VALID(NULL);
557 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000558}
559
560static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000561mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000562{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000563 Py_ssize_t offset = 0;
564 Py_ssize_t size = self->size;
565 CHECK_VALID(NULL);
566 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
567 return NULL;
568 if ((size_t)(offset + size) > self->size) {
569 PyErr_SetString(PyExc_ValueError, "flush values out of range");
570 return NULL;
571 }
Christian Heimesaf98da12008-01-27 15:18:18 +0000572#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000573 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000574#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 /* XXX semantics of return value? */
576 /* XXX flags for msync? */
577 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
578 PyErr_SetFromErrno(mmap_module_error);
579 return NULL;
580 }
581 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000582#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000583 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
584 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000585#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000586}
587
588static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000589mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000590{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000591 Py_ssize_t dist;
592 int how=0;
593 CHECK_VALID(NULL);
594 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
595 return NULL;
596 else {
597 size_t where;
598 switch (how) {
599 case 0: /* relative to start */
600 if (dist < 0)
601 goto onoutofrange;
602 where = dist;
603 break;
604 case 1: /* relative to current position */
605 if ((Py_ssize_t)self->pos + dist < 0)
606 goto onoutofrange;
607 where = self->pos + dist;
608 break;
609 case 2: /* relative to end */
610 if ((Py_ssize_t)self->size + dist < 0)
611 goto onoutofrange;
612 where = self->size + dist;
613 break;
614 default:
615 PyErr_SetString(PyExc_ValueError, "unknown seek type");
616 return NULL;
617 }
618 if (where > self->size)
619 goto onoutofrange;
620 self->pos = where;
621 Py_INCREF(Py_None);
622 return Py_None;
623 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000624
Tim Peters5ebfd362001-11-13 23:11:19 +0000625 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000626 PyErr_SetString(PyExc_ValueError, "seek out of range");
627 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628}
629
630static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000631mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000632{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000633 unsigned long dest, src, cnt;
634 CHECK_VALID(NULL);
635 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
636 !is_writable(self)) {
637 return NULL;
638 } else {
639 /* bounds check the values */
640 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
641 src < 0 || src > self->size || (src + cnt) > self->size ||
642 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
643 PyErr_SetString(PyExc_ValueError,
644 "source, destination, or count out of range");
645 return NULL;
646 }
647 memmove(self->data+dest, self->data+src, cnt);
648 Py_INCREF(Py_None);
649 return Py_None;
650 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000651}
652
Georg Brandl0bccc182010-08-01 14:50:00 +0000653static PyObject *
654mmap_closed_get(mmap_object *self)
655{
656#ifdef MS_WINDOWS
657 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
658#elif defined(UNIX)
659 return PyBool_FromLong(self->data == NULL ? 1 : 0);
660#endif
661}
662
663static PyObject *
664mmap__enter__method(mmap_object *self, PyObject *args)
665{
666 CHECK_VALID(NULL);
667
668 Py_INCREF(self);
669 return (PyObject *)self;
670}
671
672static PyObject *
673mmap__exit__method(PyObject *self, PyObject *args)
674{
675 return PyObject_CallMethod(self, "close", NULL);
676}
677
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000678static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000679 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
680 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
681 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
682 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
683 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
684 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
685 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
686 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
687 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
688 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
689 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
690 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
691 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
692 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000693 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
694 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000695 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000696};
697
Georg Brandl0bccc182010-08-01 14:50:00 +0000698static PyGetSetDef mmap_object_getset[] = {
699 {"closed", (getter) mmap_closed_get, NULL, NULL},
700 {NULL}
701};
702
703
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000704/* Functions for treating an mmap'ed file as a buffer */
705
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000706static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000707mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000708{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000709 CHECK_VALID(-1);
710 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
711 (self->access == ACCESS_READ), flags) < 0)
712 return -1;
713 self->exports++;
714 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000715}
716
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000717static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000718mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000719{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000720 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000721}
722
Martin v. Löwis18e16552006-02-15 17:27:45 +0000723static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000724mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000725{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000726 CHECK_VALID(-1);
727 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000728}
729
730static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000731mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000732{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000733 CHECK_VALID(NULL);
734 if (i < 0 || (size_t)i >= self->size) {
735 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
736 return NULL;
737 }
738 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000739}
740
741static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000742mmap_subscript(mmap_object *self, PyObject *item)
743{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000744 CHECK_VALID(NULL);
745 if (PyIndex_Check(item)) {
746 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
747 if (i == -1 && PyErr_Occurred())
748 return NULL;
749 if (i < 0)
750 i += self->size;
751 if (i < 0 || (size_t)i >= self->size) {
752 PyErr_SetString(PyExc_IndexError,
753 "mmap index out of range");
754 return NULL;
755 }
756 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
757 }
758 else if (PySlice_Check(item)) {
759 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000760
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000761 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
762 &start, &stop, &step, &slicelen) < 0) {
763 return NULL;
764 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000765
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000766 if (slicelen <= 0)
767 return PyBytes_FromStringAndSize("", 0);
768 else if (step == 1)
769 return PyBytes_FromStringAndSize(self->data + start,
770 slicelen);
771 else {
772 char *result_buf = (char *)PyMem_Malloc(slicelen);
773 Py_ssize_t cur, i;
774 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000775
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000776 if (result_buf == NULL)
777 return PyErr_NoMemory();
778 for (cur = start, i = 0; i < slicelen;
779 cur += step, i++) {
780 result_buf[i] = self->data[cur];
781 }
782 result = PyBytes_FromStringAndSize(result_buf,
783 slicelen);
784 PyMem_Free(result_buf);
785 return result;
786 }
787 }
788 else {
789 PyErr_SetString(PyExc_TypeError,
790 "mmap indices must be integers");
791 return NULL;
792 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000793}
794
795static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000796mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000797{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000798 CHECK_VALID(NULL);
799 PyErr_SetString(PyExc_SystemError,
800 "mmaps don't support concatenation");
801 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000802}
803
804static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000805mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000806{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000807 CHECK_VALID(NULL);
808 PyErr_SetString(PyExc_SystemError,
809 "mmaps don't support repeat operation");
810 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000811}
812
813static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000814mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000815{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000816 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000817
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000818 CHECK_VALID(-1);
819 if (i < 0 || (size_t)i >= self->size) {
820 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
821 return -1;
822 }
823 if (v == NULL) {
824 PyErr_SetString(PyExc_TypeError,
825 "mmap object doesn't support item deletion");
826 return -1;
827 }
828 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
829 PyErr_SetString(PyExc_IndexError,
830 "mmap assignment must be length-1 bytes()");
831 return -1;
832 }
833 if (!is_writable(self))
834 return -1;
835 buf = PyBytes_AsString(v);
836 self->data[i] = buf[0];
837 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000838}
839
Thomas Woutersed03b412007-08-28 21:37:11 +0000840static int
841mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
842{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000843 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000844
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000845 if (!is_writable(self))
846 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000847
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000848 if (PyIndex_Check(item)) {
849 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
850 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000851
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000852 if (i == -1 && PyErr_Occurred())
853 return -1;
854 if (i < 0)
855 i += self->size;
856 if (i < 0 || (size_t)i >= self->size) {
857 PyErr_SetString(PyExc_IndexError,
858 "mmap index out of range");
859 return -1;
860 }
861 if (value == NULL) {
862 PyErr_SetString(PyExc_TypeError,
863 "mmap doesn't support item deletion");
864 return -1;
865 }
866 if (!PyIndex_Check(value)) {
867 PyErr_SetString(PyExc_TypeError,
868 "mmap item value must be an int");
869 return -1;
870 }
871 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
872 if (v == -1 && PyErr_Occurred())
873 return -1;
874 if (v < 0 || v > 255) {
875 PyErr_SetString(PyExc_ValueError,
876 "mmap item value must be "
877 "in range(0, 256)");
878 return -1;
879 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000880 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000881 return 0;
882 }
883 else if (PySlice_Check(item)) {
884 Py_ssize_t start, stop, step, slicelen;
885 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000886
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000887 if (PySlice_GetIndicesEx((PySliceObject *)item,
888 self->size, &start, &stop,
889 &step, &slicelen) < 0) {
890 return -1;
891 }
892 if (value == NULL) {
893 PyErr_SetString(PyExc_TypeError,
894 "mmap object doesn't support slice deletion");
895 return -1;
896 }
897 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
898 return -1;
899 if (vbuf.len != slicelen) {
900 PyErr_SetString(PyExc_IndexError,
901 "mmap slice assignment is wrong size");
902 PyBuffer_Release(&vbuf);
903 return -1;
904 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000905
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000906 if (slicelen == 0) {
907 }
908 else if (step == 1) {
909 memcpy(self->data + start, vbuf.buf, slicelen);
910 }
911 else {
912 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000913
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000914 for (cur = start, i = 0;
915 i < slicelen;
916 cur += step, i++)
917 {
918 self->data[cur] = ((char *)vbuf.buf)[i];
919 }
920 }
921 PyBuffer_Release(&vbuf);
922 return 0;
923 }
924 else {
925 PyErr_SetString(PyExc_TypeError,
926 "mmap indices must be integer");
927 return -1;
928 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000929}
930
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000931static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000932 (lenfunc)mmap_length, /*sq_length*/
933 (binaryfunc)mmap_concat, /*sq_concat*/
934 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
935 (ssizeargfunc)mmap_item, /*sq_item*/
936 0, /*sq_slice*/
937 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
938 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000939};
940
Thomas Woutersed03b412007-08-28 21:37:11 +0000941static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000942 (lenfunc)mmap_length,
943 (binaryfunc)mmap_subscript,
944 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000945};
946
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000947static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000948 (getbufferproc)mmap_buffer_getbuf,
949 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000950};
951
Georg Brandl86def6c2008-01-21 20:36:10 +0000952static PyObject *
953new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
954
Christian Heimese1c98112008-01-21 11:20:28 +0000955PyDoc_STRVAR(mmap_doc,
956"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
957\n\
958Maps length bytes from the file specified by the file handle fileno,\n\
959and returns a mmap object. If length is larger than the current size\n\
960of the file, the file is extended to contain length bytes. If length\n\
961is 0, the maximum length of the map is the current size of the file,\n\
962except that if the file is empty Windows raises an exception (you cannot\n\
963create an empty mapping on Windows).\n\
964\n\
965Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
966\n\
967Maps length bytes from the file specified by the file descriptor fileno,\n\
968and returns a mmap object. If length is 0, the maximum length of the map\n\
969will be the current size of the file when mmap is called.\n\
970flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
971private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000972object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000973that's shared with all other processes mapping the same areas of the file.\n\
974The default value is MAP_SHARED.\n\
975\n\
976To map anonymous memory, pass -1 as the fileno (both versions).");
977
978
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000979static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000980 PyVarObject_HEAD_INIT(NULL, 0)
981 "mmap.mmap", /* tp_name */
982 sizeof(mmap_object), /* tp_size */
983 0, /* tp_itemsize */
984 /* methods */
985 (destructor) mmap_object_dealloc, /* tp_dealloc */
986 0, /* tp_print */
987 0, /* tp_getattr */
988 0, /* tp_setattr */
989 0, /* tp_reserved */
990 0, /* tp_repr */
991 0, /* tp_as_number */
992 &mmap_as_sequence, /*tp_as_sequence*/
993 &mmap_as_mapping, /*tp_as_mapping*/
994 0, /*tp_hash*/
995 0, /*tp_call*/
996 0, /*tp_str*/
997 PyObject_GenericGetAttr, /*tp_getattro*/
998 0, /*tp_setattro*/
999 &mmap_as_buffer, /*tp_as_buffer*/
1000 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1001 mmap_doc, /*tp_doc*/
1002 0, /* tp_traverse */
1003 0, /* tp_clear */
1004 0, /* tp_richcompare */
1005 0, /* tp_weaklistoffset */
1006 0, /* tp_iter */
1007 0, /* tp_iternext */
1008 mmap_object_methods, /* tp_methods */
1009 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001010 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001011 0, /* tp_base */
1012 0, /* tp_dict */
1013 0, /* tp_descr_get */
1014 0, /* tp_descr_set */
1015 0, /* tp_dictoffset */
1016 0, /* tp_init */
1017 PyType_GenericAlloc, /* tp_alloc */
1018 new_mmap_object, /* tp_new */
1019 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001020};
1021
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001022
1023/* extract the map size from the given PyObject
1024
Thomas Wouters7e474022000-07-16 12:04:32 +00001025 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001026 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001027static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001028_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001029{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001030 if (o == NULL)
1031 return 0;
1032 if (PyIndex_Check(o)) {
1033 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1034 if (i==-1 && PyErr_Occurred())
1035 return -1;
1036 if (i < 0) {
1037 PyErr_Format(PyExc_OverflowError,
1038 "memory mapped %s must be positive",
1039 param);
1040 return -1;
1041 }
1042 return i;
1043 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001044
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001045 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1046 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001047}
1048
Tim Petersec0a5f02006-02-16 23:47:20 +00001049#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001050static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001051new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001052{
Neal Norwitzb5673922002-09-05 21:48:07 +00001053#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001054 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001055#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001056 mmap_object *m_obj;
1057 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1058 Py_ssize_t map_size, offset;
1059 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1060 int devzero = -1;
1061 int access = (int)ACCESS_DEFAULT;
1062 static char *keywords[] = {"fileno", "length",
1063 "flags", "prot",
1064 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001065
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001066 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
1067 &fd, &map_size_obj, &flags, &prot,
1068 &access, &offset_obj))
1069 return NULL;
1070 map_size = _GetMapSize(map_size_obj, "size");
1071 if (map_size < 0)
1072 return NULL;
1073 offset = _GetMapSize(offset_obj, "offset");
1074 if (offset < 0)
1075 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001076
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001077 if ((access != (int)ACCESS_DEFAULT) &&
1078 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1079 return PyErr_Format(PyExc_ValueError,
1080 "mmap can't specify both access and flags, prot.");
1081 switch ((access_mode)access) {
1082 case ACCESS_READ:
1083 flags = MAP_SHARED;
1084 prot = PROT_READ;
1085 break;
1086 case ACCESS_WRITE:
1087 flags = MAP_SHARED;
1088 prot = PROT_READ | PROT_WRITE;
1089 break;
1090 case ACCESS_COPY:
1091 flags = MAP_PRIVATE;
1092 prot = PROT_READ | PROT_WRITE;
1093 break;
1094 case ACCESS_DEFAULT:
1095 /* use the specified or default values of flags and prot */
1096 break;
1097 default:
1098 return PyErr_Format(PyExc_ValueError,
1099 "mmap invalid access parameter.");
1100 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001101
Christian Heimesa156e092008-02-16 07:38:31 +00001102 if (prot == PROT_READ) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001103 access = ACCESS_READ;
Christian Heimesa156e092008-02-16 07:38:31 +00001104 }
1105
Neal Norwitzb5673922002-09-05 21:48:07 +00001106#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001107# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001108 /* on OpenVMS we must ensure that all bytes are written to the file */
1109 if (fd != -1) {
1110 fsync(fd);
1111 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001112# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001113 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1114 if (map_size == 0) {
1115 map_size = st.st_size;
1116 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
1117 PyErr_SetString(PyExc_ValueError,
1118 "mmap length is greater than file size");
1119 return NULL;
1120 }
1121 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001122#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001123 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1124 if (m_obj == NULL) {return NULL;}
1125 m_obj->data = NULL;
1126 m_obj->size = (size_t) map_size;
1127 m_obj->pos = (size_t) 0;
1128 m_obj->exports = 0;
1129 m_obj->offset = offset;
1130 if (fd == -1) {
1131 m_obj->fd = -1;
1132 /* Assume the caller wants to map anonymous memory.
1133 This is the same behaviour as Windows. mmap.mmap(-1, size)
1134 on both Windows and Unix map anonymous memory.
1135 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001136#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001137 /* BSD way to map anonymous memory */
1138 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001139#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001140 /* SVR4 method to map anonymous memory is to open /dev/zero */
1141 fd = devzero = open("/dev/zero", O_RDWR);
1142 if (devzero == -1) {
1143 Py_DECREF(m_obj);
1144 PyErr_SetFromErrno(mmap_module_error);
1145 return NULL;
1146 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001147#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001148 } else {
1149 m_obj->fd = dup(fd);
1150 if (m_obj->fd == -1) {
1151 Py_DECREF(m_obj);
1152 PyErr_SetFromErrno(mmap_module_error);
1153 return NULL;
1154 }
1155 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001156
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001157 m_obj->data = mmap(NULL, map_size,
1158 prot, flags,
1159 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001160
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001161 if (devzero != -1) {
1162 close(devzero);
1163 }
1164
1165 if (m_obj->data == (char *)-1) {
1166 m_obj->data = NULL;
1167 Py_DECREF(m_obj);
1168 PyErr_SetFromErrno(mmap_module_error);
1169 return NULL;
1170 }
1171 m_obj->access = (access_mode)access;
1172 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001173}
1174#endif /* UNIX */
1175
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001176#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001177static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001178new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001179{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001180 mmap_object *m_obj;
1181 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1182 Py_ssize_t map_size, offset;
1183 DWORD off_hi; /* upper 32 bits of offset */
1184 DWORD off_lo; /* lower 32 bits of offset */
1185 DWORD size_hi; /* upper 32 bits of size */
1186 DWORD size_lo; /* lower 32 bits of size */
1187 char *tagname = "";
1188 DWORD dwErr = 0;
1189 int fileno;
1190 HANDLE fh = 0;
1191 int access = (access_mode)ACCESS_DEFAULT;
1192 DWORD flProtect, dwDesiredAccess;
1193 static char *keywords[] = { "fileno", "length",
1194 "tagname",
1195 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001196
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001197 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
1198 &fileno, &map_size_obj,
1199 &tagname, &access, &offset_obj)) {
1200 return NULL;
1201 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001202
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001203 switch((access_mode)access) {
1204 case ACCESS_READ:
1205 flProtect = PAGE_READONLY;
1206 dwDesiredAccess = FILE_MAP_READ;
1207 break;
1208 case ACCESS_DEFAULT: case ACCESS_WRITE:
1209 flProtect = PAGE_READWRITE;
1210 dwDesiredAccess = FILE_MAP_WRITE;
1211 break;
1212 case ACCESS_COPY:
1213 flProtect = PAGE_WRITECOPY;
1214 dwDesiredAccess = FILE_MAP_COPY;
1215 break;
1216 default:
1217 return PyErr_Format(PyExc_ValueError,
1218 "mmap invalid access parameter.");
1219 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001220
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001221 map_size = _GetMapSize(map_size_obj, "size");
1222 if (map_size < 0)
1223 return NULL;
1224 offset = _GetMapSize(offset_obj, "offset");
1225 if (offset < 0)
1226 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001227
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001228 /* assume -1 and 0 both mean invalid filedescriptor
1229 to 'anonymously' map memory.
1230 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1231 XXX: Should this code be added?
1232 if (fileno == 0)
1233 PyErr_WarnEx(PyExc_DeprecationWarning,
1234 "don't use 0 for anonymous memory",
1235 1);
1236 */
1237 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001238 /* Ensure that fileno is within the CRT's valid range */
1239 if (_PyVerify_fd(fileno) == 0) {
1240 PyErr_SetFromErrno(mmap_module_error);
1241 return NULL;
1242 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001243 fh = (HANDLE)_get_osfhandle(fileno);
1244 if (fh==(HANDLE)-1) {
1245 PyErr_SetFromErrno(mmap_module_error);
1246 return NULL;
1247 }
1248 /* Win9x appears to need us seeked to zero */
1249 lseek(fileno, 0, SEEK_SET);
1250 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001251
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001252 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1253 if (m_obj == NULL)
1254 return NULL;
1255 /* Set every field to an invalid marker, so we can safely
1256 destruct the object in the face of failure */
1257 m_obj->data = NULL;
1258 m_obj->file_handle = INVALID_HANDLE_VALUE;
1259 m_obj->map_handle = NULL;
1260 m_obj->tagname = NULL;
1261 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001262
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001263 if (fh) {
1264 /* It is necessary to duplicate the handle, so the
1265 Python code can close it on us */
1266 if (!DuplicateHandle(
1267 GetCurrentProcess(), /* source process handle */
1268 fh, /* handle to be duplicated */
1269 GetCurrentProcess(), /* target proc handle */
1270 (LPHANDLE)&m_obj->file_handle, /* result */
1271 0, /* access - ignored due to options value */
1272 FALSE, /* inherited by child processes? */
1273 DUPLICATE_SAME_ACCESS)) { /* options */
1274 dwErr = GetLastError();
1275 Py_DECREF(m_obj);
1276 PyErr_SetFromWindowsErr(dwErr);
1277 return NULL;
1278 }
1279 if (!map_size) {
1280 DWORD low,high;
1281 low = GetFileSize(fh, &high);
1282 /* low might just happen to have the value INVALID_FILE_SIZE;
1283 so we need to check the last error also. */
1284 if (low == INVALID_FILE_SIZE &&
1285 (dwErr = GetLastError()) != NO_ERROR) {
1286 Py_DECREF(m_obj);
1287 return PyErr_SetFromWindowsErr(dwErr);
1288 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001289
Martin v. Löwis15186072006-02-18 12:38:35 +00001290#if SIZEOF_SIZE_T > 4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001291 m_obj->size = (((size_t)high)<<32) + low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001292#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001293 if (high)
1294 /* File is too large to map completely */
1295 m_obj->size = (size_t)-1;
1296 else
1297 m_obj->size = low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001298#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001299 } else {
1300 m_obj->size = map_size;
1301 }
1302 }
1303 else {
1304 m_obj->size = map_size;
1305 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001306
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001307 /* set the initial position */
1308 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001309
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001310 m_obj->exports = 0;
1311 /* set the tag name */
1312 if (tagname != NULL && *tagname != '\0') {
1313 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1314 if (m_obj->tagname == NULL) {
1315 PyErr_NoMemory();
1316 Py_DECREF(m_obj);
1317 return NULL;
1318 }
1319 strcpy(m_obj->tagname, tagname);
1320 }
1321 else
1322 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001323
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001324 m_obj->access = (access_mode)access;
1325 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
1326 * more than 4 bytes, we need to break it apart. Else (size_t
1327 * consumes 4 bytes), C doesn't define what happens if we shift
1328 * right by 32, so we need different code.
1329 */
Tim Peterse564e7f2006-02-16 23:46:01 +00001330#if SIZEOF_SIZE_T > 4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001331 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1332 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1333 off_hi = (DWORD)(offset >> 32);
1334 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001335#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001336 size_hi = 0;
1337 size_lo = (DWORD)(offset + m_obj->size);
1338 off_hi = 0;
1339 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001340#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001341 /* For files, it would be sufficient to pass 0 as size.
1342 For anonymous maps, we have to pass the size explicitly. */
1343 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1344 NULL,
1345 flProtect,
1346 size_hi,
1347 size_lo,
1348 m_obj->tagname);
1349 if (m_obj->map_handle != NULL) {
1350 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1351 dwDesiredAccess,
1352 off_hi,
1353 off_lo,
1354 m_obj->size);
1355 if (m_obj->data != NULL)
1356 return (PyObject *)m_obj;
1357 else {
1358 dwErr = GetLastError();
1359 CloseHandle(m_obj->map_handle);
1360 m_obj->map_handle = NULL;
1361 }
1362 } else
1363 dwErr = GetLastError();
1364 Py_DECREF(m_obj);
1365 PyErr_SetFromWindowsErr(dwErr);
1366 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001367}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001368#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001369
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001370static void
1371setint(PyObject *d, const char *name, long value)
1372{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001373 PyObject *o = PyLong_FromLong(value);
1374 if (o && PyDict_SetItemString(d, name, o) == 0) {
1375 Py_DECREF(o);
1376 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001377}
1378
Martin v. Löwis1a214512008-06-11 05:26:20 +00001379
1380static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001381 PyModuleDef_HEAD_INIT,
1382 "mmap",
1383 NULL,
1384 -1,
1385 NULL,
1386 NULL,
1387 NULL,
1388 NULL,
1389 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001390};
1391
Mark Hammond62b1ab12002-07-23 06:31:15 +00001392PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001393PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001394{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001395 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001396
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001397 if (PyType_Ready(&mmap_object_type) < 0)
1398 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001399
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001400 module = PyModule_Create(&mmapmodule);
1401 if (module == NULL)
1402 return NULL;
1403 dict = PyModule_GetDict(module);
1404 if (!dict)
1405 return NULL;
1406 mmap_module_error = PyErr_NewException("mmap.error",
1407 PyExc_EnvironmentError , NULL);
1408 if (mmap_module_error == NULL)
1409 return NULL;
1410 PyDict_SetItemString(dict, "error", mmap_module_error);
1411 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001412#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001413 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001414#endif
1415#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001416 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001417#endif
1418#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001419 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001420#endif
1421
1422#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001423 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001424#endif
1425#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001426 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001427#endif
1428#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001429 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001430#endif
1431#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001432 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001433#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001434#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001435 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1436 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001437#endif
1438
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001439 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001440
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001441 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001442
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001443 setint(dict, "ACCESS_READ", ACCESS_READ);
1444 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1445 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1446 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001447}