blob: fdf39223567ad0ff8e4c8324c7d6a5005b2b9f59 [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:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001109 /* map prot to access type */
1110 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1111 /* ACCESS_DEFAULT */
1112 }
1113 else if (prot & PROT_WRITE) {
1114 access = ACCESS_WRITE;
1115 }
1116 else {
1117 access = ACCESS_READ;
1118 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001119 break;
1120 default:
1121 return PyErr_Format(PyExc_ValueError,
1122 "mmap invalid access parameter.");
1123 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001124
1125#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001126# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001127 /* on OpenVMS we must ensure that all bytes are written to the file */
1128 if (fd != -1) {
1129 fsync(fd);
1130 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001131# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001132 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1133 if (map_size == 0) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001134 if (offset >= st.st_size) {
1135 PyErr_SetString(PyExc_ValueError,
1136 "mmap offset is greater than file size");
1137 return NULL;
1138 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001139 off_t calc_size = st.st_size - offset;
1140 map_size = calc_size;
1141 if (map_size != calc_size) {
1142 PyErr_SetString(PyExc_ValueError,
1143 "mmap length is too large");
1144 return NULL;
1145 }
1146 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001147 PyErr_SetString(PyExc_ValueError,
1148 "mmap length is greater than file size");
1149 return NULL;
1150 }
1151 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001152#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001153 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1154 if (m_obj == NULL) {return NULL;}
1155 m_obj->data = NULL;
1156 m_obj->size = (size_t) map_size;
1157 m_obj->pos = (size_t) 0;
1158 m_obj->exports = 0;
1159 m_obj->offset = offset;
1160 if (fd == -1) {
1161 m_obj->fd = -1;
1162 /* Assume the caller wants to map anonymous memory.
1163 This is the same behaviour as Windows. mmap.mmap(-1, size)
1164 on both Windows and Unix map anonymous memory.
1165 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001166#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001167 /* BSD way to map anonymous memory */
1168 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001169#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001170 /* SVR4 method to map anonymous memory is to open /dev/zero */
1171 fd = devzero = open("/dev/zero", O_RDWR);
1172 if (devzero == -1) {
1173 Py_DECREF(m_obj);
1174 PyErr_SetFromErrno(mmap_module_error);
1175 return NULL;
1176 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001177#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001178 } else {
1179 m_obj->fd = dup(fd);
1180 if (m_obj->fd == -1) {
1181 Py_DECREF(m_obj);
1182 PyErr_SetFromErrno(mmap_module_error);
1183 return NULL;
1184 }
1185 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001186
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001187 m_obj->data = mmap(NULL, map_size,
1188 prot, flags,
1189 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001190
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001191 if (devzero != -1) {
1192 close(devzero);
1193 }
1194
1195 if (m_obj->data == (char *)-1) {
1196 m_obj->data = NULL;
1197 Py_DECREF(m_obj);
1198 PyErr_SetFromErrno(mmap_module_error);
1199 return NULL;
1200 }
1201 m_obj->access = (access_mode)access;
1202 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001203}
1204#endif /* UNIX */
1205
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001206#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001207
1208/* A note on sizes and offsets: while the actual map size must hold in a
1209 Py_ssize_t, both the total file size and the start offset can be longer
1210 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1211*/
1212
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001213static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001214new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001215{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001216 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001217 PyObject *map_size_obj = NULL;
1218 Py_ssize_t map_size;
1219 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001220 DWORD off_hi; /* upper 32 bits of offset */
1221 DWORD off_lo; /* lower 32 bits of offset */
1222 DWORD size_hi; /* upper 32 bits of size */
1223 DWORD size_lo; /* lower 32 bits of size */
1224 char *tagname = "";
1225 DWORD dwErr = 0;
1226 int fileno;
1227 HANDLE fh = 0;
1228 int access = (access_mode)ACCESS_DEFAULT;
1229 DWORD flProtect, dwDesiredAccess;
1230 static char *keywords[] = { "fileno", "length",
1231 "tagname",
1232 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001233
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001234 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001235 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001236 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001237 return NULL;
1238 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001239
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001240 switch((access_mode)access) {
1241 case ACCESS_READ:
1242 flProtect = PAGE_READONLY;
1243 dwDesiredAccess = FILE_MAP_READ;
1244 break;
1245 case ACCESS_DEFAULT: case ACCESS_WRITE:
1246 flProtect = PAGE_READWRITE;
1247 dwDesiredAccess = FILE_MAP_WRITE;
1248 break;
1249 case ACCESS_COPY:
1250 flProtect = PAGE_WRITECOPY;
1251 dwDesiredAccess = FILE_MAP_COPY;
1252 break;
1253 default:
1254 return PyErr_Format(PyExc_ValueError,
1255 "mmap invalid access parameter.");
1256 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001257
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001258 map_size = _GetMapSize(map_size_obj, "size");
1259 if (map_size < 0)
1260 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001261 if (offset < 0) {
1262 PyErr_SetString(PyExc_OverflowError,
1263 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001264 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001265 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001266
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001267 /* assume -1 and 0 both mean invalid filedescriptor
1268 to 'anonymously' map memory.
1269 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1270 XXX: Should this code be added?
1271 if (fileno == 0)
1272 PyErr_WarnEx(PyExc_DeprecationWarning,
1273 "don't use 0 for anonymous memory",
1274 1);
1275 */
1276 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001277 /* Ensure that fileno is within the CRT's valid range */
1278 if (_PyVerify_fd(fileno) == 0) {
1279 PyErr_SetFromErrno(mmap_module_error);
1280 return NULL;
1281 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001282 fh = (HANDLE)_get_osfhandle(fileno);
1283 if (fh==(HANDLE)-1) {
1284 PyErr_SetFromErrno(mmap_module_error);
1285 return NULL;
1286 }
1287 /* Win9x appears to need us seeked to zero */
1288 lseek(fileno, 0, SEEK_SET);
1289 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001291 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1292 if (m_obj == NULL)
1293 return NULL;
1294 /* Set every field to an invalid marker, so we can safely
1295 destruct the object in the face of failure */
1296 m_obj->data = NULL;
1297 m_obj->file_handle = INVALID_HANDLE_VALUE;
1298 m_obj->map_handle = NULL;
1299 m_obj->tagname = NULL;
1300 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001301
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001302 if (fh) {
1303 /* It is necessary to duplicate the handle, so the
1304 Python code can close it on us */
1305 if (!DuplicateHandle(
1306 GetCurrentProcess(), /* source process handle */
1307 fh, /* handle to be duplicated */
1308 GetCurrentProcess(), /* target proc handle */
1309 (LPHANDLE)&m_obj->file_handle, /* result */
1310 0, /* access - ignored due to options value */
1311 FALSE, /* inherited by child processes? */
1312 DUPLICATE_SAME_ACCESS)) { /* options */
1313 dwErr = GetLastError();
1314 Py_DECREF(m_obj);
1315 PyErr_SetFromWindowsErr(dwErr);
1316 return NULL;
1317 }
1318 if (!map_size) {
1319 DWORD low,high;
1320 low = GetFileSize(fh, &high);
1321 /* low might just happen to have the value INVALID_FILE_SIZE;
1322 so we need to check the last error also. */
1323 if (low == INVALID_FILE_SIZE &&
1324 (dwErr = GetLastError()) != NO_ERROR) {
1325 Py_DECREF(m_obj);
1326 return PyErr_SetFromWindowsErr(dwErr);
1327 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001328
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001329 size = (((PY_LONG_LONG) high) << 32) + low;
1330 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001331 PyErr_SetString(PyExc_ValueError,
1332 "mmap offset is greater than file size");
1333 Py_DECREF(m_obj);
1334 return NULL;
1335 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001336 if (offset - size > PY_SSIZE_T_MAX)
1337 /* Map area too large to fit in memory */
1338 m_obj->size = (Py_ssize_t) -1;
1339 else
1340 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001341 } 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 }
1345 }
1346 else {
1347 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001348 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001349 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001350
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001351 /* set the initial position */
1352 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001353
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001354 m_obj->exports = 0;
1355 /* set the tag name */
1356 if (tagname != NULL && *tagname != '\0') {
1357 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1358 if (m_obj->tagname == NULL) {
1359 PyErr_NoMemory();
1360 Py_DECREF(m_obj);
1361 return NULL;
1362 }
1363 strcpy(m_obj->tagname, tagname);
1364 }
1365 else
1366 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001367
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001368 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001369 size_hi = (DWORD)(size >> 32);
1370 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001371 off_hi = (DWORD)(offset >> 32);
1372 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001373 /* For files, it would be sufficient to pass 0 as size.
1374 For anonymous maps, we have to pass the size explicitly. */
1375 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1376 NULL,
1377 flProtect,
1378 size_hi,
1379 size_lo,
1380 m_obj->tagname);
1381 if (m_obj->map_handle != NULL) {
1382 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1383 dwDesiredAccess,
1384 off_hi,
1385 off_lo,
1386 m_obj->size);
1387 if (m_obj->data != NULL)
1388 return (PyObject *)m_obj;
1389 else {
1390 dwErr = GetLastError();
1391 CloseHandle(m_obj->map_handle);
1392 m_obj->map_handle = NULL;
1393 }
1394 } else
1395 dwErr = GetLastError();
1396 Py_DECREF(m_obj);
1397 PyErr_SetFromWindowsErr(dwErr);
1398 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001399}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001400#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001401
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001402static void
1403setint(PyObject *d, const char *name, long value)
1404{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001405 PyObject *o = PyLong_FromLong(value);
1406 if (o && PyDict_SetItemString(d, name, o) == 0) {
1407 Py_DECREF(o);
1408 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001409}
1410
Martin v. Löwis1a214512008-06-11 05:26:20 +00001411
1412static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001413 PyModuleDef_HEAD_INIT,
1414 "mmap",
1415 NULL,
1416 -1,
1417 NULL,
1418 NULL,
1419 NULL,
1420 NULL,
1421 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001422};
1423
Mark Hammond62b1ab12002-07-23 06:31:15 +00001424PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001425PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001426{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001427 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001428
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001429 if (PyType_Ready(&mmap_object_type) < 0)
1430 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001431
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001432 module = PyModule_Create(&mmapmodule);
1433 if (module == NULL)
1434 return NULL;
1435 dict = PyModule_GetDict(module);
1436 if (!dict)
1437 return NULL;
1438 mmap_module_error = PyErr_NewException("mmap.error",
1439 PyExc_EnvironmentError , NULL);
1440 if (mmap_module_error == NULL)
1441 return NULL;
1442 PyDict_SetItemString(dict, "error", mmap_module_error);
1443 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001444#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001445 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001446#endif
1447#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001448 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001449#endif
1450#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001451 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001452#endif
1453
1454#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001455 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001456#endif
1457#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001458 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001459#endif
1460#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001461 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001462#endif
1463#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001464 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001465#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001466#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001467 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1468 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001469#endif
1470
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001471 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001472
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001473 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001474
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001475 setint(dict, "ACCESS_READ", ACCESS_READ);
1476 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1477 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1478 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001479}