blob: 02e0989fcc71f49d92aada4df9f8ae6f7f87229f [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 */
Antoine Pitrou97696cb2011-02-21 23:46:27 +000093#ifdef MS_WINDOWS
94 PY_LONG_LONG offset;
95#else
96 off_t offset;
97#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000098 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000099
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000100#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000101 HANDLE map_handle;
102 HANDLE file_handle;
103 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104#endif
105
106#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000107 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000108#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000109
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111} mmap_object;
112
Tim Peters5ebfd362001-11-13 23:11:19 +0000113
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000114static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000115mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000116{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000117#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000118 if (m_obj->data != NULL)
119 UnmapViewOfFile (m_obj->data);
120 if (m_obj->map_handle != NULL)
121 CloseHandle (m_obj->map_handle);
122 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
123 CloseHandle (m_obj->file_handle);
124 if (m_obj->tagname)
125 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000126#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000127
128#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000129 if (m_obj->fd >= 0)
130 (void) close(m_obj->fd);
131 if (m_obj->data!=NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 munmap(m_obj->data, m_obj->size);
133 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000134#endif /* UNIX */
135
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000137}
138
139static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000140mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000141{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000142 if (self->exports > 0) {
143 PyErr_SetString(PyExc_BufferError, "cannot close "\
144 "exported pointers exist");
145 return NULL;
146 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000147#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000148 /* For each resource we maintain, we need to check
149 the value is valid, and if so, free the resource
150 and set the member value to an invalid value so
151 the dealloc does not attempt to resource clearing
152 again.
153 TODO - should we check for errors in the close operations???
154 */
155 if (self->data != NULL) {
156 UnmapViewOfFile(self->data);
157 self->data = NULL;
158 }
159 if (self->map_handle != NULL) {
160 CloseHandle(self->map_handle);
161 self->map_handle = NULL;
162 }
163 if (self->file_handle != INVALID_HANDLE_VALUE) {
164 CloseHandle(self->file_handle);
165 self->file_handle = INVALID_HANDLE_VALUE;
166 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000167#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000168
169#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000170 if (0 <= self->fd)
171 (void) close(self->fd);
172 self->fd = -1;
173 if (self->data != NULL) {
174 munmap(self->data, self->size);
175 self->data = NULL;
176 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000177#endif
178
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000179 Py_INCREF(Py_None);
180 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000181}
182
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000183#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000184#define CHECK_VALID(err) \
185do { \
186 if (self->map_handle == NULL) { \
187 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
188 return err; \
189 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000190} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000191#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000192
193#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000194#define CHECK_VALID(err) \
195do { \
196 if (self->data == NULL) { \
197 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
198 return err; \
199 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000200} while (0)
201#endif /* UNIX */
202
203static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000204mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000205 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000206{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000207 CHECK_VALID(NULL);
208 if (self->pos < self->size) {
209 char value = self->data[self->pos];
210 self->pos += 1;
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000211 return Py_BuildValue("B", (unsigned char)value);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212 } else {
213 PyErr_SetString(PyExc_ValueError, "read byte out of range");
214 return NULL;
215 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000216}
217
218static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000219mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000220 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000221{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 char *start = self->data+self->pos;
223 char *eof = self->data+self->size;
224 char *eol;
225 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000226
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000228
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000229 eol = memchr(start, '\n', self->size - self->pos);
230 if (!eol)
231 eol = eof;
232 else
233 ++eol; /* we're interested in the position after the
234 newline. */
235 result = PyBytes_FromStringAndSize(start, (eol - start));
236 self->pos += (eol - start);
237 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000238}
239
240static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000241mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000243{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000244 Py_ssize_t num_bytes, n;
245 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 CHECK_VALID(NULL);
248 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
249 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000250
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000251 /* silently 'adjust' out-of-range requests */
252 assert(self->size >= self->pos);
253 n = self->size - self->pos;
254 /* The difference can overflow, only if self->size is greater than
255 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
256 * because the mapped area and the returned string each need more
257 * than half of the addressable memory. So we clip the size, and let
258 * the code below raise MemoryError.
259 */
260 if (n < 0)
261 n = PY_SSIZE_T_MAX;
262 if (num_bytes < 0 || num_bytes > n) {
263 num_bytes = n;
264 }
265 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
266 self->pos += num_bytes;
267 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000268}
269
270static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000271mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 PyObject *args,
273 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000274{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 Py_ssize_t start = self->pos;
276 Py_ssize_t end = self->size;
277 const char *needle;
278 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000279
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000280 CHECK_VALID(NULL);
281 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
282 &needle, &len, &start, &end)) {
283 return NULL;
284 } else {
285 const char *p, *start_p, *end_p;
286 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000287
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000288 if (start < 0)
289 start += self->size;
290 if (start < 0)
291 start = 0;
292 else if ((size_t)start > self->size)
293 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000294
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000295 if (end < 0)
296 end += self->size;
297 if (end < 0)
298 end = 0;
299 else if ((size_t)end > self->size)
300 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000301
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 start_p = self->data + start;
303 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000304
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000305 for (p = (reverse ? end_p - len : start_p);
306 (p >= start_p) && (p + len <= end_p); p += sign) {
307 Py_ssize_t i;
308 for (i = 0; i < len && needle[i] == p[i]; ++i)
309 /* nothing */;
310 if (i == len) {
311 return PyLong_FromSsize_t(p - self->data);
312 }
313 }
314 return PyLong_FromLong(-1);
315 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000316}
317
Georg Brandlfceab5a2008-01-19 20:08:23 +0000318static PyObject *
319mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000321{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000323}
324
325static PyObject *
326mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000328{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000330}
331
Tim Petersec0a5f02006-02-16 23:47:20 +0000332static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000333is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000334{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000335 if (self->access != ACCESS_READ)
336 return 1;
337 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
338 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000339}
340
Tim Petersec0a5f02006-02-16 23:47:20 +0000341static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000342is_resizeable(mmap_object *self)
343{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000344 if (self->exports > 0) {
345 PyErr_SetString(PyExc_BufferError,
346 "mmap can't resize with extant buffers exported.");
347 return 0;
348 }
349 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
350 return 1;
351 PyErr_Format(PyExc_TypeError,
352 "mmap can't resize a readonly or copy-on-write memory map.");
353 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000354}
355
356
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000357static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000358mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000359 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000360{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000361 Py_ssize_t length;
362 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000363
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000364 CHECK_VALID(NULL);
365 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
366 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000367
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000368 if (!is_writable(self))
369 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000370
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000371 if ((self->pos + length) > self->size) {
372 PyErr_SetString(PyExc_ValueError, "data out of range");
373 return NULL;
374 }
375 memcpy(self->data+self->pos, data, length);
376 self->pos = self->pos+length;
377 Py_INCREF(Py_None);
378 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000379}
380
381static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000382mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000383 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000384{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000385 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000386
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000387 CHECK_VALID(NULL);
388 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
389 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000390
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000391 if (!is_writable(self))
392 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000393
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 if (self->pos < self->size) {
395 *(self->data+self->pos) = value;
396 self->pos += 1;
397 Py_INCREF(Py_None);
398 return Py_None;
399 }
400 else {
401 PyErr_SetString(PyExc_ValueError, "write byte out of range");
402 return NULL;
403 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000404}
Tim Petersec0a5f02006-02-16 23:47:20 +0000405
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000406static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000407mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000409{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000410 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000411
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000412#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000413 if (self->file_handle != INVALID_HANDLE_VALUE) {
414 DWORD low,high;
415 PY_LONG_LONG size;
416 low = GetFileSize(self->file_handle, &high);
417 if (low == INVALID_FILE_SIZE) {
418 /* It might be that the function appears to have failed,
419 when indeed its size equals INVALID_FILE_SIZE */
420 DWORD error = GetLastError();
421 if (error != NO_ERROR)
422 return PyErr_SetFromWindowsErr(error);
423 }
424 if (!high && low < LONG_MAX)
425 return PyLong_FromLong((long)low);
426 size = (((PY_LONG_LONG)high)<<32) + low;
427 return PyLong_FromLongLong(size);
428 } else {
429 return PyLong_FromSsize_t(self->size);
430 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000431#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000432
433#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000434 {
435 struct stat buf;
436 if (-1 == fstat(self->fd, &buf)) {
437 PyErr_SetFromErrno(mmap_module_error);
438 return NULL;
439 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000440#ifdef HAVE_LARGEFILE_SUPPORT
441 return PyLong_FromLongLong(buf.st_size);
442#else
443 return PyLong_FromLong(buf.st_size);
444#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000445 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000446#endif /* UNIX */
447}
448
449/* This assumes that you want the entire file mapped,
450 / and when recreating the map will make the new file
451 / have the new size
452 /
453 / Is this really necessary? This could easily be done
454 / from python by just closing and re-opening with the
455 / new size?
456 */
457
458static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000459mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000460 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000461{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 Py_ssize_t new_size;
463 CHECK_VALID(NULL);
464 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
465 !is_resizeable(self)) {
466 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000467#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 } else {
469 DWORD dwErrCode = 0;
470 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
471 /* First, unmap the file view */
472 UnmapViewOfFile(self->data);
473 self->data = NULL;
474 /* Close the mapping object */
475 CloseHandle(self->map_handle);
476 self->map_handle = NULL;
477 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000478 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
479 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
480 off_hi = (DWORD)(self->offset >> 32);
481 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
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 }
R. David Murraye194dd62010-10-18 01:14:06 +0000573
574 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
575 return PyLong_FromLong(0);
576
Christian Heimesaf98da12008-01-27 15:18:18 +0000577#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000578 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000579#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000580 /* XXX semantics of return value? */
581 /* XXX flags for msync? */
582 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
583 PyErr_SetFromErrno(mmap_module_error);
584 return NULL;
585 }
586 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000587#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000588 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
589 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000590#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000591}
592
593static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000594mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000595{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000596 Py_ssize_t dist;
597 int how=0;
598 CHECK_VALID(NULL);
599 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
600 return NULL;
601 else {
602 size_t where;
603 switch (how) {
604 case 0: /* relative to start */
605 if (dist < 0)
606 goto onoutofrange;
607 where = dist;
608 break;
609 case 1: /* relative to current position */
610 if ((Py_ssize_t)self->pos + dist < 0)
611 goto onoutofrange;
612 where = self->pos + dist;
613 break;
614 case 2: /* relative to end */
615 if ((Py_ssize_t)self->size + dist < 0)
616 goto onoutofrange;
617 where = self->size + dist;
618 break;
619 default:
620 PyErr_SetString(PyExc_ValueError, "unknown seek type");
621 return NULL;
622 }
623 if (where > self->size)
624 goto onoutofrange;
625 self->pos = where;
626 Py_INCREF(Py_None);
627 return Py_None;
628 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000629
Tim Peters5ebfd362001-11-13 23:11:19 +0000630 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000631 PyErr_SetString(PyExc_ValueError, "seek out of range");
632 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000633}
634
635static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000636mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000637{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000638 unsigned long dest, src, cnt;
639 CHECK_VALID(NULL);
640 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
641 !is_writable(self)) {
642 return NULL;
643 } else {
644 /* bounds check the values */
645 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
646 src < 0 || src > self->size || (src + cnt) > self->size ||
647 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
648 PyErr_SetString(PyExc_ValueError,
649 "source, destination, or count out of range");
650 return NULL;
651 }
652 memmove(self->data+dest, self->data+src, cnt);
653 Py_INCREF(Py_None);
654 return Py_None;
655 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000656}
657
Georg Brandl0bccc182010-08-01 14:50:00 +0000658static PyObject *
659mmap_closed_get(mmap_object *self)
660{
661#ifdef MS_WINDOWS
662 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
663#elif defined(UNIX)
664 return PyBool_FromLong(self->data == NULL ? 1 : 0);
665#endif
666}
667
668static PyObject *
669mmap__enter__method(mmap_object *self, PyObject *args)
670{
671 CHECK_VALID(NULL);
672
673 Py_INCREF(self);
674 return (PyObject *)self;
675}
676
677static PyObject *
678mmap__exit__method(PyObject *self, PyObject *args)
679{
680 return PyObject_CallMethod(self, "close", NULL);
681}
682
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000683static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000684 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
685 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
686 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
687 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
688 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
689 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
690 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
691 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
692 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
693 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
694 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
695 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
696 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
697 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000698 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
699 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000700 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000701};
702
Georg Brandl0bccc182010-08-01 14:50:00 +0000703static PyGetSetDef mmap_object_getset[] = {
704 {"closed", (getter) mmap_closed_get, NULL, NULL},
705 {NULL}
706};
707
708
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000709/* Functions for treating an mmap'ed file as a buffer */
710
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000711static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000712mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000713{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000714 CHECK_VALID(-1);
715 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
716 (self->access == ACCESS_READ), flags) < 0)
717 return -1;
718 self->exports++;
719 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000720}
721
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000722static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000723mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000724{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000725 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000726}
727
Martin v. Löwis18e16552006-02-15 17:27:45 +0000728static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000729mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000730{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000731 CHECK_VALID(-1);
732 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000733}
734
735static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000736mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000737{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000738 CHECK_VALID(NULL);
739 if (i < 0 || (size_t)i >= self->size) {
740 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
741 return NULL;
742 }
743 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000744}
745
746static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000747mmap_subscript(mmap_object *self, PyObject *item)
748{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000749 CHECK_VALID(NULL);
750 if (PyIndex_Check(item)) {
751 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
752 if (i == -1 && PyErr_Occurred())
753 return NULL;
754 if (i < 0)
755 i += self->size;
756 if (i < 0 || (size_t)i >= self->size) {
757 PyErr_SetString(PyExc_IndexError,
758 "mmap index out of range");
759 return NULL;
760 }
761 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
762 }
763 else if (PySlice_Check(item)) {
764 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000765
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000766 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000767 &start, &stop, &step, &slicelen) < 0) {
768 return NULL;
769 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000770
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000771 if (slicelen <= 0)
772 return PyBytes_FromStringAndSize("", 0);
773 else if (step == 1)
774 return PyBytes_FromStringAndSize(self->data + start,
775 slicelen);
776 else {
777 char *result_buf = (char *)PyMem_Malloc(slicelen);
778 Py_ssize_t cur, i;
779 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000780
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000781 if (result_buf == NULL)
782 return PyErr_NoMemory();
783 for (cur = start, i = 0; i < slicelen;
784 cur += step, i++) {
785 result_buf[i] = self->data[cur];
786 }
787 result = PyBytes_FromStringAndSize(result_buf,
788 slicelen);
789 PyMem_Free(result_buf);
790 return result;
791 }
792 }
793 else {
794 PyErr_SetString(PyExc_TypeError,
795 "mmap indices must be integers");
796 return NULL;
797 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000798}
799
800static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000801mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000802{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000803 CHECK_VALID(NULL);
804 PyErr_SetString(PyExc_SystemError,
805 "mmaps don't support concatenation");
806 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000807}
808
809static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000810mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000811{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000812 CHECK_VALID(NULL);
813 PyErr_SetString(PyExc_SystemError,
814 "mmaps don't support repeat operation");
815 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000816}
817
818static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000819mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000820{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000821 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000822
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000823 CHECK_VALID(-1);
824 if (i < 0 || (size_t)i >= self->size) {
825 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
826 return -1;
827 }
828 if (v == NULL) {
829 PyErr_SetString(PyExc_TypeError,
830 "mmap object doesn't support item deletion");
831 return -1;
832 }
833 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
834 PyErr_SetString(PyExc_IndexError,
835 "mmap assignment must be length-1 bytes()");
836 return -1;
837 }
838 if (!is_writable(self))
839 return -1;
840 buf = PyBytes_AsString(v);
841 self->data[i] = buf[0];
842 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000843}
844
Thomas Woutersed03b412007-08-28 21:37:11 +0000845static int
846mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
847{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000848 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000849
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000850 if (!is_writable(self))
851 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000852
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000853 if (PyIndex_Check(item)) {
854 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
855 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000856
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000857 if (i == -1 && PyErr_Occurred())
858 return -1;
859 if (i < 0)
860 i += self->size;
861 if (i < 0 || (size_t)i >= self->size) {
862 PyErr_SetString(PyExc_IndexError,
863 "mmap index out of range");
864 return -1;
865 }
866 if (value == NULL) {
867 PyErr_SetString(PyExc_TypeError,
868 "mmap doesn't support item deletion");
869 return -1;
870 }
871 if (!PyIndex_Check(value)) {
872 PyErr_SetString(PyExc_TypeError,
873 "mmap item value must be an int");
874 return -1;
875 }
876 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
877 if (v == -1 && PyErr_Occurred())
878 return -1;
879 if (v < 0 || v > 255) {
880 PyErr_SetString(PyExc_ValueError,
881 "mmap item value must be "
882 "in range(0, 256)");
883 return -1;
884 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000885 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000886 return 0;
887 }
888 else if (PySlice_Check(item)) {
889 Py_ssize_t start, stop, step, slicelen;
890 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000891
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000892 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000893 self->size, &start, &stop,
894 &step, &slicelen) < 0) {
895 return -1;
896 }
897 if (value == NULL) {
898 PyErr_SetString(PyExc_TypeError,
899 "mmap object doesn't support slice deletion");
900 return -1;
901 }
902 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
903 return -1;
904 if (vbuf.len != slicelen) {
905 PyErr_SetString(PyExc_IndexError,
906 "mmap slice assignment is wrong size");
907 PyBuffer_Release(&vbuf);
908 return -1;
909 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000910
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000911 if (slicelen == 0) {
912 }
913 else if (step == 1) {
914 memcpy(self->data + start, vbuf.buf, slicelen);
915 }
916 else {
917 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000918
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000919 for (cur = start, i = 0;
920 i < slicelen;
921 cur += step, i++)
922 {
923 self->data[cur] = ((char *)vbuf.buf)[i];
924 }
925 }
926 PyBuffer_Release(&vbuf);
927 return 0;
928 }
929 else {
930 PyErr_SetString(PyExc_TypeError,
931 "mmap indices must be integer");
932 return -1;
933 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000934}
935
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000936static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000937 (lenfunc)mmap_length, /*sq_length*/
938 (binaryfunc)mmap_concat, /*sq_concat*/
939 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
940 (ssizeargfunc)mmap_item, /*sq_item*/
941 0, /*sq_slice*/
942 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
943 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000944};
945
Thomas Woutersed03b412007-08-28 21:37:11 +0000946static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000947 (lenfunc)mmap_length,
948 (binaryfunc)mmap_subscript,
949 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000950};
951
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000952static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000953 (getbufferproc)mmap_buffer_getbuf,
954 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000955};
956
Georg Brandl86def6c2008-01-21 20:36:10 +0000957static PyObject *
958new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
959
Christian Heimese1c98112008-01-21 11:20:28 +0000960PyDoc_STRVAR(mmap_doc,
961"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
962\n\
963Maps length bytes from the file specified by the file handle fileno,\n\
964and returns a mmap object. If length is larger than the current size\n\
965of the file, the file is extended to contain length bytes. If length\n\
966is 0, the maximum length of the map is the current size of the file,\n\
967except that if the file is empty Windows raises an exception (you cannot\n\
968create an empty mapping on Windows).\n\
969\n\
970Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
971\n\
972Maps length bytes from the file specified by the file descriptor fileno,\n\
973and returns a mmap object. If length is 0, the maximum length of the map\n\
974will be the current size of the file when mmap is called.\n\
975flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
976private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000977object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000978that's shared with all other processes mapping the same areas of the file.\n\
979The default value is MAP_SHARED.\n\
980\n\
981To map anonymous memory, pass -1 as the fileno (both versions).");
982
983
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000984static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000985 PyVarObject_HEAD_INIT(NULL, 0)
986 "mmap.mmap", /* tp_name */
987 sizeof(mmap_object), /* tp_size */
988 0, /* tp_itemsize */
989 /* methods */
990 (destructor) mmap_object_dealloc, /* tp_dealloc */
991 0, /* tp_print */
992 0, /* tp_getattr */
993 0, /* tp_setattr */
994 0, /* tp_reserved */
995 0, /* tp_repr */
996 0, /* tp_as_number */
997 &mmap_as_sequence, /*tp_as_sequence*/
998 &mmap_as_mapping, /*tp_as_mapping*/
999 0, /*tp_hash*/
1000 0, /*tp_call*/
1001 0, /*tp_str*/
1002 PyObject_GenericGetAttr, /*tp_getattro*/
1003 0, /*tp_setattro*/
1004 &mmap_as_buffer, /*tp_as_buffer*/
1005 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1006 mmap_doc, /*tp_doc*/
1007 0, /* tp_traverse */
1008 0, /* tp_clear */
1009 0, /* tp_richcompare */
1010 0, /* tp_weaklistoffset */
1011 0, /* tp_iter */
1012 0, /* tp_iternext */
1013 mmap_object_methods, /* tp_methods */
1014 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001015 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001016 0, /* tp_base */
1017 0, /* tp_dict */
1018 0, /* tp_descr_get */
1019 0, /* tp_descr_set */
1020 0, /* tp_dictoffset */
1021 0, /* tp_init */
1022 PyType_GenericAlloc, /* tp_alloc */
1023 new_mmap_object, /* tp_new */
1024 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001025};
1026
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001027
1028/* extract the map size from the given PyObject
1029
Thomas Wouters7e474022000-07-16 12:04:32 +00001030 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001031 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001032static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001033_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001034{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001035 if (o == NULL)
1036 return 0;
1037 if (PyIndex_Check(o)) {
1038 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1039 if (i==-1 && PyErr_Occurred())
1040 return -1;
1041 if (i < 0) {
1042 PyErr_Format(PyExc_OverflowError,
1043 "memory mapped %s must be positive",
1044 param);
1045 return -1;
1046 }
1047 return i;
1048 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001049
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001050 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1051 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001052}
1053
Tim Petersec0a5f02006-02-16 23:47:20 +00001054#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001055#ifdef HAVE_LARGEFILE_SUPPORT
1056#define _Py_PARSE_OFF_T "L"
1057#else
1058#define _Py_PARSE_OFF_T "l"
1059#endif
1060
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001061static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001062new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001063{
Neal Norwitzb5673922002-09-05 21:48:07 +00001064#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001065 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001066#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001067 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001068 PyObject *map_size_obj = NULL;
1069 Py_ssize_t map_size;
1070 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001071 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1072 int devzero = -1;
1073 int access = (int)ACCESS_DEFAULT;
1074 static char *keywords[] = {"fileno", "length",
1075 "flags", "prot",
1076 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001077
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001078 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001079 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001080 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001081 return NULL;
1082 map_size = _GetMapSize(map_size_obj, "size");
1083 if (map_size < 0)
1084 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001085 if (offset < 0) {
1086 PyErr_SetString(PyExc_OverflowError,
1087 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001088 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001089 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001090
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001091 if ((access != (int)ACCESS_DEFAULT) &&
1092 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1093 return PyErr_Format(PyExc_ValueError,
1094 "mmap can't specify both access and flags, prot.");
1095 switch ((access_mode)access) {
1096 case ACCESS_READ:
1097 flags = MAP_SHARED;
1098 prot = PROT_READ;
1099 break;
1100 case ACCESS_WRITE:
1101 flags = MAP_SHARED;
1102 prot = PROT_READ | PROT_WRITE;
1103 break;
1104 case ACCESS_COPY:
1105 flags = MAP_PRIVATE;
1106 prot = PROT_READ | PROT_WRITE;
1107 break;
1108 case ACCESS_DEFAULT:
1109 /* use the specified or default values of flags and prot */
1110 break;
1111 default:
1112 return PyErr_Format(PyExc_ValueError,
1113 "mmap invalid access parameter.");
1114 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001115
Christian Heimesa156e092008-02-16 07:38:31 +00001116 if (prot == PROT_READ) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001117 access = ACCESS_READ;
Christian Heimesa156e092008-02-16 07:38:31 +00001118 }
1119
Neal Norwitzb5673922002-09-05 21:48:07 +00001120#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001121# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001122 /* on OpenVMS we must ensure that all bytes are written to the file */
1123 if (fd != -1) {
1124 fsync(fd);
1125 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001126# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001127 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1128 if (map_size == 0) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001129 if (offset >= st.st_size) {
1130 PyErr_SetString(PyExc_ValueError,
1131 "mmap offset is greater than file size");
1132 return NULL;
1133 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001134 off_t calc_size = st.st_size - offset;
1135 map_size = calc_size;
1136 if (map_size != calc_size) {
1137 PyErr_SetString(PyExc_ValueError,
1138 "mmap length is too large");
1139 return NULL;
1140 }
1141 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001142 PyErr_SetString(PyExc_ValueError,
1143 "mmap length is greater than file size");
1144 return NULL;
1145 }
1146 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001147#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001148 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1149 if (m_obj == NULL) {return NULL;}
1150 m_obj->data = NULL;
1151 m_obj->size = (size_t) map_size;
1152 m_obj->pos = (size_t) 0;
1153 m_obj->exports = 0;
1154 m_obj->offset = offset;
1155 if (fd == -1) {
1156 m_obj->fd = -1;
1157 /* Assume the caller wants to map anonymous memory.
1158 This is the same behaviour as Windows. mmap.mmap(-1, size)
1159 on both Windows and Unix map anonymous memory.
1160 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001161#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001162 /* BSD way to map anonymous memory */
1163 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001164#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001165 /* SVR4 method to map anonymous memory is to open /dev/zero */
1166 fd = devzero = open("/dev/zero", O_RDWR);
1167 if (devzero == -1) {
1168 Py_DECREF(m_obj);
1169 PyErr_SetFromErrno(mmap_module_error);
1170 return NULL;
1171 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001172#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001173 } else {
1174 m_obj->fd = dup(fd);
1175 if (m_obj->fd == -1) {
1176 Py_DECREF(m_obj);
1177 PyErr_SetFromErrno(mmap_module_error);
1178 return NULL;
1179 }
1180 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001181
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001182 m_obj->data = mmap(NULL, map_size,
1183 prot, flags,
1184 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001185
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001186 if (devzero != -1) {
1187 close(devzero);
1188 }
1189
1190 if (m_obj->data == (char *)-1) {
1191 m_obj->data = NULL;
1192 Py_DECREF(m_obj);
1193 PyErr_SetFromErrno(mmap_module_error);
1194 return NULL;
1195 }
1196 m_obj->access = (access_mode)access;
1197 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001198}
1199#endif /* UNIX */
1200
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001201#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001202
1203/* A note on sizes and offsets: while the actual map size must hold in a
1204 Py_ssize_t, both the total file size and the start offset can be longer
1205 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1206*/
1207
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001208static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001209new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001210{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001211 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001212 PyObject *map_size_obj = NULL;
1213 Py_ssize_t map_size;
1214 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001215 DWORD off_hi; /* upper 32 bits of offset */
1216 DWORD off_lo; /* lower 32 bits of offset */
1217 DWORD size_hi; /* upper 32 bits of size */
1218 DWORD size_lo; /* lower 32 bits of size */
1219 char *tagname = "";
1220 DWORD dwErr = 0;
1221 int fileno;
1222 HANDLE fh = 0;
1223 int access = (access_mode)ACCESS_DEFAULT;
1224 DWORD flProtect, dwDesiredAccess;
1225 static char *keywords[] = { "fileno", "length",
1226 "tagname",
1227 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001228
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001229 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001230 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001231 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001232 return NULL;
1233 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001234
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001235 switch((access_mode)access) {
1236 case ACCESS_READ:
1237 flProtect = PAGE_READONLY;
1238 dwDesiredAccess = FILE_MAP_READ;
1239 break;
1240 case ACCESS_DEFAULT: case ACCESS_WRITE:
1241 flProtect = PAGE_READWRITE;
1242 dwDesiredAccess = FILE_MAP_WRITE;
1243 break;
1244 case ACCESS_COPY:
1245 flProtect = PAGE_WRITECOPY;
1246 dwDesiredAccess = FILE_MAP_COPY;
1247 break;
1248 default:
1249 return PyErr_Format(PyExc_ValueError,
1250 "mmap invalid access parameter.");
1251 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001252
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001253 map_size = _GetMapSize(map_size_obj, "size");
1254 if (map_size < 0)
1255 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001256 if (offset < 0) {
1257 PyErr_SetString(PyExc_OverflowError,
1258 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001259 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001260 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001261
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001262 /* assume -1 and 0 both mean invalid filedescriptor
1263 to 'anonymously' map memory.
1264 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1265 XXX: Should this code be added?
1266 if (fileno == 0)
1267 PyErr_WarnEx(PyExc_DeprecationWarning,
1268 "don't use 0 for anonymous memory",
1269 1);
1270 */
1271 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001272 /* Ensure that fileno is within the CRT's valid range */
1273 if (_PyVerify_fd(fileno) == 0) {
1274 PyErr_SetFromErrno(mmap_module_error);
1275 return NULL;
1276 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001277 fh = (HANDLE)_get_osfhandle(fileno);
1278 if (fh==(HANDLE)-1) {
1279 PyErr_SetFromErrno(mmap_module_error);
1280 return NULL;
1281 }
1282 /* Win9x appears to need us seeked to zero */
1283 lseek(fileno, 0, SEEK_SET);
1284 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001285
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001286 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1287 if (m_obj == NULL)
1288 return NULL;
1289 /* Set every field to an invalid marker, so we can safely
1290 destruct the object in the face of failure */
1291 m_obj->data = NULL;
1292 m_obj->file_handle = INVALID_HANDLE_VALUE;
1293 m_obj->map_handle = NULL;
1294 m_obj->tagname = NULL;
1295 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001296
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001297 if (fh) {
1298 /* It is necessary to duplicate the handle, so the
1299 Python code can close it on us */
1300 if (!DuplicateHandle(
1301 GetCurrentProcess(), /* source process handle */
1302 fh, /* handle to be duplicated */
1303 GetCurrentProcess(), /* target proc handle */
1304 (LPHANDLE)&m_obj->file_handle, /* result */
1305 0, /* access - ignored due to options value */
1306 FALSE, /* inherited by child processes? */
1307 DUPLICATE_SAME_ACCESS)) { /* options */
1308 dwErr = GetLastError();
1309 Py_DECREF(m_obj);
1310 PyErr_SetFromWindowsErr(dwErr);
1311 return NULL;
1312 }
1313 if (!map_size) {
1314 DWORD low,high;
1315 low = GetFileSize(fh, &high);
1316 /* low might just happen to have the value INVALID_FILE_SIZE;
1317 so we need to check the last error also. */
1318 if (low == INVALID_FILE_SIZE &&
1319 (dwErr = GetLastError()) != NO_ERROR) {
1320 Py_DECREF(m_obj);
1321 return PyErr_SetFromWindowsErr(dwErr);
1322 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001323
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001324 size = (((PY_LONG_LONG) high) << 32) + low;
1325 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001326 PyErr_SetString(PyExc_ValueError,
1327 "mmap offset is greater than file size");
1328 Py_DECREF(m_obj);
1329 return NULL;
1330 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001331 if (offset - size > PY_SSIZE_T_MAX)
1332 /* Map area too large to fit in memory */
1333 m_obj->size = (Py_ssize_t) -1;
1334 else
1335 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001336 } else {
1337 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001338 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001339 }
1340 }
1341 else {
1342 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001343 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001344 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001345
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001346 /* set the initial position */
1347 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001348
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001349 m_obj->exports = 0;
1350 /* set the tag name */
1351 if (tagname != NULL && *tagname != '\0') {
1352 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1353 if (m_obj->tagname == NULL) {
1354 PyErr_NoMemory();
1355 Py_DECREF(m_obj);
1356 return NULL;
1357 }
1358 strcpy(m_obj->tagname, tagname);
1359 }
1360 else
1361 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001362
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001363 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001364 size_hi = (DWORD)(size >> 32);
1365 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001366 off_hi = (DWORD)(offset >> 32);
1367 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001368 /* For files, it would be sufficient to pass 0 as size.
1369 For anonymous maps, we have to pass the size explicitly. */
1370 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1371 NULL,
1372 flProtect,
1373 size_hi,
1374 size_lo,
1375 m_obj->tagname);
1376 if (m_obj->map_handle != NULL) {
1377 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1378 dwDesiredAccess,
1379 off_hi,
1380 off_lo,
1381 m_obj->size);
1382 if (m_obj->data != NULL)
1383 return (PyObject *)m_obj;
1384 else {
1385 dwErr = GetLastError();
1386 CloseHandle(m_obj->map_handle);
1387 m_obj->map_handle = NULL;
1388 }
1389 } else
1390 dwErr = GetLastError();
1391 Py_DECREF(m_obj);
1392 PyErr_SetFromWindowsErr(dwErr);
1393 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001394}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001395#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001396
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001397static void
1398setint(PyObject *d, const char *name, long value)
1399{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001400 PyObject *o = PyLong_FromLong(value);
1401 if (o && PyDict_SetItemString(d, name, o) == 0) {
1402 Py_DECREF(o);
1403 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001404}
1405
Martin v. Löwis1a214512008-06-11 05:26:20 +00001406
1407static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001408 PyModuleDef_HEAD_INIT,
1409 "mmap",
1410 NULL,
1411 -1,
1412 NULL,
1413 NULL,
1414 NULL,
1415 NULL,
1416 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001417};
1418
Mark Hammond62b1ab12002-07-23 06:31:15 +00001419PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001420PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001421{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001422 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001423
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001424 if (PyType_Ready(&mmap_object_type) < 0)
1425 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001426
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001427 module = PyModule_Create(&mmapmodule);
1428 if (module == NULL)
1429 return NULL;
1430 dict = PyModule_GetDict(module);
1431 if (!dict)
1432 return NULL;
1433 mmap_module_error = PyErr_NewException("mmap.error",
1434 PyExc_EnvironmentError , NULL);
1435 if (mmap_module_error == NULL)
1436 return NULL;
1437 PyDict_SetItemString(dict, "error", mmap_module_error);
1438 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001439#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001440 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001441#endif
1442#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001443 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001444#endif
1445#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001446 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001447#endif
1448
1449#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001450 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001451#endif
1452#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001453 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001454#endif
1455#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001456 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001457#endif
1458#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001459 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001460#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001461#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001462 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1463 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001464#endif
1465
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001466 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001467
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001468 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001469
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001470 setint(dict, "ACCESS_READ", ACCESS_READ);
1471 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1472 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1473 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001474}