blob: 8c5c8ac80a00b090d3c0eeabcaab95fa9622f391 [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) {
128 msync(m_obj->data, m_obj->size, MS_SYNC);
129 munmap(m_obj->data, m_obj->size);
130 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000131#endif /* UNIX */
132
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000133 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000134}
135
136static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000137mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 if (self->exports > 0) {
140 PyErr_SetString(PyExc_BufferError, "cannot close "\
141 "exported pointers exist");
142 return NULL;
143 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000144#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 /* For each resource we maintain, we need to check
146 the value is valid, and if so, free the resource
147 and set the member value to an invalid value so
148 the dealloc does not attempt to resource clearing
149 again.
150 TODO - should we check for errors in the close operations???
151 */
152 if (self->data != NULL) {
153 UnmapViewOfFile(self->data);
154 self->data = NULL;
155 }
156 if (self->map_handle != NULL) {
157 CloseHandle(self->map_handle);
158 self->map_handle = NULL;
159 }
160 if (self->file_handle != INVALID_HANDLE_VALUE) {
161 CloseHandle(self->file_handle);
162 self->file_handle = INVALID_HANDLE_VALUE;
163 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000164#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000165
166#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 if (0 <= self->fd)
168 (void) close(self->fd);
169 self->fd = -1;
170 if (self->data != NULL) {
171 munmap(self->data, self->size);
172 self->data = NULL;
173 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000174#endif
175
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000176 Py_INCREF(Py_None);
177 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000178}
179
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000180#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000181#define CHECK_VALID(err) \
182do { \
183 if (self->map_handle == NULL) { \
184 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
185 return err; \
186 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000187} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000188#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000189
190#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000191#define CHECK_VALID(err) \
192do { \
193 if (self->data == NULL) { \
194 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
195 return err; \
196 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000197} while (0)
198#endif /* UNIX */
199
200static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000201mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000202 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000203{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 CHECK_VALID(NULL);
205 if (self->pos < self->size) {
206 char value = self->data[self->pos];
207 self->pos += 1;
208 return Py_BuildValue("b", value);
209 } else {
210 PyErr_SetString(PyExc_ValueError, "read byte out of range");
211 return NULL;
212 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000213}
214
215static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000216mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000219 char *start = self->data+self->pos;
220 char *eof = self->data+self->size;
221 char *eol;
222 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000224 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000225
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 eol = memchr(start, '\n', self->size - self->pos);
227 if (!eol)
228 eol = eof;
229 else
230 ++eol; /* we're interested in the position after the
231 newline. */
232 result = PyBytes_FromStringAndSize(start, (eol - start));
233 self->pos += (eol - start);
234 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000235}
236
237static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000238mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000239 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000240{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000241 Py_ssize_t num_bytes, n;
242 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000243
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000244 CHECK_VALID(NULL);
245 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
246 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000247
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000248 /* silently 'adjust' out-of-range requests */
249 assert(self->size >= self->pos);
250 n = self->size - self->pos;
251 /* The difference can overflow, only if self->size is greater than
252 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
253 * because the mapped area and the returned string each need more
254 * than half of the addressable memory. So we clip the size, and let
255 * the code below raise MemoryError.
256 */
257 if (n < 0)
258 n = PY_SSIZE_T_MAX;
259 if (num_bytes < 0 || num_bytes > n) {
260 num_bytes = n;
261 }
262 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
263 self->pos += num_bytes;
264 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000265}
266
267static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000268mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 PyObject *args,
270 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000271{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 Py_ssize_t start = self->pos;
273 Py_ssize_t end = self->size;
274 const char *needle;
275 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000276
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 CHECK_VALID(NULL);
278 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
279 &needle, &len, &start, &end)) {
280 return NULL;
281 } else {
282 const char *p, *start_p, *end_p;
283 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000284
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000285 if (start < 0)
286 start += self->size;
287 if (start < 0)
288 start = 0;
289 else if ((size_t)start > self->size)
290 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000291
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000292 if (end < 0)
293 end += self->size;
294 if (end < 0)
295 end = 0;
296 else if ((size_t)end > self->size)
297 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000298
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000299 start_p = self->data + start;
300 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000301
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 for (p = (reverse ? end_p - len : start_p);
303 (p >= start_p) && (p + len <= end_p); p += sign) {
304 Py_ssize_t i;
305 for (i = 0; i < len && needle[i] == p[i]; ++i)
306 /* nothing */;
307 if (i == len) {
308 return PyLong_FromSsize_t(p - self->data);
309 }
310 }
311 return PyLong_FromLong(-1);
312 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000313}
314
Georg Brandlfceab5a2008-01-19 20:08:23 +0000315static PyObject *
316mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000317 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000318{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000320}
321
322static PyObject *
323mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000324 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000325{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000326 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000327}
328
Tim Petersec0a5f02006-02-16 23:47:20 +0000329static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000330is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000331{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 if (self->access != ACCESS_READ)
333 return 1;
334 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
335 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000336}
337
Tim Petersec0a5f02006-02-16 23:47:20 +0000338static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000339is_resizeable(mmap_object *self)
340{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 if (self->exports > 0) {
342 PyErr_SetString(PyExc_BufferError,
343 "mmap can't resize with extant buffers exported.");
344 return 0;
345 }
346 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
347 return 1;
348 PyErr_Format(PyExc_TypeError,
349 "mmap can't resize a readonly or copy-on-write memory map.");
350 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000351}
352
353
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000354static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000355mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000356 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000357{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000358 Py_ssize_t length;
359 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000360
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000361 CHECK_VALID(NULL);
362 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
363 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000364
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000365 if (!is_writable(self))
366 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000367
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000368 if ((self->pos + length) > self->size) {
369 PyErr_SetString(PyExc_ValueError, "data out of range");
370 return NULL;
371 }
372 memcpy(self->data+self->pos, data, length);
373 self->pos = self->pos+length;
374 Py_INCREF(Py_None);
375 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000376}
377
378static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000379mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000380 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000381{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000382 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000383
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 CHECK_VALID(NULL);
385 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
386 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000387
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000388 if (!is_writable(self))
389 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000390
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000391 if (self->pos < self->size) {
392 *(self->data+self->pos) = value;
393 self->pos += 1;
394 Py_INCREF(Py_None);
395 return Py_None;
396 }
397 else {
398 PyErr_SetString(PyExc_ValueError, "write byte out of range");
399 return NULL;
400 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000401}
Tim Petersec0a5f02006-02-16 23:47:20 +0000402
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000403static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000404mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000405 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000406{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000407 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000408
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000409#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000410 if (self->file_handle != INVALID_HANDLE_VALUE) {
411 DWORD low,high;
412 PY_LONG_LONG size;
413 low = GetFileSize(self->file_handle, &high);
414 if (low == INVALID_FILE_SIZE) {
415 /* It might be that the function appears to have failed,
416 when indeed its size equals INVALID_FILE_SIZE */
417 DWORD error = GetLastError();
418 if (error != NO_ERROR)
419 return PyErr_SetFromWindowsErr(error);
420 }
421 if (!high && low < LONG_MAX)
422 return PyLong_FromLong((long)low);
423 size = (((PY_LONG_LONG)high)<<32) + low;
424 return PyLong_FromLongLong(size);
425 } else {
426 return PyLong_FromSsize_t(self->size);
427 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000428#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429
430#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000431 {
432 struct stat buf;
433 if (-1 == fstat(self->fd, &buf)) {
434 PyErr_SetFromErrno(mmap_module_error);
435 return NULL;
436 }
437 return PyLong_FromSsize_t(buf.st_size);
438 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000439#endif /* UNIX */
440}
441
442/* This assumes that you want the entire file mapped,
443 / and when recreating the map will make the new file
444 / have the new size
445 /
446 / Is this really necessary? This could easily be done
447 / from python by just closing and re-opening with the
448 / new size?
449 */
450
451static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000452mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000453 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000454{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000455 Py_ssize_t new_size;
456 CHECK_VALID(NULL);
457 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
458 !is_resizeable(self)) {
459 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000460#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000461 } else {
462 DWORD dwErrCode = 0;
463 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
464 /* First, unmap the file view */
465 UnmapViewOfFile(self->data);
466 self->data = NULL;
467 /* Close the mapping object */
468 CloseHandle(self->map_handle);
469 self->map_handle = NULL;
470 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000471#if SIZEOF_SIZE_T > 4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000472 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
473 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
474 off_hi = (DWORD)(self->offset >> 32);
475 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000476#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000477 newSizeHigh = 0;
478 newSizeLow = (DWORD)(self->offset + new_size);
479 off_hi = 0;
480 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000481#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000482 SetFilePointer(self->file_handle,
483 newSizeLow, &newSizeHigh, FILE_BEGIN);
484 /* Change the size of the file */
485 SetEndOfFile(self->file_handle);
486 /* Create another mapping object and remap the file view */
487 self->map_handle = CreateFileMapping(
488 self->file_handle,
489 NULL,
490 PAGE_READWRITE,
491 0,
492 0,
493 self->tagname);
494 if (self->map_handle != NULL) {
495 self->data = (char *) MapViewOfFile(self->map_handle,
496 FILE_MAP_WRITE,
497 off_hi,
498 off_lo,
499 new_size);
500 if (self->data != NULL) {
501 self->size = new_size;
502 Py_INCREF(Py_None);
503 return Py_None;
504 } else {
505 dwErrCode = GetLastError();
506 CloseHandle(self->map_handle);
507 self->map_handle = NULL;
508 }
509 } else {
510 dwErrCode = GetLastError();
511 }
512 PyErr_SetFromWindowsErr(dwErrCode);
513 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000514#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515
516#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000517#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000518 } else {
519 PyErr_SetString(PyExc_SystemError,
520 "mmap: resizing not available--no mremap()");
521 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000522#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000523 } else {
524 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000525
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000526 if (ftruncate(self->fd, self->offset + new_size) == -1) {
527 PyErr_SetFromErrno(mmap_module_error);
528 return NULL;
529 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000530
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000531#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000532 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000533#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000534 #if defined(__NetBSD__)
535 newmap = mremap(self->data, self->size, self->data, new_size, 0);
536 #else
537 newmap = mremap(self->data, self->size, new_size, 0);
538 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000539#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000540 if (newmap == (void *)-1)
541 {
542 PyErr_SetFromErrno(mmap_module_error);
543 return NULL;
544 }
545 self->data = newmap;
546 self->size = new_size;
547 Py_INCREF(Py_None);
548 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000549#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000551 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552}
553
554static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000555mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000556{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000557 CHECK_VALID(NULL);
558 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000559}
560
561static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000562mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000563{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000564 Py_ssize_t offset = 0;
565 Py_ssize_t size = self->size;
566 CHECK_VALID(NULL);
567 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
568 return NULL;
569 if ((size_t)(offset + size) > self->size) {
570 PyErr_SetString(PyExc_ValueError, "flush values out of range");
571 return NULL;
572 }
Christian Heimesaf98da12008-01-27 15:18:18 +0000573#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000574 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000575#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000576 /* XXX semantics of return value? */
577 /* XXX flags for msync? */
578 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
579 PyErr_SetFromErrno(mmap_module_error);
580 return NULL;
581 }
582 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000583#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000584 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
585 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000586#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000587}
588
589static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000590mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000591{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000592 Py_ssize_t dist;
593 int how=0;
594 CHECK_VALID(NULL);
595 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
596 return NULL;
597 else {
598 size_t where;
599 switch (how) {
600 case 0: /* relative to start */
601 if (dist < 0)
602 goto onoutofrange;
603 where = dist;
604 break;
605 case 1: /* relative to current position */
606 if ((Py_ssize_t)self->pos + dist < 0)
607 goto onoutofrange;
608 where = self->pos + dist;
609 break;
610 case 2: /* relative to end */
611 if ((Py_ssize_t)self->size + dist < 0)
612 goto onoutofrange;
613 where = self->size + dist;
614 break;
615 default:
616 PyErr_SetString(PyExc_ValueError, "unknown seek type");
617 return NULL;
618 }
619 if (where > self->size)
620 goto onoutofrange;
621 self->pos = where;
622 Py_INCREF(Py_None);
623 return Py_None;
624 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000625
Tim Peters5ebfd362001-11-13 23:11:19 +0000626 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000627 PyErr_SetString(PyExc_ValueError, "seek out of range");
628 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000629}
630
631static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000632mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000633{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000634 unsigned long dest, src, cnt;
635 CHECK_VALID(NULL);
636 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
637 !is_writable(self)) {
638 return NULL;
639 } else {
640 /* bounds check the values */
641 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
642 src < 0 || src > self->size || (src + cnt) > self->size ||
643 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
644 PyErr_SetString(PyExc_ValueError,
645 "source, destination, or count out of range");
646 return NULL;
647 }
648 memmove(self->data+dest, self->data+src, cnt);
649 Py_INCREF(Py_None);
650 return Py_None;
651 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652}
653
Georg Brandl0bccc182010-08-01 14:50:00 +0000654static PyObject *
655mmap_closed_get(mmap_object *self)
656{
657#ifdef MS_WINDOWS
658 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
659#elif defined(UNIX)
660 return PyBool_FromLong(self->data == NULL ? 1 : 0);
661#endif
662}
663
664static PyObject *
665mmap__enter__method(mmap_object *self, PyObject *args)
666{
667 CHECK_VALID(NULL);
668
669 Py_INCREF(self);
670 return (PyObject *)self;
671}
672
673static PyObject *
674mmap__exit__method(PyObject *self, PyObject *args)
675{
676 return PyObject_CallMethod(self, "close", NULL);
677}
678
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000680 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
681 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
682 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
683 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
684 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
685 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
686 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
687 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
688 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
689 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
690 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
691 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
692 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
693 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000694 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
695 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000696 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000697};
698
Georg Brandl0bccc182010-08-01 14:50:00 +0000699static PyGetSetDef mmap_object_getset[] = {
700 {"closed", (getter) mmap_closed_get, NULL, NULL},
701 {NULL}
702};
703
704
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000705/* Functions for treating an mmap'ed file as a buffer */
706
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000707static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000708mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000709{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000710 CHECK_VALID(-1);
711 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
712 (self->access == ACCESS_READ), flags) < 0)
713 return -1;
714 self->exports++;
715 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000716}
717
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000718static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000719mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000720{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000721 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000722}
723
Martin v. Löwis18e16552006-02-15 17:27:45 +0000724static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000725mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000726{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000727 CHECK_VALID(-1);
728 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000729}
730
731static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000732mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000733{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000734 CHECK_VALID(NULL);
735 if (i < 0 || (size_t)i >= self->size) {
736 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
737 return NULL;
738 }
739 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000740}
741
742static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000743mmap_subscript(mmap_object *self, PyObject *item)
744{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000745 CHECK_VALID(NULL);
746 if (PyIndex_Check(item)) {
747 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
748 if (i == -1 && PyErr_Occurred())
749 return NULL;
750 if (i < 0)
751 i += self->size;
752 if (i < 0 || (size_t)i >= self->size) {
753 PyErr_SetString(PyExc_IndexError,
754 "mmap index out of range");
755 return NULL;
756 }
757 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
758 }
759 else if (PySlice_Check(item)) {
760 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000761
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000762 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
763 &start, &stop, &step, &slicelen) < 0) {
764 return NULL;
765 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000766
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000767 if (slicelen <= 0)
768 return PyBytes_FromStringAndSize("", 0);
769 else if (step == 1)
770 return PyBytes_FromStringAndSize(self->data + start,
771 slicelen);
772 else {
773 char *result_buf = (char *)PyMem_Malloc(slicelen);
774 Py_ssize_t cur, i;
775 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000776
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000777 if (result_buf == NULL)
778 return PyErr_NoMemory();
779 for (cur = start, i = 0; i < slicelen;
780 cur += step, i++) {
781 result_buf[i] = self->data[cur];
782 }
783 result = PyBytes_FromStringAndSize(result_buf,
784 slicelen);
785 PyMem_Free(result_buf);
786 return result;
787 }
788 }
789 else {
790 PyErr_SetString(PyExc_TypeError,
791 "mmap indices must be integers");
792 return NULL;
793 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000794}
795
796static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000797mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000798{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000799 CHECK_VALID(NULL);
800 PyErr_SetString(PyExc_SystemError,
801 "mmaps don't support concatenation");
802 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000803}
804
805static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000806mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000807{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000808 CHECK_VALID(NULL);
809 PyErr_SetString(PyExc_SystemError,
810 "mmaps don't support repeat operation");
811 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000812}
813
814static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000815mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000816{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000817 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000818
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000819 CHECK_VALID(-1);
820 if (i < 0 || (size_t)i >= self->size) {
821 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
822 return -1;
823 }
824 if (v == NULL) {
825 PyErr_SetString(PyExc_TypeError,
826 "mmap object doesn't support item deletion");
827 return -1;
828 }
829 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
830 PyErr_SetString(PyExc_IndexError,
831 "mmap assignment must be length-1 bytes()");
832 return -1;
833 }
834 if (!is_writable(self))
835 return -1;
836 buf = PyBytes_AsString(v);
837 self->data[i] = buf[0];
838 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000839}
840
Thomas Woutersed03b412007-08-28 21:37:11 +0000841static int
842mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
843{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000844 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000845
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000846 if (!is_writable(self))
847 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000848
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000849 if (PyIndex_Check(item)) {
850 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
851 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000852
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000853 if (i == -1 && PyErr_Occurred())
854 return -1;
855 if (i < 0)
856 i += self->size;
857 if (i < 0 || (size_t)i >= self->size) {
858 PyErr_SetString(PyExc_IndexError,
859 "mmap index out of range");
860 return -1;
861 }
862 if (value == NULL) {
863 PyErr_SetString(PyExc_TypeError,
864 "mmap doesn't support item deletion");
865 return -1;
866 }
867 if (!PyIndex_Check(value)) {
868 PyErr_SetString(PyExc_TypeError,
869 "mmap item value must be an int");
870 return -1;
871 }
872 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
873 if (v == -1 && PyErr_Occurred())
874 return -1;
875 if (v < 0 || v > 255) {
876 PyErr_SetString(PyExc_ValueError,
877 "mmap item value must be "
878 "in range(0, 256)");
879 return -1;
880 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000881 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000882 return 0;
883 }
884 else if (PySlice_Check(item)) {
885 Py_ssize_t start, stop, step, slicelen;
886 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000887
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000888 if (PySlice_GetIndicesEx((PySliceObject *)item,
889 self->size, &start, &stop,
890 &step, &slicelen) < 0) {
891 return -1;
892 }
893 if (value == NULL) {
894 PyErr_SetString(PyExc_TypeError,
895 "mmap object doesn't support slice deletion");
896 return -1;
897 }
898 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
899 return -1;
900 if (vbuf.len != slicelen) {
901 PyErr_SetString(PyExc_IndexError,
902 "mmap slice assignment is wrong size");
903 PyBuffer_Release(&vbuf);
904 return -1;
905 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000906
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000907 if (slicelen == 0) {
908 }
909 else if (step == 1) {
910 memcpy(self->data + start, vbuf.buf, slicelen);
911 }
912 else {
913 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000914
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000915 for (cur = start, i = 0;
916 i < slicelen;
917 cur += step, i++)
918 {
919 self->data[cur] = ((char *)vbuf.buf)[i];
920 }
921 }
922 PyBuffer_Release(&vbuf);
923 return 0;
924 }
925 else {
926 PyErr_SetString(PyExc_TypeError,
927 "mmap indices must be integer");
928 return -1;
929 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000930}
931
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000932static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000933 (lenfunc)mmap_length, /*sq_length*/
934 (binaryfunc)mmap_concat, /*sq_concat*/
935 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
936 (ssizeargfunc)mmap_item, /*sq_item*/
937 0, /*sq_slice*/
938 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
939 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000940};
941
Thomas Woutersed03b412007-08-28 21:37:11 +0000942static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000943 (lenfunc)mmap_length,
944 (binaryfunc)mmap_subscript,
945 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000946};
947
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000948static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000949 (getbufferproc)mmap_buffer_getbuf,
950 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000951};
952
Georg Brandl86def6c2008-01-21 20:36:10 +0000953static PyObject *
954new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
955
Christian Heimese1c98112008-01-21 11:20:28 +0000956PyDoc_STRVAR(mmap_doc,
957"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
958\n\
959Maps length bytes from the file specified by the file handle fileno,\n\
960and returns a mmap object. If length is larger than the current size\n\
961of the file, the file is extended to contain length bytes. If length\n\
962is 0, the maximum length of the map is the current size of the file,\n\
963except that if the file is empty Windows raises an exception (you cannot\n\
964create an empty mapping on Windows).\n\
965\n\
966Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
967\n\
968Maps length bytes from the file specified by the file descriptor fileno,\n\
969and returns a mmap object. If length is 0, the maximum length of the map\n\
970will be the current size of the file when mmap is called.\n\
971flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
972private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000973object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000974that's shared with all other processes mapping the same areas of the file.\n\
975The default value is MAP_SHARED.\n\
976\n\
977To map anonymous memory, pass -1 as the fileno (both versions).");
978
979
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000980static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000981 PyVarObject_HEAD_INIT(NULL, 0)
982 "mmap.mmap", /* tp_name */
983 sizeof(mmap_object), /* tp_size */
984 0, /* tp_itemsize */
985 /* methods */
986 (destructor) mmap_object_dealloc, /* tp_dealloc */
987 0, /* tp_print */
988 0, /* tp_getattr */
989 0, /* tp_setattr */
990 0, /* tp_reserved */
991 0, /* tp_repr */
992 0, /* tp_as_number */
993 &mmap_as_sequence, /*tp_as_sequence*/
994 &mmap_as_mapping, /*tp_as_mapping*/
995 0, /*tp_hash*/
996 0, /*tp_call*/
997 0, /*tp_str*/
998 PyObject_GenericGetAttr, /*tp_getattro*/
999 0, /*tp_setattro*/
1000 &mmap_as_buffer, /*tp_as_buffer*/
1001 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1002 mmap_doc, /*tp_doc*/
1003 0, /* tp_traverse */
1004 0, /* tp_clear */
1005 0, /* tp_richcompare */
1006 0, /* tp_weaklistoffset */
1007 0, /* tp_iter */
1008 0, /* tp_iternext */
1009 mmap_object_methods, /* tp_methods */
1010 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001011 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001012 0, /* tp_base */
1013 0, /* tp_dict */
1014 0, /* tp_descr_get */
1015 0, /* tp_descr_set */
1016 0, /* tp_dictoffset */
1017 0, /* tp_init */
1018 PyType_GenericAlloc, /* tp_alloc */
1019 new_mmap_object, /* tp_new */
1020 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001021};
1022
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001023
1024/* extract the map size from the given PyObject
1025
Thomas Wouters7e474022000-07-16 12:04:32 +00001026 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001027 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001028static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001029_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001030{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001031 if (o == NULL)
1032 return 0;
1033 if (PyIndex_Check(o)) {
1034 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1035 if (i==-1 && PyErr_Occurred())
1036 return -1;
1037 if (i < 0) {
1038 PyErr_Format(PyExc_OverflowError,
1039 "memory mapped %s must be positive",
1040 param);
1041 return -1;
1042 }
1043 return i;
1044 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001045
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001046 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1047 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001048}
1049
Tim Petersec0a5f02006-02-16 23:47:20 +00001050#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001051static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001052new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001053{
Neal Norwitzb5673922002-09-05 21:48:07 +00001054#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001055 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001056#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001057 mmap_object *m_obj;
1058 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1059 Py_ssize_t map_size, offset;
1060 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1061 int devzero = -1;
1062 int access = (int)ACCESS_DEFAULT;
1063 static char *keywords[] = {"fileno", "length",
1064 "flags", "prot",
1065 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001066
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001067 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
1068 &fd, &map_size_obj, &flags, &prot,
1069 &access, &offset_obj))
1070 return NULL;
1071 map_size = _GetMapSize(map_size_obj, "size");
1072 if (map_size < 0)
1073 return NULL;
1074 offset = _GetMapSize(offset_obj, "offset");
1075 if (offset < 0)
1076 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001077
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001078 if ((access != (int)ACCESS_DEFAULT) &&
1079 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1080 return PyErr_Format(PyExc_ValueError,
1081 "mmap can't specify both access and flags, prot.");
1082 switch ((access_mode)access) {
1083 case ACCESS_READ:
1084 flags = MAP_SHARED;
1085 prot = PROT_READ;
1086 break;
1087 case ACCESS_WRITE:
1088 flags = MAP_SHARED;
1089 prot = PROT_READ | PROT_WRITE;
1090 break;
1091 case ACCESS_COPY:
1092 flags = MAP_PRIVATE;
1093 prot = PROT_READ | PROT_WRITE;
1094 break;
1095 case ACCESS_DEFAULT:
1096 /* use the specified or default values of flags and prot */
1097 break;
1098 default:
1099 return PyErr_Format(PyExc_ValueError,
1100 "mmap invalid access parameter.");
1101 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001102
Christian Heimesa156e092008-02-16 07:38:31 +00001103 if (prot == PROT_READ) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001104 access = ACCESS_READ;
Christian Heimesa156e092008-02-16 07:38:31 +00001105 }
1106
Neal Norwitzb5673922002-09-05 21:48:07 +00001107#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001108# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001109 /* on OpenVMS we must ensure that all bytes are written to the file */
1110 if (fd != -1) {
1111 fsync(fd);
1112 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001113# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001114 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1115 if (map_size == 0) {
1116 map_size = st.st_size;
1117 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
1118 PyErr_SetString(PyExc_ValueError,
1119 "mmap length is greater than file size");
1120 return NULL;
1121 }
1122 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001123#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001124 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1125 if (m_obj == NULL) {return NULL;}
1126 m_obj->data = NULL;
1127 m_obj->size = (size_t) map_size;
1128 m_obj->pos = (size_t) 0;
1129 m_obj->exports = 0;
1130 m_obj->offset = offset;
1131 if (fd == -1) {
1132 m_obj->fd = -1;
1133 /* Assume the caller wants to map anonymous memory.
1134 This is the same behaviour as Windows. mmap.mmap(-1, size)
1135 on both Windows and Unix map anonymous memory.
1136 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001137#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001138 /* BSD way to map anonymous memory */
1139 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001140#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001141 /* SVR4 method to map anonymous memory is to open /dev/zero */
1142 fd = devzero = open("/dev/zero", O_RDWR);
1143 if (devzero == -1) {
1144 Py_DECREF(m_obj);
1145 PyErr_SetFromErrno(mmap_module_error);
1146 return NULL;
1147 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001148#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001149 } else {
1150 m_obj->fd = dup(fd);
1151 if (m_obj->fd == -1) {
1152 Py_DECREF(m_obj);
1153 PyErr_SetFromErrno(mmap_module_error);
1154 return NULL;
1155 }
1156 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001157
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001158 m_obj->data = mmap(NULL, map_size,
1159 prot, flags,
1160 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001161
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001162 if (devzero != -1) {
1163 close(devzero);
1164 }
1165
1166 if (m_obj->data == (char *)-1) {
1167 m_obj->data = NULL;
1168 Py_DECREF(m_obj);
1169 PyErr_SetFromErrno(mmap_module_error);
1170 return NULL;
1171 }
1172 m_obj->access = (access_mode)access;
1173 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001174}
1175#endif /* UNIX */
1176
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001177#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001178static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001179new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001180{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001181 mmap_object *m_obj;
1182 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1183 Py_ssize_t map_size, offset;
1184 DWORD off_hi; /* upper 32 bits of offset */
1185 DWORD off_lo; /* lower 32 bits of offset */
1186 DWORD size_hi; /* upper 32 bits of size */
1187 DWORD size_lo; /* lower 32 bits of size */
1188 char *tagname = "";
1189 DWORD dwErr = 0;
1190 int fileno;
1191 HANDLE fh = 0;
1192 int access = (access_mode)ACCESS_DEFAULT;
1193 DWORD flProtect, dwDesiredAccess;
1194 static char *keywords[] = { "fileno", "length",
1195 "tagname",
1196 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001197
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001198 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
1199 &fileno, &map_size_obj,
1200 &tagname, &access, &offset_obj)) {
1201 return NULL;
1202 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001203
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001204 switch((access_mode)access) {
1205 case ACCESS_READ:
1206 flProtect = PAGE_READONLY;
1207 dwDesiredAccess = FILE_MAP_READ;
1208 break;
1209 case ACCESS_DEFAULT: case ACCESS_WRITE:
1210 flProtect = PAGE_READWRITE;
1211 dwDesiredAccess = FILE_MAP_WRITE;
1212 break;
1213 case ACCESS_COPY:
1214 flProtect = PAGE_WRITECOPY;
1215 dwDesiredAccess = FILE_MAP_COPY;
1216 break;
1217 default:
1218 return PyErr_Format(PyExc_ValueError,
1219 "mmap invalid access parameter.");
1220 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001221
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001222 map_size = _GetMapSize(map_size_obj, "size");
1223 if (map_size < 0)
1224 return NULL;
1225 offset = _GetMapSize(offset_obj, "offset");
1226 if (offset < 0)
1227 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001228
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001229 /* assume -1 and 0 both mean invalid filedescriptor
1230 to 'anonymously' map memory.
1231 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1232 XXX: Should this code be added?
1233 if (fileno == 0)
1234 PyErr_WarnEx(PyExc_DeprecationWarning,
1235 "don't use 0 for anonymous memory",
1236 1);
1237 */
1238 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001239 /* Ensure that fileno is within the CRT's valid range */
1240 if (_PyVerify_fd(fileno) == 0) {
1241 PyErr_SetFromErrno(mmap_module_error);
1242 return NULL;
1243 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001244 fh = (HANDLE)_get_osfhandle(fileno);
1245 if (fh==(HANDLE)-1) {
1246 PyErr_SetFromErrno(mmap_module_error);
1247 return NULL;
1248 }
1249 /* Win9x appears to need us seeked to zero */
1250 lseek(fileno, 0, SEEK_SET);
1251 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001252
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001253 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1254 if (m_obj == NULL)
1255 return NULL;
1256 /* Set every field to an invalid marker, so we can safely
1257 destruct the object in the face of failure */
1258 m_obj->data = NULL;
1259 m_obj->file_handle = INVALID_HANDLE_VALUE;
1260 m_obj->map_handle = NULL;
1261 m_obj->tagname = NULL;
1262 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001263
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001264 if (fh) {
1265 /* It is necessary to duplicate the handle, so the
1266 Python code can close it on us */
1267 if (!DuplicateHandle(
1268 GetCurrentProcess(), /* source process handle */
1269 fh, /* handle to be duplicated */
1270 GetCurrentProcess(), /* target proc handle */
1271 (LPHANDLE)&m_obj->file_handle, /* result */
1272 0, /* access - ignored due to options value */
1273 FALSE, /* inherited by child processes? */
1274 DUPLICATE_SAME_ACCESS)) { /* options */
1275 dwErr = GetLastError();
1276 Py_DECREF(m_obj);
1277 PyErr_SetFromWindowsErr(dwErr);
1278 return NULL;
1279 }
1280 if (!map_size) {
1281 DWORD low,high;
1282 low = GetFileSize(fh, &high);
1283 /* low might just happen to have the value INVALID_FILE_SIZE;
1284 so we need to check the last error also. */
1285 if (low == INVALID_FILE_SIZE &&
1286 (dwErr = GetLastError()) != NO_ERROR) {
1287 Py_DECREF(m_obj);
1288 return PyErr_SetFromWindowsErr(dwErr);
1289 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001290
Martin v. Löwis15186072006-02-18 12:38:35 +00001291#if SIZEOF_SIZE_T > 4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001292 m_obj->size = (((size_t)high)<<32) + low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001293#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001294 if (high)
1295 /* File is too large to map completely */
1296 m_obj->size = (size_t)-1;
1297 else
1298 m_obj->size = low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001299#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001300 } else {
1301 m_obj->size = map_size;
1302 }
1303 }
1304 else {
1305 m_obj->size = map_size;
1306 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001307
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001308 /* set the initial position */
1309 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001310
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001311 m_obj->exports = 0;
1312 /* set the tag name */
1313 if (tagname != NULL && *tagname != '\0') {
1314 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1315 if (m_obj->tagname == NULL) {
1316 PyErr_NoMemory();
1317 Py_DECREF(m_obj);
1318 return NULL;
1319 }
1320 strcpy(m_obj->tagname, tagname);
1321 }
1322 else
1323 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001325 m_obj->access = (access_mode)access;
1326 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
1327 * more than 4 bytes, we need to break it apart. Else (size_t
1328 * consumes 4 bytes), C doesn't define what happens if we shift
1329 * right by 32, so we need different code.
1330 */
Tim Peterse564e7f2006-02-16 23:46:01 +00001331#if SIZEOF_SIZE_T > 4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001332 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1333 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1334 off_hi = (DWORD)(offset >> 32);
1335 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001336#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001337 size_hi = 0;
1338 size_lo = (DWORD)(offset + m_obj->size);
1339 off_hi = 0;
1340 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001341#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001342 /* For files, it would be sufficient to pass 0 as size.
1343 For anonymous maps, we have to pass the size explicitly. */
1344 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1345 NULL,
1346 flProtect,
1347 size_hi,
1348 size_lo,
1349 m_obj->tagname);
1350 if (m_obj->map_handle != NULL) {
1351 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1352 dwDesiredAccess,
1353 off_hi,
1354 off_lo,
1355 m_obj->size);
1356 if (m_obj->data != NULL)
1357 return (PyObject *)m_obj;
1358 else {
1359 dwErr = GetLastError();
1360 CloseHandle(m_obj->map_handle);
1361 m_obj->map_handle = NULL;
1362 }
1363 } else
1364 dwErr = GetLastError();
1365 Py_DECREF(m_obj);
1366 PyErr_SetFromWindowsErr(dwErr);
1367 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001368}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001369#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001370
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001371static void
1372setint(PyObject *d, const char *name, long value)
1373{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001374 PyObject *o = PyLong_FromLong(value);
1375 if (o && PyDict_SetItemString(d, name, o) == 0) {
1376 Py_DECREF(o);
1377 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001378}
1379
Martin v. Löwis1a214512008-06-11 05:26:20 +00001380
1381static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001382 PyModuleDef_HEAD_INIT,
1383 "mmap",
1384 NULL,
1385 -1,
1386 NULL,
1387 NULL,
1388 NULL,
1389 NULL,
1390 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001391};
1392
Mark Hammond62b1ab12002-07-23 06:31:15 +00001393PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001394PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001395{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001396 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001397
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001398 if (PyType_Ready(&mmap_object_type) < 0)
1399 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001400
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001401 module = PyModule_Create(&mmapmodule);
1402 if (module == NULL)
1403 return NULL;
1404 dict = PyModule_GetDict(module);
1405 if (!dict)
1406 return NULL;
1407 mmap_module_error = PyErr_NewException("mmap.error",
1408 PyExc_EnvironmentError , NULL);
1409 if (mmap_module_error == NULL)
1410 return NULL;
1411 PyDict_SetItemString(dict, "error", mmap_module_error);
1412 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001413#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001414 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001415#endif
1416#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001417 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001418#endif
1419#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001420 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001421#endif
1422
1423#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001424 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001425#endif
1426#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001427 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001428#endif
1429#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001430 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431#endif
1432#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001433 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001434#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001435#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001436 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1437 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001438#endif
1439
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001440 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001441
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001442 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001443
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001444 setint(dict, "ACCESS_READ", ACCESS_READ);
1445 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1446 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1447 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001448}