blob: 352dd5297909fae6c38869db103cede2f58a1f93 [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
Victor Stinnera6cd0cf2011-05-02 01:05:37 +020026# ifdef __APPLE__
27# include <fcntl.h>
28# endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#endif
30
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000031#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000032#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000033static int
34my_getpagesize(void)
35{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000036 SYSTEM_INFO si;
37 GetSystemInfo(&si);
38 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000039}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000040
41static int
42my_getallocationgranularity (void)
43{
44
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000045 SYSTEM_INFO si;
46 GetSystemInfo(&si);
47 return si.dwAllocationGranularity;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000048}
49
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#endif
51
52#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000053#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000054#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000055
Fred Drake145f96e2000-10-01 17:50:46 +000056#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
57static int
58my_getpagesize(void)
59{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000060 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000061}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000062
63#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000064#else
65#define my_getpagesize getpagesize
66#endif
67
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000068#endif /* UNIX */
69
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000071
72#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000073#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000074#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000075
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000076/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000077#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
78# define MAP_ANONYMOUS MAP_ANON
79#endif
80
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000081static PyObject *mmap_module_error;
82
Tim Peters5ebfd362001-11-13 23:11:19 +000083typedef enum
84{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000085 ACCESS_DEFAULT,
86 ACCESS_READ,
87 ACCESS_WRITE,
88 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000089} access_mode;
90
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000091typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000092 PyObject_HEAD
93 char * data;
94 size_t size;
95 size_t pos; /* relative to offset */
Antoine Pitrou97696cb2011-02-21 23:46:27 +000096#ifdef MS_WINDOWS
97 PY_LONG_LONG offset;
98#else
99 off_t offset;
100#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000101 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000102
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000103#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 HANDLE map_handle;
105 HANDLE file_handle;
106 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107#endif
108
109#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000112
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000114} mmap_object;
115
Tim Peters5ebfd362001-11-13 23:11:19 +0000116
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000117static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000118mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000119{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000120#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000121 if (m_obj->data != NULL)
122 UnmapViewOfFile (m_obj->data);
123 if (m_obj->map_handle != NULL)
124 CloseHandle (m_obj->map_handle);
125 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
126 CloseHandle (m_obj->file_handle);
127 if (m_obj->tagname)
128 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000129#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000130
131#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 if (m_obj->fd >= 0)
133 (void) close(m_obj->fd);
134 if (m_obj->data!=NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000135 munmap(m_obj->data, m_obj->size);
136 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000137#endif /* UNIX */
138
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000140}
141
142static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000143mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000144{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 if (self->exports > 0) {
146 PyErr_SetString(PyExc_BufferError, "cannot close "\
147 "exported pointers exist");
148 return NULL;
149 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000150#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 /* For each resource we maintain, we need to check
152 the value is valid, and if so, free the resource
153 and set the member value to an invalid value so
154 the dealloc does not attempt to resource clearing
155 again.
156 TODO - should we check for errors in the close operations???
157 */
158 if (self->data != NULL) {
159 UnmapViewOfFile(self->data);
160 self->data = NULL;
161 }
162 if (self->map_handle != NULL) {
163 CloseHandle(self->map_handle);
164 self->map_handle = NULL;
165 }
166 if (self->file_handle != INVALID_HANDLE_VALUE) {
167 CloseHandle(self->file_handle);
168 self->file_handle = INVALID_HANDLE_VALUE;
169 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000170#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000171
172#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000173 if (0 <= self->fd)
174 (void) close(self->fd);
175 self->fd = -1;
176 if (self->data != NULL) {
177 munmap(self->data, self->size);
178 self->data = NULL;
179 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180#endif
181
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000182 Py_INCREF(Py_None);
183 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000184}
185
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000186#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187#define CHECK_VALID(err) \
188do { \
189 if (self->map_handle == NULL) { \
190 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
191 return err; \
192 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000193} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000194#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000195
196#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000197#define CHECK_VALID(err) \
198do { \
199 if (self->data == NULL) { \
200 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
201 return err; \
202 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000203} while (0)
204#endif /* UNIX */
205
206static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000207mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000209{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 CHECK_VALID(NULL);
211 if (self->pos < self->size) {
212 char value = self->data[self->pos];
213 self->pos += 1;
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000214 return Py_BuildValue("B", (unsigned char)value);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000215 } else {
216 PyErr_SetString(PyExc_ValueError, "read byte out of range");
217 return NULL;
218 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000219}
220
221static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000222mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 char *start = self->data+self->pos;
226 char *eof = self->data+self->size;
227 char *eol;
228 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000229
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000230 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000231
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000232 eol = memchr(start, '\n', self->size - self->pos);
233 if (!eol)
234 eol = eof;
235 else
236 ++eol; /* we're interested in the position after the
237 newline. */
238 result = PyBytes_FromStringAndSize(start, (eol - start));
239 self->pos += (eol - start);
240 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241}
242
243static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000244mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 Py_ssize_t num_bytes, n;
248 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000249
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000250 CHECK_VALID(NULL);
251 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
252 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000253
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000254 /* silently 'adjust' out-of-range requests */
255 assert(self->size >= self->pos);
256 n = self->size - self->pos;
257 /* The difference can overflow, only if self->size is greater than
258 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
259 * because the mapped area and the returned string each need more
260 * than half of the addressable memory. So we clip the size, and let
261 * the code below raise MemoryError.
262 */
263 if (n < 0)
264 n = PY_SSIZE_T_MAX;
265 if (num_bytes < 0 || num_bytes > n) {
266 num_bytes = n;
267 }
268 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
269 self->pos += num_bytes;
270 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000271}
272
273static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000274mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 PyObject *args,
276 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000277{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000278 Py_ssize_t start = self->pos;
279 Py_ssize_t end = self->size;
280 const char *needle;
281 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000282
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000283 CHECK_VALID(NULL);
284 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
285 &needle, &len, &start, &end)) {
286 return NULL;
287 } else {
288 const char *p, *start_p, *end_p;
289 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 if (start < 0)
292 start += self->size;
293 if (start < 0)
294 start = 0;
295 else if ((size_t)start > self->size)
296 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000297
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 if (end < 0)
299 end += self->size;
300 if (end < 0)
301 end = 0;
302 else if ((size_t)end > self->size)
303 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000304
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000305 start_p = self->data + start;
306 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000307
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000308 for (p = (reverse ? end_p - len : start_p);
309 (p >= start_p) && (p + len <= end_p); p += sign) {
310 Py_ssize_t i;
311 for (i = 0; i < len && needle[i] == p[i]; ++i)
312 /* nothing */;
313 if (i == len) {
314 return PyLong_FromSsize_t(p - self->data);
315 }
316 }
317 return PyLong_FromLong(-1);
318 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000319}
320
Georg Brandlfceab5a2008-01-19 20:08:23 +0000321static PyObject *
322mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000324{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000326}
327
328static PyObject *
329mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000330 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000331{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000333}
334
Tim Petersec0a5f02006-02-16 23:47:20 +0000335static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000336is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000337{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000338 if (self->access != ACCESS_READ)
339 return 1;
340 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
341 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000342}
343
Tim Petersec0a5f02006-02-16 23:47:20 +0000344static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000345is_resizeable(mmap_object *self)
346{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000347 if (self->exports > 0) {
348 PyErr_SetString(PyExc_BufferError,
349 "mmap can't resize with extant buffers exported.");
350 return 0;
351 }
352 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
353 return 1;
354 PyErr_Format(PyExc_TypeError,
355 "mmap can't resize a readonly or copy-on-write memory map.");
356 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000357}
358
359
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000360static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000361mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000362 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000363{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000364 Py_ssize_t length;
365 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000366
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 CHECK_VALID(NULL);
368 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
369 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000370
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000371 if (!is_writable(self))
372 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000373
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 if ((self->pos + length) > self->size) {
375 PyErr_SetString(PyExc_ValueError, "data out of range");
376 return NULL;
377 }
378 memcpy(self->data+self->pos, data, length);
379 self->pos = self->pos+length;
380 Py_INCREF(Py_None);
381 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000382}
383
384static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000385mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000387{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000388 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000389
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000390 CHECK_VALID(NULL);
391 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
392 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000393
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 if (!is_writable(self))
395 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000396
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 if (self->pos < self->size) {
398 *(self->data+self->pos) = value;
399 self->pos += 1;
400 Py_INCREF(Py_None);
401 return Py_None;
402 }
403 else {
404 PyErr_SetString(PyExc_ValueError, "write byte out of range");
405 return NULL;
406 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000407}
Tim Petersec0a5f02006-02-16 23:47:20 +0000408
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000409static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000410mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000411 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000412{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000413 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000414
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000415#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000416 if (self->file_handle != INVALID_HANDLE_VALUE) {
417 DWORD low,high;
418 PY_LONG_LONG size;
419 low = GetFileSize(self->file_handle, &high);
420 if (low == INVALID_FILE_SIZE) {
421 /* It might be that the function appears to have failed,
422 when indeed its size equals INVALID_FILE_SIZE */
423 DWORD error = GetLastError();
424 if (error != NO_ERROR)
425 return PyErr_SetFromWindowsErr(error);
426 }
427 if (!high && low < LONG_MAX)
428 return PyLong_FromLong((long)low);
429 size = (((PY_LONG_LONG)high)<<32) + low;
430 return PyLong_FromLongLong(size);
431 } else {
432 return PyLong_FromSsize_t(self->size);
433 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000434#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000435
436#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000437 {
438 struct stat buf;
439 if (-1 == fstat(self->fd, &buf)) {
440 PyErr_SetFromErrno(mmap_module_error);
441 return NULL;
442 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000443#ifdef HAVE_LARGEFILE_SUPPORT
444 return PyLong_FromLongLong(buf.st_size);
445#else
446 return PyLong_FromLong(buf.st_size);
447#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000448 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000449#endif /* UNIX */
450}
451
452/* This assumes that you want the entire file mapped,
453 / and when recreating the map will make the new file
454 / have the new size
455 /
456 / Is this really necessary? This could easily be done
457 / from python by just closing and re-opening with the
458 / new size?
459 */
460
461static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000462mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000463 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000464{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 Py_ssize_t new_size;
466 CHECK_VALID(NULL);
467 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
468 !is_resizeable(self)) {
469 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000470#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000471 } else {
472 DWORD dwErrCode = 0;
473 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
474 /* First, unmap the file view */
475 UnmapViewOfFile(self->data);
476 self->data = NULL;
477 /* Close the mapping object */
478 CloseHandle(self->map_handle);
479 self->map_handle = NULL;
480 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000481 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
482 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
483 off_hi = (DWORD)(self->offset >> 32);
484 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000485 SetFilePointer(self->file_handle,
486 newSizeLow, &newSizeHigh, FILE_BEGIN);
487 /* Change the size of the file */
488 SetEndOfFile(self->file_handle);
489 /* Create another mapping object and remap the file view */
490 self->map_handle = CreateFileMapping(
491 self->file_handle,
492 NULL,
493 PAGE_READWRITE,
494 0,
495 0,
496 self->tagname);
497 if (self->map_handle != NULL) {
498 self->data = (char *) MapViewOfFile(self->map_handle,
499 FILE_MAP_WRITE,
500 off_hi,
501 off_lo,
502 new_size);
503 if (self->data != NULL) {
504 self->size = new_size;
505 Py_INCREF(Py_None);
506 return Py_None;
507 } else {
508 dwErrCode = GetLastError();
509 CloseHandle(self->map_handle);
510 self->map_handle = NULL;
511 }
512 } else {
513 dwErrCode = GetLastError();
514 }
515 PyErr_SetFromWindowsErr(dwErrCode);
516 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000517#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000518
519#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000520#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000521 } else {
522 PyErr_SetString(PyExc_SystemError,
523 "mmap: resizing not available--no mremap()");
524 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000525#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000526 } else {
527 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000528
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000529 if (ftruncate(self->fd, self->offset + new_size) == -1) {
530 PyErr_SetFromErrno(mmap_module_error);
531 return NULL;
532 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000533
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000534#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000535 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000536#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000537 #if defined(__NetBSD__)
538 newmap = mremap(self->data, self->size, self->data, new_size, 0);
539 #else
540 newmap = mremap(self->data, self->size, new_size, 0);
541 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000542#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000543 if (newmap == (void *)-1)
544 {
545 PyErr_SetFromErrno(mmap_module_error);
546 return NULL;
547 }
548 self->data = newmap;
549 self->size = new_size;
550 Py_INCREF(Py_None);
551 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000552#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000554 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000555}
556
557static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000558mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000559{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000560 CHECK_VALID(NULL);
561 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000562}
563
564static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000565mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000566{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 Py_ssize_t offset = 0;
568 Py_ssize_t size = self->size;
569 CHECK_VALID(NULL);
570 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
571 return NULL;
572 if ((size_t)(offset + size) > self->size) {
573 PyErr_SetString(PyExc_ValueError, "flush values out of range");
574 return NULL;
575 }
R. David Murraye194dd62010-10-18 01:14:06 +0000576
577 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
578 return PyLong_FromLong(0);
579
Christian Heimesaf98da12008-01-27 15:18:18 +0000580#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000581 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000582#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000583 /* XXX semantics of return value? */
584 /* XXX flags for msync? */
585 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
586 PyErr_SetFromErrno(mmap_module_error);
587 return NULL;
588 }
589 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000590#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000591 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
592 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000593#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000594}
595
596static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000597mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000598{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000599 Py_ssize_t dist;
600 int how=0;
601 CHECK_VALID(NULL);
602 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
603 return NULL;
604 else {
605 size_t where;
606 switch (how) {
607 case 0: /* relative to start */
608 if (dist < 0)
609 goto onoutofrange;
610 where = dist;
611 break;
612 case 1: /* relative to current position */
613 if ((Py_ssize_t)self->pos + dist < 0)
614 goto onoutofrange;
615 where = self->pos + dist;
616 break;
617 case 2: /* relative to end */
618 if ((Py_ssize_t)self->size + dist < 0)
619 goto onoutofrange;
620 where = self->size + dist;
621 break;
622 default:
623 PyErr_SetString(PyExc_ValueError, "unknown seek type");
624 return NULL;
625 }
626 if (where > self->size)
627 goto onoutofrange;
628 self->pos = where;
629 Py_INCREF(Py_None);
630 return Py_None;
631 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000632
Tim Peters5ebfd362001-11-13 23:11:19 +0000633 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000634 PyErr_SetString(PyExc_ValueError, "seek out of range");
635 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000636}
637
638static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000639mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000640{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000641 unsigned long dest, src, cnt;
642 CHECK_VALID(NULL);
643 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
644 !is_writable(self)) {
645 return NULL;
646 } else {
647 /* bounds check the values */
648 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
649 src < 0 || src > self->size || (src + cnt) > self->size ||
650 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
651 PyErr_SetString(PyExc_ValueError,
652 "source, destination, or count out of range");
653 return NULL;
654 }
655 memmove(self->data+dest, self->data+src, cnt);
656 Py_INCREF(Py_None);
657 return Py_None;
658 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000659}
660
Georg Brandl0bccc182010-08-01 14:50:00 +0000661static PyObject *
662mmap_closed_get(mmap_object *self)
663{
664#ifdef MS_WINDOWS
665 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
666#elif defined(UNIX)
667 return PyBool_FromLong(self->data == NULL ? 1 : 0);
668#endif
669}
670
671static PyObject *
672mmap__enter__method(mmap_object *self, PyObject *args)
673{
674 CHECK_VALID(NULL);
675
676 Py_INCREF(self);
677 return (PyObject *)self;
678}
679
680static PyObject *
681mmap__exit__method(PyObject *self, PyObject *args)
682{
683 return PyObject_CallMethod(self, "close", NULL);
684}
685
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000686static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000687 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
688 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
689 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
690 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
691 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
692 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
693 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
694 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
695 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
696 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
697 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
698 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
699 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
700 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000701 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
702 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000703 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000704};
705
Georg Brandl0bccc182010-08-01 14:50:00 +0000706static PyGetSetDef mmap_object_getset[] = {
707 {"closed", (getter) mmap_closed_get, NULL, NULL},
708 {NULL}
709};
710
711
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000712/* Functions for treating an mmap'ed file as a buffer */
713
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000714static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000715mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000716{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000717 CHECK_VALID(-1);
718 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
719 (self->access == ACCESS_READ), flags) < 0)
720 return -1;
721 self->exports++;
722 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000723}
724
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000725static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000726mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000727{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000728 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000729}
730
Martin v. Löwis18e16552006-02-15 17:27:45 +0000731static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000732mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000733{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000734 CHECK_VALID(-1);
735 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000736}
737
738static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000739mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000740{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000741 CHECK_VALID(NULL);
742 if (i < 0 || (size_t)i >= self->size) {
743 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
744 return NULL;
745 }
746 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000747}
748
749static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000750mmap_subscript(mmap_object *self, PyObject *item)
751{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000752 CHECK_VALID(NULL);
753 if (PyIndex_Check(item)) {
754 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
755 if (i == -1 && PyErr_Occurred())
756 return NULL;
757 if (i < 0)
758 i += self->size;
759 if (i < 0 || (size_t)i >= self->size) {
760 PyErr_SetString(PyExc_IndexError,
761 "mmap index out of range");
762 return NULL;
763 }
764 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
765 }
766 else if (PySlice_Check(item)) {
767 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000768
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000769 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000770 &start, &stop, &step, &slicelen) < 0) {
771 return NULL;
772 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000773
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000774 if (slicelen <= 0)
775 return PyBytes_FromStringAndSize("", 0);
776 else if (step == 1)
777 return PyBytes_FromStringAndSize(self->data + start,
778 slicelen);
779 else {
780 char *result_buf = (char *)PyMem_Malloc(slicelen);
781 Py_ssize_t cur, i;
782 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000783
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000784 if (result_buf == NULL)
785 return PyErr_NoMemory();
786 for (cur = start, i = 0; i < slicelen;
787 cur += step, i++) {
788 result_buf[i] = self->data[cur];
789 }
790 result = PyBytes_FromStringAndSize(result_buf,
791 slicelen);
792 PyMem_Free(result_buf);
793 return result;
794 }
795 }
796 else {
797 PyErr_SetString(PyExc_TypeError,
798 "mmap indices must be integers");
799 return NULL;
800 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000801}
802
803static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000804mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000805{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000806 CHECK_VALID(NULL);
807 PyErr_SetString(PyExc_SystemError,
808 "mmaps don't support concatenation");
809 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000810}
811
812static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000813mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000814{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000815 CHECK_VALID(NULL);
816 PyErr_SetString(PyExc_SystemError,
817 "mmaps don't support repeat operation");
818 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000819}
820
821static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000822mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000823{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000824 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000825
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000826 CHECK_VALID(-1);
827 if (i < 0 || (size_t)i >= self->size) {
828 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
829 return -1;
830 }
831 if (v == NULL) {
832 PyErr_SetString(PyExc_TypeError,
833 "mmap object doesn't support item deletion");
834 return -1;
835 }
836 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
837 PyErr_SetString(PyExc_IndexError,
838 "mmap assignment must be length-1 bytes()");
839 return -1;
840 }
841 if (!is_writable(self))
842 return -1;
843 buf = PyBytes_AsString(v);
844 self->data[i] = buf[0];
845 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000846}
847
Thomas Woutersed03b412007-08-28 21:37:11 +0000848static int
849mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
850{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000851 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000852
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000853 if (!is_writable(self))
854 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000855
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000856 if (PyIndex_Check(item)) {
857 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
858 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000859
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000860 if (i == -1 && PyErr_Occurred())
861 return -1;
862 if (i < 0)
863 i += self->size;
864 if (i < 0 || (size_t)i >= self->size) {
865 PyErr_SetString(PyExc_IndexError,
866 "mmap index out of range");
867 return -1;
868 }
869 if (value == NULL) {
870 PyErr_SetString(PyExc_TypeError,
871 "mmap doesn't support item deletion");
872 return -1;
873 }
874 if (!PyIndex_Check(value)) {
875 PyErr_SetString(PyExc_TypeError,
876 "mmap item value must be an int");
877 return -1;
878 }
879 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
880 if (v == -1 && PyErr_Occurred())
881 return -1;
882 if (v < 0 || v > 255) {
883 PyErr_SetString(PyExc_ValueError,
884 "mmap item value must be "
885 "in range(0, 256)");
886 return -1;
887 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000888 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000889 return 0;
890 }
891 else if (PySlice_Check(item)) {
892 Py_ssize_t start, stop, step, slicelen;
893 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000894
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000895 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000896 self->size, &start, &stop,
897 &step, &slicelen) < 0) {
898 return -1;
899 }
900 if (value == NULL) {
901 PyErr_SetString(PyExc_TypeError,
902 "mmap object doesn't support slice deletion");
903 return -1;
904 }
905 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
906 return -1;
907 if (vbuf.len != slicelen) {
908 PyErr_SetString(PyExc_IndexError,
909 "mmap slice assignment is wrong size");
910 PyBuffer_Release(&vbuf);
911 return -1;
912 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000913
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000914 if (slicelen == 0) {
915 }
916 else if (step == 1) {
917 memcpy(self->data + start, vbuf.buf, slicelen);
918 }
919 else {
920 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000921
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000922 for (cur = start, i = 0;
923 i < slicelen;
924 cur += step, i++)
925 {
926 self->data[cur] = ((char *)vbuf.buf)[i];
927 }
928 }
929 PyBuffer_Release(&vbuf);
930 return 0;
931 }
932 else {
933 PyErr_SetString(PyExc_TypeError,
934 "mmap indices must be integer");
935 return -1;
936 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000937}
938
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000939static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000940 (lenfunc)mmap_length, /*sq_length*/
941 (binaryfunc)mmap_concat, /*sq_concat*/
942 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
943 (ssizeargfunc)mmap_item, /*sq_item*/
944 0, /*sq_slice*/
945 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
946 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000947};
948
Thomas Woutersed03b412007-08-28 21:37:11 +0000949static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000950 (lenfunc)mmap_length,
951 (binaryfunc)mmap_subscript,
952 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000953};
954
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000955static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000956 (getbufferproc)mmap_buffer_getbuf,
957 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000958};
959
Georg Brandl86def6c2008-01-21 20:36:10 +0000960static PyObject *
961new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
962
Christian Heimese1c98112008-01-21 11:20:28 +0000963PyDoc_STRVAR(mmap_doc,
964"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
965\n\
966Maps length bytes from the file specified by the file handle fileno,\n\
967and returns a mmap object. If length is larger than the current size\n\
968of the file, the file is extended to contain length bytes. If length\n\
969is 0, the maximum length of the map is the current size of the file,\n\
970except that if the file is empty Windows raises an exception (you cannot\n\
971create an empty mapping on Windows).\n\
972\n\
973Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
974\n\
975Maps length bytes from the file specified by the file descriptor fileno,\n\
976and returns a mmap object. If length is 0, the maximum length of the map\n\
977will be the current size of the file when mmap is called.\n\
978flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
979private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000980object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000981that's shared with all other processes mapping the same areas of the file.\n\
982The default value is MAP_SHARED.\n\
983\n\
984To map anonymous memory, pass -1 as the fileno (both versions).");
985
986
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000987static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000988 PyVarObject_HEAD_INIT(NULL, 0)
989 "mmap.mmap", /* tp_name */
990 sizeof(mmap_object), /* tp_size */
991 0, /* tp_itemsize */
992 /* methods */
993 (destructor) mmap_object_dealloc, /* tp_dealloc */
994 0, /* tp_print */
995 0, /* tp_getattr */
996 0, /* tp_setattr */
997 0, /* tp_reserved */
998 0, /* tp_repr */
999 0, /* tp_as_number */
1000 &mmap_as_sequence, /*tp_as_sequence*/
1001 &mmap_as_mapping, /*tp_as_mapping*/
1002 0, /*tp_hash*/
1003 0, /*tp_call*/
1004 0, /*tp_str*/
1005 PyObject_GenericGetAttr, /*tp_getattro*/
1006 0, /*tp_setattro*/
1007 &mmap_as_buffer, /*tp_as_buffer*/
1008 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1009 mmap_doc, /*tp_doc*/
1010 0, /* tp_traverse */
1011 0, /* tp_clear */
1012 0, /* tp_richcompare */
1013 0, /* tp_weaklistoffset */
1014 0, /* tp_iter */
1015 0, /* tp_iternext */
1016 mmap_object_methods, /* tp_methods */
1017 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001018 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001019 0, /* tp_base */
1020 0, /* tp_dict */
1021 0, /* tp_descr_get */
1022 0, /* tp_descr_set */
1023 0, /* tp_dictoffset */
1024 0, /* tp_init */
1025 PyType_GenericAlloc, /* tp_alloc */
1026 new_mmap_object, /* tp_new */
1027 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001028};
1029
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001030
1031/* extract the map size from the given PyObject
1032
Thomas Wouters7e474022000-07-16 12:04:32 +00001033 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001034 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001035static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001036_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001037{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001038 if (o == NULL)
1039 return 0;
1040 if (PyIndex_Check(o)) {
1041 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1042 if (i==-1 && PyErr_Occurred())
1043 return -1;
1044 if (i < 0) {
1045 PyErr_Format(PyExc_OverflowError,
1046 "memory mapped %s must be positive",
1047 param);
1048 return -1;
1049 }
1050 return i;
1051 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001052
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001053 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1054 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001055}
1056
Tim Petersec0a5f02006-02-16 23:47:20 +00001057#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001058#ifdef HAVE_LARGEFILE_SUPPORT
1059#define _Py_PARSE_OFF_T "L"
1060#else
1061#define _Py_PARSE_OFF_T "l"
1062#endif
1063
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001064static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001065new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001066{
Neal Norwitzb5673922002-09-05 21:48:07 +00001067#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001068 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001069#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001070 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001071 PyObject *map_size_obj = NULL;
1072 Py_ssize_t map_size;
1073 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001074 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1075 int devzero = -1;
1076 int access = (int)ACCESS_DEFAULT;
1077 static char *keywords[] = {"fileno", "length",
1078 "flags", "prot",
1079 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001080
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001081 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001082 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001083 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001084 return NULL;
1085 map_size = _GetMapSize(map_size_obj, "size");
1086 if (map_size < 0)
1087 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001088 if (offset < 0) {
1089 PyErr_SetString(PyExc_OverflowError,
1090 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001091 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001092 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001093
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001094 if ((access != (int)ACCESS_DEFAULT) &&
1095 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1096 return PyErr_Format(PyExc_ValueError,
1097 "mmap can't specify both access and flags, prot.");
1098 switch ((access_mode)access) {
1099 case ACCESS_READ:
1100 flags = MAP_SHARED;
1101 prot = PROT_READ;
1102 break;
1103 case ACCESS_WRITE:
1104 flags = MAP_SHARED;
1105 prot = PROT_READ | PROT_WRITE;
1106 break;
1107 case ACCESS_COPY:
1108 flags = MAP_PRIVATE;
1109 prot = PROT_READ | PROT_WRITE;
1110 break;
1111 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001112 /* map prot to access type */
1113 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1114 /* ACCESS_DEFAULT */
1115 }
1116 else if (prot & PROT_WRITE) {
1117 access = ACCESS_WRITE;
1118 }
1119 else {
1120 access = ACCESS_READ;
1121 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001122 break;
1123 default:
1124 return PyErr_Format(PyExc_ValueError,
1125 "mmap invalid access parameter.");
1126 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001127
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001128#ifdef __APPLE__
1129 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1130 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1131 if (fd != -1)
1132 (void)fcntl(fd, F_FULLFSYNC);
1133#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001134#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001135# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001136 /* on OpenVMS we must ensure that all bytes are written to the file */
1137 if (fd != -1) {
1138 fsync(fd);
1139 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001140# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001141 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1142 if (map_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001143 if (st.st_size == 0) {
1144 PyErr_SetString(PyExc_ValueError,
1145 "cannot mmap an empty file");
1146 return NULL;
1147 }
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001148 if (offset >= st.st_size) {
1149 PyErr_SetString(PyExc_ValueError,
1150 "mmap offset is greater than file size");
1151 return NULL;
1152 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001153 if (st.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001154 PyErr_SetString(PyExc_ValueError,
1155 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001156 return NULL;
1157 }
1158 map_size = (Py_ssize_t) (st.st_size - offset);
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001159 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001160 PyErr_SetString(PyExc_ValueError,
1161 "mmap length is greater than file size");
1162 return NULL;
1163 }
1164 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001165#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001166 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1167 if (m_obj == NULL) {return NULL;}
1168 m_obj->data = NULL;
1169 m_obj->size = (size_t) map_size;
1170 m_obj->pos = (size_t) 0;
1171 m_obj->exports = 0;
1172 m_obj->offset = offset;
1173 if (fd == -1) {
1174 m_obj->fd = -1;
1175 /* Assume the caller wants to map anonymous memory.
1176 This is the same behaviour as Windows. mmap.mmap(-1, size)
1177 on both Windows and Unix map anonymous memory.
1178 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001179#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001180 /* BSD way to map anonymous memory */
1181 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001182#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001183 /* SVR4 method to map anonymous memory is to open /dev/zero */
1184 fd = devzero = open("/dev/zero", O_RDWR);
1185 if (devzero == -1) {
1186 Py_DECREF(m_obj);
1187 PyErr_SetFromErrno(mmap_module_error);
1188 return NULL;
1189 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001190#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001191 } else {
1192 m_obj->fd = dup(fd);
1193 if (m_obj->fd == -1) {
1194 Py_DECREF(m_obj);
1195 PyErr_SetFromErrno(mmap_module_error);
1196 return NULL;
1197 }
1198 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001199
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001200 m_obj->data = mmap(NULL, map_size,
1201 prot, flags,
1202 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001203
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001204 if (devzero != -1) {
1205 close(devzero);
1206 }
1207
1208 if (m_obj->data == (char *)-1) {
1209 m_obj->data = NULL;
1210 Py_DECREF(m_obj);
1211 PyErr_SetFromErrno(mmap_module_error);
1212 return NULL;
1213 }
1214 m_obj->access = (access_mode)access;
1215 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001216}
1217#endif /* UNIX */
1218
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001219#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001220
1221/* A note on sizes and offsets: while the actual map size must hold in a
1222 Py_ssize_t, both the total file size and the start offset can be longer
1223 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1224*/
1225
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001226static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001227new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001228{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001229 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001230 PyObject *map_size_obj = NULL;
1231 Py_ssize_t map_size;
1232 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001233 DWORD off_hi; /* upper 32 bits of offset */
1234 DWORD off_lo; /* lower 32 bits of offset */
1235 DWORD size_hi; /* upper 32 bits of size */
1236 DWORD size_lo; /* lower 32 bits of size */
1237 char *tagname = "";
1238 DWORD dwErr = 0;
1239 int fileno;
1240 HANDLE fh = 0;
1241 int access = (access_mode)ACCESS_DEFAULT;
1242 DWORD flProtect, dwDesiredAccess;
1243 static char *keywords[] = { "fileno", "length",
1244 "tagname",
1245 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001246
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001247 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001248 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001249 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001250 return NULL;
1251 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001252
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001253 switch((access_mode)access) {
1254 case ACCESS_READ:
1255 flProtect = PAGE_READONLY;
1256 dwDesiredAccess = FILE_MAP_READ;
1257 break;
1258 case ACCESS_DEFAULT: case ACCESS_WRITE:
1259 flProtect = PAGE_READWRITE;
1260 dwDesiredAccess = FILE_MAP_WRITE;
1261 break;
1262 case ACCESS_COPY:
1263 flProtect = PAGE_WRITECOPY;
1264 dwDesiredAccess = FILE_MAP_COPY;
1265 break;
1266 default:
1267 return PyErr_Format(PyExc_ValueError,
1268 "mmap invalid access parameter.");
1269 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001270
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001271 map_size = _GetMapSize(map_size_obj, "size");
1272 if (map_size < 0)
1273 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001274 if (offset < 0) {
1275 PyErr_SetString(PyExc_OverflowError,
1276 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001277 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001278 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001279
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001280 /* assume -1 and 0 both mean invalid filedescriptor
1281 to 'anonymously' map memory.
1282 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1283 XXX: Should this code be added?
1284 if (fileno == 0)
1285 PyErr_WarnEx(PyExc_DeprecationWarning,
1286 "don't use 0 for anonymous memory",
1287 1);
1288 */
1289 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001290 /* Ensure that fileno is within the CRT's valid range */
1291 if (_PyVerify_fd(fileno) == 0) {
1292 PyErr_SetFromErrno(mmap_module_error);
1293 return NULL;
1294 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001295 fh = (HANDLE)_get_osfhandle(fileno);
1296 if (fh==(HANDLE)-1) {
1297 PyErr_SetFromErrno(mmap_module_error);
1298 return NULL;
1299 }
1300 /* Win9x appears to need us seeked to zero */
1301 lseek(fileno, 0, SEEK_SET);
1302 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001303
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001304 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1305 if (m_obj == NULL)
1306 return NULL;
1307 /* Set every field to an invalid marker, so we can safely
1308 destruct the object in the face of failure */
1309 m_obj->data = NULL;
1310 m_obj->file_handle = INVALID_HANDLE_VALUE;
1311 m_obj->map_handle = NULL;
1312 m_obj->tagname = NULL;
1313 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001314
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001315 if (fh) {
1316 /* It is necessary to duplicate the handle, so the
1317 Python code can close it on us */
1318 if (!DuplicateHandle(
1319 GetCurrentProcess(), /* source process handle */
1320 fh, /* handle to be duplicated */
1321 GetCurrentProcess(), /* target proc handle */
1322 (LPHANDLE)&m_obj->file_handle, /* result */
1323 0, /* access - ignored due to options value */
1324 FALSE, /* inherited by child processes? */
1325 DUPLICATE_SAME_ACCESS)) { /* options */
1326 dwErr = GetLastError();
1327 Py_DECREF(m_obj);
1328 PyErr_SetFromWindowsErr(dwErr);
1329 return NULL;
1330 }
1331 if (!map_size) {
1332 DWORD low,high;
1333 low = GetFileSize(fh, &high);
1334 /* low might just happen to have the value INVALID_FILE_SIZE;
1335 so we need to check the last error also. */
1336 if (low == INVALID_FILE_SIZE &&
1337 (dwErr = GetLastError()) != NO_ERROR) {
1338 Py_DECREF(m_obj);
1339 return PyErr_SetFromWindowsErr(dwErr);
1340 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001341
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001342 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001343 if (size == 0) {
1344 PyErr_SetString(PyExc_ValueError,
1345 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001346 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001347 return NULL;
1348 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001349 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001350 PyErr_SetString(PyExc_ValueError,
1351 "mmap offset is greater than file size");
1352 Py_DECREF(m_obj);
1353 return NULL;
1354 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001355 if (size - offset > PY_SSIZE_T_MAX) {
1356 PyErr_SetString(PyExc_ValueError,
1357 "mmap length is too large");
1358 Py_DECREF(m_obj);
1359 return NULL;
1360 }
1361 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001362 } else {
1363 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001364 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001365 }
1366 }
1367 else {
1368 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001369 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001370 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001371
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001372 /* set the initial position */
1373 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001374
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001375 m_obj->exports = 0;
1376 /* set the tag name */
1377 if (tagname != NULL && *tagname != '\0') {
1378 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1379 if (m_obj->tagname == NULL) {
1380 PyErr_NoMemory();
1381 Py_DECREF(m_obj);
1382 return NULL;
1383 }
1384 strcpy(m_obj->tagname, tagname);
1385 }
1386 else
1387 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001388
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001389 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001390 size_hi = (DWORD)(size >> 32);
1391 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001392 off_hi = (DWORD)(offset >> 32);
1393 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001394 /* For files, it would be sufficient to pass 0 as size.
1395 For anonymous maps, we have to pass the size explicitly. */
1396 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1397 NULL,
1398 flProtect,
1399 size_hi,
1400 size_lo,
1401 m_obj->tagname);
1402 if (m_obj->map_handle != NULL) {
1403 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1404 dwDesiredAccess,
1405 off_hi,
1406 off_lo,
1407 m_obj->size);
1408 if (m_obj->data != NULL)
1409 return (PyObject *)m_obj;
1410 else {
1411 dwErr = GetLastError();
1412 CloseHandle(m_obj->map_handle);
1413 m_obj->map_handle = NULL;
1414 }
1415 } else
1416 dwErr = GetLastError();
1417 Py_DECREF(m_obj);
1418 PyErr_SetFromWindowsErr(dwErr);
1419 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001420}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001421#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001422
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001423static void
1424setint(PyObject *d, const char *name, long value)
1425{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001426 PyObject *o = PyLong_FromLong(value);
1427 if (o && PyDict_SetItemString(d, name, o) == 0) {
1428 Py_DECREF(o);
1429 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001430}
1431
Martin v. Löwis1a214512008-06-11 05:26:20 +00001432
1433static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001434 PyModuleDef_HEAD_INIT,
1435 "mmap",
1436 NULL,
1437 -1,
1438 NULL,
1439 NULL,
1440 NULL,
1441 NULL,
1442 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001443};
1444
Mark Hammond62b1ab12002-07-23 06:31:15 +00001445PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001446PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001447{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001448 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001449
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001450 if (PyType_Ready(&mmap_object_type) < 0)
1451 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001452
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001453 module = PyModule_Create(&mmapmodule);
1454 if (module == NULL)
1455 return NULL;
1456 dict = PyModule_GetDict(module);
1457 if (!dict)
1458 return NULL;
1459 mmap_module_error = PyErr_NewException("mmap.error",
1460 PyExc_EnvironmentError , NULL);
1461 if (mmap_module_error == NULL)
1462 return NULL;
1463 PyDict_SetItemString(dict, "error", mmap_module_error);
1464 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001465#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001466 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001467#endif
1468#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001469 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001470#endif
1471#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001472 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001473#endif
1474
1475#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001476 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001477#endif
1478#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001479 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001480#endif
1481#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001482 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001483#endif
1484#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001485 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001486#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001487#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001488 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1489 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001490#endif
1491
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001492 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001493
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001494 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001495
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001496 setint(dict, "ACCESS_READ", ACCESS_READ);
1497 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1498 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1499 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001500}