blob: 680f1f1102a95ca9feecfd422957581d5aff40fd [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 }
R. David Murraye194dd62010-10-18 01:14:06 +0000572
573 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
574 return PyLong_FromLong(0);
575
Christian Heimesaf98da12008-01-27 15:18:18 +0000576#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000577 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000578#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000579 /* XXX semantics of return value? */
580 /* XXX flags for msync? */
581 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
582 PyErr_SetFromErrno(mmap_module_error);
583 return NULL;
584 }
585 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000586#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000587 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
588 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000589#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000590}
591
592static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000593mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000594{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000595 Py_ssize_t dist;
596 int how=0;
597 CHECK_VALID(NULL);
598 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
599 return NULL;
600 else {
601 size_t where;
602 switch (how) {
603 case 0: /* relative to start */
604 if (dist < 0)
605 goto onoutofrange;
606 where = dist;
607 break;
608 case 1: /* relative to current position */
609 if ((Py_ssize_t)self->pos + dist < 0)
610 goto onoutofrange;
611 where = self->pos + dist;
612 break;
613 case 2: /* relative to end */
614 if ((Py_ssize_t)self->size + dist < 0)
615 goto onoutofrange;
616 where = self->size + dist;
617 break;
618 default:
619 PyErr_SetString(PyExc_ValueError, "unknown seek type");
620 return NULL;
621 }
622 if (where > self->size)
623 goto onoutofrange;
624 self->pos = where;
625 Py_INCREF(Py_None);
626 return Py_None;
627 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000628
Tim Peters5ebfd362001-11-13 23:11:19 +0000629 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000630 PyErr_SetString(PyExc_ValueError, "seek out of range");
631 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000632}
633
634static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000635mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000636{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000637 unsigned long dest, src, cnt;
638 CHECK_VALID(NULL);
639 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
640 !is_writable(self)) {
641 return NULL;
642 } else {
643 /* bounds check the values */
644 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
645 src < 0 || src > self->size || (src + cnt) > self->size ||
646 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
647 PyErr_SetString(PyExc_ValueError,
648 "source, destination, or count out of range");
649 return NULL;
650 }
651 memmove(self->data+dest, self->data+src, cnt);
652 Py_INCREF(Py_None);
653 return Py_None;
654 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000655}
656
Georg Brandl0bccc182010-08-01 14:50:00 +0000657static PyObject *
658mmap_closed_get(mmap_object *self)
659{
660#ifdef MS_WINDOWS
661 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
662#elif defined(UNIX)
663 return PyBool_FromLong(self->data == NULL ? 1 : 0);
664#endif
665}
666
667static PyObject *
668mmap__enter__method(mmap_object *self, PyObject *args)
669{
670 CHECK_VALID(NULL);
671
672 Py_INCREF(self);
673 return (PyObject *)self;
674}
675
676static PyObject *
677mmap__exit__method(PyObject *self, PyObject *args)
678{
679 return PyObject_CallMethod(self, "close", NULL);
680}
681
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000682static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000683 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
684 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
685 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
686 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
687 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
688 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
689 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
690 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
691 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
692 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
693 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
694 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
695 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
696 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000697 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
698 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000699 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000700};
701
Georg Brandl0bccc182010-08-01 14:50:00 +0000702static PyGetSetDef mmap_object_getset[] = {
703 {"closed", (getter) mmap_closed_get, NULL, NULL},
704 {NULL}
705};
706
707
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000708/* Functions for treating an mmap'ed file as a buffer */
709
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000710static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000711mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000712{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000713 CHECK_VALID(-1);
714 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
715 (self->access == ACCESS_READ), flags) < 0)
716 return -1;
717 self->exports++;
718 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000719}
720
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000721static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000722mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000723{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000724 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000725}
726
Martin v. Löwis18e16552006-02-15 17:27:45 +0000727static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000728mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000729{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000730 CHECK_VALID(-1);
731 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000732}
733
734static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000735mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000736{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000737 CHECK_VALID(NULL);
738 if (i < 0 || (size_t)i >= self->size) {
739 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
740 return NULL;
741 }
742 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000743}
744
745static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000746mmap_subscript(mmap_object *self, PyObject *item)
747{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000748 CHECK_VALID(NULL);
749 if (PyIndex_Check(item)) {
750 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
751 if (i == -1 && PyErr_Occurred())
752 return NULL;
753 if (i < 0)
754 i += self->size;
755 if (i < 0 || (size_t)i >= self->size) {
756 PyErr_SetString(PyExc_IndexError,
757 "mmap index out of range");
758 return NULL;
759 }
760 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
761 }
762 else if (PySlice_Check(item)) {
763 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000764
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000765 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
766 &start, &stop, &step, &slicelen) < 0) {
767 return NULL;
768 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000769
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000770 if (slicelen <= 0)
771 return PyBytes_FromStringAndSize("", 0);
772 else if (step == 1)
773 return PyBytes_FromStringAndSize(self->data + start,
774 slicelen);
775 else {
776 char *result_buf = (char *)PyMem_Malloc(slicelen);
777 Py_ssize_t cur, i;
778 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000779
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000780 if (result_buf == NULL)
781 return PyErr_NoMemory();
782 for (cur = start, i = 0; i < slicelen;
783 cur += step, i++) {
784 result_buf[i] = self->data[cur];
785 }
786 result = PyBytes_FromStringAndSize(result_buf,
787 slicelen);
788 PyMem_Free(result_buf);
789 return result;
790 }
791 }
792 else {
793 PyErr_SetString(PyExc_TypeError,
794 "mmap indices must be integers");
795 return NULL;
796 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000797}
798
799static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000800mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000801{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000802 CHECK_VALID(NULL);
803 PyErr_SetString(PyExc_SystemError,
804 "mmaps don't support concatenation");
805 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000806}
807
808static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000809mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000810{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000811 CHECK_VALID(NULL);
812 PyErr_SetString(PyExc_SystemError,
813 "mmaps don't support repeat operation");
814 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000815}
816
817static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000818mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000819{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000820 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000821
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000822 CHECK_VALID(-1);
823 if (i < 0 || (size_t)i >= self->size) {
824 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
825 return -1;
826 }
827 if (v == NULL) {
828 PyErr_SetString(PyExc_TypeError,
829 "mmap object doesn't support item deletion");
830 return -1;
831 }
832 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
833 PyErr_SetString(PyExc_IndexError,
834 "mmap assignment must be length-1 bytes()");
835 return -1;
836 }
837 if (!is_writable(self))
838 return -1;
839 buf = PyBytes_AsString(v);
840 self->data[i] = buf[0];
841 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000842}
843
Thomas Woutersed03b412007-08-28 21:37:11 +0000844static int
845mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
846{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000847 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000848
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000849 if (!is_writable(self))
850 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000851
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000852 if (PyIndex_Check(item)) {
853 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
854 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000855
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000856 if (i == -1 && PyErr_Occurred())
857 return -1;
858 if (i < 0)
859 i += self->size;
860 if (i < 0 || (size_t)i >= self->size) {
861 PyErr_SetString(PyExc_IndexError,
862 "mmap index out of range");
863 return -1;
864 }
865 if (value == NULL) {
866 PyErr_SetString(PyExc_TypeError,
867 "mmap doesn't support item deletion");
868 return -1;
869 }
870 if (!PyIndex_Check(value)) {
871 PyErr_SetString(PyExc_TypeError,
872 "mmap item value must be an int");
873 return -1;
874 }
875 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
876 if (v == -1 && PyErr_Occurred())
877 return -1;
878 if (v < 0 || v > 255) {
879 PyErr_SetString(PyExc_ValueError,
880 "mmap item value must be "
881 "in range(0, 256)");
882 return -1;
883 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000884 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000885 return 0;
886 }
887 else if (PySlice_Check(item)) {
888 Py_ssize_t start, stop, step, slicelen;
889 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000890
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000891 if (PySlice_GetIndicesEx((PySliceObject *)item,
892 self->size, &start, &stop,
893 &step, &slicelen) < 0) {
894 return -1;
895 }
896 if (value == NULL) {
897 PyErr_SetString(PyExc_TypeError,
898 "mmap object doesn't support slice deletion");
899 return -1;
900 }
901 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
902 return -1;
903 if (vbuf.len != slicelen) {
904 PyErr_SetString(PyExc_IndexError,
905 "mmap slice assignment is wrong size");
906 PyBuffer_Release(&vbuf);
907 return -1;
908 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000909
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000910 if (slicelen == 0) {
911 }
912 else if (step == 1) {
913 memcpy(self->data + start, vbuf.buf, slicelen);
914 }
915 else {
916 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000917
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000918 for (cur = start, i = 0;
919 i < slicelen;
920 cur += step, i++)
921 {
922 self->data[cur] = ((char *)vbuf.buf)[i];
923 }
924 }
925 PyBuffer_Release(&vbuf);
926 return 0;
927 }
928 else {
929 PyErr_SetString(PyExc_TypeError,
930 "mmap indices must be integer");
931 return -1;
932 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000933}
934
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000935static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000936 (lenfunc)mmap_length, /*sq_length*/
937 (binaryfunc)mmap_concat, /*sq_concat*/
938 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
939 (ssizeargfunc)mmap_item, /*sq_item*/
940 0, /*sq_slice*/
941 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
942 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000943};
944
Thomas Woutersed03b412007-08-28 21:37:11 +0000945static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000946 (lenfunc)mmap_length,
947 (binaryfunc)mmap_subscript,
948 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000949};
950
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000951static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000952 (getbufferproc)mmap_buffer_getbuf,
953 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000954};
955
Georg Brandl86def6c2008-01-21 20:36:10 +0000956static PyObject *
957new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
958
Christian Heimese1c98112008-01-21 11:20:28 +0000959PyDoc_STRVAR(mmap_doc,
960"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
961\n\
962Maps length bytes from the file specified by the file handle fileno,\n\
963and returns a mmap object. If length is larger than the current size\n\
964of the file, the file is extended to contain length bytes. If length\n\
965is 0, the maximum length of the map is the current size of the file,\n\
966except that if the file is empty Windows raises an exception (you cannot\n\
967create an empty mapping on Windows).\n\
968\n\
969Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
970\n\
971Maps length bytes from the file specified by the file descriptor fileno,\n\
972and returns a mmap object. If length is 0, the maximum length of the map\n\
973will be the current size of the file when mmap is called.\n\
974flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
975private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000976object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000977that's shared with all other processes mapping the same areas of the file.\n\
978The default value is MAP_SHARED.\n\
979\n\
980To map anonymous memory, pass -1 as the fileno (both versions).");
981
982
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000983static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000984 PyVarObject_HEAD_INIT(NULL, 0)
985 "mmap.mmap", /* tp_name */
986 sizeof(mmap_object), /* tp_size */
987 0, /* tp_itemsize */
988 /* methods */
989 (destructor) mmap_object_dealloc, /* tp_dealloc */
990 0, /* tp_print */
991 0, /* tp_getattr */
992 0, /* tp_setattr */
993 0, /* tp_reserved */
994 0, /* tp_repr */
995 0, /* tp_as_number */
996 &mmap_as_sequence, /*tp_as_sequence*/
997 &mmap_as_mapping, /*tp_as_mapping*/
998 0, /*tp_hash*/
999 0, /*tp_call*/
1000 0, /*tp_str*/
1001 PyObject_GenericGetAttr, /*tp_getattro*/
1002 0, /*tp_setattro*/
1003 &mmap_as_buffer, /*tp_as_buffer*/
1004 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1005 mmap_doc, /*tp_doc*/
1006 0, /* tp_traverse */
1007 0, /* tp_clear */
1008 0, /* tp_richcompare */
1009 0, /* tp_weaklistoffset */
1010 0, /* tp_iter */
1011 0, /* tp_iternext */
1012 mmap_object_methods, /* tp_methods */
1013 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001014 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001015 0, /* tp_base */
1016 0, /* tp_dict */
1017 0, /* tp_descr_get */
1018 0, /* tp_descr_set */
1019 0, /* tp_dictoffset */
1020 0, /* tp_init */
1021 PyType_GenericAlloc, /* tp_alloc */
1022 new_mmap_object, /* tp_new */
1023 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001024};
1025
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001026
1027/* extract the map size from the given PyObject
1028
Thomas Wouters7e474022000-07-16 12:04:32 +00001029 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001030 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001031static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001032_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001033{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001034 if (o == NULL)
1035 return 0;
1036 if (PyIndex_Check(o)) {
1037 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1038 if (i==-1 && PyErr_Occurred())
1039 return -1;
1040 if (i < 0) {
1041 PyErr_Format(PyExc_OverflowError,
1042 "memory mapped %s must be positive",
1043 param);
1044 return -1;
1045 }
1046 return i;
1047 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001048
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001049 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1050 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001051}
1052
Tim Petersec0a5f02006-02-16 23:47:20 +00001053#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001054static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001055new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001056{
Neal Norwitzb5673922002-09-05 21:48:07 +00001057#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001058 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001059#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001060 mmap_object *m_obj;
1061 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1062 Py_ssize_t map_size, offset;
1063 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1064 int devzero = -1;
1065 int access = (int)ACCESS_DEFAULT;
1066 static char *keywords[] = {"fileno", "length",
1067 "flags", "prot",
1068 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001069
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001070 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
1071 &fd, &map_size_obj, &flags, &prot,
1072 &access, &offset_obj))
1073 return NULL;
1074 map_size = _GetMapSize(map_size_obj, "size");
1075 if (map_size < 0)
1076 return NULL;
1077 offset = _GetMapSize(offset_obj, "offset");
1078 if (offset < 0)
1079 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001080
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001081 if ((access != (int)ACCESS_DEFAULT) &&
1082 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1083 return PyErr_Format(PyExc_ValueError,
1084 "mmap can't specify both access and flags, prot.");
1085 switch ((access_mode)access) {
1086 case ACCESS_READ:
1087 flags = MAP_SHARED;
1088 prot = PROT_READ;
1089 break;
1090 case ACCESS_WRITE:
1091 flags = MAP_SHARED;
1092 prot = PROT_READ | PROT_WRITE;
1093 break;
1094 case ACCESS_COPY:
1095 flags = MAP_PRIVATE;
1096 prot = PROT_READ | PROT_WRITE;
1097 break;
1098 case ACCESS_DEFAULT:
1099 /* use the specified or default values of flags and prot */
1100 break;
1101 default:
1102 return PyErr_Format(PyExc_ValueError,
1103 "mmap invalid access parameter.");
1104 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001105
Christian Heimesa156e092008-02-16 07:38:31 +00001106 if (prot == PROT_READ) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001107 access = ACCESS_READ;
Christian Heimesa156e092008-02-16 07:38:31 +00001108 }
1109
Neal Norwitzb5673922002-09-05 21:48:07 +00001110#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001111# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001112 /* on OpenVMS we must ensure that all bytes are written to the file */
1113 if (fd != -1) {
1114 fsync(fd);
1115 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001116# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001117 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1118 if (map_size == 0) {
1119 map_size = st.st_size;
1120 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
1121 PyErr_SetString(PyExc_ValueError,
1122 "mmap length is greater than file size");
1123 return NULL;
1124 }
1125 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001126#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001127 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1128 if (m_obj == NULL) {return NULL;}
1129 m_obj->data = NULL;
1130 m_obj->size = (size_t) map_size;
1131 m_obj->pos = (size_t) 0;
1132 m_obj->exports = 0;
1133 m_obj->offset = offset;
1134 if (fd == -1) {
1135 m_obj->fd = -1;
1136 /* Assume the caller wants to map anonymous memory.
1137 This is the same behaviour as Windows. mmap.mmap(-1, size)
1138 on both Windows and Unix map anonymous memory.
1139 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001140#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001141 /* BSD way to map anonymous memory */
1142 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001143#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001144 /* SVR4 method to map anonymous memory is to open /dev/zero */
1145 fd = devzero = open("/dev/zero", O_RDWR);
1146 if (devzero == -1) {
1147 Py_DECREF(m_obj);
1148 PyErr_SetFromErrno(mmap_module_error);
1149 return NULL;
1150 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001151#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001152 } else {
1153 m_obj->fd = dup(fd);
1154 if (m_obj->fd == -1) {
1155 Py_DECREF(m_obj);
1156 PyErr_SetFromErrno(mmap_module_error);
1157 return NULL;
1158 }
1159 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001160
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001161 m_obj->data = mmap(NULL, map_size,
1162 prot, flags,
1163 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001164
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001165 if (devzero != -1) {
1166 close(devzero);
1167 }
1168
1169 if (m_obj->data == (char *)-1) {
1170 m_obj->data = NULL;
1171 Py_DECREF(m_obj);
1172 PyErr_SetFromErrno(mmap_module_error);
1173 return NULL;
1174 }
1175 m_obj->access = (access_mode)access;
1176 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001177}
1178#endif /* UNIX */
1179
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001180#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001181static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001182new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001183{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001184 mmap_object *m_obj;
1185 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1186 Py_ssize_t map_size, offset;
1187 DWORD off_hi; /* upper 32 bits of offset */
1188 DWORD off_lo; /* lower 32 bits of offset */
1189 DWORD size_hi; /* upper 32 bits of size */
1190 DWORD size_lo; /* lower 32 bits of size */
1191 char *tagname = "";
1192 DWORD dwErr = 0;
1193 int fileno;
1194 HANDLE fh = 0;
1195 int access = (access_mode)ACCESS_DEFAULT;
1196 DWORD flProtect, dwDesiredAccess;
1197 static char *keywords[] = { "fileno", "length",
1198 "tagname",
1199 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001200
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001201 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
1202 &fileno, &map_size_obj,
1203 &tagname, &access, &offset_obj)) {
1204 return NULL;
1205 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001206
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001207 switch((access_mode)access) {
1208 case ACCESS_READ:
1209 flProtect = PAGE_READONLY;
1210 dwDesiredAccess = FILE_MAP_READ;
1211 break;
1212 case ACCESS_DEFAULT: case ACCESS_WRITE:
1213 flProtect = PAGE_READWRITE;
1214 dwDesiredAccess = FILE_MAP_WRITE;
1215 break;
1216 case ACCESS_COPY:
1217 flProtect = PAGE_WRITECOPY;
1218 dwDesiredAccess = FILE_MAP_COPY;
1219 break;
1220 default:
1221 return PyErr_Format(PyExc_ValueError,
1222 "mmap invalid access parameter.");
1223 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001224
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001225 map_size = _GetMapSize(map_size_obj, "size");
1226 if (map_size < 0)
1227 return NULL;
1228 offset = _GetMapSize(offset_obj, "offset");
1229 if (offset < 0)
1230 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001231
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001232 /* assume -1 and 0 both mean invalid filedescriptor
1233 to 'anonymously' map memory.
1234 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1235 XXX: Should this code be added?
1236 if (fileno == 0)
1237 PyErr_WarnEx(PyExc_DeprecationWarning,
1238 "don't use 0 for anonymous memory",
1239 1);
1240 */
1241 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001242 /* Ensure that fileno is within the CRT's valid range */
1243 if (_PyVerify_fd(fileno) == 0) {
1244 PyErr_SetFromErrno(mmap_module_error);
1245 return NULL;
1246 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001247 fh = (HANDLE)_get_osfhandle(fileno);
1248 if (fh==(HANDLE)-1) {
1249 PyErr_SetFromErrno(mmap_module_error);
1250 return NULL;
1251 }
1252 /* Win9x appears to need us seeked to zero */
1253 lseek(fileno, 0, SEEK_SET);
1254 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001255
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001256 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1257 if (m_obj == NULL)
1258 return NULL;
1259 /* Set every field to an invalid marker, so we can safely
1260 destruct the object in the face of failure */
1261 m_obj->data = NULL;
1262 m_obj->file_handle = INVALID_HANDLE_VALUE;
1263 m_obj->map_handle = NULL;
1264 m_obj->tagname = NULL;
1265 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001266
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001267 if (fh) {
1268 /* It is necessary to duplicate the handle, so the
1269 Python code can close it on us */
1270 if (!DuplicateHandle(
1271 GetCurrentProcess(), /* source process handle */
1272 fh, /* handle to be duplicated */
1273 GetCurrentProcess(), /* target proc handle */
1274 (LPHANDLE)&m_obj->file_handle, /* result */
1275 0, /* access - ignored due to options value */
1276 FALSE, /* inherited by child processes? */
1277 DUPLICATE_SAME_ACCESS)) { /* options */
1278 dwErr = GetLastError();
1279 Py_DECREF(m_obj);
1280 PyErr_SetFromWindowsErr(dwErr);
1281 return NULL;
1282 }
1283 if (!map_size) {
1284 DWORD low,high;
1285 low = GetFileSize(fh, &high);
1286 /* low might just happen to have the value INVALID_FILE_SIZE;
1287 so we need to check the last error also. */
1288 if (low == INVALID_FILE_SIZE &&
1289 (dwErr = GetLastError()) != NO_ERROR) {
1290 Py_DECREF(m_obj);
1291 return PyErr_SetFromWindowsErr(dwErr);
1292 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001293
Martin v. Löwis15186072006-02-18 12:38:35 +00001294#if SIZEOF_SIZE_T > 4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001295 m_obj->size = (((size_t)high)<<32) + low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001296#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001297 if (high)
1298 /* File is too large to map completely */
1299 m_obj->size = (size_t)-1;
1300 else
1301 m_obj->size = low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001302#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001303 } else {
1304 m_obj->size = map_size;
1305 }
1306 }
1307 else {
1308 m_obj->size = map_size;
1309 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001310
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001311 /* set the initial position */
1312 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001313
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001314 m_obj->exports = 0;
1315 /* set the tag name */
1316 if (tagname != NULL && *tagname != '\0') {
1317 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1318 if (m_obj->tagname == NULL) {
1319 PyErr_NoMemory();
1320 Py_DECREF(m_obj);
1321 return NULL;
1322 }
1323 strcpy(m_obj->tagname, tagname);
1324 }
1325 else
1326 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001327
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001328 m_obj->access = (access_mode)access;
1329 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
1330 * more than 4 bytes, we need to break it apart. Else (size_t
1331 * consumes 4 bytes), C doesn't define what happens if we shift
1332 * right by 32, so we need different code.
1333 */
Tim Peterse564e7f2006-02-16 23:46:01 +00001334#if SIZEOF_SIZE_T > 4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001335 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1336 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1337 off_hi = (DWORD)(offset >> 32);
1338 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001339#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001340 size_hi = 0;
1341 size_lo = (DWORD)(offset + m_obj->size);
1342 off_hi = 0;
1343 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001344#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001345 /* For files, it would be sufficient to pass 0 as size.
1346 For anonymous maps, we have to pass the size explicitly. */
1347 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1348 NULL,
1349 flProtect,
1350 size_hi,
1351 size_lo,
1352 m_obj->tagname);
1353 if (m_obj->map_handle != NULL) {
1354 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1355 dwDesiredAccess,
1356 off_hi,
1357 off_lo,
1358 m_obj->size);
1359 if (m_obj->data != NULL)
1360 return (PyObject *)m_obj;
1361 else {
1362 dwErr = GetLastError();
1363 CloseHandle(m_obj->map_handle);
1364 m_obj->map_handle = NULL;
1365 }
1366 } else
1367 dwErr = GetLastError();
1368 Py_DECREF(m_obj);
1369 PyErr_SetFromWindowsErr(dwErr);
1370 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001371}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001372#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001373
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001374static void
1375setint(PyObject *d, const char *name, long value)
1376{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001377 PyObject *o = PyLong_FromLong(value);
1378 if (o && PyDict_SetItemString(d, name, o) == 0) {
1379 Py_DECREF(o);
1380 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001381}
1382
Martin v. Löwis1a214512008-06-11 05:26:20 +00001383
1384static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001385 PyModuleDef_HEAD_INIT,
1386 "mmap",
1387 NULL,
1388 -1,
1389 NULL,
1390 NULL,
1391 NULL,
1392 NULL,
1393 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001394};
1395
Mark Hammond62b1ab12002-07-23 06:31:15 +00001396PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001397PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001398{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001399 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001400
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001401 if (PyType_Ready(&mmap_object_type) < 0)
1402 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001403
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001404 module = PyModule_Create(&mmapmodule);
1405 if (module == NULL)
1406 return NULL;
1407 dict = PyModule_GetDict(module);
1408 if (!dict)
1409 return NULL;
1410 mmap_module_error = PyErr_NewException("mmap.error",
1411 PyExc_EnvironmentError , NULL);
1412 if (mmap_module_error == NULL)
1413 return NULL;
1414 PyDict_SetItemString(dict, "error", mmap_module_error);
1415 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001416#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001417 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001418#endif
1419#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001420 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001421#endif
1422#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001423 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001424#endif
1425
1426#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001427 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001428#endif
1429#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001430 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431#endif
1432#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001433 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001434#endif
1435#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001436 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001437#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001438#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001439 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1440 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001441#endif
1442
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001443 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001444
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001445 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001446
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001447 setint(dict, "ACCESS_READ", ACCESS_READ);
1448 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1449 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1450 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001451}