blob: cf0b687636ef25fcc3713938b70644f183d2995e [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
Tim Peters5ebfd362001-11-13 23:11:19 +000081typedef enum
82{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000083 ACCESS_DEFAULT,
84 ACCESS_READ,
85 ACCESS_WRITE,
86 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000087} access_mode;
88
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000089typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000090 PyObject_HEAD
91 char * data;
92 size_t size;
93 size_t pos; /* relative to offset */
Antoine Pitrou97696cb2011-02-21 23:46:27 +000094#ifdef MS_WINDOWS
95 PY_LONG_LONG offset;
96#else
97 off_t offset;
98#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000099 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000100
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000101#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000102 HANDLE map_handle;
103 HANDLE file_handle;
104 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000105#endif
106
107#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000108 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000109#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000110
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000111 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000112} mmap_object;
113
Tim Peters5ebfd362001-11-13 23:11:19 +0000114
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000115static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000116mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000117{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000118#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000119 if (m_obj->data != NULL)
120 UnmapViewOfFile (m_obj->data);
121 if (m_obj->map_handle != NULL)
122 CloseHandle (m_obj->map_handle);
123 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
124 CloseHandle (m_obj->file_handle);
125 if (m_obj->tagname)
126 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000127#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000128
129#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000130 if (m_obj->fd >= 0)
131 (void) close(m_obj->fd);
132 if (m_obj->data!=NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000133 munmap(m_obj->data, m_obj->size);
134 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000135#endif /* UNIX */
136
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138}
139
140static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000141mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000143 if (self->exports > 0) {
144 PyErr_SetString(PyExc_BufferError, "cannot close "\
145 "exported pointers exist");
146 return NULL;
147 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000148#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000149 /* For each resource we maintain, we need to check
150 the value is valid, and if so, free the resource
151 and set the member value to an invalid value so
152 the dealloc does not attempt to resource clearing
153 again.
154 TODO - should we check for errors in the close operations???
155 */
156 if (self->data != NULL) {
157 UnmapViewOfFile(self->data);
158 self->data = NULL;
159 }
160 if (self->map_handle != NULL) {
161 CloseHandle(self->map_handle);
162 self->map_handle = NULL;
163 }
164 if (self->file_handle != INVALID_HANDLE_VALUE) {
165 CloseHandle(self->file_handle);
166 self->file_handle = INVALID_HANDLE_VALUE;
167 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000168#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000169
170#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 if (0 <= self->fd)
172 (void) close(self->fd);
173 self->fd = -1;
174 if (self->data != NULL) {
175 munmap(self->data, self->size);
176 self->data = NULL;
177 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000178#endif
179
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000180 Py_INCREF(Py_None);
181 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000182}
183
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000184#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000185#define CHECK_VALID(err) \
186do { \
187 if (self->map_handle == NULL) { \
188 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
189 return err; \
190 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000191} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000192#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000193
194#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195#define CHECK_VALID(err) \
196do { \
197 if (self->data == NULL) { \
198 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
199 return err; \
200 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000201} while (0)
202#endif /* UNIX */
203
204static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000205mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000206 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000207{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 CHECK_VALID(NULL);
209 if (self->pos < self->size) {
210 char value = self->data[self->pos];
211 self->pos += 1;
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000212 return Py_BuildValue("B", (unsigned char)value);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000213 } else {
214 PyErr_SetString(PyExc_ValueError, "read byte out of range");
215 return NULL;
216 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217}
218
219static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000220mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000221 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000222{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223 char *start = self->data+self->pos;
224 char *eof = self->data+self->size;
225 char *eol;
226 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000227
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000228 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000229
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000230 eol = memchr(start, '\n', self->size - self->pos);
231 if (!eol)
232 eol = eof;
233 else
234 ++eol; /* we're interested in the position after the
235 newline. */
236 result = PyBytes_FromStringAndSize(start, (eol - start));
237 self->pos += (eol - start);
238 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000239}
240
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200241/* Basically the "n" format code with the ability to turn None into -1. */
242static int
243mmap_convert_ssize_t(PyObject *obj, void *result) {
244 Py_ssize_t limit;
245 if (obj == Py_None) {
246 limit = -1;
247 }
248 else if (PyNumber_Check(obj)) {
249 limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError);
250 if (limit == -1 && PyErr_Occurred())
251 return 0;
252 }
253 else {
254 PyErr_Format(PyExc_TypeError,
255 "integer argument expected, got '%.200s'",
256 Py_TYPE(obj)->tp_name);
257 return 0;
258 }
259 *((Py_ssize_t *)result) = limit;
260 return 1;
261}
262
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000263static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000264mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000265 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266{
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200267 Py_ssize_t num_bytes = -1, n;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000269
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 CHECK_VALID(NULL);
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200271 if (!PyArg_ParseTuple(args, "|O&:read", mmap_convert_ssize_t, &num_bytes))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000273
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 /* silently 'adjust' out-of-range requests */
275 assert(self->size >= self->pos);
276 n = self->size - self->pos;
277 /* The difference can overflow, only if self->size is greater than
278 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
279 * because the mapped area and the returned string each need more
280 * than half of the addressable memory. So we clip the size, and let
281 * the code below raise MemoryError.
282 */
283 if (n < 0)
284 n = PY_SSIZE_T_MAX;
285 if (num_bytes < 0 || num_bytes > n) {
286 num_bytes = n;
287 }
288 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
289 self->pos += num_bytes;
290 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000291}
292
293static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000294mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000295 PyObject *args,
296 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000297{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 Py_ssize_t start = self->pos;
299 Py_ssize_t end = self->size;
300 const char *needle;
301 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000302
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 CHECK_VALID(NULL);
304 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
305 &needle, &len, &start, &end)) {
306 return NULL;
307 } else {
308 const char *p, *start_p, *end_p;
309 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000310
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000311 if (start < 0)
312 start += self->size;
313 if (start < 0)
314 start = 0;
315 else if ((size_t)start > self->size)
316 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000317
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000318 if (end < 0)
319 end += self->size;
320 if (end < 0)
321 end = 0;
322 else if ((size_t)end > self->size)
323 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 start_p = self->data + start;
326 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000327
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000328 for (p = (reverse ? end_p - len : start_p);
329 (p >= start_p) && (p + len <= end_p); p += sign) {
330 Py_ssize_t i;
331 for (i = 0; i < len && needle[i] == p[i]; ++i)
332 /* nothing */;
333 if (i == len) {
334 return PyLong_FromSsize_t(p - self->data);
335 }
336 }
337 return PyLong_FromLong(-1);
338 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000339}
340
Georg Brandlfceab5a2008-01-19 20:08:23 +0000341static PyObject *
342mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000343 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000344{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000345 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000346}
347
348static PyObject *
349mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000350 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000351{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000353}
354
Tim Petersec0a5f02006-02-16 23:47:20 +0000355static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000356is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000357{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000358 if (self->access != ACCESS_READ)
359 return 1;
360 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
361 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000362}
363
Tim Petersec0a5f02006-02-16 23:47:20 +0000364static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000365is_resizeable(mmap_object *self)
366{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 if (self->exports > 0) {
368 PyErr_SetString(PyExc_BufferError,
369 "mmap can't resize with extant buffers exported.");
370 return 0;
371 }
372 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
373 return 1;
374 PyErr_Format(PyExc_TypeError,
375 "mmap can't resize a readonly or copy-on-write memory map.");
376 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000377}
378
379
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000380static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000381mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000382 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000383{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 Py_ssize_t length;
385 char *data;
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, "y#:write", &data, &length))
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;
Tim Peters5ebfd362001-11-13 23:11:19 +0000393
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 if ((self->pos + length) > self->size) {
395 PyErr_SetString(PyExc_ValueError, "data out of range");
396 return NULL;
397 }
398 memcpy(self->data+self->pos, data, length);
399 self->pos = self->pos+length;
400 Py_INCREF(Py_None);
401 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000402}
403
404static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000405mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000407{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000409
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000410 CHECK_VALID(NULL);
411 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
412 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000413
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000414 if (!is_writable(self))
415 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000416
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000417 if (self->pos < self->size) {
418 *(self->data+self->pos) = value;
419 self->pos += 1;
420 Py_INCREF(Py_None);
421 return Py_None;
422 }
423 else {
424 PyErr_SetString(PyExc_ValueError, "write byte out of range");
425 return NULL;
426 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000427}
Tim Petersec0a5f02006-02-16 23:47:20 +0000428
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000430mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000431 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000432{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000433 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000434
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000435#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000436 if (self->file_handle != INVALID_HANDLE_VALUE) {
437 DWORD low,high;
438 PY_LONG_LONG size;
439 low = GetFileSize(self->file_handle, &high);
440 if (low == INVALID_FILE_SIZE) {
441 /* It might be that the function appears to have failed,
442 when indeed its size equals INVALID_FILE_SIZE */
443 DWORD error = GetLastError();
444 if (error != NO_ERROR)
445 return PyErr_SetFromWindowsErr(error);
446 }
447 if (!high && low < LONG_MAX)
448 return PyLong_FromLong((long)low);
449 size = (((PY_LONG_LONG)high)<<32) + low;
450 return PyLong_FromLongLong(size);
451 } else {
452 return PyLong_FromSsize_t(self->size);
453 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000454#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000455
456#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000457 {
458 struct stat buf;
459 if (-1 == fstat(self->fd, &buf)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200460 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000461 return NULL;
462 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000463#ifdef HAVE_LARGEFILE_SUPPORT
464 return PyLong_FromLongLong(buf.st_size);
465#else
466 return PyLong_FromLong(buf.st_size);
467#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000469#endif /* UNIX */
470}
471
472/* This assumes that you want the entire file mapped,
473 / and when recreating the map will make the new file
474 / have the new size
475 /
476 / Is this really necessary? This could easily be done
477 / from python by just closing and re-opening with the
478 / new size?
479 */
480
481static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000482mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000483 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000484{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000485 Py_ssize_t new_size;
486 CHECK_VALID(NULL);
487 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
488 !is_resizeable(self)) {
489 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000490#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000491 } else {
492 DWORD dwErrCode = 0;
493 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
494 /* First, unmap the file view */
495 UnmapViewOfFile(self->data);
496 self->data = NULL;
497 /* Close the mapping object */
498 CloseHandle(self->map_handle);
499 self->map_handle = NULL;
500 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000501 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
502 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
503 off_hi = (DWORD)(self->offset >> 32);
504 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000505 SetFilePointer(self->file_handle,
506 newSizeLow, &newSizeHigh, FILE_BEGIN);
507 /* Change the size of the file */
508 SetEndOfFile(self->file_handle);
509 /* Create another mapping object and remap the file view */
510 self->map_handle = CreateFileMapping(
511 self->file_handle,
512 NULL,
513 PAGE_READWRITE,
514 0,
515 0,
516 self->tagname);
517 if (self->map_handle != NULL) {
518 self->data = (char *) MapViewOfFile(self->map_handle,
519 FILE_MAP_WRITE,
520 off_hi,
521 off_lo,
522 new_size);
523 if (self->data != NULL) {
524 self->size = new_size;
525 Py_INCREF(Py_None);
526 return Py_None;
527 } else {
528 dwErrCode = GetLastError();
529 CloseHandle(self->map_handle);
530 self->map_handle = NULL;
531 }
532 } else {
533 dwErrCode = GetLastError();
534 }
535 PyErr_SetFromWindowsErr(dwErrCode);
536 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000537#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000538
539#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000540#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000541 } else {
542 PyErr_SetString(PyExc_SystemError,
543 "mmap: resizing not available--no mremap()");
544 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000545#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000546 } else {
547 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000548
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000549 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200550 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000551 return NULL;
552 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000554#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000555 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000556#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000557 #if defined(__NetBSD__)
558 newmap = mremap(self->data, self->size, self->data, new_size, 0);
559 #else
560 newmap = mremap(self->data, self->size, new_size, 0);
561 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000562#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000563 if (newmap == (void *)-1)
564 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200565 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000566 return NULL;
567 }
568 self->data = newmap;
569 self->size = new_size;
570 Py_INCREF(Py_None);
571 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000572#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000573#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000574 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000575}
576
577static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000578mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000579{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000580 CHECK_VALID(NULL);
581 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000582}
583
584static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000585mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000586{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000587 Py_ssize_t offset = 0;
588 Py_ssize_t size = self->size;
589 CHECK_VALID(NULL);
590 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
591 return NULL;
592 if ((size_t)(offset + size) > self->size) {
593 PyErr_SetString(PyExc_ValueError, "flush values out of range");
594 return NULL;
595 }
R. David Murraye194dd62010-10-18 01:14:06 +0000596
597 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
598 return PyLong_FromLong(0);
599
Christian Heimesaf98da12008-01-27 15:18:18 +0000600#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000601 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000602#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000603 /* XXX semantics of return value? */
604 /* XXX flags for msync? */
605 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200606 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000607 return NULL;
608 }
609 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000610#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000611 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
612 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000613#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000614}
615
616static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000617mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000618{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000619 Py_ssize_t dist;
620 int how=0;
621 CHECK_VALID(NULL);
622 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
623 return NULL;
624 else {
625 size_t where;
626 switch (how) {
627 case 0: /* relative to start */
628 if (dist < 0)
629 goto onoutofrange;
630 where = dist;
631 break;
632 case 1: /* relative to current position */
633 if ((Py_ssize_t)self->pos + dist < 0)
634 goto onoutofrange;
635 where = self->pos + dist;
636 break;
637 case 2: /* relative to end */
638 if ((Py_ssize_t)self->size + dist < 0)
639 goto onoutofrange;
640 where = self->size + dist;
641 break;
642 default:
643 PyErr_SetString(PyExc_ValueError, "unknown seek type");
644 return NULL;
645 }
646 if (where > self->size)
647 goto onoutofrange;
648 self->pos = where;
649 Py_INCREF(Py_None);
650 return Py_None;
651 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000652
Tim Peters5ebfd362001-11-13 23:11:19 +0000653 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000654 PyErr_SetString(PyExc_ValueError, "seek out of range");
655 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000656}
657
658static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000659mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000660{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000661 unsigned long dest, src, cnt;
662 CHECK_VALID(NULL);
663 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
664 !is_writable(self)) {
665 return NULL;
666 } else {
667 /* bounds check the values */
Brett Cannon5fac8af2011-06-06 20:22:56 -0700668 if ((cnt + dest) < cnt || (cnt + src) < cnt ||
669 src > self->size || (src + cnt) > self->size ||
670 dest > self->size || (dest + cnt) > self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000671 PyErr_SetString(PyExc_ValueError,
672 "source, destination, or count out of range");
673 return NULL;
674 }
675 memmove(self->data+dest, self->data+src, cnt);
676 Py_INCREF(Py_None);
677 return Py_None;
678 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679}
680
Georg Brandl0bccc182010-08-01 14:50:00 +0000681static PyObject *
682mmap_closed_get(mmap_object *self)
683{
684#ifdef MS_WINDOWS
685 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
686#elif defined(UNIX)
687 return PyBool_FromLong(self->data == NULL ? 1 : 0);
688#endif
689}
690
691static PyObject *
692mmap__enter__method(mmap_object *self, PyObject *args)
693{
694 CHECK_VALID(NULL);
695
696 Py_INCREF(self);
697 return (PyObject *)self;
698}
699
700static PyObject *
701mmap__exit__method(PyObject *self, PyObject *args)
702{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200703 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200704
705 return _PyObject_CallMethodId(self, &PyId_close, NULL);
Georg Brandl0bccc182010-08-01 14:50:00 +0000706}
707
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000708static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000709 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
710 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
711 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
712 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
713 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
714 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
715 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
716 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
717 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
718 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
719 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
720 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
721 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
722 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000723 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
724 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000725 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000726};
727
Georg Brandl0bccc182010-08-01 14:50:00 +0000728static PyGetSetDef mmap_object_getset[] = {
729 {"closed", (getter) mmap_closed_get, NULL, NULL},
730 {NULL}
731};
732
733
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000734/* Functions for treating an mmap'ed file as a buffer */
735
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000736static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000737mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000738{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000739 CHECK_VALID(-1);
740 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
741 (self->access == ACCESS_READ), flags) < 0)
742 return -1;
743 self->exports++;
744 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000745}
746
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000747static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000748mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000749{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000750 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000751}
752
Martin v. Löwis18e16552006-02-15 17:27:45 +0000753static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000754mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000756 CHECK_VALID(-1);
757 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000758}
759
760static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000761mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000762{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000763 CHECK_VALID(NULL);
764 if (i < 0 || (size_t)i >= self->size) {
765 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
766 return NULL;
767 }
768 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000769}
770
771static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000772mmap_subscript(mmap_object *self, PyObject *item)
773{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000774 CHECK_VALID(NULL);
775 if (PyIndex_Check(item)) {
776 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
777 if (i == -1 && PyErr_Occurred())
778 return NULL;
779 if (i < 0)
780 i += self->size;
781 if (i < 0 || (size_t)i >= self->size) {
782 PyErr_SetString(PyExc_IndexError,
783 "mmap index out of range");
784 return NULL;
785 }
786 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
787 }
788 else if (PySlice_Check(item)) {
789 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000790
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000791 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000792 &start, &stop, &step, &slicelen) < 0) {
793 return NULL;
794 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000795
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000796 if (slicelen <= 0)
797 return PyBytes_FromStringAndSize("", 0);
798 else if (step == 1)
799 return PyBytes_FromStringAndSize(self->data + start,
800 slicelen);
801 else {
802 char *result_buf = (char *)PyMem_Malloc(slicelen);
803 Py_ssize_t cur, i;
804 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000805
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000806 if (result_buf == NULL)
807 return PyErr_NoMemory();
808 for (cur = start, i = 0; i < slicelen;
809 cur += step, i++) {
810 result_buf[i] = self->data[cur];
811 }
812 result = PyBytes_FromStringAndSize(result_buf,
813 slicelen);
814 PyMem_Free(result_buf);
815 return result;
816 }
817 }
818 else {
819 PyErr_SetString(PyExc_TypeError,
820 "mmap indices must be integers");
821 return NULL;
822 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000823}
824
825static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000826mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000827{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000828 CHECK_VALID(NULL);
829 PyErr_SetString(PyExc_SystemError,
830 "mmaps don't support concatenation");
831 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000832}
833
834static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000835mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000836{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000837 CHECK_VALID(NULL);
838 PyErr_SetString(PyExc_SystemError,
839 "mmaps don't support repeat operation");
840 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000841}
842
843static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000844mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000845{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000846 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000847
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000848 CHECK_VALID(-1);
849 if (i < 0 || (size_t)i >= self->size) {
850 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
851 return -1;
852 }
853 if (v == NULL) {
854 PyErr_SetString(PyExc_TypeError,
855 "mmap object doesn't support item deletion");
856 return -1;
857 }
858 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
859 PyErr_SetString(PyExc_IndexError,
860 "mmap assignment must be length-1 bytes()");
861 return -1;
862 }
863 if (!is_writable(self))
864 return -1;
865 buf = PyBytes_AsString(v);
866 self->data[i] = buf[0];
867 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000868}
869
Thomas Woutersed03b412007-08-28 21:37:11 +0000870static int
871mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
872{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000873 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000874
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000875 if (!is_writable(self))
876 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000877
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000878 if (PyIndex_Check(item)) {
879 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
880 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000881
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000882 if (i == -1 && PyErr_Occurred())
883 return -1;
884 if (i < 0)
885 i += self->size;
886 if (i < 0 || (size_t)i >= self->size) {
887 PyErr_SetString(PyExc_IndexError,
888 "mmap index out of range");
889 return -1;
890 }
891 if (value == NULL) {
892 PyErr_SetString(PyExc_TypeError,
893 "mmap doesn't support item deletion");
894 return -1;
895 }
896 if (!PyIndex_Check(value)) {
897 PyErr_SetString(PyExc_TypeError,
898 "mmap item value must be an int");
899 return -1;
900 }
901 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
902 if (v == -1 && PyErr_Occurred())
903 return -1;
904 if (v < 0 || v > 255) {
905 PyErr_SetString(PyExc_ValueError,
906 "mmap item value must be "
907 "in range(0, 256)");
908 return -1;
909 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000910 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000911 return 0;
912 }
913 else if (PySlice_Check(item)) {
914 Py_ssize_t start, stop, step, slicelen;
915 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000916
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000917 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000918 self->size, &start, &stop,
919 &step, &slicelen) < 0) {
920 return -1;
921 }
922 if (value == NULL) {
923 PyErr_SetString(PyExc_TypeError,
924 "mmap object doesn't support slice deletion");
925 return -1;
926 }
927 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
928 return -1;
929 if (vbuf.len != slicelen) {
930 PyErr_SetString(PyExc_IndexError,
931 "mmap slice assignment is wrong size");
932 PyBuffer_Release(&vbuf);
933 return -1;
934 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000935
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000936 if (slicelen == 0) {
937 }
938 else if (step == 1) {
939 memcpy(self->data + start, vbuf.buf, slicelen);
940 }
941 else {
942 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000943
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000944 for (cur = start, i = 0;
945 i < slicelen;
946 cur += step, i++)
947 {
948 self->data[cur] = ((char *)vbuf.buf)[i];
949 }
950 }
951 PyBuffer_Release(&vbuf);
952 return 0;
953 }
954 else {
955 PyErr_SetString(PyExc_TypeError,
956 "mmap indices must be integer");
957 return -1;
958 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000959}
960
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000961static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000962 (lenfunc)mmap_length, /*sq_length*/
963 (binaryfunc)mmap_concat, /*sq_concat*/
964 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
965 (ssizeargfunc)mmap_item, /*sq_item*/
966 0, /*sq_slice*/
967 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
968 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000969};
970
Thomas Woutersed03b412007-08-28 21:37:11 +0000971static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000972 (lenfunc)mmap_length,
973 (binaryfunc)mmap_subscript,
974 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000975};
976
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000977static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000978 (getbufferproc)mmap_buffer_getbuf,
979 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000980};
981
Georg Brandl86def6c2008-01-21 20:36:10 +0000982static PyObject *
983new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
984
Christian Heimese1c98112008-01-21 11:20:28 +0000985PyDoc_STRVAR(mmap_doc,
986"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
987\n\
988Maps length bytes from the file specified by the file handle fileno,\n\
989and returns a mmap object. If length is larger than the current size\n\
990of the file, the file is extended to contain length bytes. If length\n\
991is 0, the maximum length of the map is the current size of the file,\n\
992except that if the file is empty Windows raises an exception (you cannot\n\
993create an empty mapping on Windows).\n\
994\n\
995Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
996\n\
997Maps length bytes from the file specified by the file descriptor fileno,\n\
998and returns a mmap object. If length is 0, the maximum length of the map\n\
999will be the current size of the file when mmap is called.\n\
1000flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1001private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001002object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001003that's shared with all other processes mapping the same areas of the file.\n\
1004The default value is MAP_SHARED.\n\
1005\n\
1006To map anonymous memory, pass -1 as the fileno (both versions).");
1007
1008
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001009static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001010 PyVarObject_HEAD_INIT(NULL, 0)
1011 "mmap.mmap", /* tp_name */
1012 sizeof(mmap_object), /* tp_size */
1013 0, /* tp_itemsize */
1014 /* methods */
1015 (destructor) mmap_object_dealloc, /* tp_dealloc */
1016 0, /* tp_print */
1017 0, /* tp_getattr */
1018 0, /* tp_setattr */
1019 0, /* tp_reserved */
1020 0, /* tp_repr */
1021 0, /* tp_as_number */
1022 &mmap_as_sequence, /*tp_as_sequence*/
1023 &mmap_as_mapping, /*tp_as_mapping*/
1024 0, /*tp_hash*/
1025 0, /*tp_call*/
1026 0, /*tp_str*/
1027 PyObject_GenericGetAttr, /*tp_getattro*/
1028 0, /*tp_setattro*/
1029 &mmap_as_buffer, /*tp_as_buffer*/
1030 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1031 mmap_doc, /*tp_doc*/
1032 0, /* tp_traverse */
1033 0, /* tp_clear */
1034 0, /* tp_richcompare */
1035 0, /* tp_weaklistoffset */
1036 0, /* tp_iter */
1037 0, /* tp_iternext */
1038 mmap_object_methods, /* tp_methods */
1039 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001040 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001041 0, /* tp_base */
1042 0, /* tp_dict */
1043 0, /* tp_descr_get */
1044 0, /* tp_descr_set */
1045 0, /* tp_dictoffset */
1046 0, /* tp_init */
1047 PyType_GenericAlloc, /* tp_alloc */
1048 new_mmap_object, /* tp_new */
1049 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001050};
1051
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001052
1053/* extract the map size from the given PyObject
1054
Thomas Wouters7e474022000-07-16 12:04:32 +00001055 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001056 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001057static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001058_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001059{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001060 if (o == NULL)
1061 return 0;
1062 if (PyIndex_Check(o)) {
1063 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1064 if (i==-1 && PyErr_Occurred())
1065 return -1;
1066 if (i < 0) {
1067 PyErr_Format(PyExc_OverflowError,
1068 "memory mapped %s must be positive",
1069 param);
1070 return -1;
1071 }
1072 return i;
1073 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001074
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001075 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1076 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001077}
1078
Tim Petersec0a5f02006-02-16 23:47:20 +00001079#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001080#ifdef HAVE_LARGEFILE_SUPPORT
1081#define _Py_PARSE_OFF_T "L"
1082#else
1083#define _Py_PARSE_OFF_T "l"
1084#endif
1085
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001086static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001087new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088{
Neal Norwitzb5673922002-09-05 21:48:07 +00001089#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001090 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001091#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001092 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001093 PyObject *map_size_obj = NULL;
1094 Py_ssize_t map_size;
1095 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001096 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1097 int devzero = -1;
1098 int access = (int)ACCESS_DEFAULT;
1099 static char *keywords[] = {"fileno", "length",
1100 "flags", "prot",
1101 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001102
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001103 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001104 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001105 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001106 return NULL;
1107 map_size = _GetMapSize(map_size_obj, "size");
1108 if (map_size < 0)
1109 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001110 if (offset < 0) {
1111 PyErr_SetString(PyExc_OverflowError,
1112 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001113 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001114 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001115
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001116 if ((access != (int)ACCESS_DEFAULT) &&
1117 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1118 return PyErr_Format(PyExc_ValueError,
1119 "mmap can't specify both access and flags, prot.");
1120 switch ((access_mode)access) {
1121 case ACCESS_READ:
1122 flags = MAP_SHARED;
1123 prot = PROT_READ;
1124 break;
1125 case ACCESS_WRITE:
1126 flags = MAP_SHARED;
1127 prot = PROT_READ | PROT_WRITE;
1128 break;
1129 case ACCESS_COPY:
1130 flags = MAP_PRIVATE;
1131 prot = PROT_READ | PROT_WRITE;
1132 break;
1133 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001134 /* map prot to access type */
1135 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1136 /* ACCESS_DEFAULT */
1137 }
1138 else if (prot & PROT_WRITE) {
1139 access = ACCESS_WRITE;
1140 }
1141 else {
1142 access = ACCESS_READ;
1143 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001144 break;
1145 default:
1146 return PyErr_Format(PyExc_ValueError,
1147 "mmap invalid access parameter.");
1148 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001149
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001150#ifdef __APPLE__
1151 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1152 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1153 if (fd != -1)
1154 (void)fcntl(fd, F_FULLFSYNC);
1155#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001156#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001157# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001158 /* on OpenVMS we must ensure that all bytes are written to the file */
1159 if (fd != -1) {
1160 fsync(fd);
1161 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001162# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001163 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1164 if (map_size == 0) {
Ross Lagerwalldbfb9b82011-06-25 10:02:37 +02001165 off_t calc_size;
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001166 if (offset >= st.st_size) {
1167 PyErr_SetString(PyExc_ValueError,
1168 "mmap offset is greater than file size");
1169 return NULL;
1170 }
Ross Lagerwalldbfb9b82011-06-25 10:02:37 +02001171 calc_size = st.st_size - offset;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001172 map_size = calc_size;
1173 if (map_size != calc_size) {
1174 PyErr_SetString(PyExc_ValueError,
1175 "mmap length is too large");
1176 return NULL;
1177 }
1178 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001179 PyErr_SetString(PyExc_ValueError,
1180 "mmap length is greater than file size");
1181 return NULL;
1182 }
1183 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001184#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001185 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1186 if (m_obj == NULL) {return NULL;}
1187 m_obj->data = NULL;
1188 m_obj->size = (size_t) map_size;
1189 m_obj->pos = (size_t) 0;
1190 m_obj->exports = 0;
1191 m_obj->offset = offset;
1192 if (fd == -1) {
1193 m_obj->fd = -1;
1194 /* Assume the caller wants to map anonymous memory.
1195 This is the same behaviour as Windows. mmap.mmap(-1, size)
1196 on both Windows and Unix map anonymous memory.
1197 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001198#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001199 /* BSD way to map anonymous memory */
1200 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001201#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001202 /* SVR4 method to map anonymous memory is to open /dev/zero */
1203 fd = devzero = open("/dev/zero", O_RDWR);
1204 if (devzero == -1) {
1205 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001206 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001207 return NULL;
1208 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001209#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001210 } else {
1211 m_obj->fd = dup(fd);
1212 if (m_obj->fd == -1) {
1213 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001214 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001215 return NULL;
1216 }
1217 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001218
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001219 m_obj->data = mmap(NULL, map_size,
1220 prot, flags,
1221 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001222
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001223 if (devzero != -1) {
1224 close(devzero);
1225 }
1226
1227 if (m_obj->data == (char *)-1) {
1228 m_obj->data = NULL;
1229 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001230 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001231 return NULL;
1232 }
1233 m_obj->access = (access_mode)access;
1234 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001235}
1236#endif /* UNIX */
1237
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001238#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001239
1240/* A note on sizes and offsets: while the actual map size must hold in a
1241 Py_ssize_t, both the total file size and the start offset can be longer
1242 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1243*/
1244
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001245static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001246new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001247{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001248 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001249 PyObject *map_size_obj = NULL;
1250 Py_ssize_t map_size;
1251 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001252 DWORD off_hi; /* upper 32 bits of offset */
1253 DWORD off_lo; /* lower 32 bits of offset */
1254 DWORD size_hi; /* upper 32 bits of size */
1255 DWORD size_lo; /* lower 32 bits of size */
1256 char *tagname = "";
1257 DWORD dwErr = 0;
1258 int fileno;
1259 HANDLE fh = 0;
1260 int access = (access_mode)ACCESS_DEFAULT;
1261 DWORD flProtect, dwDesiredAccess;
1262 static char *keywords[] = { "fileno", "length",
1263 "tagname",
1264 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001265
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001266 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001267 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001268 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001269 return NULL;
1270 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001271
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001272 switch((access_mode)access) {
1273 case ACCESS_READ:
1274 flProtect = PAGE_READONLY;
1275 dwDesiredAccess = FILE_MAP_READ;
1276 break;
1277 case ACCESS_DEFAULT: case ACCESS_WRITE:
1278 flProtect = PAGE_READWRITE;
1279 dwDesiredAccess = FILE_MAP_WRITE;
1280 break;
1281 case ACCESS_COPY:
1282 flProtect = PAGE_WRITECOPY;
1283 dwDesiredAccess = FILE_MAP_COPY;
1284 break;
1285 default:
1286 return PyErr_Format(PyExc_ValueError,
1287 "mmap invalid access parameter.");
1288 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001289
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001290 map_size = _GetMapSize(map_size_obj, "size");
1291 if (map_size < 0)
1292 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001293 if (offset < 0) {
1294 PyErr_SetString(PyExc_OverflowError,
1295 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001296 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001297 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001298
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001299 /* assume -1 and 0 both mean invalid filedescriptor
1300 to 'anonymously' map memory.
1301 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1302 XXX: Should this code be added?
1303 if (fileno == 0)
1304 PyErr_WarnEx(PyExc_DeprecationWarning,
1305 "don't use 0 for anonymous memory",
1306 1);
1307 */
1308 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001309 /* Ensure that fileno is within the CRT's valid range */
1310 if (_PyVerify_fd(fileno) == 0) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001311 PyErr_SetFromErrno(PyExc_OSError);
Brian Curtinea47eaa2010-08-01 15:26:26 +00001312 return NULL;
1313 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001314 fh = (HANDLE)_get_osfhandle(fileno);
1315 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001316 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001317 return NULL;
1318 }
1319 /* Win9x appears to need us seeked to zero */
1320 lseek(fileno, 0, SEEK_SET);
1321 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001322
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001323 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1324 if (m_obj == NULL)
1325 return NULL;
1326 /* Set every field to an invalid marker, so we can safely
1327 destruct the object in the face of failure */
1328 m_obj->data = NULL;
1329 m_obj->file_handle = INVALID_HANDLE_VALUE;
1330 m_obj->map_handle = NULL;
1331 m_obj->tagname = NULL;
1332 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001333
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001334 if (fh) {
1335 /* It is necessary to duplicate the handle, so the
1336 Python code can close it on us */
1337 if (!DuplicateHandle(
1338 GetCurrentProcess(), /* source process handle */
1339 fh, /* handle to be duplicated */
1340 GetCurrentProcess(), /* target proc handle */
1341 (LPHANDLE)&m_obj->file_handle, /* result */
1342 0, /* access - ignored due to options value */
1343 FALSE, /* inherited by child processes? */
1344 DUPLICATE_SAME_ACCESS)) { /* options */
1345 dwErr = GetLastError();
1346 Py_DECREF(m_obj);
1347 PyErr_SetFromWindowsErr(dwErr);
1348 return NULL;
1349 }
1350 if (!map_size) {
1351 DWORD low,high;
1352 low = GetFileSize(fh, &high);
1353 /* low might just happen to have the value INVALID_FILE_SIZE;
1354 so we need to check the last error also. */
1355 if (low == INVALID_FILE_SIZE &&
1356 (dwErr = GetLastError()) != NO_ERROR) {
1357 Py_DECREF(m_obj);
1358 return PyErr_SetFromWindowsErr(dwErr);
1359 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001360
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001361 size = (((PY_LONG_LONG) high) << 32) + low;
1362 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001363 PyErr_SetString(PyExc_ValueError,
1364 "mmap offset is greater than file size");
1365 Py_DECREF(m_obj);
1366 return NULL;
1367 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001368 if (offset - size > PY_SSIZE_T_MAX)
1369 /* Map area too large to fit in memory */
1370 m_obj->size = (Py_ssize_t) -1;
1371 else
1372 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001373 } else {
1374 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001375 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001376 }
1377 }
1378 else {
1379 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001380 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001381 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001382
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001383 /* set the initial position */
1384 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001385
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001386 m_obj->exports = 0;
1387 /* set the tag name */
1388 if (tagname != NULL && *tagname != '\0') {
1389 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1390 if (m_obj->tagname == NULL) {
1391 PyErr_NoMemory();
1392 Py_DECREF(m_obj);
1393 return NULL;
1394 }
1395 strcpy(m_obj->tagname, tagname);
1396 }
1397 else
1398 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001399
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001400 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001401 size_hi = (DWORD)(size >> 32);
1402 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001403 off_hi = (DWORD)(offset >> 32);
1404 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001405 /* For files, it would be sufficient to pass 0 as size.
1406 For anonymous maps, we have to pass the size explicitly. */
1407 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1408 NULL,
1409 flProtect,
1410 size_hi,
1411 size_lo,
1412 m_obj->tagname);
1413 if (m_obj->map_handle != NULL) {
1414 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1415 dwDesiredAccess,
1416 off_hi,
1417 off_lo,
1418 m_obj->size);
1419 if (m_obj->data != NULL)
1420 return (PyObject *)m_obj;
1421 else {
1422 dwErr = GetLastError();
1423 CloseHandle(m_obj->map_handle);
1424 m_obj->map_handle = NULL;
1425 }
1426 } else
1427 dwErr = GetLastError();
1428 Py_DECREF(m_obj);
1429 PyErr_SetFromWindowsErr(dwErr);
1430 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001432#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001433
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001434static void
1435setint(PyObject *d, const char *name, long value)
1436{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001437 PyObject *o = PyLong_FromLong(value);
1438 if (o && PyDict_SetItemString(d, name, o) == 0) {
1439 Py_DECREF(o);
1440 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001441}
1442
Martin v. Löwis1a214512008-06-11 05:26:20 +00001443
1444static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001445 PyModuleDef_HEAD_INIT,
1446 "mmap",
1447 NULL,
1448 -1,
1449 NULL,
1450 NULL,
1451 NULL,
1452 NULL,
1453 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001454};
1455
Mark Hammond62b1ab12002-07-23 06:31:15 +00001456PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001457PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001458{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001459 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001460
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001461 if (PyType_Ready(&mmap_object_type) < 0)
1462 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001463
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001464 module = PyModule_Create(&mmapmodule);
1465 if (module == NULL)
1466 return NULL;
1467 dict = PyModule_GetDict(module);
1468 if (!dict)
1469 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001470 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001471 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001472#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001473 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001474#endif
1475#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001476 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001477#endif
1478#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001479 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001480#endif
1481
1482#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001483 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001484#endif
1485#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001486 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001487#endif
1488#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001489 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001490#endif
1491#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001492 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001493#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001494#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001495 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1496 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001497#endif
1498
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001499 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001500
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001501 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001502
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001503 setint(dict, "ACCESS_READ", ACCESS_READ);
1504 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1505 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1506 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001507}